Skip to content

Fix MCP adapter stack overflow on self-referencing input types#9850

Merged
glen-84 merged 3 commits into
mainfrom
gai/mcp-recursive-input-schema-refs
Jun 8, 2026
Merged

Fix MCP adapter stack overflow on self-referencing input types#9850
glen-84 merged 3 commits into
mainfrom
gai/mcp-recursive-input-schema-refs

Conversation

@glen-84

@glen-84 glen-84 commented Jun 4, 2026

Copy link
Copy Markdown
Member

Summary

  • MCP tools whose operations declared a variable of a self-referencing input type (e.g. a filter input with and/or: [SelfInput!]) crashed the server at startup with an uncatchable StackOverflowException: TypeExtensions.ToJsonSchemaBuilder walked the input-type graph with no cycle protection.
  • Named input object types are now emitted once under JSON Schema $defs and referenced with $ref (nullable references use anyOf: [{$ref}, {type:null}]), which represents recursive input types in a finite schema. This is the default.
  • New McpToolOptions.UseJsonSchemaReferences, configured via a fluent ModifyMcpToolOptions(...) on both the HotChocolate and Fusion builders, lets you turn references off for MCP clients with weak $ref support. With references off, input objects are inlined and a self-reference is collapsed to a generic object.
  • Output schemas are unaffected.

Test plan

  • Added OperationToolFactoryTests covering a self-referencing input variable in both modes (references on → $defs/$ref; off → inlined with the recursive branch collapsed), plus a non-recursive complex-fixture test with references off that verifies full inlining and no $ref/$defs.
  • Regenerated the four existing input-schema snapshots affected by the new default and verified each diff is purely the $defs/$ref conversion.
  • dotnet test on Adapters.Mcp.Tests: 237 passed, 0 failed.

Copilot AI review requested due to automatic review settings June 4, 2026 15:42
claude[bot]

This comment was marked as resolved.

@github-actions github-actions Bot added 📚 documentation This issue is about working on our documentation. 🌶️ hot chocolate labels Jun 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an uncatchable server startup StackOverflowException when generating MCP tool input JSON Schemas for operations whose variable types contain recursive/self-referencing input objects. It does this by emitting named input object types into JSON Schema $defs and referencing them via $ref (default), with an opt-out to inline schemas for MCP clients that cannot handle $ref (collapsing recursive branches to a generic object).

Changes:

  • Add cycle-safe JSON Schema generation for MCP tool input schemas using $defs/$ref by default, with deterministic $defs ordering.
  • Introduce McpToolOptions.UseJsonSchemaReferences plus ModifyMcpToolOptions(...) extension methods for HotChocolate and Fusion builders.
  • Add/adjust tests and snapshots to cover recursive input variables in both reference-enabled and reference-disabled modes, plus snapshot updates for the new default.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.

Show a summary per file
File Description
website/src/docs/hotchocolate/v16/build/adapters/mcp.md Documents the new default $defs/$ref behavior and how to disable it via ModifyMcpToolOptions.
website/src/docs/fusion/v16/adapters/mcp.md Same documentation update for Fusion gateway usage.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/OperationToolFactoryTests.cs Adds coverage for recursive input variables and reference disabling; updates factory construction to pass options.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNullableVariables_CreatesCorrectSchema_Input.json Snapshot update reflecting $defs/$ref default behavior.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithNonNullableVariables_CreatesCorrectSchema_Input.json Snapshot update reflecting $defs/$ref default behavior.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithDefaultedVariables_CreatesCorrectSchema_Input.json Snapshot update reflecting $defs/$ref default behavior.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithComplexVariables_ReferencesDisabled_InlinesWithoutReferences.json New snapshot ensuring full inlining and no $ref/$defs when references are disabled.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_WithComplexVariables_CreatesCorrectSchema_Input.json Snapshot update reflecting $defs/$ref default behavior (and ref reuse for shared input types).
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_SelfReferencingInputVariable_UsesReferences.json New snapshot verifying finite schema for self-referencing input via $defs/$ref.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_SelfReferencingInputVariable_ReferencesDisabled_Inlines.json New snapshot verifying recursion collapse to { "type": "object" } when references are disabled.
src/HotChocolate/Adapters/src/Fusion.Adapters.Mcp/Extensions/FusionGatewayBuilderExtensions.cs Adds ModifyMcpToolOptions(...) for Fusion gateway builder.
src/HotChocolate/Adapters/src/Adapters.Mcp/Extensions/McpRequestExecutorBuilderExtensions.cs Adds ModifyMcpToolOptions(...) for HotChocolate request executor builder.
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/OperationToolFactory.cs Threads schema-generation context/options into input schema generation and emits $defs deterministically.
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/TypeExtensions.cs Implements $defs/$ref emission for named input objects plus cycle detection for reference-disabled mode.
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/ServiceCollectionExtensions.cs Builds and registers per-schema McpToolOptions from configured delegates; wires into OperationToolFactory.
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/JsonSchemaContext.cs Adds shared schema-walk context (defs, cycle detection state, and reference toggle).
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/InputValueDefinitionExtensions.cs Passes schema-generation context through when creating field schemas.
src/HotChocolate/Adapters/src/Adapters.Mcp.Abstractions/Configuration/McpToolOptions.cs Introduces the public options surface controlling $ref usage for input schema generation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Labels

📚 documentation This issue is about working on our documentation. 🌶️ hot chocolate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants