Why MCP's readOnlyHint Can't Be Trusted: Enforce Read-Only at the Database Layer

The article explains that MCP's readOnlyHint is a server-declared hint, not an enforceable guarantee; clients must treat annotations as untrusted unless from verified servers, and true read-only enforcement requires execution-layer permissions like database roles, while also noting data exfiltration risks via openWorldHint.

Architecture Development Notes
Architecture Development Notes
Architecture Development Notes
Why MCP's readOnlyHint Can't Be Trusted: Enforce Read-Only at the Database Layer

MCP tool definitions can include an annotations field with readOnlyHint: true, which is easily misread as "this tool is read-only and safe to call." Based on the 2025-11-25 tools specification and the official 2026-03-16 tool annotations blog post, this field carries far less responsibility than intuition suggests.

Who Writes the Label, Who Decides Trust

The specification defines annotations as optional descriptions of tool behavior and requires clients to treat tool annotations as untrusted by default unless they come from a trusted server. The official blog further clarifies that these fields are hints, not enforced guarantees.

The readOnlyHint is written by the server itself. A buggy implementation, a swapped server, or an inherently untrustworthy server can all declare true. The client cannot infer from this field whether the server actually honors the claim.

Three distinct roles are involved:

Server declaration — states what the author believes the tool does.

Client policy — decides what to do with that declaration, e.g., whether to reduce confirmation dialogs. This layer depends on the host implementation; the spec does not require clients to skip confirmation based on readOnlyHint.

Execution-layer permissions — the database account, filesystem rights, or other credentials behind the tool. These are what ultimately determine whether a call can mutate data.

Per the spec, only annotations from a trusted server may be adopted — for example, a server the team deploys and audits themselves. This does not mean trusting every installed server; unverified third-party servers must have their annotations treated as untrusted.

Default Values Favor the Worst Case

Both the official blog and the schema bundled with the spec list default values for the four hint fields: readOnlyHint defaults to

false
destructiveHint

defaults to

true
idempotentHint

defaults to

false
openWorldHint

defaults to true When a server provides no annotations, the client should assume the tool may modify the environment, may be destructive, retries may be unsafe, and it may interact with the external world. Note that destructiveHint and idempotentHint are only meaningful when readOnlyHint is false.

This default direction benefits safety: a server must actively declare hints to make a tool appear lighter. Yet even after declaration, whether to adopt the hints remains the client policy's decision; defaults merely set the starting point when no declaration exists.

An Illustrative Example

The following scenario is designed to illustrate the layering; it is not a benchmark result. Assume the team self-hosts an order-query MCP server with the following tool definition:

{
  "name": "query_orders",
  "annotations": {
    "readOnlyHint": true,
    "openWorldHint": false
  }
}

The host can configure a policy: only readOnlyHint from this self-deployed server is accepted, and confirmations are reduced for it. That is a client-side decision. On the server side, the server connects to the database using a read-only role. With PostgreSQL, for example:

CREATE ROLE mcp_reader LOGIN;
GRANT SELECT ON orders TO mcp_reader;

With this setup, even if the server code malfunctions and constructs a DELETE statement, the database will reject it because the role lacks write permission. The annotation serves only as documentation for humans and clients; the real barrier against writes is the role permission. This approach assumes the backend database supports role-based authorization, the server does not bypass the role to use another account, and the role does not inherit write capabilities from the default PUBLIC privileges (e.g., in PostgreSQL versions before 15, the public schema allowed any role to create tables). The two SQL statements above are illustrative and omit authentication configuration.

Read-Only Does Not Mean No Exfiltration

In the specification's context, readOnly only means the tool does not mutate the environment. A read-only query tool still returns data into the model's context. If the same session includes tools with network access, or if the server itself has outbound network permissions, that data can be sent elsewhere. Database roles block writes; they do not block this exfiltration path. openWorldHint is also easily misused. It describes the scope of the tool's interactions — whether it deals with external open entities — and is not an authorization signal: false does not mean an operation is permitted, and true does not mean it has been approved.

Therefore, a read-only query tool requires at least two separate controls. Write restriction is enforced by execution-layer permissions, such as the read-only role shown above. Exfiltration prevention depends on network egress limits, the scope of credentials, and the combination of other tools in the same session. Treating readOnlyHint: true as the answer to both problems mistakes the server's self-description for a system guarantee.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MCPPostgreSQLdatabase permissionsprotocol securitytool annotationsreadOnlyHint
Architecture Development Notes
Written by

Architecture Development Notes

Focused on architecture design, technology trend analysis, and practical development experience sharing.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.