pi-forge 0.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +48 -4
- package/bin/pi-forge.mjs +37 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js +34 -0
- package/dist/client/assets/CodeMirrorEditor-BqaaP1EE.js.map +1 -0
- package/dist/client/assets/index-B-529kgJ.css +32 -0
- package/dist/client/assets/index-BzKzxXFs.js +392 -0
- package/dist/client/assets/index-BzKzxXFs.js.map +1 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js +3 -0
- package/dist/client/assets/workbox-window.prod.es5-BBnX5xw4.js.map +1 -0
- package/dist/client/icons/icon-192.png +0 -0
- package/dist/client/icons/icon-512.png +0 -0
- package/dist/client/icons/icon-maskable-512.png +0 -0
- package/dist/client/icons/icon.svg +9 -0
- package/dist/client/index.html +24 -0
- package/dist/client/manifest.webmanifest +1 -0
- package/dist/client/offline.html +142 -0
- package/dist/client/sw.js +3 -0
- package/dist/client/sw.js.map +1 -0
- package/dist/client/workbox-6d7155ed.js +3 -0
- package/dist/client/workbox-6d7155ed.js.map +1 -0
- package/dist/server/agent-resource-loader.js +126 -0
- package/dist/server/agent-resource-loader.js.map +1 -0
- package/dist/server/attachment-converters.js +96 -0
- package/dist/server/attachment-converters.js.map +1 -0
- package/dist/server/auth.js +209 -0
- package/dist/server/auth.js.map +1 -0
- package/dist/server/compaction-history.js +106 -0
- package/dist/server/compaction-history.js.map +1 -0
- package/dist/server/concurrency.js +49 -0
- package/dist/server/concurrency.js.map +1 -0
- package/dist/server/config-export.js +220 -0
- package/dist/server/config-export.js.map +1 -0
- package/dist/server/config-manager.js +528 -0
- package/dist/server/config-manager.js.map +1 -0
- package/dist/server/config.js +326 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/conversion-worker.mjs +90 -0
- package/dist/server/diagnostics.js +137 -0
- package/dist/server/diagnostics.js.map +1 -0
- package/dist/server/extensions-discovery.js +147 -0
- package/dist/server/extensions-discovery.js.map +1 -0
- package/dist/server/file-manager.js +734 -0
- package/dist/server/file-manager.js.map +1 -0
- package/dist/server/file-references.js +215 -0
- package/dist/server/file-references.js.map +1 -0
- package/dist/server/file-searcher.js +385 -0
- package/dist/server/file-searcher.js.map +1 -0
- package/dist/server/git-runner.js +684 -0
- package/dist/server/git-runner.js.map +1 -0
- package/dist/server/index.js +468 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp/config.js +133 -0
- package/dist/server/mcp/config.js.map +1 -0
- package/dist/server/mcp/manager.js +351 -0
- package/dist/server/mcp/manager.js.map +1 -0
- package/dist/server/mcp/tool-bridge.js +173 -0
- package/dist/server/mcp/tool-bridge.js.map +1 -0
- package/dist/server/project-manager.js +301 -0
- package/dist/server/project-manager.js.map +1 -0
- package/dist/server/pty-manager.js +354 -0
- package/dist/server/pty-manager.js.map +1 -0
- package/dist/server/routes/_schemas.js +73 -0
- package/dist/server/routes/_schemas.js.map +1 -0
- package/dist/server/routes/auth.js +164 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/config.js +1163 -0
- package/dist/server/routes/config.js.map +1 -0
- package/dist/server/routes/control.js +464 -0
- package/dist/server/routes/control.js.map +1 -0
- package/dist/server/routes/exec.js +217 -0
- package/dist/server/routes/exec.js.map +1 -0
- package/dist/server/routes/files.js +847 -0
- package/dist/server/routes/files.js.map +1 -0
- package/dist/server/routes/git.js +837 -0
- package/dist/server/routes/git.js.map +1 -0
- package/dist/server/routes/health.js +97 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/mcp.js +300 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/projects.js +259 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/prompt.js +496 -0
- package/dist/server/routes/prompt.js.map +1 -0
- package/dist/server/routes/sessions.js +783 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/stream.js +69 -0
- package/dist/server/routes/stream.js.map +1 -0
- package/dist/server/routes/terminal.js +335 -0
- package/dist/server/routes/terminal.js.map +1 -0
- package/dist/server/session-registry.js +1197 -0
- package/dist/server/session-registry.js.map +1 -0
- package/dist/server/skill-overrides.js +151 -0
- package/dist/server/skill-overrides.js.map +1 -0
- package/dist/server/skills-export.js +257 -0
- package/dist/server/skills-export.js.map +1 -0
- package/dist/server/sse-bridge.js +220 -0
- package/dist/server/sse-bridge.js.map +1 -0
- package/dist/server/tool-overrides.js +277 -0
- package/dist/server/tool-overrides.js.map +1 -0
- package/dist/server/turn-diff-builder.js +280 -0
- package/dist/server/turn-diff-builder.js.map +1 -0
- package/package.json +53 -12
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { chmodSync } from "node:fs";
|
|
2
|
+
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { config } from "../config.js";
|
|
6
|
+
const SECRET_PLACEHOLDER = "***REDACTED***";
|
|
7
|
+
async function ensureDir() {
|
|
8
|
+
await mkdir(dirname(config.mcpConfigFile), { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
async function atomicWriteJson(data) {
|
|
11
|
+
await ensureDir();
|
|
12
|
+
const path = config.mcpConfigFile;
|
|
13
|
+
const tmp = `${path}.${randomUUID()}.tmp`;
|
|
14
|
+
await writeFile(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
|
|
15
|
+
// Some kernels honour the umask on the initial create; reapply 0600
|
|
16
|
+
// explicitly so the persisted file always matches what we promised
|
|
17
|
+
// in the docstring.
|
|
18
|
+
try {
|
|
19
|
+
chmodSync(tmp, 0o600);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Best-effort — if chmod fails (e.g. read-only fs in tests), the
|
|
23
|
+
// umask-applied perms are still likely fine.
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
await rename(tmp, path);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
await unlink(tmp).catch(() => undefined);
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function readMcpJson() {
|
|
34
|
+
try {
|
|
35
|
+
const raw = await readFile(config.mcpConfigFile, "utf8");
|
|
36
|
+
if (raw.trim().length === 0)
|
|
37
|
+
return { servers: {} };
|
|
38
|
+
const parsed = JSON.parse(raw);
|
|
39
|
+
if (typeof parsed !== "object" || parsed === null || !("servers" in parsed)) {
|
|
40
|
+
return { servers: {} };
|
|
41
|
+
}
|
|
42
|
+
const servers = parsed.servers;
|
|
43
|
+
const disabled = parsed.disabled === true;
|
|
44
|
+
if (typeof servers !== "object" || servers === null) {
|
|
45
|
+
return { disabled, servers: {} };
|
|
46
|
+
}
|
|
47
|
+
return { disabled, servers: servers };
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (err.code === "ENOENT")
|
|
51
|
+
return { servers: {} };
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Same as readMcpJson but with every header VALUE replaced with the
|
|
57
|
+
* redaction sentinel. Used by the read-path API route so an inline
|
|
58
|
+
* bearer token is never echoed back to the browser.
|
|
59
|
+
*/
|
|
60
|
+
export async function readMcpJsonRedacted() {
|
|
61
|
+
const raw = await readMcpJson();
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const [name, server] of Object.entries(raw.servers)) {
|
|
64
|
+
const cleaned = { url: server.url };
|
|
65
|
+
if (server.transport !== undefined)
|
|
66
|
+
cleaned.transport = server.transport;
|
|
67
|
+
if (server.enabled !== undefined)
|
|
68
|
+
cleaned.enabled = server.enabled;
|
|
69
|
+
if (server.headers !== undefined) {
|
|
70
|
+
cleaned.headers = {};
|
|
71
|
+
for (const k of Object.keys(server.headers)) {
|
|
72
|
+
cleaned.headers[k] = SECRET_PLACEHOLDER;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
out[name] = cleaned;
|
|
76
|
+
}
|
|
77
|
+
return { disabled: raw.disabled === true, servers: out };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Write `mcp.json`, merging the secret-placeholder for header values
|
|
81
|
+
* back to the prior persisted value. Mirrors the round-trip safety
|
|
82
|
+
* config-manager.writeModelsJson uses for `apiKey` — without this, an
|
|
83
|
+
* "edit and save" round-trip from the UI would write the literal
|
|
84
|
+
* sentinel back to disk and lock the user out of their MCP server.
|
|
85
|
+
*/
|
|
86
|
+
export async function writeMcpJson(next) {
|
|
87
|
+
const existing = await readMcpJson().catch(() => ({ servers: {} }));
|
|
88
|
+
const safe = { servers: {} };
|
|
89
|
+
if (next.disabled === true)
|
|
90
|
+
safe.disabled = true;
|
|
91
|
+
for (const [name, server] of Object.entries(next.servers ?? {})) {
|
|
92
|
+
const merged = { url: server.url };
|
|
93
|
+
if (server.transport !== undefined)
|
|
94
|
+
merged.transport = server.transport;
|
|
95
|
+
if (server.enabled !== undefined)
|
|
96
|
+
merged.enabled = server.enabled;
|
|
97
|
+
if (server.headers !== undefined) {
|
|
98
|
+
merged.headers = {};
|
|
99
|
+
const prior = existing.servers[name]?.headers ?? {};
|
|
100
|
+
for (const [hk, hv] of Object.entries(server.headers)) {
|
|
101
|
+
// Sentinel ↦ keep prior value (or drop the key if no prior).
|
|
102
|
+
if (hv === SECRET_PLACEHOLDER) {
|
|
103
|
+
if (prior[hk] !== undefined)
|
|
104
|
+
merged.headers[hk] = prior[hk];
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
merged.headers[hk] = hv;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
safe.servers[name] = merged;
|
|
112
|
+
}
|
|
113
|
+
await atomicWriteJson(safe);
|
|
114
|
+
}
|
|
115
|
+
export async function upsertMcpServer(name, server) {
|
|
116
|
+
const cur = await readMcpJson();
|
|
117
|
+
cur.servers[name] = server;
|
|
118
|
+
await writeMcpJson(cur);
|
|
119
|
+
}
|
|
120
|
+
export async function setMcpDisabled(disabled) {
|
|
121
|
+
const cur = await readMcpJson();
|
|
122
|
+
cur.disabled = disabled;
|
|
123
|
+
await writeMcpJson(cur);
|
|
124
|
+
}
|
|
125
|
+
export async function deleteMcpServer(name) {
|
|
126
|
+
const cur = await readMcpJson();
|
|
127
|
+
if (cur.servers[name] === undefined)
|
|
128
|
+
return false;
|
|
129
|
+
delete cur.servers[name];
|
|
130
|
+
await writeMcpJson(cur);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/mcp/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAkDtC,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAE5C,KAAK,UAAU,SAAS;IACtB,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,IAAa;IAC1C,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,IAAI,GAAG,MAAM,CAAC,aAAa,CAAC;IAClC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,UAAU,EAAE,MAAM,CAAC;IAC1C,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,oEAAoE;IACpE,mEAAmE;IACnE,oBAAoB;IACpB,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;QACjE,6CAA6C;IAC/C,CAAC;IACD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACzD,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,EAAE,CAAC;YAC5E,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,OAAO,GAAI,MAAgC,CAAC,OAAO,CAAC;QAC1D,MAAM,QAAQ,GAAI,MAAiC,CAAC,QAAQ,KAAK,IAAI,CAAC;QACtE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACpD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACnC,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAA0C,EAAE,CAAC;IAC3E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QAC7E,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,MAAM,GAAG,GAAoC,EAAE,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,OAAO,GAAoB,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;QACrD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACzE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QACnE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC;YACrB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,kBAAkB,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,KAAK,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAa;IAC9C,MAAM,QAAQ,GAAY,MAAM,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAY,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACtC,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;QAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,MAAM,GAAoB,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC;QACpD,IAAI,MAAM,CAAC,SAAS,KAAK,SAAS;YAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACxE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS;YAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAClE,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;YACpD,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBACtD,6DAA6D;gBAC7D,IAAI,EAAE,KAAK,kBAAkB,EAAE,CAAC;oBAC9B,IAAI,KAAK,CAAC,EAAE,CAAC,KAAK,SAAS;wBAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC9D,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;IAC9B,CAAC;IACD,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,MAAuB;IACzE,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;IAC3B,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAiB;IACpD,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACxB,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
6
|
+
import { readMcpJson } from "./config.js";
|
|
7
|
+
import { bridgeMcpTool } from "./tool-bridge.js";
|
|
8
|
+
const PROJECT_MCP_FILE = ".mcp.json";
|
|
9
|
+
function entryKey(scope, name) {
|
|
10
|
+
return scope === "global" ? `global::${name}` : `project:${scope.project}::${name}`;
|
|
11
|
+
}
|
|
12
|
+
const pool = new Map();
|
|
13
|
+
/** Tracks projects we've loaded once already so repeat session
|
|
14
|
+
* creates in the same project don't redundantly re-read the file. */
|
|
15
|
+
const loadedProjects = new Set();
|
|
16
|
+
/**
|
|
17
|
+
* Mirrored from `mcp.json#disabled` on every load so the hot path
|
|
18
|
+
* (`customToolsForProject`, called every `createAgentSession`) doesn't
|
|
19
|
+
* have to do file I/O.
|
|
20
|
+
*/
|
|
21
|
+
let globallyEnabled = true;
|
|
22
|
+
export function isGloballyEnabled() {
|
|
23
|
+
return globallyEnabled;
|
|
24
|
+
}
|
|
25
|
+
/* ----------------------------- public API ----------------------------- */
|
|
26
|
+
export async function loadGlobal() {
|
|
27
|
+
const cfg = await readMcpJson();
|
|
28
|
+
globallyEnabled = cfg.disabled !== true;
|
|
29
|
+
await syncScope("global", cfg.servers);
|
|
30
|
+
}
|
|
31
|
+
export async function loadProject(projectId, projectPath) {
|
|
32
|
+
const cfg = await readProjectMcpJson(projectPath);
|
|
33
|
+
await syncScope({ project: projectId }, cfg);
|
|
34
|
+
loadedProjects.add(projectId);
|
|
35
|
+
}
|
|
36
|
+
export async function ensureProjectLoaded(projectId, projectPath) {
|
|
37
|
+
if (loadedProjects.has(projectId))
|
|
38
|
+
return;
|
|
39
|
+
await loadProject(projectId, projectPath);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Re-read the global config file and sync the pool. Called on every
|
|
43
|
+
* write through `routes/mcp.ts` so the UI's "save" reflects in
|
|
44
|
+
* connection state immediately.
|
|
45
|
+
*/
|
|
46
|
+
export async function reloadGlobal() {
|
|
47
|
+
loadedProjects.clear(); // project files may reference globals too
|
|
48
|
+
await loadGlobal();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Build the `customTools` list for a session in `projectId`. Returns
|
|
52
|
+
* the union of every connected, enabled server's bridged tools across
|
|
53
|
+
* the global scope and the project scope. On name collision the
|
|
54
|
+
* project entry wins (the session sees the project's bridged tool,
|
|
55
|
+
* not the global one).
|
|
56
|
+
*/
|
|
57
|
+
export function customToolsForProject(projectId) {
|
|
58
|
+
// Server-name override: when the project has a server with the
|
|
59
|
+
// same NAME as a global server, the project entry replaces the
|
|
60
|
+
// global one entirely (not just on tool-name collision). Reason:
|
|
61
|
+
// operators expect a project's `.mcp.json` to fully shadow a same-
|
|
62
|
+
// named global entry — different auth tokens, different `enabled`
|
|
63
|
+
// flags, and (if URLs match) one TCP connection rather than two.
|
|
64
|
+
const projectServerNames = new Set();
|
|
65
|
+
for (const e of pool.values()) {
|
|
66
|
+
if (e.scope === "global")
|
|
67
|
+
continue;
|
|
68
|
+
if (e.scope.project !== projectId)
|
|
69
|
+
continue;
|
|
70
|
+
projectServerNames.add(e.name);
|
|
71
|
+
}
|
|
72
|
+
const seenToolNames = new Set();
|
|
73
|
+
const out = [];
|
|
74
|
+
// Project entries first so their tools land in `seen` and any
|
|
75
|
+
// remaining tool-name collisions across other servers go to the
|
|
76
|
+
// project's version.
|
|
77
|
+
for (const e of pool.values()) {
|
|
78
|
+
if (e.scope === "global")
|
|
79
|
+
continue;
|
|
80
|
+
if (e.scope.project !== projectId)
|
|
81
|
+
continue;
|
|
82
|
+
if (e.state !== "connected")
|
|
83
|
+
continue;
|
|
84
|
+
for (const t of e.bridged) {
|
|
85
|
+
if (seenToolNames.has(t.name))
|
|
86
|
+
continue;
|
|
87
|
+
seenToolNames.add(t.name);
|
|
88
|
+
out.push(t);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const e of pool.values()) {
|
|
92
|
+
if (e.scope !== "global")
|
|
93
|
+
continue;
|
|
94
|
+
// Server-name shadowed by a project entry — skip the global
|
|
95
|
+
// entry entirely.
|
|
96
|
+
if (projectServerNames.has(e.name))
|
|
97
|
+
continue;
|
|
98
|
+
if (e.state !== "connected")
|
|
99
|
+
continue;
|
|
100
|
+
for (const t of e.bridged) {
|
|
101
|
+
if (seenToolNames.has(t.name))
|
|
102
|
+
continue;
|
|
103
|
+
seenToolNames.add(t.name);
|
|
104
|
+
out.push(t);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
export function getStatus(opts) {
|
|
110
|
+
const out = [];
|
|
111
|
+
for (const e of pool.values()) {
|
|
112
|
+
if (e.scope !== "global") {
|
|
113
|
+
if (opts?.projectId !== undefined && e.scope.project !== opts.projectId)
|
|
114
|
+
continue;
|
|
115
|
+
if (opts?.projectId === undefined)
|
|
116
|
+
continue; // omit project entries from global view
|
|
117
|
+
}
|
|
118
|
+
// Pair each raw `entry.tools[i]` with the bridged tool sitting
|
|
119
|
+
// at the same index — `connectEntry` builds them in lockstep, so
|
|
120
|
+
// index alignment is the load-bearing invariant. Surfacing both
|
|
121
|
+
// names lets the UI key toggles by the bridged name (which pi
|
|
122
|
+
// sees) while still showing the operator the human-friendlier
|
|
123
|
+
// unprefixed form.
|
|
124
|
+
const tools = e.tools.map((t, i) => ({
|
|
125
|
+
name: e.bridged[i]?.name ?? `${e.name}__${t.name}`,
|
|
126
|
+
shortName: t.name,
|
|
127
|
+
description: t.description,
|
|
128
|
+
}));
|
|
129
|
+
const status = {
|
|
130
|
+
scope: e.scope === "global" ? "global" : "project",
|
|
131
|
+
name: e.name,
|
|
132
|
+
url: e.config.url,
|
|
133
|
+
enabled: e.config.enabled !== false,
|
|
134
|
+
state: e.state,
|
|
135
|
+
toolCount: e.tools.length,
|
|
136
|
+
tools,
|
|
137
|
+
};
|
|
138
|
+
if (e.scope !== "global")
|
|
139
|
+
status.projectId = e.scope.project;
|
|
140
|
+
if (e.lastError !== undefined)
|
|
141
|
+
status.lastError = e.lastError;
|
|
142
|
+
if (e.config.transport !== undefined)
|
|
143
|
+
status.transport = e.config.transport;
|
|
144
|
+
out.push(status);
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Force a connection attempt (or reconnection) for the named server.
|
|
150
|
+
* Returns the resulting status entry. Useful for the "Probe" button
|
|
151
|
+
* in Settings.
|
|
152
|
+
*/
|
|
153
|
+
export async function probe(scope, name) {
|
|
154
|
+
const entry = pool.get(entryKey(scope, name));
|
|
155
|
+
if (entry === undefined)
|
|
156
|
+
return undefined;
|
|
157
|
+
await disconnectEntry(entry);
|
|
158
|
+
await connectEntry(entry);
|
|
159
|
+
const opts = scope === "global" ? undefined : { projectId: scope.project };
|
|
160
|
+
return getStatus(opts).find((s) => s.name === name && s.scope === (scope === "global" ? "global" : "project"));
|
|
161
|
+
}
|
|
162
|
+
export async function disposeAll() {
|
|
163
|
+
await Promise.allSettled(Array.from(pool.values()).map((entry) => disconnectEntry(entry)));
|
|
164
|
+
pool.clear();
|
|
165
|
+
loadedProjects.clear();
|
|
166
|
+
}
|
|
167
|
+
/* ----------------------------- internals ----------------------------- */
|
|
168
|
+
async function syncScope(scope, configs) {
|
|
169
|
+
// Disconnect + drop entries that no longer exist in the config (or
|
|
170
|
+
// moved scope). Mutating during iteration is fine because we take a
|
|
171
|
+
// snapshot of keys first.
|
|
172
|
+
const wantNames = new Set(Object.keys(configs));
|
|
173
|
+
for (const [key, entry] of Array.from(pool.entries())) {
|
|
174
|
+
if (entryScopeMatches(entry.scope, scope) && !wantNames.has(entry.name)) {
|
|
175
|
+
await disconnectEntry(entry);
|
|
176
|
+
pool.delete(key);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Add / update each declared server.
|
|
180
|
+
for (const [name, cfg] of Object.entries(configs)) {
|
|
181
|
+
const key = entryKey(scope, name);
|
|
182
|
+
const existing = pool.get(key);
|
|
183
|
+
if (existing !== undefined) {
|
|
184
|
+
const sameUrl = existing.config.url === cfg.url;
|
|
185
|
+
const sameTransport = existing.config.transport === cfg.transport;
|
|
186
|
+
const sameEnabled = (existing.config.enabled !== false) === (cfg.enabled !== false);
|
|
187
|
+
const sameHeaders = JSON.stringify(existing.config.headers ?? {}) === JSON.stringify(cfg.headers ?? {});
|
|
188
|
+
existing.config = cfg;
|
|
189
|
+
if (sameUrl && sameTransport && sameEnabled && sameHeaders) {
|
|
190
|
+
// Nothing meaningful changed; skip the disconnect/reconnect dance.
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
await disconnectEntry(existing);
|
|
194
|
+
if (cfg.enabled === false) {
|
|
195
|
+
existing.state = "disabled";
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
void connectEntry(existing);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const entry = {
|
|
202
|
+
scope,
|
|
203
|
+
name,
|
|
204
|
+
config: cfg,
|
|
205
|
+
state: cfg.enabled === false ? "disabled" : "idle",
|
|
206
|
+
tools: [],
|
|
207
|
+
bridged: [],
|
|
208
|
+
};
|
|
209
|
+
pool.set(key, entry);
|
|
210
|
+
if (cfg.enabled !== false) {
|
|
211
|
+
void connectEntry(entry);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function entryScopeMatches(a, b) {
|
|
216
|
+
if (a === "global" && b === "global")
|
|
217
|
+
return true;
|
|
218
|
+
if (a !== "global" && b !== "global")
|
|
219
|
+
return a.project === b.project;
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
async function connectEntry(entry) {
|
|
223
|
+
entry.state = "connecting";
|
|
224
|
+
delete entry.lastError;
|
|
225
|
+
try {
|
|
226
|
+
const { client, transport, resolvedTransport } = await openConnection(entry.config);
|
|
227
|
+
entry.client = client;
|
|
228
|
+
entry.transport = transport;
|
|
229
|
+
entry.config.transport = resolvedTransport;
|
|
230
|
+
const list = await client.listTools();
|
|
231
|
+
entry.tools = (list.tools ?? []).map((t) => ({
|
|
232
|
+
name: t.name,
|
|
233
|
+
description: typeof t.description === "string" ? t.description : "",
|
|
234
|
+
inputSchema: t.inputSchema ?? {
|
|
235
|
+
type: "object",
|
|
236
|
+
properties: {},
|
|
237
|
+
},
|
|
238
|
+
}));
|
|
239
|
+
entry.bridged = entry.tools.map((t) => bridgeMcpTool({
|
|
240
|
+
serverName: entry.name,
|
|
241
|
+
toolName: t.name,
|
|
242
|
+
description: t.description,
|
|
243
|
+
inputSchema: t.inputSchema,
|
|
244
|
+
getClient: () => pool.get(entryKey(entry.scope, entry.name))?.client,
|
|
245
|
+
}));
|
|
246
|
+
entry.state = "connected";
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
delete entry.client;
|
|
250
|
+
delete entry.transport;
|
|
251
|
+
entry.tools = [];
|
|
252
|
+
entry.bridged = [];
|
|
253
|
+
entry.state = "error";
|
|
254
|
+
entry.lastError = err instanceof Error ? err.message : String(err);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function disconnectEntry(entry) {
|
|
258
|
+
const client = entry.client;
|
|
259
|
+
const transport = entry.transport;
|
|
260
|
+
delete entry.client;
|
|
261
|
+
delete entry.transport;
|
|
262
|
+
entry.tools = [];
|
|
263
|
+
entry.bridged = [];
|
|
264
|
+
if (entry.state !== "disabled")
|
|
265
|
+
entry.state = "idle";
|
|
266
|
+
// Best-effort close. The MCP SDK's Client.close() also closes the
|
|
267
|
+
// transport, but we belt-and-suspender the transport too in case
|
|
268
|
+
// the client never finished handshaking.
|
|
269
|
+
// close() can be sync (void) or async (Promise<void>) depending on
|
|
270
|
+
// the transport — Promise.resolve normalizes either to a thenable.
|
|
271
|
+
await Promise.resolve(client?.close()).catch(() => undefined);
|
|
272
|
+
await Promise.resolve(transport?.close()).catch(() => undefined);
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Open a connection using the requested transport. `auto` (default)
|
|
276
|
+
* attempts StreamableHTTP first, then falls back to SSE on failure —
|
|
277
|
+
* covers fastmcp servers regardless of which transport they expose.
|
|
278
|
+
*/
|
|
279
|
+
async function openConnection(cfg) {
|
|
280
|
+
const url = new URL(cfg.url);
|
|
281
|
+
const requested = cfg.transport ?? "auto";
|
|
282
|
+
if (requested === "streamable-http") {
|
|
283
|
+
return await openStreamableHttp(url, cfg.headers);
|
|
284
|
+
}
|
|
285
|
+
if (requested === "sse") {
|
|
286
|
+
return await openSse(url, cfg.headers);
|
|
287
|
+
}
|
|
288
|
+
// auto: try streamable-http, fall back to sse
|
|
289
|
+
try {
|
|
290
|
+
return await openStreamableHttp(url, cfg.headers);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return await openSse(url, cfg.headers);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
async function openStreamableHttp(url, headers) {
|
|
297
|
+
const transport = new StreamableHTTPClientTransport(url, headers !== undefined ? { requestInit: { headers } } : undefined);
|
|
298
|
+
const client = new Client({ name: "pi-forge", version: "1.0.0" }, { capabilities: {} });
|
|
299
|
+
await client.connect(transport);
|
|
300
|
+
return { client, transport, resolvedTransport: "streamable-http" };
|
|
301
|
+
}
|
|
302
|
+
async function openSse(url, headers) {
|
|
303
|
+
// Build options inline — exactOptionalPropertyTypes refuses to
|
|
304
|
+
// accept explicit `undefined` for optional properties, so the
|
|
305
|
+
// header-bearing variant builds the full options literal in one
|
|
306
|
+
// shot rather than composing it field-by-field.
|
|
307
|
+
const transport = headers !== undefined
|
|
308
|
+
? new SSEClientTransport(url, {
|
|
309
|
+
requestInit: { headers },
|
|
310
|
+
// Custom EventSource fetch factory so the SSE GET also
|
|
311
|
+
// carries the Authorization header. Browsers' native
|
|
312
|
+
// EventSource doesn't accept headers, but the MCP SDK's
|
|
313
|
+
// bundled eventsource shim does, via this factory hook.
|
|
314
|
+
eventSourceInit: {
|
|
315
|
+
fetch: (input, init) => fetch(input, {
|
|
316
|
+
...init,
|
|
317
|
+
headers: { ...(init?.headers ?? {}), ...headers },
|
|
318
|
+
}),
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
: new SSEClientTransport(url);
|
|
322
|
+
const client = new Client({ name: "pi-forge", version: "1.0.0" }, { capabilities: {} });
|
|
323
|
+
await client.connect(transport);
|
|
324
|
+
return { client, transport, resolvedTransport: "sse" };
|
|
325
|
+
}
|
|
326
|
+
/* -------------------------- project-scope read -------------------------- */
|
|
327
|
+
async function readProjectMcpJson(projectPath) {
|
|
328
|
+
const path = join(projectPath, PROJECT_MCP_FILE);
|
|
329
|
+
try {
|
|
330
|
+
const raw = await readFile(path, "utf8");
|
|
331
|
+
if (raw.trim().length === 0)
|
|
332
|
+
return {};
|
|
333
|
+
const parsed = JSON.parse(raw);
|
|
334
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
335
|
+
return {};
|
|
336
|
+
// Accept both `{ servers: {...} }` (pi-forge shape) and
|
|
337
|
+
// `{ mcpServers: {...} }` (Claude Desktop / pi-mcp-adapter shape)
|
|
338
|
+
// so a project that already speaks the standard MCP file format
|
|
339
|
+
// works without rewriting.
|
|
340
|
+
const servers = parsed.servers ?? parsed.mcpServers;
|
|
341
|
+
if (typeof servers !== "object" || servers === null)
|
|
342
|
+
return {};
|
|
343
|
+
return servers;
|
|
344
|
+
}
|
|
345
|
+
catch (err) {
|
|
346
|
+
if (err.code === "ENOENT")
|
|
347
|
+
return {};
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/mcp/manager.ts"],"names":[],"mappings":"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"}
|