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.