modelcontextprotocol / modelcontextprotocol/typescript-sdk
Task-augmented tool call errors are wrapped incorrectly, masking actual error messages
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 15h
- Merged PRs (30d)
- 4
Description
Summary
When a task-augmented tools/call request fails (e.g., due to input validation), the error is caught and converted to a tool error result ({content: [...], isError: true}), which then fails CreateTaskResultSchema validation. This results in a confusing error message that masks the actual underlying error.
Steps to Reproduce
- Register a task-based tool with input validation:
server.experimental.tasks.registerToolTask(
'batch_process',
{
inputSchema: {
itemCount: z.number().min(1).max(10),
processingTimeMs: z.number().min(500).max(5000).optional(),
},
// ... other config
},
{
createTask: async (args, extra) => {
// ... handler
},
},
);
- Call the tool with task augmentation and invalid arguments:
{
"method": "tools/call",
"params": {
"name": "batch_process",
"arguments": { "itemCount": 5, "processingTimeMs": 100 },
"task": { "ttl": 60000 }
}
}
Expected Behavior
The client should receive a clear error message indicating the actual problem:
{
"error": {
"code": -32602,
"message": "Input validation error: Invalid arguments for tool batch_process: Too small: expected number to be >=500"
}
}
Actual Behavior
The client receives a confusing error that hides the actual cause:
{
"error": {
"code": -32602,
"message": "MCP error -32602: Invalid task creation result: [{\"expected\":\"object\",\"code\":\"invalid_type\",\"path\":[\"task\"],\"message\":\"Invalid input: expected object, received undefined\"}]"
}
}
Root Cause
The issue is in the error handling flow in server/mcp.js:
// In setToolRequestHandlers() - CallToolRequestSchema handler
try {
const args = await this.validateToolInput(tool, request.params.arguments, request.params.name);
const result = await this.executeToolHandler(tool, args, extra);
// ...
} catch (error) {
// ALL errors get wrapped as tool errors, including validation errors
return this.createToolError(error instanceof Error ? error.message : String(error));
}
Then in server/index.js, the wrapped handler validates the result:
if (params.task) {
const taskValidationResult = safeParse(CreateTaskResultSchema, result);
if (!taskValidationResult.success) {
// This fails because createToolError returns {content: [...], isError: true}
// which doesn't have a 'task' property
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
}
}
Suggested Fix
For task-augmented requests, errors thrown before task creation (like input validation errors) should be re-thrown directly instead of being wrapped as tool errors:
// In setToolRequestHandlers() - CallToolRequestSchema handler
try {
// ...
} catch (error) {
if (error instanceof McpError) {
if (error.code === ErrorCode.UrlElicitationRequired) {
throw error;
}
// For task-augmented requests, also re-throw validation errors
// instead of wrapping them as tool errors
if (isTaskRequest && error.code === ErrorCode.InvalidParams) {
throw error;
}
}
return this.createToolError(error instanceof Error ? error.message : String(error));
}
Or alternatively, modify server/index.js to not validate non-task results against CreateTaskResultSchema:
if (params.task) {
// Only validate if the result looks like a CreateTaskResult (has task property)
// If it's a tool error, return it as-is or convert to a proper error response
if ('isError' in result && result.isError) {
throw new McpError(ErrorCode.InvalidParams, result.content[0]?.text ?? 'Tool execution failed');
}
// ... existing validation
}
Environment
- SDK Version: 1.25.2
- Node.js: v24.1.0
This bug affects the developer experience significantly as the actual error (input validation, missing taskStore, handler exceptions, etc.) is completely hidden behind the generic "Invalid task creation result" message.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the CallToolRequestSchema handler in server/mcp.js and the task-result validation in server/index.js. Reproduce the task-augmented call with invalid input, then verify that the underlying validation error is returned directly instead of being wrapped and checked against CreateTaskResultSchema.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100