Skip to content

MCP tools

A Fanout instance serves MCP at /mcp. 20 tools, listed below exactly as the server reports them to an Apps-enabled client. Ordinary clients receive the 17 model-visible tools; the three app-only helpers require Apps negotiation and are never offered to the model.

Every tool is closed-world: it reads or writes what this instance holds and reaches nothing else.

The catalog below includes MCP Apps helpers. App-only helpers are omitted from ordinary clients and model tool definitions. Interactive view tools return a PanelFragment: {view, dashboard, results, vars?, trace?}. Results match every dashboard panel id exactly once. Required view contains kind (preset or query) and key, a stable SHA-256 hash computed once by Go from the spec, captured window and variables. Cosmetic titles and IDs do not affect identity. The agent and host use this key and prefer presets when equivalent views repeat. Variables retain scalar, $__all, empty-list and multi-list values. Model text is a deterministic summary of at most 16 KiB; structured content is the same bounded full fragment persisted for reload, at most 256 KiB, with visible row truncation. Oversized authored spec/variables are rejected before execution at 128 KiB rather than changing their semantics.

AG-UI mcp-app activity content uses exactly resource_uri, tool_name, tool_input, tool_result, and is_error. Protocol structuredContent, resourceUri, toolCallId, threadId, and runId keep their spelling.

ToolChanges state
create_dashboardYes — additive
edit_dashboardYes — replaces existing state
get_dashboardNo — read-only
get_intelligence_snapshotNo — read-only
get_observability_overviewNo — read-only
get_service_dependenciesNo — read-only
get_service_performanceNo — read-only
get_service_topologyNo — read-only
get_telemetry_schemaNo — read-only
inspect_traceNo — read-only
list_dashboard_versionsNo — read-only
list_dashboardsNo — read-only
list_panel_exemplarsNo — read-only
preview_panelsNo — read-only
query_panel_fragmentNo — read-only
query_telemetryNo — read-only
replace_dashboardYes — replaces existing state
resolve_panel_variablesNo — read-only
restore_dashboard_versionYes — replaces existing state
search_logsNo — read-only

