@mcpbridgeapp/cli 0.0.0-stage → 0.1.1
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 +345 -2
- package/dist/agents/broken.d.ts +24 -0
- package/dist/agents/broken.js +31 -0
- package/dist/agents/broken.js.map +1 -0
- package/dist/agents/cli.d.ts +47 -0
- package/dist/agents/cli.js +270 -0
- package/dist/agents/cli.js.map +1 -0
- package/dist/agents/health.d.ts +38 -0
- package/dist/agents/health.js +53 -0
- package/dist/agents/health.js.map +1 -0
- package/dist/agents/ollama.d.ts +27 -0
- package/dist/agents/ollama.js +118 -0
- package/dist/agents/ollama.js.map +1 -0
- package/dist/agents/openai.d.ts +35 -0
- package/dist/agents/openai.js +168 -0
- package/dist/agents/openai.js.map +1 -0
- package/dist/agents/outcome.d.ts +34 -0
- package/dist/agents/outcome.js +96 -0
- package/dist/agents/outcome.js.map +1 -0
- package/dist/agents/permissions.d.ts +44 -0
- package/dist/agents/permissions.js +68 -0
- package/dist/agents/permissions.js.map +1 -0
- package/dist/agents/registry.d.ts +56 -0
- package/dist/agents/registry.js +167 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/shim.d.ts +35 -0
- package/dist/agents/shim.js +53 -0
- package/dist/agents/shim.js.map +1 -0
- package/dist/agents/types.d.ts +69 -0
- package/dist/agents/types.js +28 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/config.d.ts +99 -0
- package/dist/config.js +78 -0
- package/dist/config.js.map +1 -0
- package/dist/connect.d.ts +35 -0
- package/dist/connect.js +124 -0
- package/dist/connect.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +269 -0
- package/dist/index.js.map +1 -0
- package/dist/limit.d.ts +14 -0
- package/dist/limit.js +33 -0
- package/dist/limit.js.map +1 -0
- package/dist/protocol.d.ts +175 -0
- package/dist/protocol.js +86 -0
- package/dist/protocol.js.map +1 -0
- package/dist/secrets.d.ts +27 -0
- package/dist/secrets.js +53 -0
- package/dist/secrets.js.map +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/dist/tasks.d.ts +48 -0
- package/dist/tasks.js +103 -0
- package/dist/tasks.js.map +1 -0
- package/dist/tools.d.ts +25 -0
- package/dist/tools.js +71 -0
- package/dist/tools.js.map +1 -0
- package/dist/ui/page.d.ts +7 -0
- package/dist/ui/page.js +428 -0
- package/dist/ui/page.js.map +1 -0
- package/dist/ui/presets.d.ts +22 -0
- package/dist/ui/presets.js +57 -0
- package/dist/ui/presets.js.map +1 -0
- package/dist/ui/server.d.ts +38 -0
- package/dist/ui/server.js +567 -0
- package/dist/ui/server.js.map +1 -0
- package/package.json +93 -4
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
import { HealthStore } from '../agents/health.js';
|
|
6
|
+
import { permissionsFor } from '../agents/permissions.js';
|
|
7
|
+
import { AgentRegistry } from '../agents/registry.js';
|
|
8
|
+
import { DEFAULT_CONFIG, configPath, loadConfig } from '../config.js';
|
|
9
|
+
import { connectToRelay } from '../connect.js';
|
|
10
|
+
import { ConcurrencyLimit } from '../limit.js';
|
|
11
|
+
import { applySecretsToEnv, loadSecrets, maskSecret, saveSecrets, secretsPath } from '../secrets.js';
|
|
12
|
+
import { TaskStore } from '../tasks.js';
|
|
13
|
+
import { uiPage } from './page.js';
|
|
14
|
+
import { PRESETS } from './presets.js';
|
|
15
|
+
const COOKIE = 'mcpbridge_ui';
|
|
16
|
+
const MAX_BODY = 64 * 1024;
|
|
17
|
+
const TEST_PROMPT = 'Reply with exactly one word: OK';
|
|
18
|
+
const NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,31}$/;
|
|
19
|
+
const ENV_PATTERN = /^[A-Z_][A-Z0-9_]{0,63}$/;
|
|
20
|
+
/**
|
|
21
|
+
* The local control panel: everything `mcpbridgeapp` asks of a terminal -- adding an agent,
|
|
22
|
+
* saving its key, checking it answers, keeping this machine connected to the relay --
|
|
23
|
+
* done from a page on this machine.
|
|
24
|
+
*
|
|
25
|
+
* <p>Three things keep it this machine's alone. It listens on 127.0.0.1 only. Every
|
|
26
|
+
* request must carry a key generated at launch, which reaches the browser only through
|
|
27
|
+
* the link printed in the terminal and is then held in an HttpOnly cookie. And requests
|
|
28
|
+
* whose Host or Origin is not this server are refused, so a web page elsewhere cannot use
|
|
29
|
+
* the browser to drive it, by DNS rebinding or by cross-site POST.
|
|
30
|
+
*/
|
|
31
|
+
export async function startUi(options) {
|
|
32
|
+
const log = options.log ?? ((line) => process.stderr.write(`${line}\n`));
|
|
33
|
+
const configFile = options.configFile ?? configPath();
|
|
34
|
+
const secretsFile = options.secretsFile ?? secretsPath();
|
|
35
|
+
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
36
|
+
const key = randomBytes(18).toString('base64url');
|
|
37
|
+
let secrets = loadSecrets(secretsFile);
|
|
38
|
+
applySecretsToEnv(secrets);
|
|
39
|
+
// outlives every rebuild of the registry, so editing an agent does not forget what
|
|
40
|
+
// earlier calls learned about the others
|
|
41
|
+
const health = new HealthStore();
|
|
42
|
+
const context = (() => {
|
|
43
|
+
const { config } = loadConfig(configFile);
|
|
44
|
+
const limit = new ConcurrencyLimit(config.maxConcurrent);
|
|
45
|
+
return { registry: new AgentRegistry(config, health), tasks: new TaskStore(limit), limit };
|
|
46
|
+
})();
|
|
47
|
+
let connection = { state: 'stopped' };
|
|
48
|
+
let connectionController;
|
|
49
|
+
const connectionLog = [];
|
|
50
|
+
const remember = (line) => {
|
|
51
|
+
connectionLog.push(`${new Date().toLocaleTimeString()} ${line}`);
|
|
52
|
+
if (connectionLog.length > 30)
|
|
53
|
+
connectionLog.shift();
|
|
54
|
+
};
|
|
55
|
+
// probing an API agent calls its provider, so a page that polls must not probe each time
|
|
56
|
+
let statusCache;
|
|
57
|
+
const statuses = async () => {
|
|
58
|
+
if (!statusCache || Date.now() - statusCache.at > 30_000) {
|
|
59
|
+
statusCache = { at: Date.now(), value: await context.registry.statuses() };
|
|
60
|
+
}
|
|
61
|
+
return statusCache.value;
|
|
62
|
+
};
|
|
63
|
+
/** Rebuilds the agents from the file; a live connection is restarted so the relay sees them. */
|
|
64
|
+
const reload = () => {
|
|
65
|
+
const { config } = loadConfig(configFile);
|
|
66
|
+
context.registry = new AgentRegistry(config, health);
|
|
67
|
+
statusCache = undefined;
|
|
68
|
+
if (connectionController)
|
|
69
|
+
startConnection();
|
|
70
|
+
};
|
|
71
|
+
const stopConnection = (reason = 'stopped from this page') => {
|
|
72
|
+
connectionController?.abort();
|
|
73
|
+
connectionController = undefined;
|
|
74
|
+
connection = { state: 'stopped', reason };
|
|
75
|
+
};
|
|
76
|
+
const startConnection = () => {
|
|
77
|
+
stopConnection('restarting');
|
|
78
|
+
const relay = secrets.relay;
|
|
79
|
+
if (!relay)
|
|
80
|
+
throw new Error('save the relay address and agent token first');
|
|
81
|
+
const controller = new AbortController();
|
|
82
|
+
connectionController = controller;
|
|
83
|
+
connection = { state: 'connecting' };
|
|
84
|
+
remember(`connecting to ${relay.url}`);
|
|
85
|
+
void connectToRelay({
|
|
86
|
+
relayUrl: relay.url,
|
|
87
|
+
token: relay.token,
|
|
88
|
+
...(relay.device ? { device: relay.device } : {}),
|
|
89
|
+
agentVersion: options.agentVersion,
|
|
90
|
+
context,
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
log: (line) => { remember(line); log(line); },
|
|
93
|
+
onState: (state) => {
|
|
94
|
+
if (connectionController !== controller)
|
|
95
|
+
return;
|
|
96
|
+
connection = state.connected
|
|
97
|
+
? { state: 'connected', device: state.device, since: Date.now() }
|
|
98
|
+
: { state: 'reconnecting', reason: state.reason };
|
|
99
|
+
},
|
|
100
|
+
}).then(() => {
|
|
101
|
+
// the loop only ends by itself when the relay refused this machine for good
|
|
102
|
+
if (connectionController === controller) {
|
|
103
|
+
connectionController = undefined;
|
|
104
|
+
connection = { state: 'stopped', reason: lastReason(connection) ?? 'the relay refused this machine' };
|
|
105
|
+
remember('stopped: the relay refused this machine; check the agent token');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
// ---- config.json, edited in place ---------------------------------------------------
|
|
110
|
+
const readFile = () => {
|
|
111
|
+
let raw;
|
|
112
|
+
try {
|
|
113
|
+
raw = readFileSync(configFile, 'utf8');
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return {};
|
|
117
|
+
}
|
|
118
|
+
// a file that does not parse is the person's to fix; overwriting it would lose their work
|
|
119
|
+
return JSON.parse(raw);
|
|
120
|
+
};
|
|
121
|
+
const writeFile = (file) => {
|
|
122
|
+
mkdirSync(dirname(configFile), { recursive: true });
|
|
123
|
+
const temporary = `${configFile}.tmp`;
|
|
124
|
+
writeFileSync(temporary, `${JSON.stringify(file, null, 2)}\n`);
|
|
125
|
+
renameSync(temporary, configFile);
|
|
126
|
+
};
|
|
127
|
+
const fileAgents = () => {
|
|
128
|
+
try {
|
|
129
|
+
return (readFile()['agents'] ?? {});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return {};
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
// ---- the API --------------------------------------------------------------------------
|
|
136
|
+
const state = async () => {
|
|
137
|
+
const mine = fileAgents();
|
|
138
|
+
const probed = await statuses();
|
|
139
|
+
let configError = null;
|
|
140
|
+
try {
|
|
141
|
+
readFile();
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
configError = `${configFile} is not valid JSON: ${error.message}`;
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
configFile,
|
|
148
|
+
secretsFile,
|
|
149
|
+
configError,
|
|
150
|
+
agents: probed.map((s) => {
|
|
151
|
+
const own = mine[s.name];
|
|
152
|
+
const keyEnv = own && own.type === 'openai' ? own.apiKeyEnv : undefined;
|
|
153
|
+
const effective = own ?? DEFAULT_CONFIG.agents[s.name];
|
|
154
|
+
const cli = effective && effective.type !== 'openai' && effective.type !== 'ollama' ? permissionsFor(effective) : null;
|
|
155
|
+
return {
|
|
156
|
+
...s,
|
|
157
|
+
origin: own ? (s.name in DEFAULT_CONFIG.agents ? 'override' : 'yours') : 'built-in',
|
|
158
|
+
config: own ?? (effective ?? null),
|
|
159
|
+
permissions: cli ? { supports: cli.supports, note: cli.note } : null,
|
|
160
|
+
key: keyEnv ? { env: keyEnv, saved: maskSecret(secrets.keys[keyEnv]), inEnvironment: Boolean(process.env[keyEnv]) } : null,
|
|
161
|
+
};
|
|
162
|
+
}),
|
|
163
|
+
relay: secrets.relay
|
|
164
|
+
? { url: secrets.relay.url, device: secrets.relay.device ?? '', token: maskSecret(secrets.relay.token) }
|
|
165
|
+
: null,
|
|
166
|
+
connection,
|
|
167
|
+
connectionLog,
|
|
168
|
+
presets: PRESETS,
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
const saveAgent = (body, { reloadAfter = true } = {}) => {
|
|
172
|
+
const name = String(body['name'] ?? '').trim().toLowerCase();
|
|
173
|
+
if (!NAME_PATTERN.test(name))
|
|
174
|
+
throw new Error('a name is lowercase letters, digits, - and _, up to 32 characters');
|
|
175
|
+
const kind = String(body['kind'] ?? '');
|
|
176
|
+
const description = String(body['description'] ?? '').trim().slice(0, 200) || undefined;
|
|
177
|
+
const timeoutMs = body['timeoutMs'] ? Number(body['timeoutMs']) : undefined;
|
|
178
|
+
if (timeoutMs !== undefined && (!Number.isInteger(timeoutMs) || timeoutMs < 1_000 || timeoutMs > 3_600_000)) {
|
|
179
|
+
throw new Error('the timeout is in milliseconds, between 1000 and 3600000');
|
|
180
|
+
}
|
|
181
|
+
let agent;
|
|
182
|
+
let keyEnv;
|
|
183
|
+
if (kind === 'openai') {
|
|
184
|
+
const baseUrl = String(body['baseUrl'] ?? '').trim().replace(/\/+$/, '');
|
|
185
|
+
if (!acceptableBaseUrl(baseUrl))
|
|
186
|
+
throw new Error('the base URL must be https://, or http:// on localhost');
|
|
187
|
+
keyEnv = String(body['apiKeyEnv'] ?? '').trim() || `${name.toUpperCase().replace(/-/g, '_')}_API_KEY`;
|
|
188
|
+
if (!ENV_PATTERN.test(keyEnv))
|
|
189
|
+
throw new Error('the key variable is uppercase letters, digits and _');
|
|
190
|
+
const model = String(body['model'] ?? '').trim();
|
|
191
|
+
agent = {
|
|
192
|
+
type: 'openai', baseUrl, apiKeyEnv: keyEnv,
|
|
193
|
+
...(model ? { model } : {}), ...(description ? { description } : {}), ...(timeoutMs ? { timeoutMs } : {}),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
else if (kind === 'cli') {
|
|
197
|
+
const command = Array.isArray(body['command']) ? body['command'].map(String).filter(Boolean) : [];
|
|
198
|
+
const promptVia = body['promptVia'] === 'stdin' ? 'stdin' : 'argv';
|
|
199
|
+
const given = (body['allow'] ?? {});
|
|
200
|
+
const allow = {
|
|
201
|
+
...(given['edits'] === true ? { edits: true } : {}),
|
|
202
|
+
...(given['commands'] === true ? { commands: true } : {}),
|
|
203
|
+
...(given['trustDirectory'] === true ? { trustDirectory: true } : {}),
|
|
204
|
+
};
|
|
205
|
+
// kept from the file: hand-written fields this form does not show, such as env
|
|
206
|
+
const previous = (fileAgents()[name] ?? {});
|
|
207
|
+
agent = {
|
|
208
|
+
...(previous['env'] ? { env: previous['env'] } : {}),
|
|
209
|
+
...(previous['capabilities'] ? { capabilities: previous['capabilities'] } : {}),
|
|
210
|
+
command, ...(promptVia === 'stdin' ? { promptVia } : {}),
|
|
211
|
+
...(Object.keys(allow).length ? { allow } : {}),
|
|
212
|
+
...(description ? { description } : {}), ...(timeoutMs ? { timeoutMs } : {}),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
else if (kind === 'ollama') {
|
|
216
|
+
const model = String(body['model'] ?? '').trim();
|
|
217
|
+
const baseUrl = String(body['baseUrl'] ?? '').trim();
|
|
218
|
+
if (baseUrl && !acceptableBaseUrl(baseUrl))
|
|
219
|
+
throw new Error('the base URL must be https://, or http:// on localhost');
|
|
220
|
+
agent = {
|
|
221
|
+
type: 'ollama', ...(model ? { model } : {}), ...(baseUrl ? { baseUrl } : {}),
|
|
222
|
+
...(description ? { description } : {}), ...(timeoutMs ? { timeoutMs } : {}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
throw new Error('kind must be openai, cli or ollama');
|
|
227
|
+
}
|
|
228
|
+
// the same construction the bridge does, so a config it would reject is refused here
|
|
229
|
+
const rejected = new AgentRegistry({ ...DEFAULT_CONFIG, agents: { [name]: agent } }).configError(name);
|
|
230
|
+
if (rejected)
|
|
231
|
+
throw new Error(rejected);
|
|
232
|
+
const file = readFile();
|
|
233
|
+
file['agents'] = { ...(file['agents'] ?? {}), [name]: agent };
|
|
234
|
+
writeFile(file);
|
|
235
|
+
const apiKey = typeof body['apiKey'] === 'string' ? body['apiKey'].trim() : '';
|
|
236
|
+
if (keyEnv && apiKey) {
|
|
237
|
+
secrets = { ...secrets, keys: { ...secrets.keys, [keyEnv]: apiKey } };
|
|
238
|
+
saveSecrets(secrets, secretsFile);
|
|
239
|
+
// a key typed here replaces whatever the variable held at startup
|
|
240
|
+
process.env[keyEnv] = apiKey;
|
|
241
|
+
}
|
|
242
|
+
// what was learned about the old configuration may not hold for the new one
|
|
243
|
+
health.forget(name);
|
|
244
|
+
if (reloadAfter)
|
|
245
|
+
reload();
|
|
246
|
+
return { saved: name };
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* One agent per model, all sharing the endpoint and key: a provider like NVIDIA offers
|
|
250
|
+
* dozens of models behind one key, and saving a second one under the same name used to
|
|
251
|
+
* replace the first. Names come from the model, so they are distinct and readable --
|
|
252
|
+
* "nvidia-deepseek-v4-1-flash" -- and an existing agent already pointing at the same
|
|
253
|
+
* model is updated rather than duplicated.
|
|
254
|
+
*/
|
|
255
|
+
const saveMany = (body) => {
|
|
256
|
+
const models = Array.isArray(body['models']) ? [...new Set(body['models'].map(String).map((m) => m.trim()).filter(Boolean))] : [];
|
|
257
|
+
if (models.length === 0)
|
|
258
|
+
throw new Error('tick at least one model');
|
|
259
|
+
if (models.length > 50)
|
|
260
|
+
throw new Error('at most 50 models at a time');
|
|
261
|
+
const prefix = String(body['name'] ?? '').trim().toLowerCase();
|
|
262
|
+
if (!NAME_PATTERN.test(prefix))
|
|
263
|
+
throw new Error('the name to start each agent with is lowercase letters, digits, - and _');
|
|
264
|
+
const baseUrl = String(body['baseUrl'] ?? '').trim().replace(/\/+$/, '');
|
|
265
|
+
const names = agentNamesFor(prefix, models, baseUrl, fileAgents(), Object.keys(DEFAULT_CONFIG.agents));
|
|
266
|
+
const saved = [];
|
|
267
|
+
models.forEach((model, i) => {
|
|
268
|
+
saveAgent({ ...body, name: names[i], model, description: `${String(body['description'] ?? '').trim() || prefix}: ${model}` }, { reloadAfter: false });
|
|
269
|
+
saved.push(names[i]);
|
|
270
|
+
});
|
|
271
|
+
// one reload, so a live relay connection restarts once rather than once per model
|
|
272
|
+
reload();
|
|
273
|
+
return { saved };
|
|
274
|
+
};
|
|
275
|
+
const removeAgent = (body) => {
|
|
276
|
+
const name = String(body['name'] ?? '').trim().toLowerCase();
|
|
277
|
+
const file = readFile();
|
|
278
|
+
const agents = { ...(file['agents'] ?? {}) };
|
|
279
|
+
if (!(name in agents))
|
|
280
|
+
throw new Error(`"${name}" is not in your config file; built-in agents cannot be removed`);
|
|
281
|
+
delete agents[name];
|
|
282
|
+
file['agents'] = agents;
|
|
283
|
+
writeFile(file);
|
|
284
|
+
reload();
|
|
285
|
+
return { removed: name, builtIn: name in DEFAULT_CONFIG.agents };
|
|
286
|
+
};
|
|
287
|
+
const testAgent = async (body) => {
|
|
288
|
+
const name = String(body['name'] ?? '');
|
|
289
|
+
const agent = context.registry.find(name);
|
|
290
|
+
if (!agent)
|
|
291
|
+
throw new Error(`no agent named "${name}"`);
|
|
292
|
+
const prompt = typeof body['prompt'] === 'string' && body['prompt'].trim() ? body['prompt'].trim() : TEST_PROMPT;
|
|
293
|
+
// the owner pressing Test is the explicit retry a remembered failure waits for
|
|
294
|
+
const result = await context.limit.run(() => agent.run(prompt, { force: true }));
|
|
295
|
+
// what the test learned belongs in the next listing, not one cached from before it
|
|
296
|
+
statusCache = undefined;
|
|
297
|
+
return result;
|
|
298
|
+
};
|
|
299
|
+
const listModels = async (body) => {
|
|
300
|
+
const baseUrl = String(body['baseUrl'] ?? '').trim().replace(/\/+$/, '');
|
|
301
|
+
if (!acceptableBaseUrl(baseUrl))
|
|
302
|
+
throw new Error('the base URL must be https://, or http:// on localhost');
|
|
303
|
+
const env = String(body['apiKeyEnv'] ?? '').trim();
|
|
304
|
+
const apiKey = (typeof body['apiKey'] === 'string' && body['apiKey'].trim()) || (env ? process.env[env] : undefined);
|
|
305
|
+
if (!apiKey)
|
|
306
|
+
throw new Error('paste the key first, so the provider will list what it can reach');
|
|
307
|
+
const response = await fetchImpl(`${baseUrl}/models`, {
|
|
308
|
+
headers: { Authorization: `Bearer ${apiKey}`, Accept: 'application/json' },
|
|
309
|
+
signal: AbortSignal.timeout(10_000),
|
|
310
|
+
});
|
|
311
|
+
if (!response.ok)
|
|
312
|
+
throw new Error(`the provider answered ${response.status} ${response.statusText}; check the key`);
|
|
313
|
+
const payload = (await response.json());
|
|
314
|
+
const models = (payload.data ?? []).map((m) => m.id).filter((id) => typeof id === 'string');
|
|
315
|
+
return { models: [...new Set(models)].sort().slice(0, 500) };
|
|
316
|
+
};
|
|
317
|
+
const saveRelay = (body) => {
|
|
318
|
+
const url = String(body['url'] ?? '').trim().replace(/\/+$/, '');
|
|
319
|
+
if (!/^(https?|wss?):\/\/[^\s/]+/.test(url))
|
|
320
|
+
throw new Error('the relay address starts with https://');
|
|
321
|
+
const token = String(body['token'] ?? '').trim() || secrets.relay?.token || '';
|
|
322
|
+
if (!token.startsWith('mba_'))
|
|
323
|
+
throw new Error('paste the agent token from the relay dashboard; it starts with mba_');
|
|
324
|
+
const device = String(body['device'] ?? '').trim().slice(0, 80);
|
|
325
|
+
secrets = { ...secrets, relay: { url, token, ...(device ? { device } : {}) } };
|
|
326
|
+
saveSecrets(secrets, secretsFile);
|
|
327
|
+
startConnection();
|
|
328
|
+
return { saved: true };
|
|
329
|
+
};
|
|
330
|
+
// ---- HTTP -----------------------------------------------------------------------------
|
|
331
|
+
let port = options.port;
|
|
332
|
+
const allowedHosts = () => [`127.0.0.1:${port}`, `localhost:${port}`];
|
|
333
|
+
const server = createServer((req, res) => {
|
|
334
|
+
void handle(req, res).catch((error) => {
|
|
335
|
+
if (!res.headersSent)
|
|
336
|
+
json(res, 500, { error: error.message });
|
|
337
|
+
else
|
|
338
|
+
res.end();
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
const handle = async (req, res) => {
|
|
342
|
+
if (!allowedHosts().includes(req.headers.host ?? '')) {
|
|
343
|
+
res.writeHead(403, { 'Content-Type': 'text/plain' }).end('this page only answers on 127.0.0.1');
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
347
|
+
if (req.method === 'GET' && url.pathname === '/') {
|
|
348
|
+
const presented = url.searchParams.get('k');
|
|
349
|
+
if (presented !== null) {
|
|
350
|
+
if (!same(presented, key)) {
|
|
351
|
+
res.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' }).end('that link is from another launch; use the one the terminal printed');
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// trade the key in the address for a cookie, so it leaves the address bar and history
|
|
355
|
+
res.writeHead(303, {
|
|
356
|
+
'Set-Cookie': `${COOKIE}=${key}; HttpOnly; SameSite=Strict; Path=/`,
|
|
357
|
+
Location: '/',
|
|
358
|
+
}).end();
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!same(cookieFrom(req), key)) {
|
|
362
|
+
res.writeHead(403, { 'Content-Type': 'text/plain; charset=utf-8' })
|
|
363
|
+
.end('open the link that `mcpbridgeapp ui` printed in the terminal; it carries this launch\'s key');
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const html = uiPage();
|
|
367
|
+
res.writeHead(200, {
|
|
368
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
369
|
+
'Content-Length': Buffer.byteLength(html),
|
|
370
|
+
'Cache-Control': 'no-store',
|
|
371
|
+
'X-Content-Type-Options': 'nosniff',
|
|
372
|
+
'X-Frame-Options': 'DENY',
|
|
373
|
+
'Referrer-Policy': 'no-referrer',
|
|
374
|
+
'Content-Security-Policy': "default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'",
|
|
375
|
+
});
|
|
376
|
+
res.end(html);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (!url.pathname.startsWith('/api/')) {
|
|
380
|
+
res.writeHead(404).end();
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// the cookie proves the browser opened the launch link; the custom header cannot be
|
|
384
|
+
// sent cross-origin without a preflight this server never approves
|
|
385
|
+
if (!same(cookieFrom(req), key) || req.headers['x-mcpbridge-ui'] !== '1') {
|
|
386
|
+
json(res, 403, { error: 'not authorised: reopen the link the terminal printed' });
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const origin = req.headers.origin;
|
|
390
|
+
if (origin && !allowedHosts().some((h) => origin === `http://${h}`)) {
|
|
391
|
+
json(res, 403, { error: 'cross-origin request refused' });
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
if (req.method === 'GET' && url.pathname === '/api/state') {
|
|
395
|
+
json(res, 200, await state());
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (req.method !== 'POST') {
|
|
399
|
+
json(res, 405, { error: 'method not allowed' });
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
let body;
|
|
403
|
+
try {
|
|
404
|
+
body = await readJson(req);
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
json(res, 400, { error: error.message });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
const routes = {
|
|
411
|
+
'/api/agents/save': (b) => saveAgent(b),
|
|
412
|
+
'/api/agents/save-many': saveMany,
|
|
413
|
+
'/api/agents/remove': removeAgent,
|
|
414
|
+
'/api/agents/test': testAgent,
|
|
415
|
+
'/api/models': listModels,
|
|
416
|
+
'/api/relay/save': saveRelay,
|
|
417
|
+
'/api/relay/connect': () => { startConnection(); return { connecting: true }; },
|
|
418
|
+
'/api/relay/disconnect': () => { stopConnection(); remember('disconnected from this page'); return { stopped: true }; },
|
|
419
|
+
'/api/reload': () => { reload(); return { reloaded: true }; },
|
|
420
|
+
};
|
|
421
|
+
const route = routes[url.pathname];
|
|
422
|
+
if (!route) {
|
|
423
|
+
json(res, 404, { error: 'no such endpoint' });
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
json(res, 200, await route(body));
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
json(res, 400, { error: error.message });
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
port = await listenNear(server, options.port);
|
|
434
|
+
// a machine set up once should come back online by itself when the page is opened
|
|
435
|
+
if (secrets.relay) {
|
|
436
|
+
try {
|
|
437
|
+
startConnection();
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
remember(error.message);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
server,
|
|
445
|
+
port,
|
|
446
|
+
url: `http://127.0.0.1:${port}/?k=${key}`,
|
|
447
|
+
close: () => new Promise((resolve) => {
|
|
448
|
+
stopConnection('closing');
|
|
449
|
+
server.close(() => resolve());
|
|
450
|
+
server.closeAllConnections();
|
|
451
|
+
}),
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
// ---- helpers ------------------------------------------------------------------------------
|
|
455
|
+
/** "deepseek-ai/deepseek-v4.1-flash" under "nvidia" -> "nvidia-deepseek-v4-1-flash", within 32 characters. */
|
|
456
|
+
export function agentNameFor(prefix, model) {
|
|
457
|
+
const slug = (model.split('/').pop() ?? model).toLowerCase().replace(/[^a-z0-9_-]+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
458
|
+
const full = `${prefix}-${slug || 'model'}`;
|
|
459
|
+
if (full.length <= 32)
|
|
460
|
+
return full;
|
|
461
|
+
// cut at a word, not inside one: "...-vision", not "...-vision-inst"
|
|
462
|
+
const cut = full.slice(0, 32);
|
|
463
|
+
const dash = cut.lastIndexOf('-');
|
|
464
|
+
return (dash > prefix.length ? cut.slice(0, dash) : cut).replace(/[-_]+$/, '');
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* A distinct name per model. A name already used by an agent on the same model and endpoint
|
|
468
|
+
* is reused, so ticking a model twice updates it; one used by anything else -- another
|
|
469
|
+
* model, a built-in -- gets a numbered suffix instead of being overwritten.
|
|
470
|
+
*/
|
|
471
|
+
export function agentNamesFor(prefix, models, baseUrl, existing, builtIn) {
|
|
472
|
+
const taken = new Set(builtIn);
|
|
473
|
+
const sameModel = (name, model) => {
|
|
474
|
+
const agent = existing[name];
|
|
475
|
+
return agent?.type === 'openai' && agent.model === model && agent.baseUrl.replace(/\/+$/, '') === baseUrl;
|
|
476
|
+
};
|
|
477
|
+
for (const name of Object.keys(existing))
|
|
478
|
+
taken.add(name);
|
|
479
|
+
const chosen = [];
|
|
480
|
+
for (const model of models) {
|
|
481
|
+
const base = agentNameFor(prefix, model);
|
|
482
|
+
let name = base;
|
|
483
|
+
for (let n = 2; (taken.has(name) && !sameModel(name, model)) || chosen.includes(name); n += 1) {
|
|
484
|
+
const suffix = `-${n}`;
|
|
485
|
+
name = `${base.slice(0, 32 - suffix.length).replace(/[-_]+$/, '')}${suffix}`;
|
|
486
|
+
}
|
|
487
|
+
chosen.push(name);
|
|
488
|
+
}
|
|
489
|
+
return chosen;
|
|
490
|
+
}
|
|
491
|
+
function lastReason(state) {
|
|
492
|
+
return state.state === 'reconnecting' || state.state === 'stopped' ? state.reason : undefined;
|
|
493
|
+
}
|
|
494
|
+
/** https anywhere; http only to this machine, which is where local model servers live. */
|
|
495
|
+
function acceptableBaseUrl(value) {
|
|
496
|
+
try {
|
|
497
|
+
const url = new URL(value);
|
|
498
|
+
if (url.protocol === 'https:')
|
|
499
|
+
return true;
|
|
500
|
+
return url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function same(a, b) {
|
|
507
|
+
if (!a)
|
|
508
|
+
return false;
|
|
509
|
+
const left = Buffer.from(a);
|
|
510
|
+
const right = Buffer.from(b);
|
|
511
|
+
return left.length === right.length && timingSafeEqual(left, right);
|
|
512
|
+
}
|
|
513
|
+
function cookieFrom(req) {
|
|
514
|
+
for (const part of (req.headers.cookie ?? '').split(';')) {
|
|
515
|
+
const [name, ...rest] = part.trim().split('=');
|
|
516
|
+
if (name === COOKIE)
|
|
517
|
+
return rest.join('=');
|
|
518
|
+
}
|
|
519
|
+
return undefined;
|
|
520
|
+
}
|
|
521
|
+
async function readJson(req) {
|
|
522
|
+
const chunks = [];
|
|
523
|
+
let size = 0;
|
|
524
|
+
for await (const chunk of req) {
|
|
525
|
+
size += chunk.length;
|
|
526
|
+
if (size > MAX_BODY)
|
|
527
|
+
throw new Error('request body too large');
|
|
528
|
+
chunks.push(chunk);
|
|
529
|
+
}
|
|
530
|
+
const text = Buffer.concat(chunks).toString('utf8');
|
|
531
|
+
if (!text)
|
|
532
|
+
return {};
|
|
533
|
+
const parsed = JSON.parse(text);
|
|
534
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
535
|
+
throw new Error('the body must be a JSON object');
|
|
536
|
+
return parsed;
|
|
537
|
+
}
|
|
538
|
+
function json(res, status, body) {
|
|
539
|
+
const text = JSON.stringify(body);
|
|
540
|
+
res.writeHead(status, {
|
|
541
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
542
|
+
'Content-Length': Buffer.byteLength(text),
|
|
543
|
+
'Cache-Control': 'no-store',
|
|
544
|
+
});
|
|
545
|
+
res.end(text);
|
|
546
|
+
}
|
|
547
|
+
/** The requested port, or the next free one: a second launch should not just fail. */
|
|
548
|
+
async function listenNear(server, start) {
|
|
549
|
+
for (let candidate = start; candidate < start + 10 || start === 0; candidate += 1) {
|
|
550
|
+
try {
|
|
551
|
+
await new Promise((resolve, reject) => {
|
|
552
|
+
const onError = (error) => { server.off('listening', onListening); reject(error); };
|
|
553
|
+
const onListening = () => { server.off('error', onError); resolve(); };
|
|
554
|
+
server.once('error', onError);
|
|
555
|
+
server.once('listening', onListening);
|
|
556
|
+
server.listen(candidate, '127.0.0.1');
|
|
557
|
+
});
|
|
558
|
+
return server.address().port;
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
if (error.code !== 'EADDRINUSE' || start === 0)
|
|
562
|
+
throw error;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
throw new Error(`ports ${start}-${start + 9} are all in use; pass --port`);
|
|
566
|
+
}
|
|
567
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ui/server.ts"],"names":[],"mappings":"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"}
|