Skip to content

Add MCP readOnlyHint/destructiveHint annotations to all tools - #40

Open
jmprathab wants to merge 1 commit into
perforce:mainfrom
jmprathab:fix/mcp-tool-readonly-annotations
Open

Add MCP readOnlyHint/destructiveHint annotations to all tools#40
jmprathab wants to merge 1 commit into
perforce:mainfrom
jmprathab:fix/mcp-tool-readonly-annotations

Conversation

@jmprathab

@jmprathab jmprathab commented Aug 6, 2026

Copy link
Copy Markdown

Summary

  • Query tools (query_shelves, query_changelists, and siblings) carried no standard MCP tool annotations — only internal FastMCP tags used by CheckPermissionMiddleware. MCP clients (e.g. Claude Code) had no standard signal that these are read-only, causing unnecessary repeated permission prompts even though the tools never mutate P4 state.
  • Adds annotations={"readOnlyHint": True} to all 8 query_* tools and annotations={"readOnlyHint": False, "destructiveHint": True} to all 7 modify_* tools, using the standard mcp.types.ToolAnnotations fields supported by FastMCP's @mcp.tool(...) decorator.
  • No behavior change: internal tags, handlers, models, and services are untouched.

Verification

  • Traced every query_* tool's full call chain (tool → params model → handler → service → p4/Swarm call) and confirmed no write/mutating P4 or Swarm calls occur in any query path — including actions that sound mutating but aren't (validate_submit, check_resolve use p4's -n preview flag; query_reviews only issues Swarm GET).
  • Smoke-tested @mcp.tool(annotations={...}) against installed fastmcp==3.3.1: confirmed the dict is accepted and coerced into ToolAnnotations with the expected field values.

Notes / tradeoffs

  • modify_jobs only supports link_job/unlink_job (no delete), yet gets destructiveHint: True like its delete-capable siblings. Chose uniformity across all modify_* tools over per-action fidelity — a false-positive caution prompt on a reversible op, not a false negative.

Test plan

  • Confirmed each query_* tool's implementation never calls a P4 write command (submit/shelve/delete/add/edit/sync-non-preview) or a Swarm POST/PUT/DELETE.
  • Confirmed FastMCP 3.3.1 accepts annotations= as a plain dict via decorator smoke test.
  • Manual: reconnect an MCP client (e.g. Claude Code) to this server build and confirm query_shelves/query_changelists no longer prompt repeatedly for permission.

Query tools carried no MCP tool annotations, only internal FastMCP
tags. MCP clients had no standard signal that query_* tools are
read-only, causing unnecessary permission prompts (e.g. query_shelves,
query_changelists) even though sibling read tools behave identically.
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.

1 participant