typescript

Don't put a union at the top of an MCP tool schema

I was building an MCP server with Mastra and Zod, exposing tools to Claude Code. Out of nowhere, Claude Code started telling me the MCP server was not authorized and showed zero tools — even ones that worked fine a minute ago.

The culprit: I had added one new tool whose outputSchema was a z.discriminatedUnion(...) at the root. One bad tool took down discovery for the whole server.

MCP transports tool schemas as JSON Schema. Clients (including Claude Code) validate that every tool's input and output schema has type: "object" at the root. A union serializes as { anyOf: [...] } with no root object type, fails that check, and the client rejects the entire tools/list response. The misleading part is the error: Claude Code surfaces it as a generic auth failure, not a schema problem.

Wrap the union in an outer z.object({ ... }). You keep the discriminated union semantics — only the root shape changes from a union to an object with one field that contains the union.

If an MCP server suddenly shows no tools or an auth error after you added or edited one tool, suspect the schema before suspecting auth. Check every new tool's inputSchema and outputSchema — if either starts with a union, wrap it.

mcptypescriptaimastra
lubosmato