Create dashboard — Create a dashboard for the authenticated user from a complete spec. Read get_telemetry_schema first and preview_panels until every panel is ok or deliberately empty. The result lists any panel that is still empty or failing. Successful saves return a receipt for that committed version: base_version, version, changes, layout_changed, dashboard_fields and save_check. Changes describe authored panel fields and position_changed; physical packing is only layout_changed. Order chips mark the minimal moved set. save_check reports checked, reason when unchecked, total elapsed_ms and one status/rows result per saved panel with elapsed_ms when executed. checked means every panel was executed, not that error or empty panels are healthy. Text rows identify nonempty content, not telemetry. Use the structured receipt rather than prose warnings as check evidence. Create receipts list added panels without layout or dashboard edit chips. No-op saves still create a new version with no change chips. Per-panel elapsed_ms is omitted when the panel did not run. A dashboard is {name, description, time:{range}, variables, panels}. Each panel: {id (lowercase), title, viz, width 1-12, query or sql}. viz: stat or gauge (one measure; gauge needs min and max), timeseries (bucket auto, at most one by), bar (one or two by), table (up to three by), text (content in Markdown), heatmap (bucket auto, no by), histogram (at most one by), scatter (exactly two measures in x then y order, one item dimension and an optional colour dimension), state_timeline (one measure, one item dimension, bucket auto and thresholds required). Rollup panel types are service_map (dependency graph) and health (overview metrics, error trend and health distribution). They require query.from=spans, no measures, by, bucket or sort, and only namespace/service equality filters with a literal or single-value variable; explicit casts and values with surrounding whitespace are rejected. Reads default to 400 services/edges and are capped at 400 even when query.limit is larger. Service scope applies before the limit; map nodes carry p95_ms and edges carry average_ms; error_rate is percent. Row panel types are logs, log_patterns and traces. Logs and traces take no measures, by or bucket. Patterns use count() by body_template. Patterns group only by body_template. Severity is the most frequent severity, ties choose the higher severity. Service is the most frequent service, ties choose ascending service name. Both describe the scoped, redacted events, not extra grouping dimensions. Each pattern returns dominant severity, top service, count and a dense trend, computed in the same bounded query after redaction and scoped filters. Redaction applies before filtering, grouping, display and drill-down. Row panels cannot use SQL. “erroring” means slowest erroring traces: filter to erroring traces, then rank by root duration. Trace candidate ranking is approximate when filters exclude the root span, as with exemplars. Categorical charts use fixed-order colour slots. Categorical options.top defaults to 6, maximum 6. Structured panels: the server computes Other; series are chosen worst-first by confidence (Wilson lower bound for error rates; at least 20 samples for latency); the rest fold into Other (N). Count, rate, sum and share rank largest first. Error rates require at least 20 requests for eligible Wilson ranking (z=1.96). Percentiles, quantile, avg, max and min require at least 20 non-null numeric samples for eligible value ranking and use better (explicit or inferred). Ineligible series follow eligible ones by sample count descending. Ties use sample count descending, then name ascending. SQL panels: series past six are left out, with a note. state_timeline defaults to 8 rows, maximum 20; other noncategorical panels use the same limits. Scatter supports options.x_scale and options.y_scale (log or linear), with distinct x_unit for x and unit for y, each inferred independently when omitted. Rows returned use the count unit. State timelines preserve null and absent buckets as unknown and keep the top items without merging them into Other. Scatter requires a structured query. SQL state_timeline requires timestamp time, a string item, one numeric measure and optional string state; its interval is one minute and thresholds are required. Items rank by volume (row count) for top N. Previous-period comparison is not drawn for scatter or state_timeline. Distribution panels use a structured query with one count() measure and histogram: {field: duration_ms, buckets: log2} for spans or {field: value, buckets: explicit} for metrics. Negative span durations clamp to [0,1); +Inf goes to overflow; NaN is excluded because it is not a measurement. Metric histograms use stored temporality and shared per-series increases; resets contribute current counts. Delta histograms sum observation weights. query: {from: spans|logs|metrics, where: [filter expressions], measures: [fn(field) as alias], by: [fields], bucket, sort, limit}. Measures: count(), rate() per second, error_rate() percent, share() percent, avg/min/max/sum(field), last(value) for metrics, p50/p75/p90/p95/p99(field), quantile(field, 0.999), count_distinct(field). Fields are columns from get_telemetry_schema or attributes[‘key’] / resource[‘key’] with the key written literally. Filters are SQL boolean expressions: service = $service, kind = ‘SPAN_KIND_SERVER’, status = ‘STATUS_CODE_ERROR’, http_route IN $routes, attributes[‘http.response.status_code’]::INTEGER >= 500. Variables: {name, kind: query|custom|constant|text, from, field, default, include_all}; $__all selects All and removes filters that use the variable. sql: one SELECT over spans, logs, metrics, service_rollup or edge_rollup that filters time with $__window(column). Use values exactly as get_telemetry_schema lists them. Example panel: {“id”:“latency”,“title”:“Checkout latency”,“viz”:“timeseries”,“width”:8,“query”:{“from”:“spans”,“where”:[“service = ‘checkout’”,“kind = ‘SPAN_KIND_SERVER’”],“measures”:[“p50(duration_ms)”,“p95(duration_ms)”,“p99(duration_ms)”],“bucket”:“auto”},“unit”:“ms”,“thresholds”:[{“value”:1500,“status”:“bad”}]}. Metrics: gauge/updown | counter | histogram. count(): points; count_distinct(): distinct. rate(): undefined | series increase/elapsed summed | count rate summed. sum(value): series means summed | increases | sum increases. avg(value): mean series means | undefined | sum/count increases. Gauge/updown sum/avg carry earlier points within 5m. Deltas spread across covered buckets; rate alone carries within 5m. rate() is per-second increase over covered elapsed time; auto >=1m. min/max: points | points | undefined. last(value): latest strictly before bucket/window end, reported within 5m, summed | same | undefined. pNN/quantile: points | undefined | interpolated bucket increases. summary: no value aggregates. Undefined: NULL. Fix name in its own where entry: one literal or single-value variable without All or multi-value; or name in by. Read type/temporality from get_telemetry_schema. state_timeline needs at least one threshold marked warn or bad, rather than only ok. Annotations attach only to timeseries, heatmap and state_timeline panels, scoped by service and namespace filters. drill: logs needs query.from=logs. Drill is not available on metrics. Every table format’s field must exist in the returned frame; formatting cannot reference an absent column. A structured-table sparkline field must be a measure alias from that table’s query. service_link needs variable to name the query or custom variable selected by the link. highlight applies to logs and log_patterns, at most 200 characters. split: deploy needs a service equality filter, as a literal or a single-value variable; other filters are allowed. When the service is All, a split: deploy panel shows the plain bar with a note explaining the missing service scope. Use service_map for dependency context, health for service health; neither proves causality. Example 1: Reference shapes; use only the types the question needs. {“name”:“Investigation shapes”,“annotations”:{“deploys”:true,“anomalies”:true},“variables”:[{“name”:“service”,“kind”:“query”,“from”:“spans”,“field”:“service”}],“panels”:[{“id”:“latency_heat”,“title”:“Latency over time”,“viz”:“heatmap”,“query”:{“from”:“spans”,“where”:[“service = $service”],“measures”:[“count()”],“bucket”:“auto”,“histogram”:{“field”:“duration_ms”,“buckets”:“log2”}},“drill”:“traces”},{“id”:“latency_hist”,“title”:“Latency by operation”,“viz”:“histogram”,“query”:{“from”:“spans”,“where”:[“service = $service”],“measures”:[“count()”],“by”:[“operation”],“histogram”:{“field”:“duration_ms”,“buckets”:“log2”}},“drill”:“traces”},{“id”:“items”,“title”:“Calls versus tail latency”,“viz”:“scatter”,“query”:{“from”:“spans”,“where”:[“service = $service”],“measures”:[“count() as rows”,“p95(duration_ms) as tail_latency”],“by”:[“operation”]},“drill”:“traces”},{“id”:“states”,“title”:“Error states”,“viz”:“state_timeline”,“query”:{“from”:“spans”,“where”:[“service = $service”],“measures”:[“error_rate()”],“by”:[“operation”],“bucket”:“auto”},“thresholds”:[{“value”:5,“status”:“bad”}],“drill”:“traces”},{“id”:“log_rows”,“title”:“Recent logs”,“viz”:“logs”,“query”:{“from”:“logs”,“where”:[“service = $service”],“sort”:“time”,“limit”:100},“drill”:“logs”},{“id”:“patterns”,“title”:“Repeated log patterns”,“viz”:“log_patterns”,“query”:{“from”:“logs”,“where”:[“service = $service”],“measures”:[“count()”],“by”:[“body_template”],“bucket”:“auto”,“limit”:50},“drill”:“logs”},{“id”:“trace_rows”,“title”:“Slow traces”,“viz”:“traces”,“query”:{“from”:“spans”,“where”:[“service = $service”],“sort”:“duration_ms”,“limit”:20},“drill”:“traces”},{“id”:“map”,“title”:“Service calls”,“viz”:“service_map”,“query”:{“from”:“spans”}},{“id”:“health”,“title”:“Service health”,“viz”:“health”,“query”:{“from”:“spans”}}]} Example 2: Reference shapes; use only the types the question needs. {“name”:“Interaction shapes”,“variables”:[{“name”:“service”,“kind”:“query”,“from”:“spans”,“field”:“service”}],“panels”:[{“id”:“hist”,“title”:“Metric distribution”,“viz”:“histogram”,“query”:{“from”:“metrics”,“where”:[“service = $service”],“measures”:[“count()”],“histogram”:{“field”:“value”,“buckets”:“explicit”}}},{“id”:“table”,“title”:“Service calls and trends”,“viz”:“table”,“query”:{“from”:“spans”,“measures”:[“count() as calls”],“by”:[“service”]},“options”:{“columns”:[{“field”:“service”,“format”:“service_link”,“variable”:“service”},{“field”:“calls”,“format”:“sparkline”}]}},{“id”:“prior”,“title”:“Service calls one day earlier”,“viz”:“bar”,“query”:{“from”:“spans”,“measures”:[“count()”],“by”:[“service”]},“click”:{“set_variable”:“service”},“time”:{“shift”:“1d”}}]} Metric examples; use when the discovered type fits. {“name”:“Metric measures”,“panels”:[{“id”:“network”,“title”:“Network bytes per second”,“viz”:“timeseries”,“query”:{“from”:“metrics”,“where”:[“name = ‘system.network.io’”],“measures”:[“rate()”],“by”:[“attributes[‘direction’]”],“bucket”:“auto”}},{“id”:“duration”,“title”:“Request duration p95”,“viz”:“timeseries”,“query”:{“from”:“metrics”,“where”:[“name = ‘http.server.request.duration’”],“measures”:[“p95(value)”],“bucket”:“auto”},“unit”:“s”}]}

