@rui.branco/revit-mcp 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,16 +3,16 @@
3
3
  [![Revit](https://img.shields.io/badge/Revit-2025%20%7C%202026%20%7C%202027-006666)](https://www.autodesk.com/products/revit/overview)
4
4
  [![Platform](https://img.shields.io/badge/platform-Windows-0078D4)](#installation)
5
5
  [![Node.js](https://img.shields.io/badge/node-%E2%89%A518-339933)](https://nodejs.org)
6
- [![Tests](https://img.shields.io/badge/tests-507%20passing-success)](#development)
6
+ [![Tests](https://img.shields.io/badge/tests-521%20passing-success)](#development)
7
7
  [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
8
 
9
9
  **Drive Autodesk Revit from Claude.** Query the model open on your desktop, edit
10
10
  it, and produce a full drawing set in plain language — levels and elements,
11
11
  sheets and schedules, views and PDF exports.
12
12
 
13
- **Windows · Revit 2025, 2026 or 2027.** The add-in ships precompiled — nothing
14
- to build, no .NET SDK. The Claude Desktop extension needs no Node.js either; the
15
- Claude Code route uses `npx`, so it wants Node 18+.
13
+ **Windows · Revit 2025, 2026 or 2027 · Node.js 18+.** The Revit add-in ships
14
+ precompiled and installs itself on first run nothing to build, no .NET SDK,
15
+ and nothing to copy by hand.
16
16
 
17
17
  ## Installation
18
18
 
@@ -93,12 +93,22 @@ arguments and needs no environment beyond the optional
93
93
 
94
94
  </details>
95
95
 
96
- ### 2. Install the Revit add-in
96
+ ### 2. Install the Revit add-in — automatic
97
97
 
98
- Ask Claude to **install the Revit bridge**. That runs `revit_install_bridge`,
99
- which copies the add-in and its `.addin` manifest into
100
- `%APPDATA%\Autodesk\Revit\Addins\<version>\` for every Revit it finds. Revit
101
- need not be running, and re-running is safe.
98
+ Nothing to do. The server installs the add-in itself the first time it starts:
99
+ it looks for `RevitMcpBridge.addin` in
100
+ `%APPDATA%\Autodesk\Revit\Addins\<version>\` and, when no Revit has it, copies
101
+ the bundled add-in and its manifest into place for every Revit it finds. That
102
+ runs in the background on Windows, so it never delays or breaks the server, and
103
+ once the add-in is there it does nothing at all.
104
+
105
+ **If it is turned off or fails**, ask Claude to **install the Revit bridge**.
106
+ That runs `revit_install_bridge` — the same installer, on demand. Revit need not
107
+ be running, and re-running is safe. Auto-install is off whenever
108
+ `REVIT_MCP_NO_AUTO_INSTALL` is set; see [Configuration](#configuration).
109
+
110
+ Either way the add-in is only on disk at this point. Revit does not load it
111
+ until it restarts, which is step 3.
102
112
 
103
113
  ### 3. Restart Revit and approve the add-in
104
114
 
@@ -408,6 +418,7 @@ Two habits worth keeping:
408
418
  | `REVIT_MCP_URL` | `http://localhost:48884/revit-mcp` | Bridge base URL. Change it for a second Revit instance. |
409
419
  | `REVIT_MCP_TIMEOUT` | `30000` | Per-request timeout, in milliseconds. |
410
420
  | `REVIT_MCP_BRIDGE_TIMEOUT_MS` | `30000` | Read by the add-in: how long a request waits for Revit's main thread. Clamped to 1–600 s. |
421
+ | `REVIT_MCP_NO_AUTO_INSTALL` | unset | Set it to `1` to stop the server installing the add-in on startup. `revit_install_bridge` still installs it on demand. Either way, Revit must be restarted before it loads. |
411
422
 
412
423
  ## Unattended operation
413
424
 
@@ -484,7 +495,7 @@ npm install
484
495
  npm test
485
496
  ```
486
497
 
487
- `npm test` is `node --test` over `tests/` — 507 tests. It touches no Revit and
498
+ `npm test` is `node --test` over `tests/` — 521 tests. It touches no Revit and
488
499
  opens no socket: the HTTP layer is stubbed and the tools are exercised through a
489
500
  real MCP client over an in-memory transport.
490
501
 
package/index.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { pathToFileURL } from "url";
6
+ import { autoInstallBridge } from "./lib/auto-install.js";
6
7
  import { createBridge } from "./lib/bridge.js";
7
8
  import { registerReadTools } from "./lib/tools/read.js";
8
9
  import { registerWriteTools } from "./lib/tools/write.js";
@@ -111,6 +112,11 @@ async function main() {
111
112
  const transport = new StdioServerTransport();
112
113
  await server.connect(transport);
113
114
 
115
+ // Never awaited: the transport is already up, and a slow or failing install
116
+ // must not delay the handshake or stop the server from serving tool calls.
117
+ // It is startup only, so it stays out of createRevitServer().
118
+ autoInstallBridge();
119
+
114
120
  process.stderr.write("Revit MCP server running on stdio\n");
115
121
  }
116
122
 
@@ -0,0 +1,83 @@
1
+ // Installing the bridge add-in without being asked.
2
+ //
3
+ // The add-in already ships inside this package, so a new user should not have
4
+ // to ask for it to be copied into place: on startup, when no Revit has the
5
+ // manifest, we run the very installer revit_install_bridge runs.
6
+ //
7
+ // Two rules shape everything here. Nothing is awaited and every failure is
8
+ // swallowed — the MCP handshake must never wait on this, and a machine with no
9
+ // Revit on it is not an error. And stdout belongs to the JSON-RPC channel, so
10
+ // every byte written from here goes to stderr instead.
11
+
12
+ import fs from "fs";
13
+ import path from "path";
14
+ import { runInstaller } from "./tools/install.js";
15
+
16
+ // Set it to anything to never auto-install; revit_install_bridge still works.
17
+ export const OPT_OUT_ENV = "REVIT_MCP_NO_AUTO_INSTALL";
18
+
19
+ // Where install.ps1 puts the manifest, and what it calls it. Revit 2024 and
20
+ // earlier load add-ins on .NET Framework 4.8 and the installer refuses them, so
21
+ // a manifest under one of those years is not this add-in installed.
22
+ const MANIFEST_FILE = "RevitMcpBridge.addin";
23
+ const MINIMUM_REVIT_YEAR = 2025;
24
+
25
+ export function isInstalled({ env = process.env, fsImpl = fs } = {}) {
26
+ if (!env.APPDATA) return false;
27
+
28
+ const root = path.join(env.APPDATA, "Autodesk", "Revit", "Addins");
29
+ let years;
30
+
31
+ try {
32
+ years = fsImpl.readdirSync(root);
33
+ } catch {
34
+ // No add-ins folder at all, so nothing is installed.
35
+ return false;
36
+ }
37
+
38
+ return years.some(
39
+ (year) =>
40
+ /^\d{4}$/.test(year) &&
41
+ Number(year) >= MINIMUM_REVIT_YEAR &&
42
+ fsImpl.existsSync(path.join(root, year, MANIFEST_FILE)),
43
+ );
44
+ }
45
+
46
+ async function install(options, write) {
47
+ try {
48
+ const result = await runInstaller({}, options);
49
+
50
+ if (result.ok) {
51
+ write(
52
+ "revit-mcp: installed the Revit bridge add-in. RESTART REVIT to load it — Revit only scans the Addins folder at startup.\n",
53
+ );
54
+ return;
55
+ }
56
+
57
+ write(
58
+ `revit-mcp: could not install the Revit bridge add-in automatically. ${result.explanation || result.message} Run revit_install_bridge to see the full result, or set ${OPT_OUT_ENV}=1 to stop trying.\n`,
59
+ );
60
+ } catch (error) {
61
+ write(
62
+ `revit-mcp: could not install the Revit bridge add-in automatically: ${error.message} Set ${OPT_OUT_ENV}=1 to stop trying.\n`,
63
+ );
64
+ }
65
+ }
66
+
67
+ // Returns as soon as it has decided what to do. The install itself is
68
+ // deliberately left running: its promise is never handed back, so no caller can
69
+ // accidentally wait on it, and nothing it does can fail the server's startup.
70
+ export function autoInstallBridge(options = {}) {
71
+ const {
72
+ env = process.env,
73
+ platform = process.platform,
74
+ write = (line) => process.stderr.write(line),
75
+ } = options;
76
+
77
+ if (platform !== "win32") return "not-windows";
78
+ if (env[OPT_OUT_ENV]) return "opted-out";
79
+ if (isInstalled(options)) return "already-installed";
80
+
81
+ install(options, write);
82
+ return "started";
83
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rui.branco/revit-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server for Autodesk Revit: read and edit the open model from an MCP client, via a bundled C# bridge add-in that runs inside Revit",
5
5
  "keywords": [
6
6
  "revit",