MCP tool `strict` field not forwarded to Anthropic API
Description
When an MCP server sets strict: true on a tool definition (via mcp.types.Tool's ConfigDict(extra="allow")), the field is present in the list_tools response but is not forwarded to the Anthropic API request body. This means grammar-constrained sampling is never applied to MCP tools, even when the server explicitly opts in.
Reproduction
- Create an MCP server that sets
strict: trueon tools:
from fastmcp import FastMCP
from mcp.types import Tool as MCPTool
app = FastMCP("test")
@app.tool()
async def my_tool(name: str, value: int) -> str:
return "ok"
# Inject strict: true via list_tools handler
original = app.list_tools
@app._mcp_server.list_tools()
async def patched() -> list[MCPTool]:
tools = await original()
mcp_tools = []
for t in tools:
mt = t.to_mcp_tool()
mt.strict = True
mcp_tools.append(mt)
return mcp_tools
- Verify the MCP server returns
strict: truein its tool definitions (confirmed via directlist_toolscall)
- Connect Claude Code (v2.1.89) to this server and intercept the outgoing Anthropic API request using a local reverse proxy on
ANTHROPIC_BASE_URL
- Observe that
strictisnull/missing for all tools in the API request body — both MCP and built-in
Observed behavior
Proxy capture of the Anthropic API request:
[CAPTURE] /v1/messages — 33 tools
Agent: strict=None, additionalProperties=False
Bash: strict=None, additionalProperties=False
Read: strict=None, additionalProperties=False
Edit: strict=None, additionalProperties=False
mcp__test__get_historical_crypto_prices: strict=None, additionalProperties=False
mcp__test__get_available_crypto_tickers: strict=None, additionalProperties=False
... (all 33 tools)
[SUMMARY] strict=true: 0, strict missing/false: 33
[HEADER] anthropic-beta: oauth-2025-04-20,interleaved-thinking-2025-05-14,...
[HEADER] ✗ structured-outputs beta header not included
Consequence: Without strict mode, the model occasionally generates tool calls with incorrect parameter names. For example, calling get_historical_crypto_prices with from/to/multiplier/timespan instead of the schema-defined start_date/end_date/interval/interval_multiplier, resulting in Pydantic validation errors on the server side.
Expected behavior
- If an MCP server returns
strict: trueon a tool, that field should be preserved and forwarded to the Anthropic API - The
structured-outputsbeta header should be included when strict tools are present - Built-in tools that define
strict: truein their source should also have it forwarded
Impact
For agent systems that use MCP tools for critical operations (trading, database writes, etc.), incorrect parameter generation can cause silent failures or require retry loops. Grammar-constrained sampling via strict: true would prevent this class of errors at generation time.
Workaround attempted
We tried using a local proxy to inject strict: true into the API request body, but hit the "compiled grammar is too large" error when applying it to multiple tools. Selectively applying to fewer tools still triggered the size limit with 33 total tools in the request. There doesn't appear to be a viable workaround from the user side.
Environment
- Claude Code: v2.1.89
- Agent SDK: 0.1.48
- Platform: macOS Darwin 23.2.0
- MCP SDK: fastmcp 3.2.0
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