Additive. It creates something new and alters nothing that exists.

InputTypeRequiredMeans
dashboardobjectyesComplete v1 dashboard spec

Edit dashboard — Change a dashboard with typed operations, applied in order and saved as one version: add_panel, update_panel (set replaces the named fields), remove_panel, move_panel, set_variable, remove_variable, set_time, rename. Panels not named are left unchanged. Only edit when the user asks to change that dashboard. Successful saves return a receipt for that committed version: base_version, version, changes, layout_changed, dashboard_fields and save_check. Changes describe authored panel fields and position_changed; physical packing is only layout_changed. Order chips mark the minimal moved set. save_check reports checked, reason when unchecked, total elapsed_ms and one status/rows result per saved panel with elapsed_ms when executed. checked means every panel was executed, not that error or empty panels are healthy. Text rows identify nonempty content, not telemetry. Use the structured receipt rather than prose warnings as check evidence. Create receipts list added panels without layout or dashboard edit chips. No-op saves still create a new version with no change chips. Per-panel elapsed_ms is omitted when the panel did not run. See create_dashboard for the spec guide.

Replaces existing state.

InputTypeRequiredMeans
idstringyesDashboard ID
operationsarrayyesEdits applied in order, atomically
base_versionintegernoVersion you read; the call fails if someone saved since
messagestringnoOne line describing the change, shown in history

