What MCP Tool Annotations Tell You About Agent Behavior
Four boolean hints preview tool behavior, but only if you trust the server supplying them.

MCP tool annotations give hosts a way to read agent behavior before a tool call ever fires. The system works, but only within a narrow range of trust, coverage, and enforcement that the rest of this piece maps out.
MCP tool annotation hints
Tool annotations shipped as part of the 2025-03-26 spec revision, and the interface they introduced still stands today: four boolean hints attached to a tool's definition, read by the host before the tool runs. readOnlyHint, destructiveHint, idempotentHint, and openWorldHint are those four.
readOnlyHint set to true tells the host that the tool only reads data and produces no side effects, which is the signal that lets a client skip a confirmation prompt and approve the call automatically. destructiveHint set to true flags a tool that performs irreversible actions, the kind where a host should stop and ask a person before proceeding. idempotentHint set to true marks a tool as safe to call again with the same arguments, without the repeated call compounding whatever effect the first one had. openWorldHint set to true means the tool reaches outside the server's own boundary, into external services like email or social media, and that one matters as much for what comes back as for what goes out: once a tool touches something external, anything it returns to the agent could carry content the host never generated and never vetted.
None of these four hints are guarantees. The spec states the practical implication directly: every one of them is a hint, and clients are expected to treat them as untrusted unless the server supplying them has already earned trust some other way. A tool that ships with no annotations at all gets the most cautious reading by default: assumed not read-only, assumed potentially destructive, assumed non-idempotent, assumed open-world. The spec would rather a host over-ask for confirmation than under-ask.
openWorldHint deserves a second look, because what counts as "external" shifts depending on where the server sits. For one deployment, external might mean anything outside a corporate network. For another, it might mean anything beyond the single machine running the agent. The safest posture treats anything a tool itself considers external as a possible source of content the host didn't write and can't yet trust, which is the exact seam later sections return to when the subject turns to exfiltration.
How hosts use annotations to shape agent behavior
Annotations give a host a decision point before a tool call executes: approve automatically, ask the user first, or block the call.
A real production system makes a real scheduling decision based on a single boolean, showing annotations doing exactly the job they were designed for when the server supplying them can be trusted.
openWorldHint sits apart from the other three. Where readOnlyHint, destructiveHint, and idempotentHint shape what happens before the call, openWorldHint shapes how the host should treat what comes back after the call, because output from an open-world tool may carry content from outside the server's own control. A host that takes that distinction seriously treats open-world output with more scrutiny than output from a tool that never left its own sandbox.
The four hints form a working system only when they're accurate and the server supplying them is trustworthy. Claude Code's parallelism behavior demonstrates that the system has real teeth: a hint can change how fast an agent works and how much a user gets asked to confirm. The question that follows is how much of the MCP ecosystem actually supplies these hints in the first place, and that's where the system starts to show its limits.
How widely annotations are set across the MCP ecosystem
Annotation coverage across the MCP ecosystem is sparse, and it's uneven in a way that makes it unreliable as a control applied across the whole population of tools. A July 2026 census of the official MCP registry, a snapshot taken on 2026-07-27 covering 98,291 tools, stands as the largest available measure of how often servers actually set these fields. destructiveHint has no meaning once readOnlyHint is already true, and because that pairing describes more than half of all tools in the registry, most recorded "set" fields carry no usable information. A majority of the fields recorded as "set" carry no usable information at all, because the value is logically redundant given the other hint already present.
A second complication sits beneath the raw coverage numbers. Many of the annotation values present in these registries likely trace back to SDK defaults or boilerplate server templates, rather than a deliberate choice an author made about a specific tool. A field being present doesn't mean anyone looked at that tool and decided what readOnlyHint or openWorldHint should say about it. It may just mean the SDK the author used sets a default value and nobody changed it.
The two gaps feed each other. Server authors have little incentive to spend time writing precise annotations when most clients don't act on them yet, and clients have little incentive to build annotation-aware features when most servers don't supply reliable data to act on. The result splits the ecosystem into a vetted minority of servers with annotations worth trusting and a much larger body where annotations are either absent, templated, or structurally redundant.
An organization can only safely build annotation-based policy, auto-approving reads, demanding confirmation for destructive actions, around the subset of servers it has explicitly reviewed. Applying that same policy to the registry at large would mean trusting fields that, in a majority of cases, were never meaningfully chosen. And even where a server has set its annotations deliberately and correctly, that accuracy is worth nothing if the server itself can't be trusted, which is the question the next section takes up directly.
Why unvetted servers' annotations offer no safety guarantee
An annotation is only as good as the server declaring it, and the spec's authors knew that from the start. MCP co-creator Justin Spahr-Summers raised the issue directly during review of the original annotation proposal: the information these hints carry would be genuinely useful if it could be trusted, but a client has no way to use a hint while knowing that hint isn't trustworthy, a limit they named on purpose and built the rest of the system around.
The resolution baked into the spec reflects that limit honestly: call every one of these fields a hint, require clients to treat hints as untrusted unless the server supplying them has earned trust some other way, and leave the weighting decision to each client based on what it actually knows about where the server came from. That's a deliberate, narrow design choice, not an oversight.
For anyone building a client, the practical consequence is specific: treat annotations from servers you haven't vetted as informational only, useful for shaping the user experience, and keep the actual safety guarantees somewhere else, in deterministic controls the host enforces regardless of what any server claims about itself.
The NSA's cybersecurity guidance frames the whole situation structurally rather than as a server-by-server problem: MCP's rapid growth has outpaced the development of its own security model, the protocol shipped with a design that's flexible and underspecified, and the agencies behind that guidance are blunt that critical security behaviors have to be enforced through implementation rigor, because the protocol itself won't enforce them by default.
Research on malicious tool behavior bears this out directly. A malicious tool can keep a completely benign-looking interface, correct metadata included, while the implementation underneath does something unsafe. Reading a tool's description or its annotations tells almost nothing about what the tool's code actually does when called. Putting the coverage gap from the last section next to this trust gap shows the annotation system ends up governing only the vetted slice of the ecosystem that an organization has already done the work to check. The unvetted majority operates entirely outside the vocabulary the spec provides, and an attacker who understands that limit has a clear opening to exploit it.
Attackers exploiting the gap between declared annotations and actual tool behavior
Annotations are unverified hints, and that single fact gives a capable attacker three distinct ways in: falsify the hint, hide an instruction inside the description field instead, or change the tool's behavior after a human has already approved it. None of these require breaking the protocol. They work within what MCP allows.
The description field is the sharpest version of the problem, because MCP mixes instructions and data in the same channel, and the description field is the unsanitized part of that mix. Invariant Labs demonstrated the mechanism in April 2025 with a poisoned calculator tool: the description embedded exfiltration directives, and when a user invoked the tool, the agent silently read the developer's SSH private key and sent it to a remote endpoint, all while returning the correct arithmetic answer, with no visible anomaly, no prompt to the user, and no trace left behind. At the protocol level, a description reading "Add two numbers and return the result" looks no different from one that also instructs the agent to read ~/.ssh/id_rsa and include its contents in the response. Nothing in the annotation system catches that difference, because annotations describe the tool's category of behavior, not the literal text sitting in its description field.
Regulators and standards bodies have started treating that field as what it actually is. Microsoft's June 2026 security guidance classifies MCP tool descriptions as supply-chain assets that need the same review rigor as production code. OWASP has placed tool poisoning third on its MCP Top 10.
A second pattern works on a delay. A server can advertise a harmless description when a user first installs it, then switch that description to something malicious after the tool has already earned the user's trust. Microsoft's guidance treats a description change the same way it would treat a dependency update: a modification that needs review before anyone lets it become active.
The third pattern is the combination Simon Willison calls the lethal trifecta: access to private data, exposure to untrusted content, and the ability to communicate externally. When all three sit in the same place, an attacker who controls just one piece of untrusted content can get the model to read private data and send it back out. openWorldHint is supposed to flag exactly this risk, but even a correctly set hint can't stop the combination once all three conditions exist on the same server. And the blast radius compounds quickly: a single MCP server commonly holds credentials for Slack, GitHub, Postgres, and Salesforce all at once, so compromising that one server breaches every system it touches.
Adversa AI's TrustFall disclosure in May 2026 found that Claude Code, Cursor CLI, Gemini CLI, and GitHub Copilot CLI all auto-executed project-defined MCP servers the moment a user accepted a folder trust prompt, without a separate disclosure that code execution was about to happen. This execution happens at developer-level OS privileges, with no process isolation.
These patterns have already moved past proof-of-concept and into measured, repeatable results. The MCPTox benchmark ran 45 live MCP servers against 20 large language models and recorded a substantial average success rate for tool-poisoning attacks, with the worst single-model result landing at a level no production security control would tolerate. A shared-repository variant called MCPoison, tracked as CVE-2025-54136, showed that a single committed configuration file can compromise an entire team at once, multiplying the damage across every developer who opens that repository. A systemic architectural flaw disclosed in April 2026 by OX Security exposed a large estimated number of vulnerable instances across a supply chain touching more than 150 million package downloads. The NSA's May 2026 guidance adds that some MCP implementations let actor-controlled input reach execution environments without the constraints that should stop it, producing vulnerabilities generally rated high severity, and states that these risks are demonstrable rather than hypothetical. Multiple critical CVEs and real data-leak incidents have already followed from exactly this gap between what a tool's annotation declares and what its code actually does.


