Skip to content

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”.

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.

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, plaintext

Both 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.

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.

Claude Code (CLI or VS Code extension) — use --scope user so the server is available in every project and directory:

Terminal window
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:

Terminal window
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"}'

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.

  • 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, and poll_now each record an audit entry attributing the action to the token that made it — the same trail the WebUI’s own actions leave.