Get dashboard — Read one dashboard’s complete spec and version. Read it before editing so operations name real panel ids. See create_dashboard for the spec guide.

Read-only. Calling it changes nothing.

InputTypeRequiredMeans
idstringyesDashboard ID returned by list_dashboards or create_dashboard

Latest detected anomalies — Return the latest precomputed health score, anomalies, insights, and recurring warning or error log patterns.

Read-only. Calling it changes nothing.

Takes no arguments.

System health overview — Summarize service health for a bounded telemetry window. Start here for incident triage.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
fromstringnoAbsolute start, RFC3339Nano; requires to and excludes window
limitintegernoMaximum services or edges to return, from 1 to 500
namespacestringnoOpenTelemetry service namespace; empty queries all namespaces
tostringnoAbsolute end, RFC3339Nano; requires from and excludes window
windowstringnoTime window such as 15m, 1h, 24h, 168h, or 720h; defaults to 1h

Service dependency traversal — Find upstream or downstream dependencies of one service with minimum hop counts. Uses the full scoped edge rollup, handles cycles, and reports truncation from depth or node limits.

Read-only. Calling it changes nothing.

InputTypeRequiredMeans
servicestringyesRoot service name
directionstringnoupstream or downstream; defaults to downstream
max_depthintegernoMaximum hops from 1 to 32; defaults to 8
max_nodesintegernoMaximum accumulated nodes from 1 to 500 including roots; defaults to 100
namespacestringnoFilter by namespace; traversal always keeps namespaces separate
windowstringnoBounded telemetry window, defaults to 1h

Service performance explorer — Display separate latency, error rate and request rate panels plus slow endpoints for one service or the system.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
fromstringnoAbsolute start, RFC3339Nano; requires to and excludes window
limitintegernoMaximum endpoints to return, from 1 to 500
namespacestringnoOpenTelemetry service namespace; empty queries all namespaces
servicestringnoOptional exact OpenTelemetry service name; omit for the whole system
tostringnoAbsolute end, RFC3339Nano; requires from and excludes window
windowstringnoTime window such as 15m, 1h, 24h, 168h, or 720h; defaults to 1h

Service dependency topology — Return services and observed dependency edges with health, traffic, latency, and error data.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
fromstringnoAbsolute start, RFC3339Nano; requires to and excludes window
limitintegernoMaximum services or edges to return, from 1 to 500
namespacestringnoOpenTelemetry service namespace; empty queries all namespaces
tostringnoAbsolute end, RFC3339Nano; requires from and excludes window
windowstringnoTime window such as 15m, 1h, 24h, 168h, or 720h; defaults to 1h

