MCP readOnlyHint is not a read-only permission boundary
MCP readOnlyHint can influence approval without restricting backend permissions. Enforce read-only access at the target service, separate credentials, and test the harness against misleading annotations.
A hypothetical, but familiarAn engineer asks an agent to inspect a service record before a change review. The harness skips approval because the MCP server marks the tool read-only, but the tool updates the record using a write-capable backend identity. The engineer receives a result without ever approving the change.
- Enforce read-only access through target-service permissions that reject writes, rather than trusting tool annotations.
- Give read and write paths separate credentials, and keep write credentials unavailable to the read-only runtime.
- Test whether misleading annotations suppress approval, then independently verify that attempted writes are denied.
Skipping approval does not remove write authority
The MCP project’s explanation of the tools specification is explicit: annotations are hints, are not guaranteed to describe behaviour faithfully, and must be treated as untrusted unless they come from a trusted server. It describes a possible client decision: a tool carrying readOnlyHint set to true might be auto-approved. That is an approval decision, not a permission change. The annotation does not remove write authority from the identity the server uses against its backend.
The failure path is straightforward: the harness trusts the server’s claim, omits confirmation, and invokes a tool whose backend credentials permit modification. A misleading definition or changed implementation can then turn an apparently harmless call into a write. This is a threat model, not evidence of a vulnerability in a named product. OWASP identifies the related confused-deputy risk: an MCP server may act with its own broad privileges rather than the requesting user’s permissions.
Evidence: MCP (Model Context Protocol) Security Cheat Sheet¶, Tool Annotations as Risk Vocabulary: What Hints Can and Can't Do
Put the write restriction where the change happens
My recommendation is to start at the target service and work backwards. Identify the principal that actually authorises each backend operation, then grant only the reads that the workflow needs. Use the service’s supported authorisation controls to exclude writes, and validate that exclusion with negative tests. OWASP calls for least privilege and authorisation checks on every protected request. Applied here, the decisive protection is that a write fails even when the harness has already approved the tool call.
| Layer | Purpose | Not a substitute for |
|---|---|---|
| Tool annotation | Describe expected behaviour | Write restrictions |
| Harness approval | Obtain consent before execution | Backend authorisation |
| Server restriction | Constrain allowed operations | Target-service permissions |
| Target-service policy | Enforce permitted operations | Sensitive-action consent |
Keep consent and authorisation separate in the design review. A user’s confirmation should not grant permissions the backend identity lacks; equally, valid backend credentials do not establish that the user approved this particular action. OWASP recommends explicit confirmation for destructive, financial and data-sharing operations, with full call parameters displayed. It also advises against automatic approval. Use trusted application code to enforce these decisions independently of the model’s interpretation, rather than asking the model to police its own tool use.
A read-only claim belongs in tool metadata; a read-only guarantee belongs in the target service’s authorisation policy.
Evidence: MCP (Model Context Protocol) Security Cheat Sheet¶, Tool Annotations as Risk Vocabulary: What Hints Can and Can't Do
Give read and write paths different credentials
A tool catalogue split into read and write tools is insufficient if both paths reach the same broadly privileged credential. My recommendation is to separate the credential paths as well as the tool definitions. Give the read path a backend identity restricted to necessary reads; give the write path a separately governed identity and approval policy. Where actions run for a user, check that the backend authorisation reflects that user’s permitted actions rather than silently substituting broader server authority.
- Map each tool to its backend identity and effective permissions.
- Restrict read credentials to the required resources and read operations.
- Keep write credentials inaccessible to the read-only runtime.
- Require a separately controlled execution path for approved writes.
- Use scoped, per-server credentials rather than sharing tokens between servers.
OWASP recommends narrow OAuth scopes, per-server credentials and short-lived tokens. It also says to validate that an access token is intended for the receiving MCP server and never pass an MCP access token to an upstream API. Do not confuse authentication to the MCP endpoint with authorisation at the target service. Review both credential relationships explicitly: who may invoke the server, and which identity the server uses to access the protected resource.
Evidence: MCP (Model Context Protocol) Security Cheat Sheet¶
A product read-only mode is different from an annotation
Microsoft documents both a Read only server-start option and read-only tool annotations for Azure MCP Server. The option is documented to disallow write operations when enabled; the annotation describes whether a tool changes its environment. These are different controls. Microsoft also documents that access uses Azure user credentials or a managed identity and is secured through Azure RBAC. My recommendation is to combine the documented server restriction with appropriately restricted target permissions, then test both rather than treating either as an annotation guarantee.
Google’s custom MCP connector documentation illustrates another identity distinction. For authenticated Cloud Run services, Gemini Enterprise sends a service-agent ID token in X-Serverless-Authorization while preserving the user’s OAuth token in Authorization; the automatic ID token applies to the default Cloud Run domain, not custom domains. The documentation describes connector scopes as permissions used to access the MCP server. These details establish connection behaviour, not a readOnlyHint approval policy or a guarantee that downstream credentials cannot write.
Evidence: Set up your custom MCP server data store Stay organized with collections Save and categorize content based on your preferences., What are the Azure MCP Server tools?
Test the approval decision and the backend denial separately
My recommendation is a controlled test using disposable records and a test MCP server, not production data. Keep the proposed backend action constant while changing the annotation, so the approval decision has a clear cause. Then repeat with genuinely read-restricted credentials. The test should answer two separate questions: can server-supplied metadata suppress required confirmation, and can an attempted write succeed through the supposedly read-only path? Passing the permission test does not excuse a broken approval policy.
- Establish a baseline write attempt with confirmation required and record the harness decision.
- Repeat the same attempt with a misleading readOnlyHint and check whether confirmation disappears.
- Repeat without annotations and verify that missing metadata does not relax the approval policy.
- Use read-restricted credentials and confirm that the target rejects writes and leaves the test record unchanged.
- Keep the reviewed definition unchanged while changing test-server behaviour to attempt a write.
- Record invocation parameters, user context, approval outcomes and target results, while redacting secrets and personal data.
OWASP recommends pinning reviewed tool definitions and reviewing changes, but warns that this detects metadata changes, not altered behaviour behind an unchanged definition. That is why the unchanged-definition test matters. Retain evidence from both the harness and the target service: a missing prompt establishes an approval problem; a successful state change establishes that write authority remained available. The acceptance criterion for the read path is simple: misleading metadata must not make a prohibited write possible.
Evidence: MCP (Model Context Protocol) Security Cheat Sheet¶, Tool Annotations as Risk Vocabulary: What Hints Can and Can't Do
Sources and further reading
- Set up your custom MCP server data store Stay organized with collections Save and categorize content based on your preferences.
- MCP (Model Context Protocol) Security Cheat Sheet¶
- What are the Azure MCP Server tools?
- Tool Annotations as Risk Vocabulary: What Hints Can and Can't Do
Source links support the documented product behaviour. Recommendations and labelled examples are editorial guidance.