Tool selection accuracy degrades as the surface grows: more near-neighbours to confuse, more tokens spent before the first user message. Fewer, intent-shaped tools outperform one-tool-per-endpoint surfaces.
Grafana MCP server tool surface audit
- Token footprint
- ~16,794
- Tools
- 65
- Findings
- 86
- Scanned
Every conversation with the Grafana MCP server begins with 65 tool definitions already in context — about 16,794 tokens of it. MCP Surface Lint scores that surface 77 out of 100 (grade C), with 86 scored findings spread across 5 of the six rule categories.
The spread runs from 100/100 for naming down to 36/100 for design. It is catalogued here under Observability, alongside other servers agents reach for in the same kind of work.
Token footprint
At 16,794 tokens the surface takes about 8% of a 200,000-token context window, and it takes it on every turn — this is rent, not a one-off cost. That averages 258 tokens per tool definition, counted with the o200k_base encoding.
That lands exactly on the Observability median of 16,794 tokens.
Findings
Every finding below names the rule behind it and the tool it fired on.
28 findings come from `schemas/param-desc-missing`. Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes. On this surface it fires on `analyze_loki_labels`, `create_incident` and `list_prometheus_label_names`, among 3 others.
`design/list-no-limit` accounts for 16 findings. A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less. On this surface it fires on `find_error_pattern_logs`, `find_slow_requests` and `get_dashboard_panel_queries`, among 13 others.
`schemas/loose` contributes 10 findings. Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes. On this surface it fires on `alerting_manage_rules`, `create_annotation` and `create_datasource`, among 5 others.
Grafana's surface raises 9 further rules — `design/overlap-cluster`, `annotations/missing-hints`, `design/confusable-params`, `design/enum-in-prose`, `schemas/complexity-budget`, `design/crud-mirror`, `descriptions/too-long`, `surface/token-budget` and `surface/tool-budget` — listed in full below.
error 1 finding
Findings that actively harm tool selection.
warn 85 findings
Findings that measurably degrade tool selection.
readOnlyHint/destructiveHint are machine-readable: clients use them to decide when to ask the user for confirmation. Prose like 'confirm with the user first' is invisible to that machinery.
readOnlyHint/destructiveHint are machine-readable: clients use them to decide when to ask the user for confirmation. Prose like 'confirm with the user first' is invisible to that machinery.
readOnlyHint/destructiveHint are machine-readable: clients use them to decide when to ask the user for confirmation. Prose like 'confirm with the user first' is invisible to that machinery.
readOnlyHint/destructiveHint are machine-readable: clients use them to decide when to ask the user for confirmation. Prose like 'confirm with the user first' is invisible to that machinery.
readOnlyHint/destructiveHint are machine-readable: clients use them to decide when to ask the user for confirmation. Prose like 'confirm with the user first' is invisible to that machinery.
Very long tool descriptions are paid for in every conversation. Detail that only matters once a parameter is used belongs in that parameter's description.
The same concept spelled differently across tools (hotel_id vs hotelId vs id) makes the model carry a per-tool spelling table and produces cross-tool argument bleed. One concept, one name, everywhere.
"datasource_uid" (alerting_manage_routing, alerting_manage_rules) vs "datasourceUid" (analyze_loki_labels, generate_deeplink, list_loki_label_names, list_loki_label_values, list_prometheus_label_names, list_prometheus_label_values, list_prometheus_metric_metadata, list_prometheus_metric_names, query_loki_logs, query_loki_patterns, query_loki_stats, query_prometheus, query_prometheus_histogram) vs "data_source_uid" (list_pyroscope_label_names, list_pyroscope_label_values, list_pyroscope_profile_types, query_pyroscope)
The same concept spelled differently across tools (hotel_id vs hotelId vs id) makes the model carry a per-tool spelling table and produces cross-tool argument bleed. One concept, one name, everywhere.
"folder_uid" (alerting_manage_rules) vs "folderUid" (update_dashboard)
The same concept spelled differently across tools (hotel_id vs hotelId vs id) makes the model carry a per-tool spelling table and produces cross-tool argument bleed. One concept, one name, everywhere.
"endRfc3339" (analyze_loki_labels, list_loki_label_names, list_loki_label_values, list_prometheus_label_names, list_prometheus_label_values, list_prometheus_metric_names, query_loki_logs, query_loki_patterns, query_loki_stats) vs "end_rfc_3339" (list_pyroscope_label_names, list_pyroscope_label_values, list_pyroscope_profile_types, query_pyroscope)
The same concept spelled differently across tools (hotel_id vs hotelId vs id) makes the model carry a per-tool spelling table and produces cross-tool argument bleed. One concept, one name, everywhere.
"startRfc3339" (analyze_loki_labels, list_loki_label_names, list_loki_label_values, list_prometheus_label_names, list_prometheus_label_values, list_prometheus_metric_names, query_loki_logs, query_loki_patterns, query_loki_stats) vs "start_rfc_3339" (list_pyroscope_label_names, list_pyroscope_label_values, list_pyroscope_profile_types, query_pyroscope)
The same concept spelled differently across tools (hotel_id vs hotelId vs id) makes the model carry a per-tool spelling table and produces cross-tool argument bleed. One concept, one name, everywhere.
"queryType" (query_loki_logs, query_prometheus) vs "query_type" (query_pyroscope)
A get/create/update/delete family over one noun is the fingerprint of an OpenAPI-autogenerated surface: it mirrors your REST API, not your users' intents. Agents work in workflows, not endpoints — consolidate around tasks.
create_annotation, get_annotations, update_annotation
A get/create/update/delete family over one noun is the fingerprint of an OpenAPI-autogenerated surface: it mirrors your REST API, not your users' intents. Agents work in workflows, not endpoints — consolidate around tasks.
create_datasource, get_datasource, list_datasources, update_datasource
A get/create/update/delete family over one noun is the fingerprint of an OpenAPI-autogenerated surface: it mirrors your REST API, not your users' intents. Agents work in workflows, not endpoints — consolidate around tasks.
create_snapshot, delete_snapshot, get_snapshot, list_snapshots
Values enumerated in prose ('one of: a, b, c') are invisible to schema validation: the model can misspell them and the server only finds out at call time. If the value set is closed, encode it as an enum.
Filter by alert group state (one of: new, acknowledged, resolved, silenced)
Values enumerated in prose ('one of: a, b, c') are invisible to schema validation: the model can misspell them and the server only finds out at call time. If the value set is closed, encode it as an enum.
The status of the incidents to include. Valid values: 'active', 'resolved'
Values enumerated in prose ('one of: a, b, c') are invisible to schema validation: the model can misspell them and the server only finds out at call time. If the value set is closed, encode it as an enum.
One of the '=' or '!=' or '=~' or '!~'
Values enumerated in prose ('one of: a, b, c') are invisible to schema validation: the model can misspell them and the server only finds out at call time. If the value set is closed, encode it as an enum.
One of the '=' or '!=' or '=~' or '!~'
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
A list/search tool with no limit or pagination parameter can dump an unbounded payload into the context window. The caller must be able to ask for less.
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
get_dashboard_by_uid, get_dashboard_panel_queries, get_dashboard_property, get_dashboard_summary
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
list_oncall_schedules, list_oncall_teams, list_oncall_users
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
list_prometheus_label_names, list_prometheus_label_values, list_prometheus_metric_metadata, list_prometheus_metric_names
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
list_pyroscope_label_names, list_pyroscope_label_values, list_pyroscope_profile_types
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
query_loki_logs, query_loki_patterns, query_loki_stats
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
list_loki_label_names, list_pyroscope_label_names, list_pyroscope_label_values
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
list_prometheus_label_names, list_prometheus_label_values
Tools whose descriptions substantially overlap force the model to pick between near-synonyms — the classic cause of wrong-tool calls. Clusters are usually one tool wearing several names; consolidate with include-flags or a mode parameter.
search_dashboards, search_folders
Deeply nested inputs, very wide property lists, and stacked oneOf/anyOf force the model to solve a constraint puzzle before every call. Flatter, narrower inputs get filled correctly more often.
Deeply nested inputs, very wide property lists, and stacked oneOf/anyOf force the model to solve a constraint puzzle before every call. Flatter, narrower inputs get filled correctly more often.
Deeply nested inputs, very wide property lists, and stacked oneOf/anyOf force the model to solve a constraint puzzle before every call. Flatter, narrower inputs get filled correctly more often.
Deeply nested inputs, very wide property lists, and stacked oneOf/anyOf force the model to solve a constraint puzzle before every call. Flatter, narrower inputs get filled correctly more often.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Loose schemas (bare objects, untyped arrays, open additionalProperties) turn schema validation off exactly where the model is most likely to hallucinate argument shapes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
Undescribed parameters get filled by guesswork. Every property the model must populate deserves a sentence saying what it means and what shape it takes.
The serialized tools/list payload is injected into every conversation that connects the server, before any work happens. Its token cost is a per-message tax.
info 3 findings
Advisory only — these deduct nothing from the score.
A description should say what the tool does. Imperatives aimed at the client ('RENDER RESULTS IMMEDIATELY', 'do not call tool X') are prompt injection into your own surface: paid for in every conversation, unevenly obeyed, and when copy-pasted across tools they drown the words that actually disambiguate. Escalates to warn when the same directive block appears in multiple tools.
Second call: provide the type, the display name in the top-level name argument, schemaReviewed=true, and the fields map populated with values confirmed by the user.
Positive check. 'When NOT to use this tool' guidance is one of the highest-value lines a description can carry — it prevents speculative calls that waste quota and context. Credit it; keep it during any consolidation.
When NOT to use:
Positive check. 'When NOT to use this tool' guidance is one of the highest-value lines a description can carry — it prevents speculative calls that waste quota and context. Credit it; keep it during any consolidation.
When NOT to use:
What this surface does well
Grafana scores a full 100 in naming, which is to say the tool names follow one convention end to end.
Tool inventory
The heaviest definition is `alerting_manage_rules` at 1,368 tokens, roughly 8% of the total; the lightest, `delete_snapshot`, costs 65. Every tool carries a description, ranging from 42 to 2,177 characters.
All 65 declare annotations, so a client can tell a read from a write before running one. Across the surface, schemas carry 5 top-level parameters on average and reach a maximum depth of 5.
All 65 tools as published, heaviest first. Token counts use the o200k_base encoding and are approximate.
| Tool | Tokens | Description | Params | Required | Depth | Annotations |
|---|---|---|---|---|---|---|
alerting_manage_rules | 1,368 | 461 chars | 28 | 1 | 2 | yes |
update_dashboard | 1,006 | 2177 chars | 7 | 0 | 3 | yes |
get_panel_image | 602 | 428 chars | 10 | 0 | 2 | yes |
query_loki_logs | 567 | 791 chars | 8 | 2 | 1 | yes |
generate_deeplink | 562 | 600 chars | 9 | 1 | 2 | yes |
query_prometheus | 437 | 340 chars | 7 | 3 | 1 | yes |
create_datasource | 419 | 652 chars | 10 | 2 | 1 | yes |
alerting_manage_routing | 414 | 561 chars | 6 | 1 | 1 | yes |
list_alert_groups | 407 | 503 chars | 9 | 0 | 2 | yes |
query_loki_stats | 407 | 837 chars | 4 | 2 | 1 | yes |
query_pyroscope | 403 | 451 chars | 9 | 2 | 2 | yes |
list_prometheus_label_values | 392 | 264 chars | 7 | 2 | 5 | yes |
query_prometheus_histogram | 390 | 312 chars | 9 | 3 | 1 | yes |
list_prometheus_label_names | 365 | 156 chars | 6 | 1 | 5 | yes |
analyze_loki_labels | 360 | 258 chars | 8 | 0 | 4 | yes |
query_loki_patterns | 333 | 514 chars | 5 | 2 | 1 | yes |
get_dashboard_property | 318 | 680 chars | 2 | 2 | 1 | yes |
list_prometheus_metric_names | 316 | 350 chars | 7 | 1 | 1 | yes |
list_pyroscope_label_values | 306 | 407 chars | 5 | 2 | 1 | yes |
list_pyroscope_label_names | 280 | 452 chars | 4 | 1 | 1 | yes |
list_loki_label_values | 270 | 324 chars | 4 | 2 | 1 | yes |
get_assertions | 268 | 100 chars | 7 | 2 | 1 | yes |
list_pyroscope_profile_types | 266 | 442 chars | 3 | 1 | 1 | yes |
create_annotation | 259 | 125 chars | 11 | 0 | 2 | yes |
create_incident | 259 | 244 chars | 8 | 3 | 3 | yes |
get_annotations | 241 | 83 chars | 10 | 0 | 2 | yes |
grafana_api_request | 235 | 224 chars | 5 | 1 | 1 | yes |
validate_provisioning_file | 231 | 441 chars | 4 | 2 | 1 | yes |
list_loki_label_names | 222 | 262 chars | 3 | 1 | 1 | yes |
get_dashboard_panel_queries | 221 | 507 chars | 3 | 1 | 1 | yes |
search_plugin_information | 189 | 531 chars | 1 | 1 | 1 | yes |
update_datasource | 186 | 121 chars | 8 | 1 | 1 | yes |
create_snapshot | 183 | 115 chars | 6 | 1 | 1 | yes |
list_prometheus_metric_metadata | 181 | 132 chars | 5 | 1 | 1 | yes |
get_dashboard_by_uid | 177 | 560 chars | 1 | 1 | 1 | yes |
list_oncall_users | 172 | 251 chars | 3 | 0 | 1 | yes |
find_error_pattern_logs | 170 | 172 chars | 4 | 2 | 1 | yes |
list_oncall_schedules | 166 | 256 chars | 3 | 0 | 1 | yes |
install_plugin | 163 | 198 chars | 2 | 1 | 1 | yes |
suggest_loki_alloy_label_config | 159 | 166 chars | 5 | 1 | 2 | yes |
update_annotation | 159 | 140 chars | 6 | 0 | 2 | yes |
find_slow_requests | 158 | 115 chars | 4 | 2 | 1 | yes |
list_datasources | 152 | 145 chars | 3 | 0 | 1 | yes |
get_sift_investigation | 151 | 153 chars | 1 | 1 | 1 | yes |
add_activity_to_incident | 150 | 185 chars | 3 | 2 | 1 | yes |
list_provisioning_repositories | 149 | 339 chars | 1 | 0 | 1 | yes |
get_sift_analysis | 148 | 147 chars | 2 | 2 | 1 | yes |
get_datasource | 140 | 260 chars | 2 | 0 | 1 | yes |
get_plugin | 134 | 273 chars | 1 | 1 | 1 | yes |
list_incidents | 134 | 158 chars | 3 | 0 | 1 | yes |
search_dashboards | 133 | 139 chars | 3 | 0 | 1 | yes |
check_datasources_health | 119 | 72 chars | 3 | 0 | 2 | yes |
create_folder | 119 | 86 chars | 3 | 1 | 1 | yes |
get_current_oncall_users | 110 | 178 chars | 1 | 1 | 1 | yes |
get_oncall_shift | 105 | 201 chars | 1 | 1 | 1 | yes |
get_dashboard_summary | 103 | 236 chars | 1 | 1 | 1 | yes |
list_snapshots | 98 | 78 chars | 2 | 0 | 1 | yes |
list_sift_investigations | 93 | 120 chars | 1 | 0 | 1 | yes |
get_annotation_tags | 91 | 99 chars | 2 | 0 | 1 | yes |
get_alert_group | 89 | 95 chars | 1 | 1 | 1 | yes |
get_incident | 88 | 137 chars | 1 | 1 | 1 | yes |
list_oncall_teams | 83 | 112 chars | 1 | 0 | 1 | yes |
search_folders | 80 | 109 chars | 1 | 0 | 1 | yes |
get_snapshot | 71 | 81 chars | 1 | 1 | 1 | yes |
delete_snapshot | 65 | 42 chars | 1 | 1 | 1 | yes |
How this compares
Within Observability this is rank 1 of 1 scanned servers — exactly on the category median of 77.
The closest comparisons in this directory are Notion, MongoDB and Chrome DevTools, which sit nearest on score and face the same kind of surface-design pressure.
- Category
- Observability
- Rank in category
- 1
- Category median score
- 77
- Category median tokens
- 16,794
A fix plan turns these findings into an ordered set of changes with the token saving of each one.
This page is a static analysis of Grafana's published tools/list surface on the date shown. It is not a security review, a performance benchmark, or a judgement of the product behind the surface. Read how the score is computed, or browse every audited server.