modelcontextprotocol / modelcontextprotocol/typescript-sdk

Task-augmented tool call errors are wrapped incorrectly, masking actual error messages

Open
#1,385 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug fix proposed P2 ready for work
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
  1. 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
    },
  },
);
  1. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.