{"record":{"id":"bf4b87b4407a4275","repo":"mastra-ai/mastra","slug":"mcp-client-tool-execution-failed","errorCode":"MCP_CLIENT_TOOL_EXECUTION_FAILED","errorMessage":"${errorText}","messagePattern":"\\$\\{errorText\\}","errorType":"error_code","errorClass":"MastraError","httpStatus":null,"severity":"error","filePath":"packages/mcp/src/client/client.ts","lineNumber":1485,"sourceCode":"                    arguments: input,\n                    ...(combinedMeta ? { _meta: combinedMeta } : {}),\n                  },\n                  {\n                    timeout: this.timeout,\n                    signal: context?.abortSignal,\n                  },\n                );\n\n                // Per the MCP spec, tool *execution* failures are reported in-band:\n                // the server returns a normal CallToolResult with `isError: true` and\n                // the failure details in `content`. Map that onto Mastra's failed-tool-call\n                // path (unless the consumer opted into the legacy `'return'` behaviour) so\n                // tool spans, stream chunks, scorers, and persisted message parts reflect the\n                // failure, and the model sees the error text so it can self-correct.\n                if (res.isError && this.onToolError === 'throw') {\n                  const errorText = extractToolErrorText(res.content);\n                  this.log('debug', `Tool reported an error: ${tool.name}`, { error: errorText });\n                  throw new MastraError({\n                    id: 'MCP_CLIENT_TOOL_EXECUTION_FAILED',\n                    domain: ErrorDomain.MCP,\n                    category: ErrorCategory.THIRD_PARTY,\n                    text: errorText,\n                    details: { toolName: tool.name, serverName: this.name },\n                  });\n                }\n\n                this.log('debug', `Tool executed successfully: ${tool.name}`);\n\n                if (res.structuredContent !== undefined) {\n                  return attachMcpCallToolContent(\n                    res.structuredContent,\n                    res.content,\n                    res._meta ? this.stampServerIdInMeta(res._meta) : undefined,\n                  );\n                }\n","sourceCodeStart":1467,"sourceCodeEnd":1503,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/mcp/src/client/client.ts#L1467-L1503","documentation":"Thrown when an MCP tool executes successfully at the transport level but the tool's result carries isError: true, and the client is configured with onToolError: 'throw'. The library extracts the human-readable error text from the result content and wraps it in a MastraError (id MCP_CLIENT_TOOL_EXECUTION_FAILED, category THIRD_PARTY) so the failure surfaces through spans, stream chunks, scorers, and persisted message parts. The error text comes from the MCP server itself, not from Mastra.","triggerScenarios":"Calling an MCP tool via InternalMastraMCPClient (e.g. await tool.execute(...)) when the remote tool returns { isError: true, content: [...] } while the client was constructed with onToolError: 'throw' (the strict behavior).","commonSituations":"The tool's internal logic failed on the server (invalid arguments the schema allowed, missing upstream resource, permission denied on the server side, rate limit); server-side bugs; large payloads the server rejects.","solutions":["Read the errorText in the message/details — it is the server's own failure reason; fix the arguments or server-side condition it reports.","If you want the model to see the error text and self-correct instead of the call throwing, configure the client with onToolError: 'propagate' (or the legacy 'return') so the error is returned as a tool result rather than thrown.","Add argument validation on your side before invoking the tool (check required params, formats, ranges against the tool's input schema).","Check MCP server logs for the corresponding execution to find the underlying failure."],"exampleFix":"// before\nconst client = new MastraMCPClient({ name: 'my-server', server, onToolError: 'throw' });\nconst res = await tool.execute({ query: 'drop table' }); // throws MCP_CLIENT_TOOL_EXECUTION_FAILED\n// after: let the model see and recover from the error text\nconst client = new MastraMCPClient({ name: 'my-server', server, onToolError: 'propagate' });\nconst res = await tool.execute({ query: 'select * from users' });","handlingStrategy":"try-catch","validationCode":"// Validate inputs against the tool's schema before executing\nimport { z } from 'zod';\ntool.inputSchema.parse(args); // throws early on bad client-side arguments","typeGuard":"function isToolExecutionError(e: unknown): e is MastraError {\n  return e instanceof MastraError && e.id === 'MCP_CLIENT_TOOL_EXECUTION_FAILED';\n}","tryCatchPattern":"try {\n  return await tool.execute(args);\n} catch (e) {\n  if (isToolExecutionError(e)) {\n    logger.warn({ tool: e.details.toolName, server: e.details.serverName }, e.message); // e.message is the server's error text\n    return { isError: true, content: [{ type: 'text', text: e.message }] }; // feed back to the model\n  }\n  throw e;\n}","preventionTips":["Prefer onToolError: 'propagate' (or 'return') when you want the model to self-correct instead of throwing.","Validate tool arguments against the input schema before every call.","Read the server's error text in the message — it names the actual server-side cause.","Monitor server logs for the corresponding execution to catch recurring failures."],"tags":["mcp","tool-execution","remote-error","third-party"],"backgroundTag":"remote-tool-execution-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}