fix: forward auto_close in create_project_handler

The MCP project_create tool has passed auto_close=False since 8f8abe410
(2026-06-13), but create_project_handler only forwarded {"name": name}
to the REST API — auto_close was silently dropped and the controller's
Project.__init__ default (True, unchanged since 2016) won. Every project
created via MCP since June has auto_close=true on disk and closes when
the last client disconnects.

- projects.py: forward auto_close when present in params
- test_handlers.py: assert the forwarded json_data (with and without
  auto_close)
- test_tool_params.py: the tool/handler param consistency test never
  actually checked anything — three blind spots now fixed:
  1. dispatch is asyncio.to_thread(_run_handler_sync, ...) whose
     node.func is an Attribute, not a Name — no call ever matched
  2. tools that build 'params' as a variable before passing it were
     skipped; now the initial dict literal is resolved (extra-passed
     direction only)
  3. tool functions are async defs (ast.AsyncFunctionDef) but the
  enclosing-function lookup only matched ast.FunctionDef, so tool_name
  was always None
  Also: map the two marker handlers missing from HANDLER_FILES, skip
  handlers that forward params.items() generically (wildcard), union
  passed keys across multi-branch dispatches (node_create single/batch),
  and drop two dead helpers.

Verified: full suite 1568 passed; reverting the handler fix turns both
test_tool_handler_param_consistency and test_create red.
This commit is contained in:
YueGuobin committed 2026-08-23 08:57:39 +08:00
1 parent 641d10177a
commit d3ceb453a6
3 files changed
+126 -85

No files matched your search

+4 -1
View File
@@ -66,7 +66,10 @@ def create_project_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) ->
if not name:
return {"error": "name is required"}
conn = _get_connector(gns3_ctx)
return conn.http_call("post", f"{conn.base_url}/projects", json_data={"name": name}).json()
json_data: dict[str, Any] = {"name": name}
if params.get("auto_close") is not None:
json_data["auto_close"] = params["auto_close"]
return conn.http_call("post", f"{conn.base_url}/projects", json_data=json_data).json()
def delete_project_handler(params: dict[str, Any], gns3_ctx: dict[str, Any]) -> dict[str, Any]: