Repository navigation
add_issue_comment's top-level anyOf (added in v1.10.0 / #3085) breaks Claude tool-use API compatibility #3126
Description
Activity
Maintainer investigation: MCP schema era and provider compatibility
We validated that this regression crosses two distinct compatibility boundaries.
MCP specification history
- Through protocol version
2025-11-25,Tool.inputSchemawas structurally restricted to$schema, roottype: "object",properties, andrequired. - SEP-2106, shipped in protocol version
2026-07-28, explicitly added arbitrary JSON Schema 2020-12 keywords including rootanyOf,oneOf, andallOfalongsidetype: "object". - There is no published
2026-02-28MCP protocol version; the relevant full-schema boundary is2026-07-28.
This means the v1.10.0 schema was valid for modern MCP 2026-07-28, but not representable by the legacy Tool envelope when serving negotiated versions through 2025-11-25.
Not limited to Claude
This is also a separate provider-adapter compatibility problem:
- Claude rejects root
anyOf/oneOf/allOfwhen MCP clients forward the full tool list, as reproduced in this issue. - OpenAI/Codex reports the same root-object restriction and immediate 400 rejection for top-level combinators: openai/codex#27877.
- The MCP ecosystem already records practical issues with valid composition schemas: modelcontextprotocol/modelcontextprotocol#2806, modelcontextprotocol/typescript-sdk#2341, and modelcontextprotocol/typescript-sdk#1643.
So protocol-version handling alone would not fix a modern MCP client that forwards schemas to a narrower provider API.
Fix
#3127 restores a portable canonical schema:
- removes root
anyOfanddependentSchemas; - retains simple field constraints (
minLength, reaction enum, positive integercomment_id); - keeps all cross-field and mutual-exclusion rules authoritative in the handler;
- preserves every valid comment/reaction mode and returns explicit errors for invalid combinations;
- does not mutate schemas at runtime;
- adds a non-mutating inventory regression guard against root composition keywords.
The patch is valid for legacy MCP clients, modern MCP clients, Claude-forwarding clients, and OpenAI-style provider adapters. The emitted schema is also 356 bytes / 85 tokens smaller than v1.10.0.
A future client-specific schema transformation, if needed, should deep-clone/copy-on-write per inventory response and use explicit provider capabilities. Shared canonical schemas must never be mutated in place.
Negotiation behavior in this server
The GitHub MCP Server supports both
2025-11-25and2026-07-28, but tool schemas are canonical/static rather than rendered per negotiated protocol version. A client negotiating2025-11-25therefore received the same v1.10.0 rootanyOf, even though that keyword was outside the legacyTool.inputSchemaenvelope. A client negotiating2026-07-28received an MCP-valid SEP-2106 schema, but Claude's downstream tool-use subset still rejected it.The merged flat schema is consequently an intersection-safe representation for both supported MCP eras and the provider subset, without runtime version branching or shared-schema mutation.
- Through protocol version
What's Wrong?
add_issue_comment'sinputSchemagained a top-levelanyOfin v1.10.0 (introduced by #3085, fixing #3048):Anthropic's Claude tool-use API rejects any custom tool whose
input_schemausesoneOf/allOf/anyOfat the top level:Since MCP clients typically send the entire tool list in one request, this single non-conformant schema causes the whole request to fail with a 400 — even if
add_issue_commentitself is never invoked in that turn.Who hits this
Clients that eagerly forward the full MCP tool list to the Claude Messages API without sanitizing schemas first. Concretely:
claudeCLI in headless mode (claude -p), e.g. as used byanthropics/claude-code-actionin GitHub Actions withghcr.io/github/github-mcp-serverconfigured as a Docker MCP server. The 400 is request-level tool-schema validation, so it is model- and provider-independent (see Subagent/Workflow creation forwards raw MCP tool schemas → 400 on connector tool with top-level oneOf/anyOf/allOf anthropics/claude-code#63436).@anthropic-ai/claude-agent-sdkwithout a schema-sanitization layer.Interactive Claude Code sessions are generally unaffected because they defer full tool-schema loading via Tool Search (see anthropics/claude-code#64113 and #63436), but that mitigation does not apply to headless/CI/subagent invocations, so this is a real-world breaking regression for anyone running Claude-based automation against this server.
Suggested fix
Other tools in this same release already express "at least one of A or B" without a top-level combinator, by nesting under
properties/dependentSchemasinstead (e.g.issue_write,projects_write,update_issue_assignees,update_issue_labels,update_issue_type). Couldadd_issue_comment's validation be restructured the same way?Version
v1.10.0 (regression from v1.9.0 — introduced by #3085). The change is on
main, so the latestmainis affected as well.Related
Client-side (Claude Code) issues describing the same 400 mechanism and proposing schema sanitization before forwarding:
claude -preturns 400 when a connector tool has a top-level anyOf/oneOf/allOf in input_schema anthropics/claude-code#64113 (headlessclaude -p)