diff --git a/docs/features/mcp-service.md b/docs/features/mcp-service.md index ccd02b61c..422b9ca42 100644 --- a/docs/features/mcp-service.md +++ b/docs/features/mcp-service.md @@ -127,7 +127,6 @@ All subsequent tool handler REST API calls use this JWT → zero extra bcrypt | `node_update` | Update node properties | | `node_start` | Start node(s) — `node_id` or `node_ids` array | | `node_stop` | Stop node(s) — `node_id` or `node_ids` array | -| `node_reload` | Reload node(s) — `node_id` or `node_ids` array | | `node_suspend` | Suspend node(s) — `node_id` or `node_ids` array | | `node_console` | Get WebSocket console URL | | `node_file_list` | List files in node directory | @@ -137,7 +136,6 @@ All subsequent tool handler REST API calls use this JWT → zero extra bcrypt | `node_start_all` | Start all nodes | | `node_stop_all` | Stop all nodes | | `node_suspend_all` | Suspend all nodes | -| `node_reload_all` | Reload all nodes | | `node_duplicate` | Duplicate a node | | `node_isolate` | Isolate a node (suspend links) | | `node_unisolate` | Un-isolate a node (resume links) | @@ -288,7 +286,8 @@ device_show_run(project_id, device_configs=[ config = node_file_get(project_id, node_id, "startup-config.cfg") # Restore if config breaks node_file_write(project_id, node_id, "startup-config.cfg", config) -node_reload(project_id, node_id) +node_stop(project_id, node_id) +node_start(project_id, node_id) ``` ### Device Config Workflow diff --git a/gns3server/api/routes/mcp/__init__.py b/gns3server/api/routes/mcp/__init__.py index 032c8269a..03e6ff67a 100644 --- a/gns3server/api/routes/mcp/__init__.py +++ b/gns3server/api/routes/mcp/__init__.py @@ -86,13 +86,13 @@ from .device_config import ( ) from .nodes import ( get_nodes_handler, get_node_handler, start_node_handler, - stop_node_handler, reload_node_handler, suspend_node_handler, + stop_node_handler, suspend_node_handler, create_node_handler, delete_node_handler, update_node_handler, get_node_console_info_handler, list_node_files_handler, get_node_file_handler, write_node_file_handler, delete_node_file_handler, start_all_nodes_handler, stop_all_nodes_handler, - suspend_all_nodes_handler, reload_all_nodes_handler, + suspend_all_nodes_handler, duplicate_node_handler, isolate_node_handler, unisolate_node_handler, get_node_links_handler, ) @@ -470,20 +470,6 @@ async def node_stop( params["node_id"] = node_id return await asyncio.to_thread(_run_handler_sync, stop_node_handler, params) -@mcp.tool() -async def node_reload( - project_id: Annotated[str, Field(description="UUID of the project")], - node_id: Annotated[str | None, Field(description="Node UUID (single mode)")] = None, - node_ids: Annotated[list[str] | None, Field(description="Batch mode: [\"uuid1\",\"uuid2\"] — reload multiple nodes in parallel")] = None, -) -> list[dict[str, Any]]: - """Reload (restart) one or more nodes. Provide node_id for single, or node_ids for batch.""" - params = {"project_id": project_id} - if node_ids: - params["node_ids"] = node_ids - else: - params["node_id"] = node_id - return await asyncio.to_thread(_run_handler_sync, reload_node_handler, params) - @mcp.tool() async def node_suspend( project_id: Annotated[str, Field(description="UUID of the project")], @@ -884,16 +870,6 @@ async def node_suspend_all( }) -@mcp.tool() -async def node_reload_all( - project_id: Annotated[str, Field(description="UUID of the project")], -) -> list[dict[str, Any]]: - """Reload (restart) all nodes in a project.""" - return await asyncio.to_thread(_run_handler_sync, reload_all_nodes_handler, { - "project_id": project_id, - }) - - @mcp.tool() async def node_duplicate( project_id: Annotated[str, Field(description="UUID of the project")], diff --git a/gns3server/api/routes/mcp/nodes.py b/gns3server/api/routes/mcp/nodes.py index dcdfc96c6..0a7c1320c 100644 --- a/gns3server/api/routes/mcp/nodes.py +++ b/gns3server/api/routes/mcp/nodes.py @@ -159,24 +159,6 @@ def stop_node_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[ return {"message": f"Node {node_id} stopped", "node_id": node_id} -def reload_node_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[str, Any]: - project_id = params.get("project_id") - if not project_id: - return {"error": "project_id is required"} - node_ids = params.get("node_ids") - if node_ids: - if not isinstance(node_ids, list): - return {"error": "node_ids must be a list"} - conn = _get_connector(gns3_ctx) - return _batch_lifecycle(project_id, node_ids, "reload", conn, "reloaded") - node_id = params.get("node_id") - if not node_id: - return {"error": "node_id or node_ids is required"} - conn = _get_connector(gns3_ctx) - conn.http_call("post", f"{conn.base_url}/projects/{project_id}/nodes/{node_id}/reload") - return {"message": f"Node {node_id} reloaded", "node_id": node_id} - - def suspend_node_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[str, Any]: project_id = params.get("project_id") if not project_id: @@ -452,15 +434,6 @@ def suspend_all_nodes_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) return {"message": "All nodes suspended", "project_id": project_id} -def reload_all_nodes_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[str, Any]: - project_id = params.get("project_id") - if not project_id: - return {"error": "project_id is required"} - conn = _get_connector(gns3_ctx) - conn.http_call("post", f"{conn.base_url}/projects/{project_id}/nodes/reload") - return {"message": "All nodes reloaded", "project_id": project_id} - - def duplicate_node_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[str, Any]: project_id = params.get("project_id") node_id = params.get("node_id") @@ -556,19 +529,6 @@ NODE_TOOLS = [ }, "handler": stop_node_handler, }, - { - "name": "reload_node", - "description": "Reload (restart) a node in a project", - "parameters": { - "type": "object", - "properties": { - "project_id": {"type": "string", "description": "Project UUID"}, - "node_id": {"type": "string", "description": "Node UUID"}, - }, - "required": ["project_id", "node_id"], - }, - "handler": reload_node_handler, - }, { "name": "suspend_node", "description": "Suspend a node in a project", diff --git a/tests/api/routes/mcp/test_handlers.py b/tests/api/routes/mcp/test_handlers.py index 02b15a989..c181c1c87 100644 --- a/tests/api/routes/mcp/test_handlers.py +++ b/tests/api/routes/mcp/test_handlers.py @@ -200,13 +200,6 @@ class TestNode: result = suspend_node_handler({"project_id": "p1", "node_ids": ["n1"]}, ctx) assert result[0]["status"] == "success" - def test_reload_batch(self, ctx): - from gns3server.api.routes.mcp.nodes import reload_node_handler - with patch(f"{BASE}.{self.mod}._get_connector") as m: - m.return_value = _mock_conn({"status": "started"}) - result = reload_node_handler({"project_id": "p1", "node_ids": ["n1"]}, ctx) - assert result[0]["status"] == "success" - def test_console(self, ctx): from gns3server.api.routes.mcp.nodes import get_node_console_info_handler with patch(f"{BASE}.{self.mod}._get_connector") as m: diff --git a/tests/api/routes/mcp/test_tool_params.py b/tests/api/routes/mcp/test_tool_params.py index 59f634f37..8eee59f72 100644 --- a/tests/api/routes/mcp/test_tool_params.py +++ b/tests/api/routes/mcp/test_tool_params.py @@ -38,7 +38,6 @@ HANDLER_FILES = { "get_node_handler": "nodes.py", "start_node_handler": "nodes.py", "stop_node_handler": "nodes.py", - "reload_node_handler": "nodes.py", "suspend_node_handler": "nodes.py", "create_node_handler": "nodes.py", "delete_node_handler": "nodes.py", @@ -51,7 +50,6 @@ HANDLER_FILES = { "start_all_nodes_handler": "nodes.py", "stop_all_nodes_handler": "nodes.py", "suspend_all_nodes_handler": "nodes.py", - "reload_all_nodes_handler": "nodes.py", "duplicate_node_handler": "nodes.py", "isolate_node_handler": "nodes.py", "unisolate_node_handler": "nodes.py",