Error Handling Patterns for Revit Connection Failures in revit-mcp

The revit-mcp server implements a layered defensive-programming strategy that combines promise-based handshake timeouts, socket-level error listeners, command execution timeouts, and guaranteed resource cleanup to ensure Revit connection failures are caught early, reported clearly, and never leak resources.

The revit-mcp repository provides a Model Context Protocol (MCP) server that enables AI assistants to communicate with Autodesk Revit via socket connections. Understanding the error handling patterns for Revit connection failures is critical for building robust integrations that gracefully handle network instability, Revit crashes, or unresponsive plugins.

Layered Error Handling Architecture

The codebase organizes error handling into distinct layers, each responsible for a specific failure domain. This separation ensures that low-level socket errors do not propagate uncaught while higher-level business logic remains clean.

  • Connection Layer: Manages the initial TCP handshake and authentication
  • Transport Layer: Handles socket errors, disconnections, and data buffering
  • Application Layer: Implements command timeouts and JSON parsing validation
  • API Layer: Surfaces errors to MCP tool callers with meaningful messages

Connection Handshake Protection

The withRevitConnection helper in src/utils/ConnectionManager.ts implements a defensive handshake pattern that guarantees either a valid connection or a clear rejection within five seconds.

The implementation registers temporary event listeners for both connect and error events before invoking revitClient.connect(). If the connect event never fires, a setTimeout rejects the promise with the message "connect to revit client failed" or its Chinese equivalent "连接到Revit客户端失败".

import { withRevitConnection } from "./utils/ConnectionManager.js";

async function listWalls() {
  try {
    const result = await withRevitConnection(async (client) => {
      return await client.sendCommand("list_walls", {});
    });
    console.log("Walls:", result);
  } catch (err) {
    // Catches handshake timeout, socket errors, or command failures
    console.error("Failed to talk to Revit:", err instanceof Error ? err.message : err);
  }
}

Socket-Level Error Management

The SocketClient class in src/utils/SocketClient.ts centralizes low-level network failure handling through persistent socket.on('error') listeners. When a socket error occurs, the implementation logs the error, sets the internal isConnected flag to false, and prevents further operations on the broken socket.

This pattern ensures that higher-level code never accidentally assumes a socket is still alive after a network interruption. The error listener operates independently of active commands, providing a safety net for unexpected disconnections.

Command Execution Safeguards

Each command sent through sendCommand includes a two-minute timeout mechanism that prevents hanging promises when the Revit side stalls or responses are lost. The implementation creates a setTimeout that rejects with Command timed out after 2 minutes: <command> if no response arrives within the window.

Additionally, response parsing includes defensive try-catch blocks around JSON.parse. Both the buffer processor and per-request callbacks catch malformed JSON and reject with descriptive errors (Failed to parse response), ensuring that malformed payloads do not crash the client.

// Example of adjusting the handshake timeout for slower environments
const HANDSHAKE_TIMEOUT_MS = 10_000; // 10 seconds

// In ConnectionManager.ts, replace the 5000ms value with this constant
setTimeout(() => {
  revitClient.socket.removeListener("connect", onConnect);
  revitClient.socket.removeListener("error", onError);
  reject(new Error("连接到Revit客户端失败"));
}, HANDSHAKE_TIMEOUT_MS);

Resource Cleanup Guarantees

The withRevitConnection function implements a finally block that always calls revitClient.disconnect() after operations complete, regardless of success or failure. This pattern guarantees that sockets are closed and resources are released even when errors occur during command execution.

This cleanup prevents resource leaks and zombie connections that could exhaust file descriptors or leave Revit in an inconsistent state. The disconnect logic operates independently of the operation result, ensuring deterministic resource management.

Surfacing Errors to Users

Higher-level MCP tools such as send_code_to_revit in src/tools/send_code_to_revit.ts wrap withRevitConnection in try-catch blocks that propagate connection-related failures to the caller. These tools catch rejections from the connection layer and surface the error messages through the MCP protocol, providing users with actionable diagnostics.

This pattern ensures that low-level socket errors translate into meaningful API responses rather than silent failures or crashes.

Summary

  • Handshake Protection: withRevitConnection enforces a 5-second timeout with explicit promise resolution/rejection to prevent indefinite hanging during initial connection.
  • Socket Error Isolation: The socket.on('error') listener in SocketClient.ts immediately marks connections as failed and prevents operations on broken sockets.
  • Command Timeouts: Every sendCommand includes a 2-minute timeout to handle stalled Revit processes or lost responses.
  • Parsing Safety: Try-catch blocks around JSON.parse prevent malformed payloads from crashing the client.
  • Resource Guarantees: finally blocks ensure disconnect() runs even when operations throw, preventing resource leaks.
  • Error Propagation: Tool wrappers surface connection failures to MCP callers with descriptive messages.

Frequently Asked Questions

What happens if Revit is not running when revit-mcp tries to connect?

The withRevitConnection helper will reject with the message "connect to revit client failed" (or "连接到Revit客户端失败") after a 5-second timeout. This rejection propagates to the calling MCP tool, which surfaces the error to the user indicating that the Revit client is unavailable.

How does revit-mcp handle network interruptions during active commands?

The SocketClient class maintains a persistent socket.on('error') listener that immediately sets isConnected to false when network errors occur. Additionally, each command has a 2-minute timeout that will reject if the response is lost due to network issues. These layered protections ensure that hanging promises are prevented and resources are cleaned up properly.

Can the connection timeout be adjusted for slower environments?

Yes, the 5-second handshake timeout in ConnectionManager.ts can be modified by changing the setTimeout duration value. For environments with slower startup times, increasing this value to 10 seconds or more allows the Revit client additional time to respond without sacrificing the fail-fast protection that prevents indefinite hanging.

What prevents memory leaks when connections fail?

The withRevitConnection function implements a finally block that guarantees revitClient.disconnect() is called regardless of whether the operation succeeds or throws an error. This ensures that socket file descriptors are released and event listeners are removed, preventing resource exhaustion even during repeated connection failures.

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 →