mastra-ai/mastra · error · Error

The "extra" key is now nested under "mcp.extra" in tool…

Error message

The "extra" key is now nested under "mcp.extra" in tool arguments

What it means

Companion to the `elicitation` migration guard: accessing the top-level `extra` key in tool arguments now throws with a pointer to the new location, `mcp.extra`. The throwing getter exists solely to surface the rename to developers instead of silently returning undefined.

Solutions

  1. Access request/session data via `mcp.extra` instead of the top-level `extra` argument.
  2. Update destructured parameters to pull `extra` from the nested `mcp` object.
  3. Grep tools for `extra.` and `extra}` usages and migrate them to `mcp.extra`.

Example fix

// before
execute: async (args, { extra }) => console.log(extra.sessionId)
// after
execute: async (args, mcp) => console.log(mcp.extra.sessionId)
Defensive patterns

Strategy: type-guard

Validate before calling

// static check before deploy
grep -rn "\bextra\b" src/tools/ | grep -v "mcp.extra" && echo 'migrate to mcp.extra'

Type guard

function getExtra(mcp: unknown): McpExtra | undefined { return !!mcp && typeof mcp === 'object' && 'extra' in mcp ? (mcp as any).extra : undefined; }

Try / catch

try { return await tool.execute(args, mcpOptions); } catch (e) { if (String(e?.message).includes('mcp.extra')) { throw new Error('Tool uses deprecated top-level extra; migrate to mcp.extra'); } throw e; }

Prevention

When it happens

Trigger: During a `tools/call`, the tool's execute function accesses `context.extra` (e.g. `extra.requestInfo`, `extra.sessionId`, or request metadata) on the proxied MCP context.

Common situations: Tools that read HTTP request info, auth context, or per-session data via `extra` written before the `mcp.extra` nesting was introduced.

Related errors


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

Appendix: source

Thrown at packages/mcp/src/server/server.ts:1141

        };

        const mcpOptions: MastraToolInvocationOptions = {
          messages: [],
          toolCallId: '',
          requestContext: proxiedContext,
          // Pass MCP-specific context through the mcp property
          mcp: {
            elicitation: sessionElicitation,
            extra,
            log: sessionLog,
            progress: sessionProgress,
          },
          // @ts-expect-error this is to let people know that the elicitation and extra keys are now nested under mcp.elicitation and mcp.extra in tool arguments
          get elicitation() {
            throw new Error(`The "elicitation" key is now nested under "mcp.elicitation" in tool arguments`);
          },
          get extra() {
            throw new Error(`The "extra" key is now nested under "mcp.extra" in tool arguments`);
          },
        };

        await this.enforceToolExecutionFGA(request.params.name, proxiedContext);

        const result = await tool.execute(validation?.value ?? request.params.arguments ?? {}, mcpOptions);

        const duration = Date.now() - startTime;

        // Check if the tool builder returned a validation error (e.g. input failed Zod validation
        // after passing the JSON Schema first-pass validation above)
        if (isValidationError(result)) {
          this.logger.warn(`CallTool: Tool '${request.params.name}' returned a validation error in ${duration}ms.`, {
            error: result.message,
          });
          return {
            content: [{ type: 'text', text: result.message }],
            isError: true,

View on GitHub (pinned to 75dd419e61)