Merge pull request #281 from nicolabottini/feat/mcp-approve-delete-design

feat(mcp): design_id on approve_device + delete_design tool
This commit is contained in:
Pouzor - Rémy Jardient
2026-07-16 17:04:25 +02:00
committed by GitHub
2 changed files with 23 additions and 0 deletions
+11
View File
@@ -115,6 +115,7 @@ def _build_tools() -> list[Tool]:
"id": {"type": "string"}, "id": {"type": "string"},
"type": {"type": "string", "enum": NODE_TYPES, "default": "generic"}, "type": {"type": "string", "enum": NODE_TYPES, "default": "generic"},
"label": {"type": "string"}, "label": {"type": "string"},
**_DESIGN_ID_FIELD,
}, },
}), }),
Tool(name="hide_device", description="Hide a pending discovered device", inputSchema={ Tool(name="hide_device", description="Hide a pending discovered device", inputSchema={
@@ -162,6 +163,13 @@ def _build_tools() -> list[Tool]:
"design_type": {"type": "string", "description": "Design type (default: network)."}, "design_type": {"type": "string", "description": "Design type (default: network)."},
}, },
}), }),
Tool(name="delete_design", description="Delete a design (canvas) and all its nodes and edges. The last remaining design cannot be deleted.", inputSchema={
"type": "object",
"required": ["design_id"],
"properties": {
"design_id": {"type": "string", "description": "ID of the design to delete. Call list_designs to discover IDs."},
},
}),
] ]
@@ -271,4 +279,7 @@ async def _dispatch(name: str, args: dict) -> dict:
if name == "create_design": if name == "create_design":
return await backend.post("/api/v1/designs", args) return await backend.post("/api/v1/designs", args)
if name == "delete_design":
return await backend.delete(f"/api/v1/designs/{args['design_id']}")
raise ValueError(f"Unknown tool: {name}") raise ValueError(f"Unknown tool: {name}")
+12
View File
@@ -262,6 +262,18 @@ def test_create_design_schema_requires_name():
assert tool.inputSchema["required"] == ["name"] assert tool.inputSchema["required"] == ["name"]
@pytest.mark.anyio
async def test_delete_design(mock_backend):
await _dispatch("delete_design", {"design_id": "d-old"})
mock_backend.delete.assert_called_once_with("/api/v1/designs/d-old")
def test_delete_design_schema_requires_design_id():
tool = next(t for t in TOOLS if t.name == "delete_design")
assert tool.inputSchema["required"] == ["design_id"]
assert "design_id" in tool.inputSchema["properties"]
@pytest.mark.anyio @pytest.mark.anyio
async def test_unknown_tool(): async def test_unknown_tool():
with pytest.raises(ValueError, match="Unknown tool"): with pytest.raises(ValueError, match="Unknown tool"):