Apply null-omitting JSON serialization to MCP stdio result responses and validate wire output#3616
Merged
Merged
Conversation
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/d241dbab-be22-45e9-b5f1-f537a2c7b91e Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/d241dbab-be22-45e9-b5f1-f537a2c7b91e Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix MCP content blocks emitting null annotations
Omit null MCP content metadata in stdio responses
May 20, 2026
Aniruddh25
reviewed
May 20, 2026
… null SDK ContentBlock fields Root cause: TextContentBlock from ModelContextProtocol.Core lacks [JsonIgnore(WhenWritingNull)] on its Annotations and _meta properties, so default serialization emits them as explicit nulls that strict MCP clients reject. Fix: add a static JsonSerializerOptions with DefaultIgnoreCondition = WhenWritingNull and use it in WriteResult. This fixes the root cause at the serialization layer for all responses and all SDK types, eliminating the need for the post-processing SanitizeContentBlock / RemovePropertyIfJsonNull helpers introduced in the previous approach. Updated test serializes with matching options to reflect actual wire format.
benmccallum
approved these changes
May 20, 2026
benmccallum
left a comment
There was a problem hiding this comment.
Nice, was about to suggest global options. Thanks for working on this so quickly. Looking forward to being able to get it working with Claude.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aims to make MCP stdio JSON-RPC tool responses compatible with strict MCP clients by ensuring optional MCP content-block metadata is omitted instead of emitted as explicit null.
Changes:
- Added JSON serialization options to omit null-valued properties when writing JSON-RPC results to stdout.
- Added a unit test intended to validate that
TextContentBlockoutput omitsannotationsand_metawhen unset.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs | Applies WhenWritingNull serialization when emitting JSON-RPC results to stdout. |
| src/Service.Tests/UnitTests/McpStdioServerContentBlockTests.cs | Adds coverage around omitting annotations and _meta for a text content block. |
2 tasks
Copilot
AI
changed the title
Omit null MCP content metadata in stdio responses
Apply null-omitting JSON serialization to MCP stdio result responses
May 20, 2026
## Why make this change? Addresses review comment from PR #3616: The existing test serialized content blocks with locally-defined `JsonSerializerOptions`, so it would pass even if `McpStdioServer.WriteResult` emitted `"annotations": null` and `"_meta": null` in the actual wire output. Not a true regression test. ## What is this change? Rewrote `McpStdioServerContentBlockTests` to capture actual stdio JSON-RPC wire output: - **Wire output capture**: Inject `McpStdoutWriter` backed by `StringWriter` into `McpStdioServer` - **Full path execution**: Invoke `WriteResult` via reflection with simulated `CallToolResult` containing `TextContentBlock` - **Protocol-level validation**: Parse captured JSON-RPC response and assert `annotations` and `_meta` are omitted (not present as null keys) Test correctly fails when `WhenWritingNull` serialization policy is removed from `WriteResult`, confirming regression detection. ## How was this tested? - [x] Integration Tests - [x] Unit Tests ## Sample Request(s) N/A - Test-only change --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
Copilot
AI
changed the title
Apply null-omitting JSON serialization to MCP stdio result responses
Apply null-omitting JSON serialization to MCP stdio result responses and validate wire output
May 20, 2026
RubenCerna2079
approved these changes
May 21, 2026
Contributor
RubenCerna2079
left a comment
There was a problem hiding this comment.
LGTM! Thanks for addressing my concerns.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why make this change?
Strict MCP clients reject DAB stdio tool responses when optional content-block metadata is emitted as explicit
null(for example,annotations: nulland_meta: null). This causes otherwise successful tool calls to fail schema validation on strict clients.What is this change?
MCP stdio result serialization update
McpStdioServer.WriteResultto serialize JSON-RPC result payloads withJsonIgnoreCondition.WhenWritingNull.CoerceToMcpContentBlocksremain unchanged.Wire-output regression coverage
McpStdioServerContentBlockTestscoverage that captures actual stdio JSON-RPC output fromWriteResultand verifiesTextContentBlockoutput omitsannotationsand_metawhen unset.Illustrative behavior
How was this tested?
Sample Request(s)
Example CLI usage:
Example MCP request/response shape:
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"describe_entities","arguments":{}}}{ "jsonrpc":"2.0", "id":1, "result":{ "content":[ { "type":"text", "text":"..." } ] } }