Data Flow from AI Tool Call Through MCP to Revit Execution: A Complete Technical Guide

The data flow from an AI tool call through MCP to Revit execution follows a seven-stage pipeline: tool registration, AI client request, tool handler execution, connection management, JSON-RPC socket communication, Revit add-in processing, and result propagation back to the AI assistant.

The revit-mcp repository implements a Model-Context-Protocol (MCP) server that bridges AI assistants with Autodesk Revit. Understanding this data flow is essential for developers building AI-powered BIM workflows, as it reveals how high-level natural language commands translate into precise Revit API operations.

The Seven-Stage MCP to Revit Data Flow Architecture

Stage 1: Tool Registration and Discovery

When the MCP server initializes, the registerTools function in src/tools/register.ts dynamically discovers and exposes all available Revit operations to AI clients.

The registration system scans the src/tools directory and imports every module exporting a function prefixed with register. Each registration function calls server.registerTool() from the MCP SDK, binding a tool name (e.g., "ai_element_filter") to its handler implementation.

// src/tools/register.ts
for (const file of toolFiles) {
  const module = await import(`./${file.replace(/\.(ts|js)$/, ".js")}`);
  const registerFn = Object.keys(module).find(
    k => k.startsWith("register") && typeof module[k] === "function"
  );
  if (registerFn) module[registerFn](server);
}

Stage 2: AI Client JSON-RPC Request

When an AI assistant decides to invoke a Revit operation, its MCP client sends a JSON-RPC 2.0 request to the server. The request specifies the tool name and parameters required for the Revit operation.

// AI client using the Model-Context-Protocol SDK
const result = await mcpServer.callTool("ai_element_filter", {
  filterCategory: "OST_Walls",
  includeInstances: true
});
console.log("Walls returned:", result);

Stage 3: Tool Handler Execution

The MCP SDK routes the incoming request to the registered tool handler. In src/tools/ai_element_filter.ts, the handler wraps its logic inside withRevitConnection, ensuring a valid TCP link to Revit exists before proceeding.

// src/tools/ai_element_filter.ts
export function registerAiElementFilterTool(server: McpServer) {
  server.registerTool({
    name: "ai_element_filter",
    description: "Query Revit elements for AI assistants",
    // … schema omitted …
    async handler(params) {
      // Ensure we have a live Revit connection
      return await withRevitConnection(async revitClient => {
        // Forward the request to the Revit add‑in
        return await revitClient.sendCommand("ai_element_filter", params);
      });
    },
  });
}

Stage 4: Connection Management and TCP Handshake

The withRevitConnection helper in src/utils/ConnectionManager.ts manages the lifecycle of the TCP connection to Revit. It instantiates a RevitClientConnection targeting localhost:8080 and implements a 5-second timeout for the initial handshake.

If the socket is not already connected, the manager waits for the TCP handshake to complete before invoking the tool-specific callback with the live client instance.

// src/utils/ConnectionManager.ts
export async function withRevitConnection<T>(operation: (c: RevitClientConnection) => Promise<T>) {
  const revitClient = new RevitClientConnection("localhost", 8080);
  // … connect logic (5 s timeout) …
  try {
    return await operation(revitClient);
  } finally {
    revitClient.disconnect();
  }
}

Stage 5: JSON-RPC over TCP Socket Communication

The RevitClientConnection class in src/utils/SocketClient.ts implements the low-level JSON-RPC 2.0 protocol over TCP. When sendCommand is invoked, it:

  1. Generates a unique request ID using generateRequestId
  2. Constructs a JSON-RPC 2.0 payload with method, params, and id
  3. Writes the serialized JSON to the TCP socket
  4. Stores a callback in responseCallbacks keyed by the request ID
  5. Returns a promise that resolves when the Revit add-in responds or rejects on error/timeout
// src/utils/SocketClient.ts (excerpt)
public sendCommand(command: string, params: any = {}): Promise<any> {
  return new Promise((resolve, reject) => {
    const requestId = this.generateRequestId();
    const payload = { jsonrpc: "2.0", method: command, params, id: requestId };
    this.responseCallbacks.set(requestId, data => {
      const resp = JSON.parse(data);
      resp.error ? reject(new Error(resp.error.message)) : resolve(resp.result);
    });
    this.socket.write(JSON.stringify(payload));
    // … timeout handling …
  });
}

