MCP server
Yagra can expose an opt-in MCP tool surface so an AI client — Claude Code, Claude Desktop, or another MCP-capable assistant — can query live monitoring state in natural language: “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 34 tools: 31 read, 3 write. The read tools see the same data the WebUI does, and the Troubleshoot trio runs the same on-demand analyses the WebUI runs — they 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 | Viewer |
list_node_groups |
The folder tree, with map coordinates and optional per-folder health tallies | 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 and error history, aligned on a shared time axis | Viewer |
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 |
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, 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_config |
kind= Yagra’s own configuration, over 28 reads: 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/polling, 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: 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.
Enable the server
Section titled “Enable the server”Off by default. Set YAGRA_ENABLE_MCP=true for core (uncomment it in docker-compose.yml, or add
it to your .env for the deploy compose) and restart. The endpoint is then served on the API
port at:
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 / 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, i.e. a public HTTPS URL (e.g. front it with a reverse proxy or a Cloudflare Tunnel) —
a LAN/VPN-only address won’t work here. The same public-HTTPS requirement applies to the Gemini
web app / 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 / Vertex AI agents), which 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 — and 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.