dsh-tool-grafana
English | 简体中文
Grafana capability for DeepSeek Harness (dsh).
This plugin owns no Grafana tool logic. It composes the community
mcp-grafana server as a child
@deepseek-ai/dsh-mcp-client
plugin — the model sees mcp__grafana__* tools exactly as in any MCP-aware
agent — and layers on what a plain MCP bridge cannot provide:
- One config owner for connection material (URL, service-account token,
tool-category selection, read-only mode) instead of raw env passthrough.
- A standing system-prompt section (
grafana:workflow, order 115)
encoding the upstream context-window discipline: summary before full JSON,
JSONPath for partial reads, datasource discovery before querying.
- An embedded runtime skill (
grafana-troubleshooting) teaching a
systematic alert → dashboard → metrics → logs → incident workflow,
invocable on both model and user surfaces.
┌─ dsh-tool-grafana (this plugin) ─────────────┐
│ config validation · prompt section · skill │
└──────────────┬─────────────────────────────────────┘
│ ctx.plugin(dsh-mcp-client, plan)
▼
┌─ mcp-grafana (community Go binary, stdio) ────────┐
│ mcp__grafana__search_dashboards │
│ mcp__grafana__query_prometheus / loki / ... │
└───────────────────────────────────────────────────┘
The same mcp-grafana binary remains directly usable by Cursor, Claude Code,
OpenClaw, etc. — one core, both ecosystems.
Install into a profile
dsh plugin --profile web add dsh-tool-grafana
That is the whole installation: the package ships a bundle patch
(cordis.patch.yml + dsh.bundle declaration), so the plugin mounts with
its schema defaults — no YAML required. Finish setup in Settings →
Plugins → Grafana observability: enter the Grafana URL and the
service-account token, then restart the profile.
Custom configuration (optional)
To pin categories, a launcher, or defaults without the card, add a
same-id row to ~/.dsh/profiles/web/cordis.patch.yml — the profile
layer wins over the shipped bundle layer:
- insert:
- id: grafana
name: 'dsh-tool-grafana'
config:
url: https://myinstance.grafana.net # default; the settings card can override
# The token is resolved through the DSH credential store under this
# reference — never inline in this file:
tokenCredentialRef: GRAFANA_SERVICE_ACCOUNT_TOKEN
readOnly: true
categories: [search, datasource, dashboard, prometheus, loki, alerting]
launcher:
kind: uvx
version: '0.7.9' # pin the upstream release; omit to track latest
# kind: binary
# path: /usr/local/bin/mcp-grafana # go install github.com/grafana/mcp-grafana/cmd/mcp-grafana@vX.Y.Z
Card values are stored in the DSH settings document / credential store and
override the patch config per field; the patch url remains the
fallback default.
Config
| Field | Default | Meaning |
|---|
url | '' | Default Grafana base URL; the settings card value (web) overrides it. Both empty fails activation with guidance |
tokenCredentialRef | GRAFANA_SERVICE_ACCOUNT_TOKEN | Credential reference resolved through ctx.credentials (see below). No inline token field exists, by design |
categories | upstream default set* | mcp-grafana --enabled-tools categories |
readOnly | true | Default for --disable-write; the settings card toggle overrides it (web) |
launcher | {kind: 'uvx', version: ''} | How to start the server process; pin version (uvx) or use a versioned binary/docker tag to avoid upstream drift |
env | {} | Extra env merged into the server process |
toolCallTimeoutMs | 60000 | Per-tool-call timeout (dsh-mcp-client) |
* search, datasource, dashboard, folder, prometheus, loki, alerting, incident, oncall, sift, navigation, annotations. Heavy backends
(clickhouse, cloudwatch, snowflake, athena, elasticsearch,
quickwit, graphite, influxdb) and the runpanelquery/examples/
agento11y/assistant groups stay opt-in.
Credentials
The token is resolved through the DSH credential seam (ctx.credentials),
not read from a plugin-owned env var. With the default local provider
(dsh-credentials-local), the first configured source wins:
- Launching environment —
GRAFANA_SERVICE_ACCOUNT_TOKEN=… dsh web
- Managed store —
$DSH_HOME/.credentials.yaml (what the Web Models
page writes; writable from inside DSH)
- Project
.env in the invocation directory
- User
.env at $DSH_HOME/.env
There is no inline token config field, so the token can never be committed
into cordis.patch.yml or leak through --dump-config output.
Connection changes take effect on profile restart. The token and URL
are resolved once at activation and handed to the mcp-grafana process
environment; stdio MCP servers cannot receive env updates after spawn.
(Native-tool plugins like the dsh-grafana dashboard editor resolve per
tool call and pick up changes live — that is the trade-off of composition
over re-implementation.)
Web settings card
The package ships a dsh.client entry (client.js) that mounts a card
under Settings → Plugins → Grafana observability:
- Service Account Token — written to the credential store (write-only;
the card shows a mask, never the value)
- Grafana URL — stored in the
grafana settings namespace, shown
verbatim after saving
- Read-only toggle — stored in the same namespace
Precedence is card value > patch config > activation error, per field.
Development
npm install
npm run build # tsc → lib/
npm test # node --test (unit + real-Cordis integration)
The integration test boots the plugin under a real Cordis context with the
real dsh-system-prompt and dsh-skill services, stubbing only the child
mcp-client mount so no Grafana is needed.
Design notes
- Why not re-implement the tools natively? The community server ships 60+
tools with per-category flags, auth handling, and active upstream
maintenance. Re-implementing buys nothing and forks the maintenance burden.
- Why not just
dsh-mcp-client directly? You can — one YAML row works.
This plugin exists for the delta MCP can't express: validated config,
prompt-level usage discipline, and bundled workflow knowledge.
- Token hygiene: the token only ever travels into the child process env,
never into prompts, tool output, or logs (declared as this package's
invariant in
./invariant).
License
MIT