@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.
- package/README.md +63 -0
- package/launcher.mjs +83 -0
- 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
|
+
}
|