Services → Grafana
Connect Grafana
Dashboards, panel queries, alert rules, what is firing right now, and PromQL or LogQL through your datasources. One URL and one token — Prodpeek speaks Grafana's own API, so there is nothing to install.
Setting this up with your own agent? Give it these instructions.
The whole setup
Two things, and you already have one of them.
### 1. Mint the token (about two minutes)
- In Grafana: Administration → Users and access → Service accounts.
- Add service account. Name it
prodpeek. Set the role to Viewer. - Add service account token. Name it, set an expiry, generate.
- Copy it. It starts
glsa_.
### 2. Add it in Prodpeek
Services → Add a service, pick grafana/read-only:
| Field | Value |
|---|---|
| Upstream | https://your-stack.grafana.net — just the origin |
| Credential | the glsa_… token |
Press Test connection. That is the whole thing.
!!! tip "Use the origin, not the page you are looking at"
https://ejendomstorvet.grafana.net — not the URL of a dashboard. Prodpeek
will tell you if you paste a /d/abc123/... link rather than failing
mysteriously on every call.
From an agent, with no credential, then hand over the drop link:
{"name": "ejd-grafana",
"profile": "grafana/read-only",
"url": "https://ejendomstorvet.grafana.net"}
Why there is no MCP server to install
If you searched for "Grafana MCP" you found https://mcp.grafana.com/mcp, and it
is the wrong address for Prodpeek — not misconfigured, wrong in kind.
That endpoint authenticates with **OAuth 2.1 browser authorization, scoped to the
signed-in Grafana user**. Your editor opens a browser, you approve, and the
connection acts as *you*. Notice the config you find for it has no token in it.
Send a service account token and you get HTTP 401, always.
Prodpeek is a server-side gateway holding a stored credential for a team. It has
no browser and no signed-in user, and it should not have one — a gateway whose
authority is "whichever human last clicked approve" is not a gateway.
The other option was to have you run Grafana's own mcp-grafana in a sidecar,
with your Grafana token in its environment and a *second* token for Prodpeek to
authenticate to it. That works. It is also a container, a private network and two
tokens to read some dashboards.
So Prodpeek speaks Grafana's HTTP API directly, with a fixed menu, the way it
already does for SSH, Postgres, Git and Prometheus. Your glsa_ token is exactly
what that API wants.
What your agent can then do
ejd-grafana__search_dashboards find the dashboard somebody already built
ejd-grafana__get_panel_queries learn the right PromQL for a system it has not seen
ejd-grafana__query PromQL or LogQL through a datasource
ejd-grafana__list_firing_alerts what is on fire right now
ejd-grafana__list_alert_rules what is being watched, and at what threshold
ejd-grafana__list_annotations deploys and incidents, as the team marked them
ejd-grafana__whoami what this token is actually permitted to do
get_panel_queries is the one people do not expect to want. An agent that has
never seen your stack does not know your metric names. The queries behind a
dashboard your team already built are the fastest way for it to learn them — and
they come with the datasource UIDs that query needs, so the two tools chain.
Grafana tells you what the token can do
Most vendors will not answer "what is this credential allowed to do?". Grafana
will, at /api/access-control/user/permissions, and it needs no permission to
ask.
So this profile carries a scope probe, and every [prove](../use/prove.md) run
checks that your token holds no permission whose name contains :write,
:create or :delete. A token that gains one demotes the service and says so.
That is the difference between a Tier 2 you are asked to trust and a Tier 2 that
is re-checked on a schedule.
Call whoami yourself any time a call is refused. A 403 means the token
reached Grafana and was not allowed — the answer is a permission, not a role
upgrade.
What it refuses, and the two that surprise people
There is no tool that exports contact points.
GET /api/v1/provisioning/contact-points/export?decrypt=true returns your Slack
webhook URLs, PagerDuty integration keys and SMTP passwords in full. Grafana
documents it as a read. It is the most dangerous endpoint in the Grafana API, and
the adapter has no code path that builds it.
list_contact_points returns names and types only. "Where do alerts go" is a
real incident question. "And with which credential" is not one an agent gets to
ask, so the settings object is stripped before the answer is returned.
Likewise list_datasources gives you UID, name and type — not the URL, not the
auth configuration. A query needs the UID and nothing else.
Checking the token is really Viewer
STACK=https://your-stack.grafana.net
# Should succeed: reading dashboards
curl -sS -H "Authorization: Bearer $GLSA_TOKEN" "$STACK/api/search?limit=1" | head -c 200
# Should FAIL with 403: creating one
curl -sS -o /dev/null -w '%{http_code}\n' -X POST \
-H "Authorization: Bearer $GLSA_TOKEN" -H 'Content-Type: application/json' \
-d '{"dashboard":{"title":"prodpeek-permission-test"},"overwrite":false}' \
"$STACK/api/dashboards/db"
# What Grafana thinks this token may do
curl -sS -H "Authorization: Bearer $GLSA_TOKEN" \
"$STACK/api/access-control/user/permissions" | python3 -m json.tool
A 403 on the second is the part of the Tier 1 story Grafana *can* give you. A
200 means the token is Editor or better — delete it and make a Viewer one. The
gateway would still refuse the call, but you would be relying on one fence.
One connection per stack
Production and staging are two Grafana stacks, so two connections. Name them for
the stack, because the service name is the namespace an agent sees:
ejd-grafana-prod__query reads unambiguously in a transcript, and
grafana__query does not.
Screenshots
Screenshot pending — the steps above stand on their own.
Screenshot pending — the steps above stand on their own.