MCP server
Yagra serves an MCP tool surface out of the box, so an AI client — Claude Code, Claude Desktop, or another MCP-capable assistant — can query live monitoring state in natural language.
For example: “which nodes are down?”, “summarize the active alerts”, “show CPU on edge-router-1 for the last hour”, “run anomaly detection and tell me what looks wrong”.
What it is
Section titled “What it is”The server exposes 41 tools: 38 read, 3 write.
The read tools see the same data the WebUI does. The Troubleshoot trio runs the same on-demand analyses the WebUI runs, and both only read stored history and return findings.
The three write tools act on the monitoring system, never on the network itself. There are no tools that configure or change network devices, by design.
The guiding rule is read parity: whatever the WebUI can see, an MCP client can see. A new read endpoint ships with its tool, or with a written reason it has none.
That rule deliberately does not extend to writes. The write surface stays frozen at the three below.
| Tool | What it does | Minimum role |
|---|---|---|
get_fleet_summary |
Fleet health summary: node counts per state, active alert count | Viewer |
list_nodes |
List nodes with rolled-up state, with search | Viewer |
get_node_status |
Full status for one node: summary, active alerts, interfaces, and whether SNMP polling is configured for it | Viewer |
list_node_metrics |
Which metrics a node actually has, whether each is arriving, and how each must be read (a gauge or a counter; one per node, per interface or per table row). Ask this before query_metrics |
Viewer |
list_node_groups |
The folder tree, with map coordinates and optional per-folder health tallies | Viewer |
get_prefix_gaps |
The subnets a folder’s devices carry that its IP prefixes do not cover, with why each is listed | Viewer |
get_site_prefix_gaps |
The same comparison for every site at once: each site’s status and gaps, at most 2,000 gaps shared between sites | Viewer |
get_subnet_overlaps |
Address ranges that more than one site carries — the same range at two sites, or one site’s range inside another’s — each with a status and a hint | Viewer |
get_active_alerts |
Active alerts, newest first, filterable by node and severity | Viewer |
get_alert_history |
Recent alert fires and clears, with paging | Viewer |
alert_trends |
How alerting behaves over time: chronic offenders, recent transitions, or a weekday×hour heat map | Viewer |
list_suppressions |
Maintenance windows and mutes — what is currently silencing alerts | Viewer |
query_metrics |
A node’s metric time series — latest value, a range, or a rate³ | Viewer |
get_interface_series |
One interface’s traffic, packet-rate, error, discard and optical-power history, aligned on a shared time axis | Viewer |
get_interface_thresholds |
Which threshold rules reach one interface, from all six scope levels, and which of them are in force | Operator |
top_metrics |
Rank nodes fleet-wide by any metric | Viewer |
top_interfaces |
Rank interfaces fleet-wide by throughput, errors, discards or biggest change | Viewer |
fleet_throughput |
Aggregate fleet traffic over a window | Viewer |
get_neighbors |
What a node is cabled to (CDP/LLDP), current and as a change log | Viewer |
get_topology |
kind= the dependency graph with root-cause attribution, the derived connectivity links, the operator overrides on them, or the shadow comparison |
Viewer |
list_discovered_endpoints |
Hosts seen on the network that nothing is monitoring, from router ARP caches | Viewer |
list_wireless_aps |
Access points behind the wireless controllers Yagra monitors: state, clients, and which controllers report each one, whether or not it is a node yet | Viewer |
top_flows |
Top flows for one node or the whole fleet: talkers, conversations, ports, protocols, AS | Viewer |
flow_fanout |
Per-source fan-out — distinct destinations and ports (a scan/worm signal) | Viewer |
search_events |
Search passive events: syslog, traps, webhooks | Viewer |
event_stats |
Passive-event triage stats: noisiest nodes, severity mix, unmatched signatures | Viewer |
run_analysis |
Run an on-demand Troubleshoot analysis and wait for findings | Operator |
get_analysis_findings |
Fetch an analysis run and its findings by id | Viewer |
list_analyses |
List recent analysis runs — narrowed by tool, state or start time, as the WebUI’s runs list is — or the recurring schedules | Viewer |
search_analysis_findings |
Search Troubleshoot findings across every run, by node, folder, severity or time | Viewer |
get_system_health |
section= Yagra’s own state: the poller fleet, poll-loop counters, which poller holds which nodes, recent core↔poller outages, per-store reachability, host resources, forwarding delivery, whether stored credentials still decrypt, the running version, and which optional tiers are on |
Viewer¹ |
get_report_runs |
Recent report runs and their outcomes | Viewer |
get_audit |
Who changed or acknowledged what | View-audit |
get_notification_deliveries |
The notification delivery log: whether each delivery arrived, and on whose side a failed one failed | Admin |
get_config |
kind= Yagra’s own configuration, one read per area: thresholds, event rules and sources, notification channels and routing rules, profiles and collection templates, a node’s collected metrics, classification rules, the MIB catalog, a node’s URL/DNS check, discovery candidates and scans, Meraki orgs/networks/devices/polling, NetBox servers, forwarding destinations, report definitions and schedules, and the retention / adjacency / LLM / roles / OIDC / LDAP settings |
Varies² |
fleet_state_history |
How the fleet’s state mix moved over a window | Viewer |
get_dns_chain |
The resolution chain behind a DNS monitor | Viewer |
run_rca |
An LLM explanation of one incident — the same one the WebUI’s “Explain this incident” produces | Operator |
ack_alert |
Write. Acknowledge (or clear the ack on) an active alert | Operator |
open_maintenance |
Write. Open a maintenance window for one node | Operator |
poll_now |
Write. Trigger an immediate out-of-schedule poll of one node | Admin |
Every write — and every launched analysis — is recorded in the audit log, attributed to the token that made it.
¹ get_system_health sections require different permissions, matching the WebUI exactly. Most
need view, forwarding status needs manage-config, and credential health needs manage-credentials.
Read-only does not mean readable-by-anyone. Report runs and the state timeline refuse a group-scoped token rather than showing it the whole fleet, exactly as the REST endpoints do.
² get_config works the same way, per kind. Each one demands the permission its REST
counterpart demands, so a Viewer is served the role matrix and refused the threshold ruleset from the
same tool.
The split is manage-users for OIDC and LDAP, manage-config for fourteen of them, and view for
the rest. No stored secret is returned: a node’s URL check reports whether a credential is bound
(has_credential), never which one.
³ query_metrics asks a node-level question, so it answers only where a node-level answer
exists. A metric that has one series per interface or per component is collapsed to the node
maximum for gauges — the response says so in a note, and names which direction that is, since
for a metric where low is the fault (an optical receive level) the maximum is the healthiest port.
Per-interface counters are refused outright, with a message naming the tool that can answer:
get_interface_series for one interface, top_interfaces for the fleet.
A metric with one series per table row (a memory pool, a CPU, a sensor) can be read row by row. A
latest answer lists every row’s key, name and latest value in rows. Pass one of those keys as
row to read that row alone, in any mode. A named row is one series, so it is never collapsed. A
per-row counter is refused unless row names one.
Find the endpoint
Section titled “Find the endpoint”On by default — there is nothing to enable. To remove it instead, set YAGRA_ENABLE_MCP=false
for core and restart; /mcp is then not mounted and a request to it returns 404.
The endpoint is served on the API port, at two addresses:
https://<yagra-host>/mcp # through the WebUI's TLS edge (preferred)http://<yagra-host>:8080/mcp # core's API port directly, plaintextBoth work, and both speak the Streamable HTTP transport. Prefer the first: the WebUI container
proxies /mcp to core, so the connection is encrypted.
While a deployment is still on its self-signed bootstrap certificate, a client that cannot be told to trust it has to fall back to core’s plaintext port. Importing a real certificate at Settings ▸ TLS is what makes the TLS URL usable everywhere.
When MCP is disabled the path is not mounted (404), byte-identical to before. MCP always requires authentication, even if the public-dashboard option is on.
Authentication is the gate, so the server accepts any Host header by default. To additionally pin
the hostnames clients may use, set YAGRA_MCP_ALLOWED_HOSTS to a comma-separated list.
The server’s own activity shows up in core’s Prometheus metrics. Tool calls are counted per tool and outcome, and authentication failures separately.
So an assistant hammering the endpoint, or a revoked token still being tried, is visible the same way everything else in Yagra is.
Create a token
Section titled “Create a token”Sign in to the WebUI as an admin → Settings ▸ API tokens ▸ New token → choose a role → copy the
yat_… value shown once. This is the bearer token the AI client sends.
-
Viewer — a read-only assistant. Every read tool works, except
run_analysis.Running a Troubleshoot analysis is an Operator action — the same permission that acknowledges alerts — so a Viewer token can browse past runs and findings but cannot launch new ones.
-
Operator — everything above, plus launching analyses, acknowledging alerts (
ack_alert), and opening maintenance windows (open_maintenance). -
Admin — everything, including
poll_now, which takes the same permission as any other change to what and when Yagra polls.
A token can also be limited to node groups, and every tool honours it. Lists and searches come back narrowed, rankings and histories are filtered, and a tool asked about a node outside the scope answers exactly what it answers for an id that does not exist.
One view is deliberately omitted rather than narrowed. event_stats’ unmatched-signature ranking is
aggregated across nodes and keeps no attribution to filter by, so a scoped token gets it back empty,
with a note saying why.
Roles, permissions and scoping are described in Users & SSO.
A regular login session token from the REST API works too, but it expires. An API token is meant for an unattended client, and is revocable from the same page.
Register it with your client
Section titled “Register it with your client”Claude Code (CLI or VS Code extension) — use --scope user so the server is available in
every project and directory:
claude mcp add --scope user --transport http yagra http://<yagra-host>:8080/mcp \ --header "Authorization: Bearer yat_your_token"Without --scope user, claude mcp add defaults to local scope. The CLI sees it, but the VS Code
extension does not load local-scope servers — it reads user-scope and project .mcp.json servers
only — so /mcp in the extension won’t show it.
MCP servers are also loaded at session start, so reload the window or start a new session after
adding. Then /mcp should list yagra as connected. Ask it to list nodes or summarize alerts.
Claude Desktop — Desktop bridges to a remote HTTP server via the mcp-remote helper. Add this
to claude_desktop_config.json (Settings ▸ Developer ▸ Edit config), then restart Desktop:
{ "mcpServers": { "yagra": { "command": "npx", "args": [ "-y", "mcp-remote", "http://<yagra-host>:8080/mcp", "--header", "Authorization: Bearer yat_your_token" ] } }}Gemini CLI — add the server to ~/.gemini/settings.json (or a project-local
.gemini/settings.json). The httpUrl key selects the Streamable HTTP transport:
{ "mcpServers": { "yagra": { "httpUrl": "http://<yagra-host>:8080/mcp", "headers": { "Authorization": "Bearer yat_your_token" } } }}Restart gemini, then /mcp lists the Yagra tools. Gemini Code Assist (VS Code) reads the same
settings.json.
claude.ai (web) / Team / Enterprise — add Yagra as a Custom Connector (Settings ▸ Connectors).
This requires the /mcp endpoint to be reachable from Anthropic’s servers, which means a public
HTTPS URL — front it with a reverse proxy or a Cloudflare Tunnel, for example. A LAN/VPN-only
address won’t work here.
The same public-HTTPS requirement applies to the Gemini web app and Vertex AI agent connectors.
Any MCP client / quick check with curl — the transport is plain JSON-RPC over HTTP, so you
can smoke-test without a client:
curl -sN http://<yagra-host>:8080/mcp \ -H "Authorization: Bearer yat_your_token" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Reachability
Section titled “Reachability”The AI client makes the HTTP call from your machine, not from the model provider’s cloud. A
desktop or CLI assistant only needs network access to <yagra-host>:8080, over the same LAN or a
VPN.
No public inbound exposure is required, unless you want a hosted connector — the claude.ai web app,
or the Gemini web app and Vertex AI agents. Those must reach /mcp over public HTTPS, as noted
above.
Privacy and security notes
Section titled “Privacy and security notes”- Tool results become conversation context. The AI reads live monitoring data: node names, addresses, alerts. For a cloud-hosted assistant, that data is sent to the model provider you connected. Treat tool output as you would any data leaving your boundary.
- Device credentials are never included in any tool result. SNMP communities, SNMPv3 credentials, and poll-target API keys stay encrypted at rest, and are excluded from every response shape.
- Keep the token least-privileged. A Viewer token is the right default for an assistant that only answers questions; grant Operator only when you want it acting on alerts, maintenance, and analyses.
- Revoke when done. Delete the token from Settings ▸ API tokens when a client no longer needs it; it stops working immediately.
- Every write is audited.
ack_alert,open_maintenance, andpoll_noweach record an audit entry attributing the action to the token that made it — the same trail the WebUI’s own actions leave.