@diffui.mcp/install 0.1.0

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.
Files changed (3) hide show
  1. package/README.md +63 -0
  2. package/launcher.mjs +83 -0
  3. package/package.json +20 -0
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @diffui.mcp/install
2
+
3
+ Thin Node launcher for the diffui MCP server. Cursor (and other MCP hosts) run:
4
+
5
+ ```json
6
+ {
7
+ "type": "stdio",
8
+ "command": "npx",
9
+ "args": ["-y", "@diffui.mcp/install@latest"],
10
+ "env": {
11
+ "DIFFUI_API_BASE": "https://diffui.ai",
12
+ "DIFFUI_API_KEY": "dui_..."
13
+ }
14
+ }
15
+ ```
16
+
17
+ On first start, the launcher downloads the platform `diffui-mcp` binary from
18
+ `{DIFFUI_API_BASE}/mcp/` into `~/.diffui/bin/diffui-mcp`, then execs it with
19
+ inherited stdio. Credentials can also come from the MCP `authenticate` tool
20
+ (`~/.diffui/credentials`).
21
+
22
+ ## Publish to npm
23
+
24
+ Prerequisites:
25
+
26
+ 1. MCP binaries served at `https://diffui.ai/mcp/*` (run `./scripts/build-mcp.sh`
27
+ and deploy `frontend/mcp/` with the app).
28
+ 2. npm account in the [@diffui.mcp](https://www.npmjs.com/org/diffui.mcp) org.
29
+
30
+ ```bash
31
+ cd packages/mcp-install
32
+ npm login
33
+ npm publish --access public
34
+ ```
35
+
36
+ Scoped packages must use `--access public` unless the org is on a private plan.
37
+
38
+ Bump version for updates:
39
+
40
+ ```bash
41
+ npm version patch
42
+ npm publish --access public
43
+ ```
44
+
45
+ ## Local test before publish
46
+
47
+ ```bash
48
+ cd packages/mcp-install
49
+ chmod +x launcher.mjs
50
+ DIFFUI_API_BASE=http://localhost:3040 DIFFUI_API_KEY=dui_... node launcher.mjs
51
+ ```
52
+
53
+ Or link into a global MCP config:
54
+
55
+ ```bash
56
+ npm link
57
+ # mcp.json: "command": "diffui-mcp-install", "args": []
58
+ ```
59
+
60
+ ## Cursor deeplink
61
+
62
+ The diffui app builds install links with `command: npx` and
63
+ `args: ["-y", "@diffui.mcp/install@latest"]` plus env for API base and key.
package/launcher.mjs ADDED
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * diffui MCP launcher for Cursor / Claude / npx.
4
+ * Ensures ~/.diffui/bin/diffui-mcp exists, then execs it with inherited stdio.
5
+ *
6
+ * Env (from Cursor mcp.json or shell):
7
+ * DIFFUI_API_BASE — API origin (default https://diffui.ai)
8
+ * DIFFUI_API_KEY — optional; authenticate tool can store ~/.diffui/credentials
9
+ */
10
+ import { spawn, spawnSync } from "node:child_process";
11
+ import { chmodSync, createWriteStream, existsSync, mkdirSync } from "node:fs";
12
+ import { arch, homedir, platform } from "node:os";
13
+ import { dirname, join } from "node:path";
14
+ import { pipeline } from "node:stream/promises";
15
+ import { get as httpsGet } from "node:https";
16
+ import { get as httpGet } from "node:http";
17
+
18
+ const base = String(process.env.DIFFUI_API_BASE || "https://diffui.ai").replace(/\/+$/, "");
19
+ const dest = join(homedir(), ".diffui", "bin", "diffui-mcp");
20
+
21
+ function binaryName() {
22
+ if (platform() === "darwin") {
23
+ return arch() === "arm64" ? "diffui-mcp-darwin-arm64" : "diffui-mcp-darwin-x64";
24
+ }
25
+ if (platform() === "linux") {
26
+ return "diffui-mcp-linux-x64";
27
+ }
28
+ if (platform() === "win32") {
29
+ return "diffui-mcp-windows-x64.exe";
30
+ }
31
+ throw new Error(`diffui-mcp: unsupported platform ${platform()}-${arch()}`);
32
+ }
33
+
34
+ async function download(url, path) {
35
+ const getter = url.startsWith("https:") ? httpsGet : httpGet;
36
+ await new Promise((resolve, reject) => {
37
+ getter(url, (res) => {
38
+ if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
39
+ download(res.headers.location, path).then(resolve, reject);
40
+ return;
41
+ }
42
+ if (res.statusCode !== 200) {
43
+ reject(new Error(`GET ${url} failed: HTTP ${res.statusCode}`));
44
+ res.resume();
45
+ return;
46
+ }
47
+ const type = String(res.headers["content-type"] || "").toLowerCase();
48
+ if (type.includes("text/html")) {
49
+ reject(new Error(`GET ${url} returned HTML — MCP binary missing on ${base}`));
50
+ res.resume();
51
+ return;
52
+ }
53
+ mkdirSync(dirname(path), { recursive: true });
54
+ pipeline(res, createWriteStream(path)).then(resolve, reject);
55
+ }).on("error", reject);
56
+ });
57
+ }
58
+
59
+ function clearQuarantine(path) {
60
+ if (platform() !== "darwin") return;
61
+ spawnSync("xattr", ["-dr", "com.apple.quarantine", path], { stdio: "ignore" });
62
+ }
63
+
64
+ async function ensureBinary() {
65
+ if (existsSync(dest)) return dest;
66
+ const name = binaryName();
67
+ const url = `${base}/mcp/${name}`;
68
+ process.stderr.write(`diffui-mcp: downloading ${name} from ${base}/mcp/\n`);
69
+ await download(url, dest);
70
+ chmodSync(dest, 0o755);
71
+ clearQuarantine(dest);
72
+ return dest;
73
+ }
74
+
75
+ const bin = await ensureBinary();
76
+ const child = spawn(bin, [], {
77
+ stdio: "inherit",
78
+ env: process.env,
79
+ });
80
+ child.on("exit", (code, signal) => {
81
+ if (signal) process.kill(process.pid, signal);
82
+ process.exit(code ?? 1);
83
+ });
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@diffui.mcp/install",
3
+ "version": "0.1.0",
4
+ "description": "Launcher for the diffui MCP server (stdio). Used by Cursor Add to Cursor.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "diffui-mcp-install": "launcher.mjs"
9
+ },
10
+ "files": [
11
+ "launcher.mjs",
12
+ "README.md"
13
+ ],
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ }
20
+ }