Stage 6: Revit Add-in Execution

On the Revit side (external to this repository but communicating via the established protocol), a dedicated add-in listens on TCP port 8080. Upon receiving the JSON-RPC command, it:

  • Parses the method name and parameters
  • Executes the corresponding Revit API operation (e.g., filtering elements, creating geometry, modifying parameters)
  • Constructs a JSON-RPC response containing either a result object or an error object
  • Sends the response back through the TCP socket

Stage 7: Result Propagation to AI Client

The response travels back up the chain:

  1. The socket listener in SocketClient.ts receives the JSON, parses it, and invokes the stored callback from responseCallbacks
  2. The promise returned by sendCommand resolves with response.result (or rejects on error)
  3. This bubbles up through withRevitConnection to the tool handler in ai_element_filter.ts
  4. The MCP server packages the result into the original JSON-RPC response to the AI client
  5. The AI assistant receives the structured data and can present results or continue the workflow

Key Implementation Files in the Data Flow

Purpose File Path
Server entry point – creates McpServer and starts the stdio transport src/index.ts
Dynamic discovery and registration of all tool modules src/tools/register.ts
Example AI-focused tool exposing "ai_element_filter" src/tools/ai_element_filter.ts
Helper guaranteeing a live TCP link to the Revit add-in src/utils/ConnectionManager.ts
Low-level socket wrapper implementing JSON-RPC over TCP src/utils/SocketClient.ts
Additional tool implementations following the same pattern src/tools/*.ts (e.g., create_line_based_element.ts, operate_element.ts)

Summary

  • Tool Registration: The registerTools function dynamically discovers and exposes Revit operations via the MCP SDK at server startup.
  • AI Client Communication: AI assistants invoke tools through JSON-RPC 2.0 requests handled by the MCP server.
  • Connection Management: The withRevitConnection helper ensures a live TCP connection to Revit on localhost:8080 with a 5-second timeout.
  • Protocol Implementation: SocketClient.ts handles JSON-RPC serialization, request ID generation, and promise-based response handling over TCP.
  • Revit Execution: The Revit add-in receives commands, executes Revit API operations, and returns structured responses back through the same chain.

Frequently Asked Questions

How does the MCP server handle multiple concurrent tool calls to Revit?

Each tool invocation creates its own promise chain through withRevitConnection, which manages the TCP socket lifecycle. While the current implementation in ConnectionManager.ts creates a new RevitClientConnection instance per operation, the underlying TCP connection to localhost:8080 is managed sequentially. For true concurrency, the Revit add-in would need to implement request queuing or the connection manager would need to implement connection pooling.

What happens if Revit is not running when an AI tool call is made?

The withRevitConnection function implements a 5-second connection timeout when attempting to connect to localhost:8080. If the TCP handshake fails because Revit is not running or the add-in is not loaded, the connection promise rejects with a timeout error. This error propagates back through the tool handler to the MCP server, which returns a JSON-RPC error response to the AI client indicating that the Revit connection is unavailable.

Is the communication between MCP and Revit encrypted?

The current implementation in src/utils/SocketClient.ts uses a standard Node.js net.Socket for TCP communication without TLS/SSL encryption. The connection operates over plain TCP on localhost:8080, which is suitable for local development but would require implementation of TLS wrappers or VPN tunnels for production environments where Revit and the MCP server run on separate machines.

How are tool parameters validated before reaching Revit?

Parameter validation occurs at two levels in the data flow. First, the MCP SDK validates incoming requests against the JSON schema defined in the tool registration (e.g., in registerAiElementFilterTool). Second, the Revit add-in performs business logic validation when it receives the JSON-RPC command, ensuring that parameters like element IDs exist and that operations are valid for the current Revit document state. Errors from either validation layer propagate back to the AI client as JSON-RPC error objects.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →