diffler-mcp 0.6.6 → 0.6.8
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 +11 -6
- package/index.js +29 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,8 +31,9 @@ Or in a checked-in `.mcp.json`:
|
|
|
31
31
|
}
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
`.diffler/mcp.json`. No diffler running ⇒
|
|
34
|
+
Start Claude anywhere inside the repo and the proxy auto-discovers the port
|
|
35
|
+
from `.diffler/mcp.json`. No diffler running ⇒ every tool call reports which
|
|
36
|
+
directory it searched.
|
|
36
37
|
|
|
37
38
|
## Configuration
|
|
38
39
|
|
|
@@ -40,21 +41,25 @@ Resolution order (first match wins):
|
|
|
40
41
|
|
|
41
42
|
1. `--url <url>` / `DIFFLER_MCP_URL` — full endpoint, e.g. `http://127.0.0.1:8417/mcp`
|
|
42
43
|
2. `--port <n>` / `DIFFLER_MCP_PORT` and `--host <h>` / `DIFFLER_MCP_HOST`
|
|
43
|
-
3. the live port in
|
|
44
|
-
|
|
44
|
+
3. the live port in the nearest `.diffler/mcp.json`, searching the start
|
|
45
|
+
directory (`--repo <path>`, default: cwd) and then each parent
|
|
46
|
+
|
|
47
|
+
Discovery covers the normal case, so nothing needs configuring:
|
|
45
48
|
|
|
46
49
|
```json
|
|
47
50
|
{
|
|
48
51
|
"mcpServers": {
|
|
49
52
|
"diffler": {
|
|
50
53
|
"command": "npx",
|
|
51
|
-
"args": ["-y", "diffler-mcp"
|
|
52
|
-
"env": { "DIFFLER_MCP_HOST": "127.0.0.1" }
|
|
54
|
+
"args": ["-y", "diffler-mcp"]
|
|
53
55
|
}
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
```
|
|
57
59
|
|
|
60
|
+
Reach for `--port`, `--host` or `--repo` when diffler runs somewhere the walk-up
|
|
61
|
+
cannot see, such as another machine over a tunnel.
|
|
62
|
+
|
|
58
63
|
## Prefer HTTP directly?
|
|
59
64
|
|
|
60
65
|
Claude Code speaks HTTP natively, so you can skip this proxy entirely:
|
package/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// (re)connecting so it survives diffler quitting and restarting on a new port.
|
|
4
4
|
|
|
5
5
|
import { readFileSync } from "node:fs";
|
|
6
|
-
import { join } from "node:path";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
7
|
|
|
8
8
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9
9
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
16
16
|
|
|
17
17
|
const DEFAULT_HOST = "127.0.0.1";
|
|
18
|
-
const
|
|
18
|
+
const ENDPOINT_FILE = join(".diffler", "mcp.json");
|
|
19
19
|
|
|
20
20
|
function parseArgs(argv) {
|
|
21
21
|
const opts = {};
|
|
@@ -41,12 +41,27 @@ function parseArgs(argv) {
|
|
|
41
41
|
return opts;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
// Each diffler publishes its live port under its own repo root, so the walk-up
|
|
45
|
+
// finds the instance owning the directory the editor launched from. Falling
|
|
46
|
+
// back to a fixed port would instead attach to whichever repo's diffler happens
|
|
47
|
+
// to hold it and serve that repo's review.
|
|
48
|
+
function discoverPort(from) {
|
|
49
|
+
const start = resolve(from);
|
|
50
|
+
let dir = start;
|
|
51
|
+
for (;;) {
|
|
52
|
+
try {
|
|
53
|
+
const { port } = JSON.parse(readFileSync(join(dir, ENDPOINT_FILE), "utf8"));
|
|
54
|
+
if (typeof port === "number") {
|
|
55
|
+
return port;
|
|
56
|
+
}
|
|
57
|
+
} catch {
|
|
58
|
+
// unreadable or malformed reads like absent: keep walking up
|
|
59
|
+
}
|
|
60
|
+
const parent = dirname(dir);
|
|
61
|
+
if (parent === dir) {
|
|
62
|
+
throw new Error(`no diffler is running in ${start} or any parent (no ${ENDPOINT_FILE})`);
|
|
63
|
+
}
|
|
64
|
+
dir = parent;
|
|
50
65
|
}
|
|
51
66
|
}
|
|
52
67
|
|
|
@@ -57,8 +72,7 @@ function resolveUrl(opts) {
|
|
|
57
72
|
return explicit;
|
|
58
73
|
}
|
|
59
74
|
const host = opts.host || env.DIFFLER_MCP_HOST || DEFAULT_HOST;
|
|
60
|
-
const
|
|
61
|
-
const port = opts.port || env.DIFFLER_MCP_PORT || discoverPort(repo) || DEFAULT_PORT;
|
|
75
|
+
const port = opts.port || env.DIFFLER_MCP_PORT || discoverPort(opts.repo || process.cwd());
|
|
62
76
|
return `http://${host}:${port}/mcp`;
|
|
63
77
|
}
|
|
64
78
|
|
|
@@ -134,7 +148,11 @@ async function main() {
|
|
|
134
148
|
});
|
|
135
149
|
|
|
136
150
|
await server.connect(new StdioServerTransport());
|
|
137
|
-
|
|
151
|
+
// stdout is the MCP channel, so the startup diagnosis goes to stderr, where
|
|
152
|
+
// clients surface it; the proxy stays up and reconnects when diffler starts
|
|
153
|
+
void ensureUpstream().catch((err) => {
|
|
154
|
+
process.stderr.write(`diffler-mcp: ${err.message ?? err}\n`);
|
|
155
|
+
});
|
|
138
156
|
}
|
|
139
157
|
|
|
140
158
|
main().catch((err) => {
|