Skip to content

Narrow fragment spreads to their type condition in MCP tool schemas - #10329

Open
glen-84 wants to merge 1 commit into
mainfrom
gai/mcp-tool-fragment-spread-narrowing
Open

Narrow fragment spreads to their type condition in MCP tool schemas#10329
glen-84 wants to merge 1 commit into
mainfrom
gai/mcp-tool-fragment-spread-narrowing

Conversation

@glen-84

@glen-84 glen-84 commented Aug 31, 2026

Copy link
Copy Markdown
Member

Summary

  • OperationToolFactory visited a named fragment's selection set without narrowing to the fragment's type condition, so a fragment on a concrete type selecting an implementation-declared field failed the field lookup on the abstract parent type (KeyNotFoundException from CreateTool). Fragment spreads now push a narrowed frame for the duration of the fragment, exactly like inline fragments.
  • A spread's type condition now also feeds the output schema's requiredness: a field reached through a fragment whose type condition does not match the parent type is optional, matching the existing inline-fragment rule. This changes emitted output schemas for such operations — previously those fields were marked required.

Test plan

  • New snapshot tests: a fragment on an implementation selecting an implementation-declared field resolves and is optional (previously threw), and a fragment on the parent type itself keeps its fields required.
  • One existing snapshot updated deliberately: fields selected only through fragments on concrete types are no longer required, aligning spread and inline-fragment semantics.
  • Full Adapters.Mcp.Tests suite passes (246 tests).

Copilot AI lite review requested due to automatic review settings August 31, 2026 16:06

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 MCP tool output-schema generation for GraphQL operations that use named fragment spreads by narrowing field resolution to the fragment’s type condition (matching inline-fragment behavior) and aligning requiredness rules so fields selected only through a type-conditional fragment are not marked required.

Changes:

  • Narrow the OperationToolFactory walker frame to a fragment spread’s type condition while visiting that fragment’s selection set.
  • Use a fragment spread’s type condition when computing SelectionState so requiredness matches inline-fragment semantics.
  • Add snapshot coverage for fragment spreads selecting implementation-declared fields and for spreads on the parent type; update one existing snapshot to reflect new requiredness.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/OperationToolFactory.cs Narrows walker type during fragment spread visitation and passes fragment type condition into selection-state computation.
src/HotChocolate/Adapters/src/Adapters.Mcp.Core/Extensions/FieldNodeExtensions.cs Extends selection-state computation to treat fragment spreads as type-conditional when their type condition differs from the parent type.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/OperationToolFactoryTests.cs Adds tests covering spread narrowing to an implementation type and requiredness when spreading on the parent type.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_FragmentSpreadsSelectSameField_MergesIntoSingleProperty.json Updates requiredness snapshot to reflect optional fields when reached only via concrete-type fragment spreads.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_FragmentSpreadSelectsImplementationDeclaredField_NarrowsToTypeCondition.json New snapshot for successful schema generation when a concrete-type fragment selects an implementation-declared field.
src/HotChocolate/Adapters/test/Adapters.Mcp.Tests/snapshots/OperationToolFactoryTests.CreateTool_FragmentSpreadOnParentType_KeepsFieldsRequired.json New snapshot ensuring spreads on the parent type keep fields required.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +443 to +447
var declaringNode = context.Nodes.ElementAtOrDefault(2);

NamedTypeNode? fragmentTypeCondition = null;
if (declaringNode is FragmentSpreadNode spreadNode
&& context.Fragments.TryGetValue(spreadNode.Name.Value, out var fragmentNode))
@github-actions

Copy link
Copy Markdown
Contributor

Patch coverage

100.0% of changed lines covered (20/20)

File Covered Changed Patch %
…/src/Adapters.Mcp.Core/Extensions/FieldNodeExtensions.cs 5 5 100.0% 🟢
…/Adapters/src/Adapters.Mcp.Core/OperationToolFactory.cs 15 15 100.0% 🟢

Project coverage: 57.7% (286089/495867 lines)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants