Skip to main content
Run anvil mcp to serve your MCP-exposed routes and any standalone tool files in server/tools/ as a Model Context Protocol (MCP) tool server. AI agents, orchestrators, and local clients such as Claude Desktop can then discover and call your tools without any additional glue code. Anvil supports two transport modes: Streamable HTTP (the default) for networked agents and hosted deployments, and --stdio for local clients that communicate over standard input/output.

Usage

anvil mcp [options]

Flags

-r, --routes <dir>
string
default:"server/routes"
Directory Anvil scans for route files. Only routes that carry meta.mcp.expose = true are registered as MCP tools.
-t, --tools <dir>
string
default:"server/tools"
Directory of standalone tool files to include alongside route-derived tools. If this directory does not exist, it is silently skipped — no error is thrown.
--stdio
boolean
Serve the MCP server over stdio instead of HTTP. Use this mode when connecting a local client such as Claude Desktop directly to the process. In stdio mode, the protocol channel is stdout; all Anvil diagnostics are written to stderr so they do not corrupt the protocol stream.
-p, --port <port>
number
default:"3100"
HTTP port for Streamable HTTP mode. Ignored when --stdio is set.
-e, --endpoint <path>
string
default:"/mcp"
URL path at which the Streamable HTTP endpoint is mounted. Ignored when --stdio is set.

HTTP mode (default)

Start the MCP server on its default port:
anvil mcp
[anvil] mcp (Streamable HTTP) on http://localhost:3100/mcp
[anvil] 3 tool(s): get_user, create_order, search_products
Connect any MCP-compatible HTTP client to http://localhost:3100/mcp.

Custom port and endpoint

anvil mcp --port 4200 --endpoint /tools/mcp
[anvil] mcp (Streamable HTTP) on http://localhost:4200/tools/mcp
[anvil] 2 tool(s): summarize, classify

stdio mode

Start the MCP server over stdio for use with Claude Desktop or another local client:
anvil mcp --stdio
[anvil] mcp stdio: 3 tool(s) — get_user, create_order, search_products
The process then communicates exclusively over stdin/stdout using the MCP wire protocol. Add it to your Claude Desktop config like this:
{
  "mcpServers": {
    "my-anvil-app": {
      "command": "npx",
      "args": ["anvil", "mcp", "--stdio"],
      "cwd": "/path/to/your/project"
    }
  }
}

Exposing a route as an MCP tool

To include a route as an MCP tool, add a meta export to the route file with mcp.expose set to true:
// server/routes/api/summarize/POST.ts
export const meta = {
  mcp: {
    expose: true,
    description: "Summarize a block of text to a given maximum length.",
  },
};

export const bodySchema = z.object({
  text: z.string(),
  maxWords: z.number().int().optional(),
});

export default async function handler(req) { /* ... */ }
If server/tools/ does not exist, anvil mcp silently skips it. You do not need to create the directory or pass --tools with a different path unless you have standalone tool files to include.
In stdio mode, do not write to stdout from inside your route handlers or tools. Any non-protocol bytes on stdout will corrupt the MCP stream. Use process.stderr.write(...) or a logging library configured to write to stderr.
Run anvil lint before anvil mcp in CI. Lint catches schema-lossy errors — schemas that cannot round-trip to JSON Schema — which would cause tools to be unregistered or malformed at runtime.