feat(mcp): expose parent_id in update_node tool
- Add parent_id to NodeUpdate schema in backend so PATCH /nodes/{id}
accepts it (was silently ignored before)
- Expose parent_id in update_node MCP tool schema so the MCP SDK
forwards it to the backend instead of stripping it
- Add regression tests in both backend and MCP layers
This commit is contained in:
@@ -42,6 +42,7 @@ class NodeUpdate(BaseModel):
|
|||||||
notes: str | None = None
|
notes: str | None = None
|
||||||
pos_x: float | None = None
|
pos_x: float | None = None
|
||||||
pos_y: float | None = None
|
pos_y: float | None = None
|
||||||
|
parent_id: str | None = None
|
||||||
container_mode: bool | None = None
|
container_mode: bool | None = None
|
||||||
custom_colors: dict[str, Any] | None = None
|
custom_colors: dict[str, Any] | None = None
|
||||||
custom_icon: str | None = None
|
custom_icon: str | None = None
|
||||||
|
|||||||
@@ -102,6 +102,16 @@ async def test_update_node_container_mode(client: AsyncClient, headers: dict):
|
|||||||
assert res.json()["container_mode"] is True
|
assert res.json()["container_mode"] is True
|
||||||
|
|
||||||
|
|
||||||
|
async def test_update_node_parent_id(client: AsyncClient, headers: dict):
|
||||||
|
parent = await client.post("/api/v1/nodes", json={"type": "proxmox", "label": "PVE", "status": "unknown"}, headers=headers)
|
||||||
|
parent_id = parent.json()["id"]
|
||||||
|
child = await client.post("/api/v1/nodes", json={"type": "lxc", "label": "Child", "status": "unknown"}, headers=headers)
|
||||||
|
child_id = child.json()["id"]
|
||||||
|
res = await client.patch(f"/api/v1/nodes/{child_id}", json={"parent_id": parent_id}, headers=headers)
|
||||||
|
assert res.status_code == 200
|
||||||
|
assert res.json()["parent_id"] == parent_id
|
||||||
|
|
||||||
|
|
||||||
async def test_create_node_requires_auth(client: AsyncClient):
|
async def test_create_node_requires_auth(client: AsyncClient):
|
||||||
res = await client.post("/api/v1/nodes", json={"type": "server", "label": "N", "status": "unknown"})
|
res = await client.post("/api/v1/nodes", json={"type": "server", "label": "N", "status": "unknown"})
|
||||||
assert res.status_code == 401
|
assert res.status_code == 401
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ def register_tools(server: Server):
|
|||||||
"ip": {"type": "string"},
|
"ip": {"type": "string"},
|
||||||
"hostname": {"type": "string"},
|
"hostname": {"type": "string"},
|
||||||
"status": {"type": "string"},
|
"status": {"type": "string"},
|
||||||
|
"parent_id": {"type": "string", "description": "ID of the parent node (e.g. Proxmox host for a VM/LXC). Pass null to detach."},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Tool(name="delete_node", description="Delete a node from the canvas", inputSchema={
|
Tool(name="delete_node", description="Delete a node from the canvas", inputSchema={
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ async def test_update_node(mock_backend):
|
|||||||
mock_backend.patch.assert_called_once_with("/api/v1/nodes/42", {"label": "New name"})
|
mock_backend.patch.assert_called_once_with("/api/v1/nodes/42", {"label": "New name"})
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.anyio
|
||||||
|
async def test_update_node_parent_id(mock_backend):
|
||||||
|
await _dispatch("update_node", {"id": "42", "parent_id": "proxmox-1"})
|
||||||
|
mock_backend.patch.assert_called_once_with("/api/v1/nodes/42", {"parent_id": "proxmox-1"})
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_delete_node(mock_backend):
|
async def test_delete_node(mock_backend):
|
||||||
await _dispatch("delete_node", {"id": "42"})
|
await _dispatch("delete_node", {"id": "42"})
|
||||||
|
|||||||
Reference in New Issue
Block a user