netx-mcp 0.3.1: fix alarm paging, tool-level arg errors, leaner outputs.

- queryNmsAlarms no longer silently clamps page to 2; add is_cleared.
- Bad integer args return invalid_argument tool errors instead of JSON-RPC crashes.
- Nested {"ok": true, "data": {"ok": false}} results are flagged isError.
- stdio: answer ping, never respond to notifications, version from metadata.
- getNmsNe resolves exact host_name/IP; severity lowercased.
- Outputs use nms_ne_id/source=nms; drop ME{uuid} names, echoed field lists, idle hop_* fields.
- Fabric paths: parallel links count as one hop (edges[].parallel_links).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
oliver 2026-10-14 01:46:38 +08:00
parent aac4521766
commit c141a37263
9 changed files with 358 additions and 63 deletions

View file

@ -12,9 +12,9 @@ import pytest
from netx_mcp.http_tools import HTTP_MCP_TOOLS, call_http_tool
def test_http_mcp_tool_list_has_fourteen_tools() -> None:
def test_http_mcp_tool_list_has_fifteen_tools() -> None:
names = [str(t.get("name") or "") for t in HTTP_MCP_TOOLS]
assert len(names) == 14
assert len(names) == 15
assert "queryNmsAlarms" in names
assert "queryNmsAlarmsRaw" in names
assert "execManagedNe" in names
@ -92,7 +92,7 @@ def test_stdio_initialize_and_tools_list() -> None:
assert "error" not in list_resp, list_resp
tools = list_resp["result"]["tools"]
names = {t["name"] for t in tools}
assert len(tools) == 14
assert len(tools) == 15
assert "queryNmsAlarms" in names
assert "findTopologyPaths" in names

View file

@ -3404,6 +3404,27 @@ Management Addresses:
self.assertEqual(full["detail"], "full")
self.assertIn("attrs", full["paths"][0]["nodes"][0])
# A parallel A—B link must not spawn a duplicate 1-hop path.
svc.upsert_fabric_edge(
self.db,
a_node_id=nodes[1].id,
b_node_id=nodes[0].id,
a_port="Gi0/9",
b_port="Gi0/9",
source="manual",
)
self.db.commit()
dedup = svc.find_fabric_paths(
self.db,
from_managed_ne_id=nes[0].id,
to_managed_ne_id=nes[1].id,
max_paths=3,
max_hops=6,
)
self.assertEqual([p["hops"] for p in dedup["paths"]], [1, 2])
self.assertEqual(dedup["paths"][0]["edges"][0]["parallel_links"], 2)
self.assertNotIn("parallel_links", dedup["paths"][1]["edges"][0])
if __name__ == "__main__":
unittest.main()