MCP server¶
ngsw-mcp exposes the library as Model Context Protocol tools, so an LLM-driven client can inspect
— and, if you let it, reconfigure — your switches.
pip install 'python-netgear-switch-library[mcp]'
ngsw-mcp # stdio: one client, on stdin/stdout
ngsw-mcp --transport streamable-http --host 127.0.0.1 --port 8766 # shared
Transports¶
--transport stdio (the default) serves the one client that spawned the
process. --transport streamable-http listens on --host/--port so any
number of clients share one long-lived server — for example a systemd
socket-activated service that several agents on the same host connect to.
Each option also has an environment form, NGSW_MCP_TRANSPORT,
NGSW_MCP_HOST and NGSW_MCP_PORT (a flag beats the environment), so a
service unit can set them once and keep ExecStart=ngsw-mcp. An invalid
transport or port — from either tier — is rejected at start-up.
Configuring a client¶
A client that spawns its own server (stdio):
{
"mcpServers": {
"netgear": {
"command": "ngsw-mcp",
"env": {
"NGSW_INVENTORY": "/etc/ngsw/inventory.toml"
}
}
}
}
Every tool resolves its target switch through the same resolver the CLI uses
— either a named switch from a TOML inventory (switch= plus config=, or
$NGSW_INVENTORY for the path), or an ad-hoc host= and model= pair,
with credentials layered from arguments, environment and inventory. See
Inventories and credentials.
A client connecting to a shared streamable-http server instead names its URL:
{
"mcpServers": {
"netgear": {"type": "http", "url": "http://127.0.0.1:8765/mcp"}
}
}
Note
$NGSW_INVENTORY is an MCP-server convenience — an MCP client has no
command line to pass --config on. The ngsw CLI requires --config
explicitly.
Read tools¶
Registered unconditionally.
Tool |
Returns |
|---|---|
|
The switches in the configured inventory. |
|
The switch’s real model, from |
Per-port link status and speed. |
|
Per-port byte and packet counters. |
|
VLANs with member, tagged and untagged ports. |
|
Per-port PVID. |
|
The MAC/FDB table. |
|
LLDP neighbours. |
|
Fan, temperature and PSU sensors. |
|
Per-port PoE status and delivered power. |
|
Management IP configuration and base MAC. |
|
|
Every read at once, over one backend. |
|
The complete raw NSDP device record (Plus switches). |
Results are the library’s own dataclasses serialised to plain JSON.
Write tools¶
Only registered when NGSW_MCP_ALLOW_WRITES is truthy. They do not
exist otherwise — a model cannot call a tool that was never advertised.
NGSW_MCP_ALLOW_WRITES=1 ngsw-mcp
set_port_enabled, set_poe, cycle_poe, clear_poe_fault,
set_pvid, set_vlan_membership, create_vlan, delete_vlan,
set_mgmt_ip, upload_certificate, upload_certificate_scp.
Even with writes enabled, each disruptive operation requires the caller to pass
force=true — the same rail the library and the CLI enforce — and
protected_ports from the inventory still applies.
Warning
An MCP tool call is model-initiated. Reconfiguring a live switch is
destructive and can cut you off from the device that carries your management
traffic. Enable writes deliberately, and put your uplinks in
protected_ports first.
Choosing a backend¶
Every read and write tool takes an optional backend argument
(snmp/nsdp/http/ssh/telnet/console), with the same
meaning as everywhere else: that protocol runs, or the call fails. An unknown
name is a ConfigError rather than a silent default.
The two certificate-upload tools deliberately do not take one — their transport is intrinsic to the operation.
Honest refusals¶
An operation a model’s backend genuinely cannot serve returns a structured result rather than an exception or, worse, plausible-looking data:
{
"unsupported": true,
"op": "get_poe",
"detail": "model 'gs110emx': the default backend NSDP cannot serve this operation: NSDP has no PoE status tag ..."
}
Any other library error becomes {"error": "...", "op": "..."}, so the client
sees a clean message rather than a stack trace. Both carry the library’s rule
through: nothing is fabricated, and nothing is quietly answered over a different
protocol.
Implementation¶
See MCP server. The server is built on FastMCP; its tool surface is tested
in tests/test_mcp_server.py.