Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions jmcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,11 +581,9 @@ async def handle_add_device(arguments: dict, context: Context) -> list[types.Con
log.error(f"Unexpected error in add_device: {e}")
return [types.TextContent(type="text", text=f"❌ Failed to add device: {str(e)}")]



def _run_junos_cli_command(router_name: str, command: str, timeout: int = 360) -> str:
def _run_junos_cli_command(router_name: str, command: str, format: str = "text", timeout: int = 360) -> str:
"""Internal helper to connect and run a Junos CLI command."""
log.debug(f"Executing command {command} on router {router_name} with timeout {timeout}s (internal)")
log.debug(f"Executing command {command} on router {router_name} with format {format} and timeout {timeout}s (internal)")
device_info = devices[router_name]
try:
connect_params = prepare_connection_params(device_info, router_name)
Expand All @@ -594,7 +592,12 @@ def _run_junos_cli_command(router_name: str, command: str, timeout: int = 360) -
try:
with Device(**connect_params) as junos_device:
junos_device.timeout = timeout
op = junos_device.cli(command, warning=False)
op = junos_device.cli(command, warning=False, format=format)
if format.lower() == "json":
try:
op = json.dumps(op, indent=2)
except json.JSONDecodeError:
op = f"Error: Could not parse JSON output from command {command}"
return op
except ConnectError as ce:
return f"Connection error to {router_name}: {ce}"
Expand Down Expand Up @@ -689,14 +692,15 @@ async def handle_execute_junos_command(arguments: dict, context: Context) -> lis
start_timestamp = datetime.now(timezone.utc).isoformat()
router_name = arguments.get("router_name", "")
command = arguments.get("command", "")
out_format = arguments.get("format", "text")
timeout = get_timeout_with_fallback(arguments.get("timeout"))

if router_name not in devices:
result = f"Router {router_name} not found in the device mapping."
else:
log.debug(f"Executing command {command} on router {router_name} with timeout {timeout}s")
result = _run_junos_cli_command(router_name, command, timeout)
log.debug(f"Executing command {command} on router {router_name} with format {out_format} and timeout {timeout}s")
result = _run_junos_cli_command(router_name, command, out_format, timeout)

end_time = time.time()
end_timestamp = datetime.now(timezone.utc).isoformat()
execution_duration = round(end_time - start_time, 3)
Expand Down Expand Up @@ -957,6 +961,7 @@ async def list_tools() -> list[types.Tool]:
"properties": {
"router_name": {"type": "string", "description": "The name of the router"},
"command": {"type": "string", "description": "The command to execute on the router"},
"format": {"type": "string", "description": "Output format: text or json", "default": "text"},
"timeout": {"type": "integer", "description": "Command timeout in seconds", "default": 360}
},
"required": ["router_name", "command"]
Expand Down
8 changes: 8 additions & 0 deletions test_junos_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ def main():
help='Enable verbose logging'
)

parser.add_argument(
'--format',
choices=['json', 'text'],
default='text',
help='Output format for command results'
)

args = parser.parse_args()

# Set logging level
Expand Down Expand Up @@ -192,6 +199,7 @@ def main():
result = jmcp._run_junos_cli_command(
args.router,
args.command,
format=args.format,
timeout=args.timeout
)
print("\nResult:")
Expand Down