On this page
MCP tool annotations are labels a server puts on each tool: read-only or not, destructive or not, safe to repeat or not, and whether it reaches outside services. They help clients and people decide what to approve. But they are hints from the server, not guarantees, and the spec says to ignore them from servers you don't trust.
Two r/mcp threads made this topic hot. One tester found that "most MCP servers I test skip two of the four tool safety labels" (thread). Another user "approved a clean MCP server. 30 days later its tool description asked the agent for my SSH key" (thread).
The four annotations
These come from the ToolAnnotations type in the
MCP schema
(version 2026-07-28, the current one). The definitions and defaults are quoted
from it, and they read the same as in the previous version, 2025-11-25.
| Annotation | Spec definition | Default |
|---|---|---|
readOnlyHint |
"If true, the tool does not modify its environment." | false |
destructiveHint |
"If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates." Only meaningful when readOnlyHint is false. |
true |
idempotentHint |
"If true, calling the tool repeatedly with the same arguments will have no additional effect on its environment." Only meaningful when readOnlyHint is false. |
false |
openWorldHint |
"If true, this tool may interact with an 'open world' of external entities." A web search tool is open-world; a memory tool is not. | true |
There is also an optional title for display.
Notice the defaults. A tool with no annotations is assumed to write
(readOnlyHint false), to be possibly destructive (destructiveHint true), to
be unsafe to repeat, and to reach the outside world. So a server that skips the
labels isn't hiding anything. Its tools are just treated as the riskiest kind,
which is the safe assumption.
They are hints, not guarantees
The spec says this twice. In the schema: "all properties in ToolAnnotations are hints. They are not guaranteed to provide a faithful description of tool behavior", and "Clients should never make tool use decisions based on ToolAnnotations received from untrusted servers."
And in the Tools section: "clients MUST consider tool annotations to be untrusted unless they come from trusted servers."
That makes sense. The server writes its own labels. A buggy or malicious server
can mark a delete tool readOnlyHint: true, and nothing in the protocol stops
it. The spec's real safety rule is elsewhere: "there SHOULD always be a
human in the loop with the ability to deny tool invocations."
How clients use them
Only rely on what a client documents. Claude Code's MCP docs describe these uses:
- Retries after a dropped connection. If a call was pending when an HTTP
connection closed, Claude Code can repeat it once on a new connection, but
only for tools marked
idempotentHintorreadOnlyHint. - Parallel calls. Tools marked
readOnlyHintrun in parallel with other read-only calls. - Forcing a full approval prompt. A server can set
"anthropic/requiresUserInteraction": truein a tool's_meta. On surfaces that normally allow one-tap approval, Claude Code then shows the full permission prompt for that tool.
Claude Code's MCP docs don't say that annotations skip permission prompts. Your permission rules decide that. Treat any claim that a tool "is read-only, so it's auto-approved" with care unless your client documents it.
The bigger risk: tools that change after you approve them
Annotations describe a tool at one moment. MCP lets a server's tool list
change over time. Under the 2026-07-28 spec, a server that declares
listChanged "SHOULD send a notification" when its tools change to clients
that have opened a subscriptions/listen stream asking for tool-list changes,
and the client fetches the new list. Lists now also carry a ttlMs freshness
hint that tells a client how long it may cache them
(changelog).
Updates to a package can change tool descriptions too.
That is the "rug pull" from the Reddit thread: a description that was harmless when you approved it later contains instructions aimed at the model. A related thread tests "positional prompt-injection scanning for MCP tool descriptions" (thread).
What you can do:
- Pin versions of local servers. Use an exact version in your config, for
example
package@1.2.3instead of@latest, or a Docker image digest. Then updates only happen when you choose. - Re-review on update. When you bump a version, read the changelog and the tool list again. The 5-minute safety check covers what to look for.
- Keep tool approval on for anything that writes, whatever its labels say.
- Watch for advisories. Our registry watch checks the official MCP registry daily and flags new security advisories against servers, so you can see when something you run needs a look.
- Prefer hosted servers from the vendor for high-risk systems. A vendor that runs its own server is accountable for what its tools say.
Read-only modes in our directory
A real read-only mode, enforced by the server or the token, is stronger than a
readOnlyHint label. These listings document one:
| Server | Grade | Read-only option |
|---|---|---|
| GitHub | A | Read-only endpoint (/mcp/readonly) |
| Buildkite | A | /mcp/readonly endpoint that issues a read-only token |
| Cloudflare | A | Read-only grant at sign-in |
| Linear | A | Read-only endpoint |
| Supabase | A | read_only option |
| MongoDB | A | --readOnly flag |
| Salesforce | B | Read-only server |
| Snowflake | C | SQL tool is read-only (SELECT only) unless you turn that off |
| Figma | B | The desktop server has no write tools |
Servers without one can still be narrowed: deny their write tools in your client's permission rules, or connect with a restricted token. See MCP authentication explained for which grants are too broad.
Frequently asked questions
What is readOnlyHint in MCP?
A label meaning the tool doesn't change anything. It defaults to false, so a tool is assumed to write unless the server says otherwise. It's a hint from the server, not a guarantee.
If a tool says destructiveHint: false, is it safe?
It means the server says the tool only adds things, never deletes or overwrites. That's useful, but it's the server's own claim. Only trust it from servers you trust, and keep approval on for writes.
Why do so many servers leave annotations out?
They're optional. Leaving them out isn't dangerous in itself, because the defaults assume the worst. It does lose useful information, like which tools are safe to repeat after a dropped connection.
Can a malicious server lie in its annotations?
Yes. That's why the spec says clients must treat annotations as untrusted unless the server is trusted. Your defence is a trusted source, pinned versions and human approval, not the labels.
I build an MCP server. Which annotations should I set?
Set readOnlyHint: true on tools that only read, and idempotentHint: true on
writes that are safe to repeat. Set destructiveHint: false on tools that only
add. Be accurate: clients like Claude Code use these to decide retries and
parallel calls.