This is a copy of an article first published on AgentShortlist, where the tables and cards live.
On 18 and 19 October 2026 we read the documentati...
For further actions, you may consider blocking this person and/or reporting abuse
The read-only finding is the most actionable part: 5 of 25 documented is low, but the MySQL example shows the fix is not always in the MCP layer itself. Enforcing the limit in the underlying credential, like a read-only database user or a narrowly scoped token, survives a server update or a misconfigured flag in a way that a README recipe does not. Did any of the five documented read-only modes enforce it that way at the credential level, rather than just filtering tools inside the server process?
Closest is DBHub: its README says it checks statements and runs them under the database's own read-only mechanism, so enforcement sits at the engine, not only in the server. n8n-mcp suggests a read-only API key as defence in depth. GitHub and MongoDB filter tools inside the server. That's what the docs say; we haven't tested any of it. Your point stands: a read-only credential is the layer that survives a bad flag or an update.
One layer below the read-only credential: who holds it. In the sandbox I run, the records key exists as a Secret in two namespaces, the service's and the MCP server's, and admission refuses any agent pod that references a Secret in a volume or its environment.
The agent's one credential is a ServiceAccount token for the server's audience, valid ten minutes, bound to its pod and refused by the API server. A fooled agent can still misuse a tool it was granted. It can't carry the key out.
That is a useful extra layer: a read-only credential limits what a leaked key can do, but who holds it decides whether it can leak at all. Short-lived, pod-bound tokens and refusing secrets in the agent’s environment is a stronger setup than anything the cards we’ve read describe. Most documented setups put the credential in an env var in the client config. We can’t verify your sandbox from here, but “where the credential lives” is a good axis to add next to “what it allows”.
You can check it from there: the refusal is a test in a public repo, not a description of one.
On every change, the e2e on a fresh kind cluster applies twelve planted manifests, among them a Secret in the environment, a Secret as a volume, a token with no audience and a token valid for a day. Each must be refused for the reason it names, and two compliant controls must be admitted, so the check can't pass by refusing everything.
The rules are ValidatingAdmissionPolicies, so the API server enforces them itself, with no webhook that can be down. kubernetes-ai-agent-sandbox
Thanks, that is the distinction I was missing: a refusal that is a test, not a description of one. I read the repo’s README and tree: two ValidatingAdmissionPolicies in manifests/admission.yaml, and an e2e on kind with twelve planted manifests, each refusal paired with compliant controls so it can’t pass by refusing everything. I haven’t run it or read the CEL rules, so on our side I would record it as “documented by the project, not tested by us”, with the link. The axis I’d add to our cards is yours: where the credential lives, separate from what it allows. If I got any detail wrong, tell me and I’ll fix it.
The pinning advice runs into how most people install these. A lot of README config snippets start the server with
npx -y package-nameand no version, so every client restart pulls whatever is latest. A version you checked against OSV only stays checked if the version sits in the client config itself.On telemetry, "not stated" could become a measured line on the card: run each server once with outbound traffic logged and record which hosts it actually contacts. That would move several of the 20 silent ones from unknown to observed, without waiting on the maintainers.
Agreed on pinning: a version only stays checked if it's in the client config, which is why the checker flags
npxwithout a version. The traffic-log idea is good. I'd label it as observed on one version with the tools actually exercised, so it doesn't claim more than it saw. Starting with the silent ones makes sense.The “not verified” category matters: silence about telemetry or read-only mode is not evidence of absence. For the server cards, I'd separate a documented switch, source-level enforcement, and a negative write probe under a constrained credential. Your MySQL example shows the real boundary may be the database role, not the MCP server. Are runnable capability checks on your roadmap?
Yes, that's the next step: a documented switch, what the source enforces, and a write attempt under a constrained credential, each line labelled by how it was learned. We'll start with read-only on a handful of servers and publish the failures too. Not started yet, so no date.
the readme says read-only, the readme also says a lot of things