From e627481ec26bf13ddf788f9ece1e4c613f0f1289 Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Tue, 16 Jun 2026 12:23:15 +0800 Subject: [PATCH] Fix device_command_run KeyError('commands'): tool desc said show_commands but backend expects commands - Tool description and param schema now use 'commands' (matching ExecuteMultipleDeviceCommands) - Updated error message in handler - Clarified in docstring that this is read-only; use device_config_send for config changes --- gns3server/api/routes/mcp/__init__.py | 5 +++-- gns3server/api/routes/mcp/device_config.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/gns3server/api/routes/mcp/__init__.py b/gns3server/api/routes/mcp/__init__.py index 9e0935ae6..448d93322 100644 --- a/gns3server/api/routes/mcp/__init__.py +++ b/gns3server/api/routes/mcp/__init__.py @@ -1388,17 +1388,18 @@ async def device_config_send( async def device_command_run( project_id: Annotated[str, Field(description="UUID of the project")], device_configs: Annotated[list, Field( - description="List of device commands. Each entry: {\"device_name\": \"R1\", \"show_commands\": [\"show ip int brief\", \"show running-config\"]}" + description="List of device commands. Each entry: {\"device_name\": \"R1\", \"commands\": [\"show ip int brief\", \"show running-config\"]}" )], template: Annotated[str | None, Field(description="Optional Jinja2 template. Use with vars per device. Example: \"show ip route {{ protocol }}\"")] = None, ) -> list[dict[str, Any]]: """Run read-only diagnostic (show) commands on network devices via console. Two modes: - 1. Direct commands: each device has show_commands=[...] + 1. Direct commands: each device has commands=[...] (read-only show/display/ping/traceroute only) 2. Jinja2 template: provide template + vars per device Use this to inspect device status, view configurations, or verify changes. + For configuration changes use device_config_send instead. Devices must be started first. """ params = {"project_id": project_id, "device_configs": device_configs} diff --git a/gns3server/api/routes/mcp/device_config.py b/gns3server/api/routes/mcp/device_config.py index f7a2009ae..3c06cc994 100644 --- a/gns3server/api/routes/mcp/device_config.py +++ b/gns3server/api/routes/mcp/device_config.py @@ -108,7 +108,7 @@ def device_command_run_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) device_configs = params.get("device_configs") template = params.get("template") if not project_id or not device_configs: - return [{"error": "project_id and device_configs (list of {device_name, show_commands}) are required"}] + return [{"error": "project_id and device_configs (list of {device_name, commands}) are required"}] if template: device_configs = _render_template(template, device_configs, commands_field="commands")