mastra-ai/mastra · error · MastraError

MCP_CLIENT_TOOL_EXECUTION_FAILED

MCP_CLIENT_TOOL_EXECUTION_FAILED

Error message

${errorText}

What it means

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.

Source

Thrown at packages/mcp/src/client/client.ts:1485

                    arguments: input,
                    ...(combinedMeta ? { _meta: combinedMeta } : {}),
                  },
                  {
                    timeout: this.timeout,
                    signal: context?.abortSignal,
                  },
                );

                // Per the MCP spec, tool *execution* failures are reported in-band:
                // the server returns a normal CallToolResult with `isError: true` and
                // the failure details in `content`. Map that onto Mastra's failed-tool-call
                // path (unless the consumer opted into the legacy `'return'` behaviour) so
                // tool spans, stream chunks, scorers, and persisted message parts reflect the
                // failure, and the model sees the error text so it can self-correct.
                if (res.isError && this.onToolError === 'throw') {
                  const errorText = extractToolErrorText(res.content);
                  this.log('debug', `Tool reported an error: ${tool.name}`, { error: errorText });
                  throw new MastraError({
                    id: 'MCP_CLIENT_TOOL_EXECUTION_FAILED',
                    domain: ErrorDomain.MCP,
                    category: ErrorCategory.THIRD_PARTY,
                    text: errorText,
                    details: { toolName: tool.name, serverName: this.name },
                  });
                }

                this.log('debug', `Tool executed successfully: ${tool.name}`);

                if (res.structuredContent !== undefined) {
                  return attachMcpCallToolContent(
                    res.structuredContent,
                    res.content,
                    res._meta ? this.stampServerIdInMeta(res._meta) : undefined,
                  );
                }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the errorText in the message/details — it is the server's own failure reason; fix the arguments or server-side condition it reports.
  2. 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.
  3. Add argument validation on your side before invoking the tool (check required params, formats, ranges against the tool's input schema).
  4. Check MCP server logs for the corresponding execution to find the underlying failure.

Example fix

// before
const client = new MastraMCPClient({ name: 'my-server', server, onToolError: 'throw' });
const res = await tool.execute({ query: 'drop table' }); // throws MCP_CLIENT_TOOL_EXECUTION_FAILED
// after: let the model see and recover from the error text
const client = new MastraMCPClient({ name: 'my-server', server, onToolError: 'propagate' });
const res = await tool.execute({ query: 'select * from users' });
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate inputs against the tool's schema before executing
import { z } from 'zod';
tool.inputSchema.parse(args); // throws early on bad client-side arguments

Type guard

function isToolExecutionError(e: unknown): e is MastraError {
  return e instanceof MastraError && e.id === 'MCP_CLIENT_TOOL_EXECUTION_FAILED';
}

Try / catch

try {
  return await tool.execute(args);
} catch (e) {
  if (isToolExecutionError(e)) {
    logger.warn({ tool: e.details.toolName, server: e.details.serverName }, e.message); // e.message is the server's error text
    return { isError: true, content: [{ type: 'text', text: e.message }] }; // feed back to the model
  }
  throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/bf4b87b4407a4275. Report an issue: GitHub.