anthropics / anthropics/claude-agent-sdk-python
create_sdk_mcp_server tools cannot opt into strict tool use: tools/list reconstruction drops the field
- 主要言語
- Python
- スター
- 8.1k
- フォーク
- 1.3k
- PR マージ指標
- PR 指標を取得中
説明
## Summary
Tools registered through `create_sdk_mcp_server` cannot opt into [strict tool use](https://platform.claude.com/docs/en/agents-and-tools/tool-use/strict-tool-use). The SDK rebuilds the `tools/list` response by hand and keeps only `name` / `description` / `inputSchema` / `annotations` / `_meta`, so a `strict` field set by the tool author is silently dropped before it reaches the CLI. There is no other route: the CLI has no `_meta` key for it either, and no hook fires for the failure strict would prevent.
For agents whose custom tools take array parameters this matters in production: we measure the model emitting unparseable JSON for an array argument in 17 of 18 turns on one tool shape (details below), the exact failure class `strict: true` exists to eliminate.
## Where the field is dropped
`claude_agent_sdk/_internal/query.py`, `_handle_sdk_mcp_request`, `tools/list` branch (v0.2.131, lines ~653-672):
```python
tool_data: dict[str, Any] = {
"name": tool.name,
"description": tool.description,
"inputSchema": (...),
}
if tool.annotations:
tool_data["annotations"] = tool.annotations.model_dump(exclude_none=True)
if tool.meta:
tool_data["_meta"] = tool.meta
tools_data.append(tool_data)
```
`mcp.types.Tool` is `extra="allow"`, so `Tool.model_validate({..., "strict": True})` succeeds — but the reconstruction above discards the extra field instead of forwarding it.
## What we verified before filing (SDK 0.2.131, CLI 2.1.252, macOS arm64)
1. **The CLI honors `strict` when its internal tool object carries it.** The bundled binary contains the pipeline: `if(e.strict===!0){...fe.strict=!0, fe.input_schema=} else `, and the API tool definition builder spreads `...fe.strict&&{strict:!0}`. So the gap is transport, not capability.
2. **Top-level `strict` on the MCP `Tool` never crosses the wire** — dropped by the reconstruction above (confirmed by invoking `_handle_sdk_mcp_request` directly with a synthetic `tools/list` message: the emitted dict has keys `name`/`description`/`inputSchema` only).
3. **`_meta: {"anthropic/strict": true}` crosses the wire but nothing reads it** — a byte search of the CLI binary finds zero occurrences of `anthropic/strict`; the closed set of `anthropic/*` `_meta` keys it knows is `alwaysLoad, claude, configs, devicePassthrough, dirSync, hearth, id, maxResultSizeChars, models, permissionDisplay, remoteToolExecution, requiresUserInteraction, searchHint, v`.
4. **Live confirmation:** with both injection variants applied, 5 of 5 turns still produced a tool call whose input the CLI replaced with `{"__unparsedToolInput": ...}`, and the CLI's strict-incompatible-schema warning never appeared on stderr.
5. **No hook can compensate:** for a tool call whose input JSON cannot be parsed, no hook fires at all — `PreToolUse`, `PostToolUse`, `PostToolUseFailure` were all instrumented; 20/20 successful calls in the same turns logged hooks, the malformed call logged none.
## Why this matters (measured impact)
Production agent (claude-sonnet-5, effort=high, adaptive thinking), five in-process MCP retrieval tools. One tool has an array-of-strings parameter next to a required enum parameter. The model emits the array value as bare unquoted words — `{"jurisdiction": "se", "terms": token machine payout percentage}` — in **17 of 18 turns** on that tool shape (1 of 9 on the same tool without the enum). The call never runs; the CLI substitutes `__unparsedToolInput` and returns its own `InputValidationError`. Description engineering reduced it to 4/18; it cannot reach zero, and the model sometimes abandons the search after the rejection instead of re-sending it.
Independent report of the same regression class on this model family, where `strict: true` eliminated it via the raw API: https://lucumr.pocoo.org/2026/7/4/better-models-worse-tools/
## Ask
Let an `SdkMcpTool` (and/or the MCP `Tool` listing) declare `strict: true` and forward it to the CLI's tool-definition pipeline, which already knows how to normalize the schema or warn. The same forwarding gap presumably applies to `input_examples`.
## Environment
- claude-agent-sdk 0.2.131 (Python 3.12), mcp 1.29.1
- Claude Code CLI 2.1.252, macOS arm64
- Model: claude-sonnet-5, effort high, adaptive thinking
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
評価
この issue はまだ評価されていません。