Telemetry schema — List the signals, columns with their common values, attribute keys seen per service, metric names, services, measure functions and units. Read this before drafting panels so filters use values that exist. See create_dashboard for the spec guide.

Read-only. Calling it changes nothing.

InputTypeRequiredMeans
namespacestringnoLimit discovery to one service namespace
windowstringno5m, 15m, 1h, 3h, 6h, 12h or 24h; default 1h

Trace detail — Inspect an exact trace, or select the most relevant recent error or slow trace, with spans, waterfall, flame graph, and correlated logs.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
fromstringnoAbsolute start, RFC3339Nano; requires to and excludes window
limitintegernoMaximum spans and correlated logs to return, from 1 to 500
namespacestringnoOpenTelemetry service namespace; empty queries all namespaces
servicestringnoOptional service filter when choosing a recent trace
tostringnoAbsolute end, RFC3339Nano; requires from and excludes window
trace_idstringnoExact trace ID; omit to inspect the most relevant recent error or slow trace
windowstringnoTrace lookup window such as 1h, 24h, 168h, or 720h; defaults to 1h

List dashboard versions — List the authenticated user’s saved versions of one dashboard, newest first, with author and message. The historical version identifies a restore target; restore_dashboard_version saves it as a new version.

Read-only. Calling it changes nothing.

InputTypeRequiredMeans
idstringyesDashboard ID returned by list_dashboards or create_dashboard

List dashboards — List the authenticated user’s dashboards with panel counts and versions. See create_dashboard for the spec guide.

Read-only. Calling it changes nothing.

Takes no arguments.

Panel exemplars — Find bounded traces for a panel selection.

Read-only. Calling it changes nothing.

Visibility: app only; no resource attachment.

InputTypeRequiredMeans
dashboardobjectyesComplete v1 dashboard specification; every panel is executed
fromstringyesSelection start as an RFC3339Nano UTC timestamp
panel_idstringyesID of the selected panel in dashboard
tostringyesSelection end as an RFC3339Nano UTC timestamp, after from
bucketobjectnoOptional selected bucket with its exact bounds
dimensionsobjectnoExact dimension values of the selected series or row
kindstringnoSelection signal: traces or logs; defaults from the selected panel
timeobjectnoOptional dashboard time override: exact from/to or a relative range
varsobjectnoResolved variable values: strings or lists; preserves $__all and empty lists

Preview panels — Check and run panels without saving them. Each panel reports ok with rows and a sample, empty with the reason, error, or invalid with the exact field and a suggestion. The result includes total elapsed_ms and executed per-panel elapsed_ms; invalid and not_run panels omit elapsed_ms because they were not executed. Fix every invalid panel and replace or explain every empty one before saving. Spec guide: see create_dashboard.

Read-only. Calling it changes nothing.

InputTypeRequiredMeans
panelsarrayyesPanels to check and run, in the same format as dashboard panels
timeobjectnoTime range; default the last hour
variablesarraynoVariables the panels reference
varsobjectnoVariable values to preview with; $__all selects All

Refresh telemetry panels — Run every panel in a dashboard fragment; panel subsets are forbidden.

Read-only. Calling it changes nothing.

Visibility: app only; no resource attachment.

InputTypeRequiredMeans
dashboardobjectyesComplete v1 dashboard specification; every panel is executed
comparebooleannoOverride previous-period comparison for the complete fragment
timeobjectnoOptional dashboard time override: exact from/to or a relative range
varsobjectnoResolved variable values: strings or lists; preserves $__all and empty lists
widthsobjectnoOptional panel widths in pixels, keyed by panel ID

Telemetry panel — Display one v1 panel in chat as an executable dashboard fragment. Use get_telemetry_schema to discover fields; see create_dashboard for the spec guide. The authored spec plus vars must fit 128 KiB (131072 serialized JSON bytes); larger inputs are rejected with their actual size.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
panelobjectyesOne v1 panel to display in the answer
timeobjectnoOptional dashboard time override: exact from/to or a relative range
variablesarraynoOptional v1 variable definitions used by this panel
varsobjectnoResolved variable values: strings or lists; preserves $__all and empty lists

