Tool annotations (readOnlyHint, destructiveHint, openWorldHint) are set
Why it matters
MCP tool annotations (readOnlyHint, destructiveHint, openWorldHint) are the mechanism by which clients decide whether to auto-approve a tool call or prompt the user for confirmation. Without annotations, the MCP spec defaults destructiveHint to true and readOnlyHint to true — meaning a tool that permanently deletes files could be treated as read-only and auto-approved, bypassing any confirmation dialog. Clients that implement safe-by-default behavior rely entirely on these fields to gate destructive operations.
Severity rationale
Low because missing annotations degrade client safety UX but do not themselves cause data loss — the risk depends on how aggressively the client auto-approves unannotated tools.
Remediation
Set annotations on every tool that modifies state, deletes data, or calls external services. Read-only tools should explicitly mark readOnlyHint: true.
// src/tools/delete.ts
server.tool(
'delete_file',
{
description: 'Permanently delete a file from disk',
annotations: {
readOnlyHint: false,
destructiveHint: true,
openWorldHint: false,
},
},
{ path: z.string() },
async ({ path }) => { /* handler */ }
)
For pure read tools like search_files, set readOnlyHint: true, destructiveHint: false so clients can auto-approve them without a confirmation dialog.
Detection
-
ID:
tool-annotations -
Severity:
low -
What to look for: Count all tools. Enumerate which have MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) vs. which lack them. Check whether tools that perform side effects have appropriate annotations. The MCP spec defines
readOnlyHint(defaults true — tool doesn't modify state),destructiveHint(defaults true — tool may perform destructive operations), andopenWorldHint(defaults true — tool interacts with external systems). Check that write/delete tools havereadOnlyHint: falseanddestructiveHint: true. Check that pure read tools havereadOnlyHint: true. These annotations help clients display confirmation dialogs and make safer tool selection decisions. -
Pass criteria: Tools that modify state set
readOnlyHint: false. Destructive tools (delete, overwrite) setdestructiveHint: true. Read-only tools explicitly setreadOnlyHint: true. At least the most impactful tools have annotations. At least 80% of tools should have at least 1 behavior annotation. -
Fail criteria: Tools that delete or overwrite data have no annotations, or annotations contradict the tool's actual behavior (e.g.,
readOnlyHint: trueon a tool that writes files). -
Skip (N/A) when: The server registers no tools, or all tools are read-only. All checks skip when no MCP server is detected.
-
Cross-reference: For capability declarations, see
capability-declaration. -
Detail on fail:
"Tool 'delete_file' has no annotations — defaults to readOnlyHint: true which is incorrect for a destructive operation. Clients may auto-approve this tool when they shouldn't"or"Tool 'search_files' has destructiveHint: true but only reads files — annotation is misleading" -
Remediation: Annotations help clients make safe decisions about auto-approving vs. confirming tool calls:
// src/tools/delete.ts — annotated tool { name: "delete_item", annotations: { destructiveHint: true, idempotentHint: false } }server.tool( 'delete_file', { description: 'Permanently delete a file from disk', annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false, }, }, { path: z.string() }, async ({ path }) => { /* handler */ } ) server.tool( 'search_files', { description: 'Search for files matching a pattern', annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false, }, }, { pattern: z.string() }, async ({ pattern }) => { /* handler */ } )
External references
- external · mcp-spec-tool-annotations — MCP Specification — Tool annotations (readOnlyHint, destructiveHint, openWorldHint)
Taxons
History
- 2026-04-18·v1.0.0·Initial import from mcp-server·automated