ax-check rule
AXC-D010: No side-effect annotations
The tool declares no readOnlyHint or destructiveHint, so clients fall back to the cautious defaults.
ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.
| Severity | info |
| Kind | Conformance. A finding is a fact about the input. |
| Mode | ax-check lint |
| Applies to | MCP tool lists |
| Pattern tags | approval, confirmation, idempotency |
| Fix in one line | Declare readOnlyHint, destructiveHint, idempotentHint and openWorldHint explicitly. |
The tool declares none of readOnlyHint, destructiveHint, idempotentHint or openWorldHint. Clients then fall back to the defaults in the MCP schema, which assume the worst: the tool may change things, may destroy data, is not safe to repeat and reaches the outside world. A harmless lookup gets the same friction as a delete.
What it checks
For each MCP tool, ax-check checks whether at least one of the four side-effect hints is set to true or false.
Why it matters
The MCP schema gives every hint a default. readOnlyHint defaults to false, destructiveHint to true, idempotentHint to false and openWorldHint to true. These defaults are cautious on purpose. A client that respects them may ask the user to confirm every call, including calls that only read data, and it cannot tell the agent which calls are safe to retry after a timeout.
Stating the hints gives a trusted client what it needs to ask for approval only where it matters. See Human approval workflows for AI agents.
Whether a call is safe to repeat matters more than it may seem. In a related study of the tool contract itself, Li ran 25,930 sandbox episodes with nine models; the paper’s claim (LIMBO, September 2026) is that an idempotency key on every write lowered the duplicate rate from 28% to 4%, because agents use keys when they exist. idempotentHint does not create such a key, but it tells the client which calls can be retried without one. See Record agent retries as product history.
Remember that hints are only hints. The specification says clients should never make tool use decisions based on annotations received from untrusted servers, so enforce the real boundary in the server too.
How to fix
Declare readOnlyHint, destructiveHint, idempotentHint and openWorldHint explicitly for every tool. For a read-only tool, readOnlyHint: true is the most useful single hint, because destructiveHint and idempotentHint only matter when the tool can write.
Example
Before
{
"name": "get_invoice",
"description": "Returns one invoice with its line items and payment history. Use this when you know the invoice ID; otherwise use search_invoices instead."
}
After
{
"name": "get_invoice",
"description": "Returns one invoice with its line items and payment history. Use this when you know the invoice ID; otherwise use search_invoices instead.",
"annotations": {
"readOnlyHint": true,
"openWorldHint": false
}
}
How ax-check detects it
The rule fires when none of the four hints is a boolean. A missing annotations object, an empty one, or hints written as strings such as "true" all count as no annotations. A title inside annotations does not count, because it says nothing about side effects.
The message adds advice from the tool’s verbs, found the same way as in AXC-D009. If the name or first sentence suggests a write (“create”, “send”, “delete”), it suggests destructiveHint and idempotentHint. If it suggests a read (“get”, “list”, “search”), it suggests readOnlyHint: true. Otherwise it says clients will assume the tool may be destructive.
This rule is info because missing hints are safe, only costly. It does not check whether the hints you set are correct; AXC-D009 and AXC-D011 catch the clearest contradictions.
Known false positives: a server whose only client ignores annotations gains little from them today. Silence the rule with --disable AXC-D010 if that is a deliberate choice.
Sources
- Specification: Model Context Protocol schema reference, ToolAnnotations, revision 2026-07-28. https://modelcontextprotocol.io/specification/2026-07-28/schema . Defines the four hints and their defaults, and says clients should never make tool use decisions based on annotations from untrusted servers.
- Paper: Li, “Where Does Exactly-Once Live? Model, Harness, and Tool-Contract Effects on Duplicate Side Effects in LLM Agents” (LIMBO), arXiv 2609.29095, 24 September 2026 (preprint, not peer reviewed). https://arxiv.org/abs/2609.29095 . The paper’s claim, from 25,930 deterministic sandbox episodes across nine models, is that an idempotency key on every write lowered the duplicate rate from 28% to 4%.
Related evidence
Records in the AX evidence register that share a pattern tag with this rule. A shared tag means the record is about the same pattern, not that it tests this rule. Read the evidence class before the number.
- EV-0014: Allow/ask/never policies blocked less overreach than per-action approval (Preprint). In a study of 113 people without software backgrounds (preprint), user-authored allow/ask/never policies blocked 20.1 percentage points less agent overreach than per-action approval, partly because participants chose 'ask' for 114 of 140 rules and then approved most overreach at runtime.
- EV-0016: Approval records omit the effects a command goes on to trigger (Preprint). A preprint reports that coding-agent approval records name the approved command but omit effects its workflow exercises: across 111 approval and trace pairs, unrecorded residual effects fell from 40 with explicit fields to 17 with command semantics and 13 with decision-time metadata.
- EV-0034: Vendor claim: users approved about 93% of permission prompts (Vendor claim). Anthropic states that its telemetry showed users approved roughly 93% of Claude Code permission prompts, and that an operating-system sandbox reduced permission prompts by 84%.
- EV-0005: Idempotency keys cut duplicate writes from 28% to 4% (Preprint). LIMBO (preprint) reports that offering an idempotency key on every write cut duplicate side effects from 28% to 4% of episodes because agents use keys when they exist, and that agents reported success in 90% of the episodes in which they had duplicated an effect.
- EV-0015: Approvals that outlive their task raise attack success (Preprint). A preprint reports that approvals persisted beyond the context that justified them raised prompt-injection attack success by up to 35.1 percentage points on 508 AgentDojo cases, and by 24.9 points on average in live tests on three production coding agents.
- EV-0036: A CLI exits 0 when a destructive command is refused (Independent measurement). Cloudflare's cf CLI documents that in a non-interactive session a destructive command without --force prints 'Aborted.' and exits with status 0, and a public issue reproduces this for workflows delete.