Replace dashboard — Replace a dashboard’s whole spec; omitted panels are removed. Use only for a redesign the user asked for; use edit_dashboard to change a few panels. Successful saves return a receipt for that committed version: base_version, version, changes, layout_changed, dashboard_fields and save_check. Changes describe authored panel fields and position_changed; physical packing is only layout_changed. Order chips mark the minimal moved set. save_check reports checked, reason when unchecked, total elapsed_ms and one status/rows result per saved panel with elapsed_ms when executed. checked means every panel was executed, not that error or empty panels are healthy. Text rows identify nonempty content, not telemetry. Use the structured receipt rather than prose warnings as check evidence. Create receipts list added panels without layout or dashboard edit chips. No-op saves still create a new version with no change chips. Per-panel elapsed_ms is omitted when the panel did not run. See create_dashboard for the spec guide.

Replaces existing state.

InputTypeRequiredMeans
dashboardobjectyesComplete replacement spec; omitted panels are removed
idstringyesDashboard ID
base_versionintegernoVersion you read; the call fails if someone saved since
messagestringnoOne line describing the change, shown in history

Panel variable options — Resolve variable options within a dashboard fragment window.

Read-only. Calling it changes nothing.

Visibility: app only; no resource attachment.

InputTypeRequiredMeans
dashboardobjectyesComplete v1 dashboard specification; every panel is executed
timeobjectnoOptional dashboard time override: exact from/to or a relative range
varsobjectnoResolved variable values: strings or lists; preserves $__all and empty lists

Restore dashboard version — Restore a saved historical version of the authenticated user’s dashboard only on an explicit user request. The input version selects the historical spec; the result’s version is the newly saved version. Every successful call appends another version, even when restoring the latest spec. A missing or pruned target returns error.code dashboard_version_not_found; list_dashboard_versions shows retained versions. Successful saves return a receipt for that committed version: base_version, version, changes, layout_changed, dashboard_fields and save_check. Changes describe authored panel fields and position_changed; physical packing is only layout_changed. Order chips mark the minimal moved set. save_check reports checked, reason when unchecked, total elapsed_ms and one status/rows result per saved panel with elapsed_ms when executed. checked means every panel was executed, not that error or empty panels are healthy. Text rows identify nonempty content, not telemetry. Use the structured receipt rather than prose warnings as check evidence. Create receipts list added panels without layout or dashboard edit chips. No-op saves still create a new version with no change chips. Per-panel elapsed_ms is omitted when the panel did not run.

Replaces existing state.

InputTypeRequiredMeans
idstringyesDashboard ID
versionintegeryesPositive stored version to restore; restoring creates a new version

Log explorer — Search and filter logs with a severity timeline and links back to correlated traces.

Read-only. Calling it changes nothing.

View resource: ui://fanout/panels.html (model and app visible).

InputTypeRequiredMeans
fromstringnoAbsolute start, RFC3339Nano; requires to and excludes window
limitintegernoMaximum log entries to return, from 1 to 500
namespacestringnoOpenTelemetry service namespace; empty queries all namespaces
searchstringnoOptional case-insensitive text contained in the log body, at most 200 characters
servicestringnoOptional exact OpenTelemetry service name
severitystringnoOptional exact severity such as ERROR, WARN, or INFO
tostringnoAbsolute end, RFC3339Nano; requires from and excludes window
windowstringnoTime window such as 15m, 1h, 24h, 168h, or 720h; defaults to 1h

MCP uses OAuth, not a static key, and not the ingest token — an agent presenting the ingest token is rejected. A client discovers the endpoints, registers itself, and is issued a token bound to this instance’s resource URI. Connect an agent covers the flow.

The dashboard tools act on the authenticated user’s own dashboards. The capability boundary is dashboards:manage-own: an agent acts as the user whose credential it holds and cannot reach anyone else’s. A tool description that tells a model when to call it is guidance to the model, not a permission check — see roles.

No tool writes telemetry, changes configuration, manages users, or edits alert rules. Ingest is OTLP only and the rest is HTTP surface — see HTTP routes. An agent connected over MCP can read everything the instance knows and manage its own dashboards, and that is the whole envelope.