Describe the bug
When the C# SDK server handles requests declaring the 2026-07-28 protocol version, the resultType field is absent from the completed (non-input-required) result objects I tested.
The Result base class declares a ResultType property that defaults to null. The SDK's JSON serialization options include DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull (McpJsonUtilities.cs), so the null default is omitted from the wire format. As a result, "resultType" is omitted unless a result-construction path explicitly assigns it. In the completed-response server paths tested below, no such assignment appears to happen, so ordinary "complete" responses are serialized without resultType.
The 2026-07-28 draft schema defines resultType as required on the base Result type and on the result schemas relevant to these server responses:
"Result": {
"required": ["resultType"],
"properties": {
"resultType": {
"description": "... Servers implementing this protocol version MUST include this field. ..."
}
}
}
The InputRequiredResult subclass correctly sets ResultType = "input_required" in its constructor, so MRTR input-required responses do serialize resultType. The issue is limited to default/"complete" result paths that do not explicitly set ResultType. Task-specific result DTOs appear to set their own ResultType values and are not the subject of this report.
This appears to be a 2026-07-28 schema-compliance issue. It is related to — but distinct from — the ttlMs/cacheScope omission tracked in #1650. That issue covers SEP-2549 caching fields; this one covers resultType, which applies to result objects generally, including non-cacheable ones.
Environment tested:
main snapshot from 2026-06-28: d6b1615988d3a73ffb653d08778b14fa695e1318
- Servers used:
tests/ModelContextProtocol.TestServer (stdio), tests/ModelContextProtocol.ConformanceServer (HTTP)
- Transports: stdio and stateless Streamable HTTP
To Reproduce
Steps to reproduce the behavior:
- Start the C# SDK server with 2026-07-28 draft protocol support enabled.
- Over stdio, complete initialization and send a
tools/list request.
- Inspect the JSON response —
resultType is absent.
- Repeat with
server/discover, prompts/list, resources/list, completion/complete, tools/call.
- Observe that
resultType is absent from the tested completed responses.
Over stateless HTTP:
- Send a
server/discover request with per-request _meta.
- Inspect the JSON-RPC result —
resultType is absent.
Expected behavior
Completed result objects should include "resultType": "complete" in the serialized JSON when the negotiated protocol version is 2026-07-28. The schema's required constraint and the spec text "Servers implementing this protocol version MUST include this field" appear to apply to result objects generally, not only to input-required or task-specific result paths.
Observed behavior
Across both transports, the tested completed "complete" responses did not include resultType. The field does appear in InputRequiredResult responses, which appear to set ResultType = "input_required" in the constructor. Task-specific DTOs also appear to assign their own ResultType values.
This was observed consistently across the tested methods: server/discover, tools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read, completion/complete.
Additional context
The likely cause appears to be the interaction of two pieces:
Result.cs: ResultType defaults to null, and the docstring notes "Defaults to null, which is equivalent to "complete"."
McpJsonUtilities.cs: DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull causes null values to be omitted from serialization.
One possible fix would be to default ResultType to "complete" rather than null, so that the existing WhenWritingNull setting still serializes it. As a possible reference point, the Python SDK appears to use this model-level approach: concrete Result subclasses declare result_type: ResultType = "complete" as a Pydantic field default.
Note: I read the spec's backward-compatibility clause ("the client MUST treat the absent field as "complete"") as a client-side resilience rule, not as a server-side exemption from the required constraint.
Related: #1650 tracks client-side tolerance for missing ttlMs/cacheScope fields. resultType is a separate concern that applies to result objects generally, including non-cacheable ones such as CompleteResult and CallToolResult.
Describe the bug
When the C# SDK server handles requests declaring the 2026-07-28 protocol version, the
resultTypefield is absent from the completed (non-input-required) result objects I tested.The
Resultbase class declares aResultTypeproperty that defaults tonull. The SDK's JSON serialization options includeDefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull(McpJsonUtilities.cs), so thenulldefault is omitted from the wire format. As a result,"resultType"is omitted unless a result-construction path explicitly assigns it. In the completed-response server paths tested below, no such assignment appears to happen, so ordinary"complete"responses are serialized withoutresultType.The 2026-07-28 draft schema defines
resultTypeas required on the baseResulttype and on the result schemas relevant to these server responses:The
InputRequiredResultsubclass correctly setsResultType = "input_required"in its constructor, so MRTR input-required responses do serializeresultType. The issue is limited to default/"complete" result paths that do not explicitly setResultType. Task-specific result DTOs appear to set their ownResultTypevalues and are not the subject of this report.This appears to be a 2026-07-28 schema-compliance issue. It is related to — but distinct from — the
ttlMs/cacheScopeomission tracked in #1650. That issue covers SEP-2549 caching fields; this one coversresultType, which applies to result objects generally, including non-cacheable ones.Environment tested:
mainsnapshot from 2026-06-28:d6b1615988d3a73ffb653d08778b14fa695e1318tests/ModelContextProtocol.TestServer(stdio),tests/ModelContextProtocol.ConformanceServer(HTTP)To Reproduce
Steps to reproduce the behavior:
tools/listrequest.resultTypeis absent.server/discover,prompts/list,resources/list,completion/complete,tools/call.resultTypeis absent from the tested completed responses.Over stateless HTTP:
server/discoverrequest with per-request_meta.resultTypeis absent.Expected behavior
Completed result objects should include
"resultType": "complete"in the serialized JSON when the negotiated protocol version is 2026-07-28. The schema'srequiredconstraint and the spec text "Servers implementing this protocol version MUST include this field" appear to apply to result objects generally, not only to input-required or task-specific result paths.Observed behavior
Across both transports, the tested completed
"complete"responses did not includeresultType. The field does appear inInputRequiredResultresponses, which appear to setResultType = "input_required"in the constructor. Task-specific DTOs also appear to assign their ownResultTypevalues.This was observed consistently across the tested methods:
server/discover,tools/list,tools/call,prompts/list,prompts/get,resources/list,resources/read,completion/complete.Additional context
The likely cause appears to be the interaction of two pieces:
Result.cs:ResultTypedefaults tonull, and the docstring notes "Defaults tonull, which is equivalent to"complete"."McpJsonUtilities.cs:DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNullcausesnullvalues to be omitted from serialization.One possible fix would be to default
ResultTypeto"complete"rather thannull, so that the existingWhenWritingNullsetting still serializes it. As a possible reference point, the Python SDK appears to use this model-level approach: concreteResultsubclasses declareresult_type: ResultType = "complete"as a Pydantic field default.Note: I read the spec's backward-compatibility clause ("the client MUST treat the absent field as
"complete"") as a client-side resilience rule, not as a server-side exemption from therequiredconstraint.Related: #1650 tracks client-side tolerance for missing
ttlMs/cacheScopefields.resultTypeis a separate concern that applies to result objects generally, including non-cacheable ones such asCompleteResultandCallToolResult.