Skip to content

fix: require status field to discriminate GetTaskResult from GetTaskPayloadResult#734

Open
blackwell-systems wants to merge 1 commit intomodelcontextprotocol:mainfrom
blackwell-systems:fix-task-result-deserialization
Open

fix: require status field to discriminate GetTaskResult from GetTaskPayloadResult#734
blackwell-systems wants to merge 1 commit intomodelcontextprotocol:mainfrom
blackwell-systems:fix-task-result-deserialization

Conversation

@blackwell-systems
Copy link
Copy Markdown

Motivation and Context

Fixes #601

The content-based polymorphic deserializer in selectClientResultDeserializer and selectServerResultDeserializer matches GetTaskResult on the presence of "taskId" alone. This incorrectly captures GetTaskPayloadResult responses (tasks/result), which wrap arbitrary JSON and may also contain a "taskId" key but not a "status" key.

When Protocol.request<GetTaskPayloadResult>() receives a response that was deserialized as GetTaskResult, the unchecked as T cast at line 478 of Protocol.kt throws a ClassCastException.

Fix

Tighten the discriminator in both selectClientResultDeserializer and selectServerResultDeserializer to require both "taskId" and "status", since GetTaskResult always has both fields (status is required per the MCP task schema). GetTaskPayloadResult responses (which lack "status") now correctly fall through to other deserializers or the empty result handler.

How Has This Been Tested?

Added two test cases to TasksTest:

  1. task payload result with content field is not deserialized as GetTaskResult: verifies that a CallToolResult-shaped JSON (with "content" but no "status") is correctly deserialized as CallToolResult, not GetTaskResult
  2. task get result with status is correctly deserialized as GetTaskResult: verifies that JSON with both "taskId" and "status" is still correctly deserialized as GetTaskResult

All 37 existing tests continue to pass.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling

…ayloadResult

The content-based polymorphic deserializer matches GetTaskResult on the
presence of "taskId" alone. This incorrectly captures GetTaskPayloadResult
responses (tasks/result), which wrap arbitrary JSON and may also contain
a "taskId" key but not a "status" key.

Tighten the discriminator to require both "taskId" and "status", since
GetTaskResult always has both fields. GetTaskPayloadResult responses
(which lack "status") now correctly fall through to other deserializers
or the empty result handler.

Fixes modelcontextprotocol#601

Signed-off-by: Dayna Blackwell <dayna@blackwell-systems.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

type-unsafe cast in Protocol result deserialization

1 participant