MCP Tool Annotations: readOnlyHint, destructiveHint and the Rest | MCP Hunter

tool annotations

Also written annotations

Tool annotations are optional hints on a tool object describing how it behaves: readOnlyHint (it only reads), destructiveHint (it may delete or overwrite), idempotentHint (repeating it changes nothing more) and openWorldHint (it reaches outside systems). The specification requires clients to treat them as untrusted unless the server is trusted.

Updated

What are tool annotations?

Annotations are a small object of behavioural hints attached to a tool. They describe the kind of operation the tool performs rather than its arguments, and they arrive inside each tool in a tools/list answer.

What are the four hints?

There are four, plus an optional title. Each one is a boolean, and each has a default that applies when the server leaves it out. These are the definitions in the 2025-11-25 schema, unchanged in 2026-07-28:

Hint When true Default if absent
readOnlyHint The tool does not modify its environment false
destructiveHint It may perform destructive updates; false means only additive ones true
idempotentHint Calling it again with the same arguments has no further effect false
openWorldHint It interacts with an open set of outside entities, like web search true

destructiveHint and idempotentHint only mean something when readOnlyHint is false. A read-only tool cannot destroy anything, so the other two are moot for it.

The defaults are the cautious reading: a tool that says nothing about itself is treated as one that writes, may destroy, is not safe to repeat, and reaches the outside world.

How often do real servers set each one?

We counted the annotations on the 288 tools that 14 public MCP servers returned in the run behind our tools/list reference. 262 of those tools carried an annotations object, which is 91%. Inside those 262:

Hint Set Set to true Set to false
readOnlyHint 262 145 117
idempotentHint 138 126 12
destructiveHint 49 5 44
openWorldHint 44 17 27
title 13

Every annotated tool says whether it is read-only, and almost nothing else is said consistently. Only 49 tools state whether they are destructive, so for 213 of the 262 a client falls back on the default, which is "may be destructive". 5 tools in the whole sample declared themselves destructive outright.

This is one sample of 14 servers, so read the shares as what those servers did, not as a census of the ecosystem.

Why does the specification call them untrusted?

Because they are the server's own claims about itself, and nothing verifies them. The specification is explicit that a client "MUST consider tool annotations to be untrusted unless they come from trusted servers".

A tool annotated read-only can still write. The annotation is a hint for presentation and caution, never a guarantee, and a client that gates a confirmation prompt purely on the annotation has trusted a stranger's assertion.

Example

One tool from the same sample, list-models, annotated itself like this:

{
  "readOnlyHint": true,
  "destructiveHint": false,
  "idempotentHint": true,
  "openWorldHint": false
}

It lists things, so read-only and idempotent are the honest answers, and it sets all four explicitly rather than leaning on defaults. A tool that deletes a record would set readOnlyHint: false and leave destructiveHint at its default of true, and a careful client would ask before calling it. Both annotations are written by the same server author, which is precisely why the specification tells clients not to rely on them for safety decisions.

Go deeper

Related terms