With Claude Code¶
Point Claude Code at your Prodpeek and it can read your production without being able to touch it.
Connect it¶
You need a client key (mint one) and your Prodpeek URL.
claude mcp add --transport http prodpeek https://prodpeek.example.dk/mcp \
--header "Authorization: Bearer ppk_your_client_key"
Then /mcp inside Claude Code to confirm it connected.
Prodpeek is a standard streamable-HTTP MCP server. Point your client at
/mcp with an Authorization: Bearer header. There is no session to
establish and no vendor SDK involved.
The key is a secret
It is not as powerful as the underlying production credentials — that is the whole point — but it does read your production. Keep it out of the repository and out of a shared shell history, and give it a short lifetime.
Start by asking what it can do¶
The first thing worth asking, every time:
What can you see through Prodpeek?
Claude calls prodpeek__explain, which answers from local state without touching
your systems. You get back which services the key holds, which tools each allows,
which it refuses and why.
This is faster than probing and it does not fill your audit log with refusals.
What it is good at¶
Triage across systems. The thing a single dashboard cannot do.
The EJD site is slow. Check Coolify for the app status, Prometheus for the request rate and error rate over the last hour, and Grafana for anything firing.
"When did this change."
Compare the deploy times in Coolify with the error rate in Prometheus for the last 24 hours. Did anything line up?
CI archaeology.
How long has the main branch been failing, and which step started it?
Cardinality and cost.
Prometheus is using 40GB. Which metrics have the most series?
What it will refuse, and what that looks like¶
Ask it to restart something and you get a refusal with a reason:
{
"error": {
"code": -32003,
"message": "prodpeek denied this call: tool_explicitly_denied",
"data": {
"reason": "tool_explicitly_denied",
"detail": "tool 'restart_application' is denied by profile 'coolify/read-only'",
"rule": "tools[restart_application].verdict=deny"
}
}
}
Claude reports that rather than looking for another route, because there is not one. The refusal is in your audit log with Claude's key label on it.
The refusal is information
If you keep hitting one, that is worth knowing: either the agent is trying to do something it should not, or the profile is missing a read people genuinely need. Audit → Denials groups every refusal by tool and reason — a pile on one tool is a profile's to-do list.
Give it the context it needs¶
Claude does not know your architecture. A short CLAUDE.md in the repository you
work in pays for itself:
## Production access
Read-only, through Prodpeek. Start with `prodpeek__explain`.
- `ejd-coolify` — the app platform. Deploys, container status, logs.
- `ejd-prom` — metrics. `rate(http_requests_total[5m])` is the request rate;
the app's own metrics are prefixed `ejd_`.
- `ejd-grafana` — dashboards and alert rules.
- `ejd-actions` — CI. Run metadata only; raw logs are deliberately not available.
You cannot write, restart, deploy or cancel anything. Do not look for a way
round a refusal — there is not one, and the attempt is audited. Report the
refusal and what you needed instead.
Several customers at once¶
Prodpeek projects are customers. A key belongs to one project and cannot reach another, so the safe shape is one key per customer:
claude mcp add --transport http ejd https://prodpeek.example.dk/mcp \
--header "Authorization: Bearer ppk_ejd_key"
claude mcp add --transport http acme https://prodpeek.example.dk/mcp \
--header "Authorization: Bearer ppk_acme_key"
Same instance, same URL, two keys that cannot see each other's systems. That separation is checked when the key is minted and again when the gateway builds its policy, so a hand-edited row still grants nothing across the line.