Tool Annotations & Output Schemas

+15 Mana ✨

Introduction

Tool definitions in MCP go beyond name, description, and input schema. Annotations provide metadata hints that help clients make smarter decisions about how to present and execute tools. Output schemas add structured validation to tool results. Together, these features make MCP tools safer, more predictable, and easier for both humans and LLMs to work with.

Key Concepts

Annotations are optional metadata fields attached to a tool definition. They communicate behavioral hints to the client without changing the tool's functionality:

  • readOnlyHint: Indicates the tool does not modify any state. A client might auto-approve read-only tools.
  • destructiveHint: Signals the tool may delete or overwrite data. A client might require human confirmation.
  • openWorldHint: Tells the client the tool contacts external services beyond the local environment.
  • idempotentHint: Indicates the tool is safe to retry — calling it multiple times with the same arguments produces the same result.

These are hints, not guarantees. Clients use them to adjust their trust and approval policies.

Here is an example of a tool definition with annotations:

json
{
  "name": "delete_file",
  "description": "Permanently delete a file from the filesystem",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": { "type": "string" }
    },
    "required": ["path"]
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": true,
    "openWorldHint": false
  }
}

This definition tells the client that delete_file is destructive (may remove data) but idempotent (deleting an already-deleted file is a no-op) and does not contact external services.

Real World Context

Consider an AI assistant connected to a database. A read_query tool would have readOnlyHint: true, letting the client auto-approve it. A drop_table tool would have destructiveHint: true, triggering a confirmation dialog. A call_api tool would have openWorldHint: true, alerting the user that data will leave the local environment. These annotations let clients build trust-aware UIs without hardcoding behavior for each tool.

Deep Dive

Output schemas extend MCP's type safety to tool results. By defining a structuredContent schema on the tool, the server declares the shape of successful responses. Clients can validate results automatically and present them in structured formats like tables or forms.

When a tool defines an output schema, its result includes a structuredContent field alongside the regular content array. The content array remains for backward compatibility and human-readable output, while structuredContent provides machine-parseable data.

Here is a tool with an output schema:

json
{
  "name": "get_user",
  "description": "Retrieve user profile information",
  "inputSchema": {
    "type": "object",
    "properties": {
      "userId": { "type": "string" }
    },
    "required": ["userId"]
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "name": { "type": "string" },
      "email": { "type": "string" },
      "role": { "type": "string" }
    },
    "required": ["name", "email"]
  }
}

The output schema tells clients exactly what fields to expect, enabling type-safe integrations.

A critical design principle in MCP is that the server never decides to call a tool on its own. Tool invocation is always initiated by the LLM (with optional human approval). The server only advertises available tools and executes them when asked. This keeps the human or LLM in control of all actions.

Common Pitfalls

  • Treating annotations as guarantees: Annotations are hints. A malicious or buggy server could set readOnlyHint: true on a destructive tool. Clients should use annotations for UX optimization, not security enforcement.
  • Ignoring annotations entirely: Failing to use annotations means missing opportunities to auto-approve safe tools or flag dangerous ones.
  • Assuming servers initiate tool calls: The MCP architecture ensures tool calls always flow from client to server, never the reverse.

Best Practices

  • Set annotations accurately on every tool to help clients build trust-appropriate interfaces.
  • Combine destructiveHint: true with idempotentHint when applicable — it tells clients the tool is dangerous but safe to retry on failure.
  • Use output schemas for tools that return structured data to enable validation and richer client rendering.
  • Remember the control principle: the LLM or human always decides, the server only executes.

Summary

Tool annotations provide behavioral metadata that helps clients make informed decisions about trust and approval. Output schemas add structured validation to tool results. The MCP design ensures that tool invocation is always controlled by the LLM or human, never by the server — keeping users in command of all actions.

Code Examples

json
{
  "name": "delete_file",
  "description": "Permanently delete a file from the filesystem",
  "inputSchema": {
    "type": "object",
    "properties": {
      "path": { "type": "string" }
    },
    "required": ["path"]
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": true,
    "idempotentHint": true,
    "openWorldHint": false
  }
}
✓ Completed