Skip to content

CallToolRequest Deserialization Error in McpAsyncServer #354

@cobach

Description

@cobach

Motivation and Context

The MCP Java SDK v0.10.0 has a bug where tools/call requests fail with a deserialization error:

Cannot construct instance of `io.modelcontextprotocol.spec.McpSchema$CallToolRequest` 
(although at least one Creator exists): no String-argument constructor/factory 
method to deserialize from String value

This occurs because McpAsyncServer.toolsCallRequestHandler() attempts to directly convert the params object to CallToolRequest, but params arrives as a LinkedHashMap (generic JSON object) from the transport layer, not as a typed instance.

How Has This Been Tested?

  • Created test client using official Node.js SDK that calls tools
  • Tested with multiple tools (SystemInformation, DomainAvailability)
  • Verified the fix resolves the deserialization error
  • All tool calls execute successfully after applying the fix
  • Existing tests continue to pass

Test setup:

// Using official Node.js SDK
await client.callTool({
  name: 'any-tool',
  arguments: {}
});

Breaking Changes

No breaking changes. This is a bug fix that maintains the existing API. The fix adds proper type handling for the params object.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

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
  • I have added or updated documentation as needed

Additional context

The fix updates McpAsyncServer.toolsCallRequestHandler() to properly handle the conversion:

private McpServerSession.RequestHandler<CallToolResult> toolsCallRequestHandler() {
    return (exchange, params) -> {
        McpSchema.CallToolRequest callToolRequest;
        
        if (params instanceof McpSchema.CallToolRequest) {
            // Already the correct type
            callToolRequest = (McpSchema.CallToolRequest) params;
        }
        else if (params instanceof java.util.Map) {
            // Expected case - params is a Map representing the CallToolRequest
            try {
                callToolRequest = objectMapper.convertValue(params, McpSchema.CallToolRequest.class);
            } catch (Exception e) {
                throw new IllegalArgumentException("Invalid params for tools/call: " + params, e);
            }
        }
        else {
            // Fallback for other types
            try {
                callToolRequest = objectMapper.convertValue(params, McpSchema.CallToolRequest.class);
            } catch (Exception e) {
                throw new IllegalArgumentException("Cannot convert params to CallToolRequest: " + params, e);
            }
        }
        
        // ... rest of the method remains the same
    };
}

This issue affects all tool calls made through the MCP protocol when using the Java SDK as the server.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions