Skip to content

Conversation

@triepod-ai
Copy link

Summary

Add MCP tool annotations to generated tools to improve AI assistant understanding of tool capabilities:

  • readOnlyHint: true for GET operations
  • destructiveHint: true for DELETE operations
  • openWorldHint: true for all operations (they call external APIs)
  • title set to the operation ID

Motivation

Tool annotations are an MCP spec feature (available since SDK 1.8.0) that help AI assistants make better decisions about tool usage. For example:

  • readOnlyHint tells the AI a tool won't modify any data
  • destructiveHint warns the AI a tool may destroy resources
  • openWorldHint indicates the tool interacts with external systems

Since fastapi_mcp generates tools from HTTP endpoints, we can automatically derive these annotations from the HTTP method, giving all downstream users better tool metadata.

Changes

Single file change in fastapi_mcp/openapi/convert.py:

  • Added ToolAnnotations creation based on HTTP method
  • Passed annotations to the Tool constructor

Test plan

  • All 89 existing tests pass
  • 83% test coverage maintained

🤖 Generated with Claude Code

Add ToolAnnotations to generated MCP tools to improve AI assistant
understanding of tool capabilities:

- readOnlyHint: true for GET operations
- destructiveHint: true for DELETE operations
- openWorldHint: true for all operations (external API calls)
- title: set to the operation ID

This enables AI assistants to make better decisions about tool usage
safety and impact on external systems.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@parente
Copy link

parente commented Dec 31, 2025

Curious how this compares to #253 which has more flexibility in how hints can be applied.

Copy link

@horus-bot horus-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding destructiveHint=True for PUT/POST/PATCH methods as well, since they can also modify or create resources.

Per MCP spec, destructiveHint indicates a tool MAY perform destructive
updates. POST/PUT/PATCH methods modify or create resources, so they
should be marked destructive alongside DELETE.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@triepod-ai
Copy link
Author

triepod-ai commented Dec 31, 2025

Great question! These two approaches are complementary:

Ideal outcome: Both PRs merge, with explicit annotations (PR #253) taking precedence over defaults (PR #258). This gives developers the best of both worlds:

  1. Out-of-the-box annotations for common patterns (GET=readOnly, POST/PUT/PATCH/DELETE=destructive)
  2. Explicit override capability when default behavior doesn't match actual tool semantics

For example, a POST endpoint that's actually idempotent (returns cached result) could use x-mcp-annotations to override the default destructiveHint=True.

There will be a merge conflict since both PRs touch the same code block, but the resolution is straightforward - use explicit annotations when available, fall back to HTTP method defaults otherwise.


Also addressed @horus-bot's review feedback: expanded destructiveHint to include POST/PUT/PATCH methods (not just DELETE), since they can also modify or create resources.

Per MCP spec, destructiveHint should only be true for operations
that DELETE or DESTROY data, not for all write operations.

- POST (create) → destructiveHint: false (additive)
- PUT (update) → destructiveHint: false (modifies, doesn't destroy)
- PATCH (partial update) → destructiveHint: false (modifies, doesn't destroy)
- DELETE → destructiveHint: true (actually destroys data)

Also added idempotentHint for GET, PUT, and DELETE operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
@triepod-ai
Copy link
Author

Fix: Corrected destructiveHint Semantics

Updated to properly distinguish between additive and destructive operations per the MCP spec.

Previous (Incorrect)

destructiveHint=(method in ("post", "put", "patch", "delete"))

Now (Correct)

destructiveHint=(method == "delete"),  # Only DELETE destroys data
idempotentHint=(method in ("get", "put", "delete")),  # GET, PUT, DELETE are idempotent

Semantic Meaning

Method destructiveHint Reason
GET false Read-only
POST false Creates (additive)
PUT false Updates (replaces, doesn't destroy)
PATCH false Partial update (doesn't destroy)
DELETE true Actually destroys data

Per MCP spec: destructiveHint means the tool may DELETE or DESTROY data, not just "writes data".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants