meta export that opts the route in, and a paramsSchema (or bodySchema) that describes its inputs. Anvil does the rest — it converts the Zod schema to JSON Schema, names the tool, and wires it into the MCP server.
The meta.mcp annotation
Add a meta export with an mcp key to any route handler file:
boolean
required
Set to
true to include this route in the MCP toolset. Routes without this field are ignored by anvil mcp.string
The human-readable description shown to MCP clients and AI agents when they list available tools. Keep it concise and imperative: “Fetch a user by ID”, not “This endpoint fetches a user”.
string
An explicit tool name. Must match
[a-zA-Z0-9_-]{1,64}. When omitted, Anvil derives a name from the route method and path segments — for example, GET /users/:id becomes get_users_by_id.z.ZodObject
A Zod object schema that describes the route’s URL parameters. Keys must match the dynamic segments in the folder path (
[id] → id). Anvil merges paramsSchema and bodySchema into a single tool input schema.z.ZodObject
A Zod object schema for the request body (non-GET routes). Merged with
paramsSchema when both are present.Automatic schema conversion
Whenanvil mcp starts, it calls the built-in Zod-to-JSON-Schema converter on each exposed route’s merged input schema. The result is advertised to MCP clients in the tools/list response so agents know exactly what arguments to pass.
At call time, Anvil re-validates the incoming arguments against the original Zod schema before invoking your handler — so any refinements or constraints you defined still enforce, even if the JSON Schema representation was slightly looser.
Zod types that convert cleanly
The converter supports the full data-shape subset of Zod:Tool naming
Anvil derives the tool name from the HTTP method and path segments by default:meta.mcp.name to override this when you want a domain-friendly name:
Validating with anvil lint
Run anvil lint before deploying to catch schema and naming issues at build time:
anvil lint checks two things for every MCP-exposed route:
- Param key match — every key in
paramsSchemacorresponds to a[dynamic]segment in the folder path, and vice versa. - Lossless conversion — the schema converts to JSON Schema without throwing
SchemaConversionError.
Running the MCP server
Once your routes are annotated, start the server:meta.mcp.expose = true route that Anvil found under server/routes/. The server is now ready to accept tools/list and tools/call requests from any MCP-compatible client.