From d6c362b3f0185c3c7be1ffcf241a47bb184b2f5d Mon Sep 17 00:00:00 2001 From: YueGuobin Date: Sun, 14 Jun 2026 22:37:10 +0800 Subject: [PATCH] feat: Add fields filter to link_list --- gns3server/api/routes/mcp/__init__.py | 9 ++++++--- gns3server/api/routes/mcp/links.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/gns3server/api/routes/mcp/__init__.py b/gns3server/api/routes/mcp/__init__.py index c08c4507a..d544460a3 100644 --- a/gns3server/api/routes/mcp/__init__.py +++ b/gns3server/api/routes/mcp/__init__.py @@ -569,9 +569,12 @@ async def node_console( # ── Link tools ──────────────────────────────────────────────────────── @mcp.tool() -async def link_list(project_id: str) -> list[dict[str, Any]]: - """List all links in a project.""" - return await asyncio.to_thread(_run_handler_sync, get_links_handler, {"project_id": project_id}) +async def link_list( + project_id: Annotated[str, Field(description="UUID of the project")], + fields: Annotated[list[str] | None, Field(description="Optional: return only these fields. e.g. [\"link_id\",\"nodes\"]. Available: link_id, project_id, link_type, nodes, suspend, filters, capturing, capture_file_name, link_style")] = None, +) -> list[dict[str, Any]]: + """List all links in a project. Use fields=[] to return only what you need.""" + return await asyncio.to_thread(_run_handler_sync, get_links_handler, {"project_id": project_id, "fields": fields}) @mcp.tool() diff --git a/gns3server/api/routes/mcp/links.py b/gns3server/api/routes/mcp/links.py index 0e9be5e29..83627d47c 100644 --- a/gns3server/api/routes/mcp/links.py +++ b/gns3server/api/routes/mcp/links.py @@ -48,12 +48,31 @@ def _get_connector(gns3_ctx: dict[str, Any]): # ── Tool handlers ────────────────────────────────────────────────────────── +VALID_LINK_FIELDS = { + "link_id", "project_id", "link_type", "nodes", "suspend", + "link_style", "filters", "show_filters_icon", + "capturing", "capture_file_name", "capture_file_path", + "capture_compute_id", "wireshark", +} + + def get_links_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) links = conn.http_call("get", f"{conn.base_url}/projects/{project_id}/links").json() + fields = params.get("fields") + if fields: + if not isinstance(fields, list): + return {"error": "fields must be a list, e.g. [\"link_id\", \"nodes\"]"} + invalid = [f for f in fields if f not in VALID_LINK_FIELDS] + if invalid: + return { + "error": f"Unknown fields: {invalid}", + "available_fields": sorted(VALID_LINK_FIELDS), + } + links = [{k: l[k] for k in fields if k in l} for l in links] return {"links": links, "count": len(links)}