server/tools/ and anvil mcp picks it up automatically — no registration, no config change needed.
File shape
Every file inserver/tools/ must default-export a function. Alongside the default export, provide an inputSchema and a description:
The tool implementation. Receives the validated arguments as its first argument and may return any serializable value. Async functions are supported.
Describes the arguments the tool accepts. Pass a Zod object and Anvil converts it to JSON Schema automatically. When omitted (or when the export is not a Zod schema), Anvil falls back to an empty schema — so always export a Zod object to get input validation and accurate schema advertisement.
A plain-English description shown to MCP clients and AI agents. You can also export
meta.description if you prefer to group metadata together.An explicit tool name. When omitted, Anvil uses the filename without its extension (e.g.
wordCount.ts → wordCount). Must match [a-zA-Z0-9_-]{1,64}.Multi-parameter tools
Tools can accept any number of inputs. Define them all in the Zod object:Generating the input schema dynamically
If you need constructs that Zod can’t express losslessly — or you’re generating tool definitions programmatically — build the Zod schema at module load time rather than inlining it:Always export a Zod object as
inputSchema. Anvil uses the Zod schema both to advertise the tool’s shape to MCP clients (via JSON Schema conversion) and to validate arguments at call time. If inputSchema is absent or not a Zod schema, Anvil falls back to an empty schema and skips validation.How tools are served
Whenanvil mcp starts, it scans server/tools/ for all .ts, .mts, .js, and .mjs files (recursive, sorted alphabetically, excluding _-prefixed files and .d.ts declaration files). Each valid file becomes one MCP tool.
Standalone tools are merged with route-derived tools into a single toolset. Tool names must be unique across both sources — a collision between a file in server/tools/ and a route with the same derived name is a hard startup error.