Debugging MCP-Revit Communication Issues: A Complete Troubleshooting Guide
The most effective way to debug MCP-Revit communication issues is to enable verbose logging in SocketClient.ts, validate JSON-RPC message integrity, and systematically verify the TCP connection lifecycle through withRevitConnection.
The mcp-servers-for-revit/revit-mcp repository implements a lightweight JSON-RPC bridge that enables Model Context Protocol (MCP) servers to communicate with Autodesk Revit. When troubleshooting debugging MCP-Revit communication issues, understanding the TCP socket architecture and message flow between the MCP client and Revit server is essential for rapid diagnosis.
Understanding the MCP-Revit Architecture
Core Components Overview
The communication stack consists of three primary layers:
-
RevitClientConnection(src/utils/SocketClient.ts): Manages the TCP socket connection to Revit, handles incoming data buffering, and parses JSON-RPC responses. It wires up listeners forconnect,data,close, anderrorevents insetupSocketListeners()(lines 18-22). -
withRevitConnection(src/utils/ConnectionManager.ts): A higher-order function that guarantees a live socket before executing any tool command. It creates aRevitClientConnectiontargetinglocalhost:8080and waits up to 5 seconds for theconnectevent (lines 14-39), ensuring cleanup viadisconnect()afterward (lines 44-47). -
Tool Modules (e.g.,
src/tools/send_code_to_revit.ts,src/tools/tag_all_walls.ts): Encode specific Revit operations, invokerevitClient.sendCommand(), and propagate errors back to the MCP server. Each tool wraps RPC calls insidewithRevitConnectionand catches exceptions to return user-friendly error messages.
Communication Flow
When an MCP tool executes, the data flows through this pipeline:
- The tool invokes
withRevitConnection(), which instantiatesRevitClientConnection. - The socket client attempts TCP connection to
localhost:8080with a 5-second timeout. - Upon connection, the tool calls
sendCommand(method, params), which generates a unique request ID viagenerateRequestId()(lines 73-75), constructs the JSON-RPC envelope, and transmits it. - The Revit server processes the command and returns a response, which
processBuffer()(lines 42-49) attempts to parse as complete JSON. handleResponse()(lines 77-90) matches the response ID to the pending callback and resolves or rejects the promise.
Common MCP-Revit Communication Failure Points
| Symptom | Likely Cause | Investigation Location |
|---|---|---|
| "connect to revit client failed" | Revit socket server not listening on port 8080, firewall blocking TCP traffic, or Revit process crash. | withRevitConnection timeout handling (lines 34-38 in ConnectionManager.ts). |
| "Command timed out after 2 minutes" | Revit received the request but failed to respond, typically due to long-running API operations, thread deadlocks, or unhandled exceptions in the Revit add-in. | sendCommand() timeout logic (lines 35-41 in SocketClient.ts). |
| JSON parse errors | Malformed or fragmented responses, usually caused by multiple concatenated JSON messages in the buffer or truncated TCP packets. | processBuffer() try/catch block (lines 44-51) and handleResponse() (lines 77-90). |
response.error present |
Revit-side execution failure, such as invalid element IDs, missing family types, or API permission errors. The error object is relayed back to the tool. | sendCommand() callback handling (lines 13-22). |
Debugging Strategies for MCP-Revit Communication Issues
Enable Verbose Logging in SocketClient.ts
The first step in troubleshooting is to instrument the raw data flow. Add debug statements to src/utils/SocketClient.ts around line 18 to capture socket events:
this.socket.on("data", (data) => {
console.debug("[MCP] Received raw bytes:", data.toString());
this.buffer += data.toString();
this.processBuffer();
});
Similarly, log connection state changes in setupSocketListeners():
this.socket.on("connect", () => {
console.info("[MCP] Socket connected to Revit on localhost:8080");
this.isConnected = true;
});
Validate JSON-RPC Message Integrity
Communication failures often stem from malformed envelopes. Verify that:
- The
idfield is unique per request, generated bygenerateRequestId()(lines 73-75). - The Revit server echoes the identical
idin its response; mismatched IDs will leave callbacks hanging indefinitely. - The
jsonrpcversion is consistently"2.0".
Inspect the raw buffer content in processBuffer() (lines 42-49) to ensure complete JSON objects are being extracted before parsing.
Verify Connection Lifecycle with withRevitConnection
The withRevitConnection helper in src/utils/ConnectionManager.ts manages the critical connection window. To debug lifecycle issues:
- Check the timeout window: The default 5-second timeout (lines 34-38) may be insufficient on slower systems. Temporarily increase this value to see if the Revit process is simply slow to start.
- Confirm cleanup: Ensure
disconnect()is called in thefinallyblock (lines 44-47) to prevent socket leaks that could exhaust available ports. - Monitor
isConnectedstate: Log the state ofRevitClientConnection.isConnectedbefore and after tool execution to verify the socket is actually ready.
Inspect Buffer Handling in processBuffer()
Fragmented messages are a common source of "JSON parse error" exceptions. The current implementation in processBuffer() (lines 42-49) attempts to parse the entire buffer as a single JSON object. If the Revit server sends multiple concatenated messages or splits a large response across TCP packets, parsing will fail.
To diagnose buffer issues:
- Log the buffer content before parsing:
console.debug("[MCP] Buffer content:", this.buffer); - Check for multiple JSON objects by attempting to split on newline characters or by validating JSON length prefixes if the protocol supports them.
- Look for truncated data by checking if the buffer ends with incomplete JSON structures (e.g., missing closing braces).
Simulate Requests with TCP Clients
Isolate the MCP client from the Revit server by using raw TCP tools to verify connectivity and message format:
# Test basic connectivity
telnet localhost 8080
Or use Node.js to send a valid JSON-RPC request:
const net = require("net");
const client = net.createConnection({ host: "localhost", port: 8080 }, () => {
const payload = JSON.stringify({
jsonrpc: "2.0",
method: "ping",
params: {},
id: "test123"
});
client.write(payload);
});
client.on("data", (data) => console.log("Response:", data.toString()));
client.on("error", (err) => console.error("Connection error:", err));
This approach confirms whether issues stem from the transport layer (TCP) or the application layer (JSON-RPC).
Correlate with Revit-Side Logs
The Revit add-in maintains separate logs typically located at %APPDATA%/MCPRevit/log.txt. Cross-reference timestamps between these logs and the MCP client output to identify:
- Whether commands reached the Revit process.
- How long Revit took to process specific API calls.
- Any exceptions thrown by the Revit API before a response was sent.
Quick Diagnostic Checklist
Use this systematic checklist to isolate MCP-Revit communication issues:
| Step | Action | Expected Result |
|---|---|---|
| 1 | Run telnet localhost 8080 or nc -vz localhost 8080 |
Connection established message appears immediately. |
| 2 | Send manual JSON-RPC ping payload | Receive response containing matching "id" and "result" fields. |
| 3 | Check src/utils/SocketClient.ts logs for "RevitClientConnection error" |
No error lines; isConnected should be true. |
| 4 | Run a simple tool (e.g., send_code_to_revit) from the MCP CLI and verify the JSON response. |
Successful execution or a clear error message. |
Practical Debugging Code Examples
Manual RPC Call Using the MCP Helper
This TypeScript example uses the same withRevitConnection flow that all production tools use, making it ideal for isolating connection issues:
import { withRevitConnection } from "./src/utils/ConnectionManager.js";
async function testPing() {
try {
const result = await withRevitConnection(async (client) => {
return await client.sendCommand("ping", {});
});
console.log("Revit responded:", result);
} catch (e) {
console.error("Ping failed:", e);
}
}
testPing();
Enhanced Logging Wrapper
Add this instrumentation to src/utils/SocketClient.ts near line 18 to capture raw network traffic:
// Place inside setupSocketListeners() method
this.socket.on("data", (data) => {
console.debug("[MCP] Received raw:", data.toString());
this.buffer += data.toString();
this.processBuffer();
});
Key Files for Debugging MCP-Revit Communication
Understanding these source files is essential for effective troubleshooting:
| File | Purpose | Critical Functions |
|---|---|---|
src/utils/SocketClient.ts |
Low-level TCP client implementation, JSON-RPC parsing, and timeout handling. | setupSocketListeners() (L18-L22), processBuffer() (L42-L49), sendCommand() (L35-L41), generateRequestId() (L73-L75), handleResponse() (L77-L90) |
src/utils/ConnectionManager.ts |
Connection lifecycle management and resource cleanup. | withRevitConnection() (L14-L47) |
src/tools/send_code_to_revit.ts |
Example tool showing error propagation and command execution. | Tool implementation wrapping RPC calls (L28-L56) |
src/tools/tag_all_walls.ts |
Reference for element manipulation command patterns. | Response handling implementation |
src/index.ts |
MCP server entry point and tool registration. | Server initialization and tool registration flow |
Summary
- Start with architecture: Understanding the roles of
RevitClientConnection,withRevitConnection, and the tool modules provides the foundation for systematic debugging. - Log everything: Instrument
src/utils/SocketClient.tsto capture raw TCP data and connection state changes before attempting complex fixes. - Validate JSON-RPC integrity: Ensure unique request IDs and complete JSON objects to prevent hanging callbacks and parse errors.
- Isolate the layers: Use raw TCP clients like
telnetor Node.jsnetto determine if issues are transport-layer (TCP) or application-layer (JSON-RPC). - Check both sides: Correlate MCP client logs with Revit-side logs at
%APPDATA%/MCPRevit/log.txtto trace command execution across the bridge.
Frequently Asked Questions
Why does my MCP client fail to connect to Revit with a timeout error?
The connection timeout typically indicates that the Revit socket server is not listening on localhost:8080, a firewall is blocking TCP traffic, or the Revit process has crashed. Verify that the Revit add-in is loaded and listening using telnet localhost 8080. If this fails, check the Revit-side logs at %APPDATA%/MCPRevit/log.txt for startup errors before investigating the MCP client code in src/utils/ConnectionManager.ts.
How do I fix "JSON parse error" messages in SocketClient.ts?
JSON parse errors occur when processBuffer() in src/utils/SocketClient.ts (lines 42-49) receives incomplete or concatenated JSON messages. This happens when TCP packets fragment the data or the Revit server sends multiple JSON objects without delimiters. To debug, add console.debug() statements to log the raw buffer content before parsing. For a permanent fix, implement a delimiter-based protocol (such as newline-separated JSON) or use length-prefixed messages rather than assuming single-object packets.
What causes command timeouts after 2 minutes even when Revit is connected?
The 2-minute timeout originates in sendCommand() at lines 35-41 of src/utils/SocketClient.ts. This indicates the Revit server received the JSON-RPC request but failed to send a response, typically due to long-running Revit API operations, thread deadlocks, or unhandled exceptions in the Revit add-in. Check the Revit-side logs for exceptions during command execution, and consider breaking long operations into smaller chunks or increasing the timeout for legitimate long-running tasks.
How can I verify that my JSON-RPC requests are properly formatted?
Valid JSON-RPC requests must include a unique id field (generated by generateRequestId() at lines 73-75), the jsonrpc: "2.0" version string, a valid method name, and a params object. Use a raw TCP client like Node.js net to send test payloads to localhost:8080 and verify that the response echoes the same id and contains either a result or error field. If the id mismatches or is missing, the handleResponse() function (lines 77-90) will be unable to match the response to the pending callback, causing the promise to hang indefinitely.
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 →