@rui.branco/revit-mcp 1.0.3 → 1.0.5

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,31 +3,34 @@
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
 
19
19
  ### 1. Register the server
20
20
 
21
- Same plugin either way. Type both lines into the chat box, one after the other.
21
+ Same plugin either way, but the two apps add it differently.
22
22
 
23
- **Claude Desktop** in any chat:
23
+ > It has to be the **Windows machine Revit runs on**. The server reaches Revit
24
+ > through a listener bound to `127.0.0.1`, so a cloud session or another
25
+ > computer cannot see it.
24
26
 
25
- ```
26
- /plugin marketplace add rui-branco/revit-mcp
27
- /plugin install revit@revit-tools
28
- ```
27
+ **Claude Desktop** — through Settings, not the chat box:
29
28
 
30
- **Claude Code** in the CLI:
29
+ 1. **Settings Plugins Add ▾ → Add marketplace → Add from a repository**
30
+ 2. Enter `rui-branco/revit-mcp`
31
+ 3. Install **revit** from the marketplace that appears
32
+
33
+ **Claude Code** — slash commands in the CLI:
31
34
 
32
35
  ```
33
36
  /plugin marketplace add rui-branco/revit-mcp
@@ -45,8 +48,8 @@ claude plugin install revit@revit-tools
45
48
  </details>
46
49
 
47
50
  That is the whole step. The plugin updates itself from this repo, so there is
48
- nothing to re-download when a new version ships; `/plugin update` pulls it
49
- early if you do not want to wait.
51
+ nothing to re-download when a new version ships; in Claude Code,
52
+ `/plugin update` pulls it early if you do not want to wait.
50
53
 
51
54
  <details>
52
55
  <summary><b>Other ways to install</b></summary>
@@ -93,12 +96,22 @@ arguments and needs no environment beyond the optional
93
96
 
94
97
  </details>
95
98
 
96
- ### 2. Install the Revit add-in
99
+ ### 2. Install the Revit add-in — automatic
100
+
101
+ Nothing to do. The server installs the add-in itself the first time it starts:
102
+ it looks for `RevitMcpBridge.addin` in
103
+ `%APPDATA%\Autodesk\Revit\Addins\<version>\` and, when no Revit has it, copies
104
+ the bundled add-in and its manifest into place for every Revit it finds. That
105
+ runs in the background on Windows, so it never delays or breaks the server, and
106
+ once the add-in is there it does nothing at all.
107
+
108
+ **If it is turned off or fails**, ask Claude to **install the Revit bridge**.
109
+ That runs `revit_install_bridge` — the same installer, on demand. Revit need not
110
+ be running, and re-running is safe. Auto-install is off whenever
111
+ `REVIT_MCP_NO_AUTO_INSTALL` is set; see [Configuration](#configuration).
97
112
 
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.
113
+ Either way the add-in is only on disk at this point. Revit does not load it
114
+ until it restarts, which is step 3.
102
115
 
103
116
  ### 3. Restart Revit and approve the add-in
104
117
 
@@ -408,6 +421,7 @@ Two habits worth keeping:
408
421
  | `REVIT_MCP_URL` | `http://localhost:48884/revit-mcp` | Bridge base URL. Change it for a second Revit instance. |
409
422
  | `REVIT_MCP_TIMEOUT` | `30000` | Per-request timeout, in milliseconds. |
410
423
  | `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. |
424
+ | `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
425
 
412
426
  ## Unattended operation
413
427
 
@@ -484,7 +498,7 @@ npm install
484
498
  npm test
485
499
  ```
486
500
 
487
- `npm test` is `node --test` over `tests/` — 507 tests. It touches no Revit and
501
+ `npm test` is `node --test` over `tests/` — 521 tests. It touches no Revit and
488
502
  opens no socket: the HTTP layer is stubbed and the tools are exercised through a
489
503
  real MCP client over an in-memory transport.
490
504
 
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.5",
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",