How to Add a New Tool to the Revit MCP Server Using Dynamic Registration
You can add a new tool to the revit-mcp server by creating a TypeScript file in src/tools/ that exports a function named register[ToolName]Tool, which receives an McpServer instance and calls server.tool() with your tool's ID, Zod schema, and async handler.
The revit-mcp repository implements a dynamic registration system that eliminates manual registry updates when extending server capabilities. This architecture allows you to add a new tool to the MCP server using dynamic registration simply by dropping a properly structured file into the tools directory, where it is automatically discovered and loaded at runtime.
How Dynamic Registration Works in revit-mcp
The dynamic registration pipeline operates through a convention-based discovery mechanism implemented in src/tools/register.ts. When the server initializes in src/index.ts, it invokes registerTools(server), which performs the following steps:
- Directory Scanning: Reads the contents of the
src/tools/directory, excluding its own file and any non-TypeScript/JavaScript files. - Dynamic Import: Uses
import()to load each tool module asynchronously. - Function Detection: Searches for an exported function whose name starts with
register(e.g.,registerEchoTool). - Registration Invocation: Calls the discovered function, passing the
McpServerinstance, which then executesserver.tool()to make the tool available to MCP clients.
This approach ensures that adding a new tool requires zero changes to central configuration files.
Step-by-Step Guide to Adding a New Tool
Follow these steps to implement and register a new tool using the dynamic registration system.
1. Create the Tool File in src/tools/
Create a new TypeScript file in the src/tools/ directory. Use a descriptive filename that reflects the tool's purpose, such as my_new_tool.ts or echo.ts.
2. Export a Registration Function Following the Naming Convention
Your file must export a single function whose name follows the pattern register[ToolName]Tool. The registration system specifically looks for functions starting with register. The function signature must accept an McpServer instance:
export function registerMyNewToolTool(server: McpServer) {
// Registration logic here
}
3. Define the Tool Schema and Handler
Inside your registration function, call server.tool() with four arguments:
- Tool ID: A unique string identifier (e.g.,
"my_new_tool") - Description: A human-readable explanation of what the tool does
- Zod Schema: An object defining and validating the tool's arguments using Zod
- Async Handler: An async function implementing the tool's logic, usually utilizing
withRevitConnectionor other utilities fromsrc/utils/ConnectionManager.tsto communicate with Revit
4. Save and Restart the Server
Save your file. No additional imports or registry updates are required. When the server restarts, src/tools/register.ts automatically discovers your file, imports the module, detects your register* function, and invokes it to register the tool.
Complete Example: Creating an Echo Tool
Here is a complete, runnable example demonstrating how to implement a simple "echo" tool that returns the input text unchanged.
Create src/tools/echo.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
/**
* Registers the `echo` tool.
* The tool simply returns the received message.
*/
export function registerEchoTool(server: McpServer) {
server.tool(
"echo", // ← tool ID
"Returns the supplied text unchanged.", // ← description
{
// ← argument validation with Zod
message: z.string().describe("Text to echo back"),
},
// ← async handler
async (args) => ({
content: [
{ type: "text", text: `🗣️ ${args.message}` },
],
})
);
}
When the server initializes, src/tools/register.ts performs the following sequence:
- Reads the
src/toolsdirectory and identifiesecho.ts. - Dynamically imports
./echo.js(the compiled output). - Detects the exported
registerEchoToolfunction (matching theregister*pattern). - Invokes
registerEchoTool(server), making theechotool available to MCP clients.
Key Files in the Dynamic Registration Pipeline
Understanding these core files helps you debug and extend the registration system:
-
src/tools/register.ts: Implements the discovery logic. It scans the tools directory, filters for TypeScript/JavaScript files, dynamically imports each module, searches for exported functions starting withregister, and invokes them with theMcpServerinstance. -
src/index.ts: The server entry point. It instantiates theMcpServer, callsregisterTools(server)to trigger the dynamic registration process, and connects the server to the stdio transport. -
src/tools/tag_all_walls.ts: A production-ready example demonstrating complex tool implementation, including Zod schema definitions, Revit connection handling viawithRevitConnection, error handling, and structured response formatting. -
src/utils/ConnectionManager.ts: Provides thewithRevitConnectionutility used by most tools to establish and manage communication with the Revit application.
Summary
- Dynamic registration in revit-mcp eliminates manual registry updates by automatically discovering tools in
src/tools/at runtime. - To add a tool, create a file in
src/tools/and export a function namedregister[ToolName]Toolthat callsserver.tool()with a Zod schema and async handler. - The registration system in
src/tools/register.tsscans the directory, dynamically imports modules, and invokes any function starting withregister, passing theMcpServerinstance. - No changes to
src/index.tsor central configuration files are required when adding, removing, or modifying tools.
Frequently Asked Questions
What naming convention must the registration function follow?
The function must start with the prefix register and end with Tool, following the pattern register[ToolName]Tool (e.g., registerEchoTool or registerTagAllWallsTool). The dynamic registration system in src/tools/register.ts specifically searches for exported functions matching this prefix and invokes them automatically.
Do I need to modify any central registry files when adding a new tool?
No. The dynamic registration architecture requires zero changes to central files like src/index.ts or src/tools/register.ts. Simply create your tool file in src/tools/, export the registration function, and restart the server. The discovery mechanism automatically imports your module and registers the tool with the McpServer instance.
How does the server validate tool arguments?
The server uses Zod schemas for runtime type validation and type safety. When calling server.tool() inside your registration function, you pass a Zod object defining the expected arguments (e.g., { message: z.string() }). The MCP SDK automatically validates incoming requests against this schema before invoking your async handler, ensuring type-safe communication between clients and the Revit server.
Can I organize tools into subdirectories within src/tools/?
The current implementation in src/tools/register.ts scans only the immediate src/tools/ directory, skipping non-TypeScript/JavaScript files and its own file. It does not recursively traverse subdirectories. To ensure your tool is discovered, place it directly in src/tools/ rather than in nested folders, or modify the discovery logic in src/tools/register.ts to support recursive scanning.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →