@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
package/dist/connect.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
3
|
+
import WebSocket from 'ws';
|
|
4
|
+
import { PROTOCOL_VERSION, parseRelayMessage } from './protocol.js';
|
|
5
|
+
import { executeTool } from './tools.js';
|
|
6
|
+
const MIN_BACKOFF_MS = 1_000;
|
|
7
|
+
const MAX_BACKOFF_MS = 30_000;
|
|
8
|
+
/** http -> ws, https -> wss; a URL with no path gets the relay's agent endpoint. */
|
|
9
|
+
export function toWebSocketUrl(relayUrl) {
|
|
10
|
+
const url = new URL(relayUrl);
|
|
11
|
+
if (url.protocol === 'http:')
|
|
12
|
+
url.protocol = 'ws:';
|
|
13
|
+
if (url.protocol === 'https:')
|
|
14
|
+
url.protocol = 'wss:';
|
|
15
|
+
if (url.pathname === '/' || url.pathname === '')
|
|
16
|
+
url.pathname = '/agent';
|
|
17
|
+
return url.toString();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Keeps this machine connected to a relay and answers the calls it forwards.
|
|
21
|
+
*
|
|
22
|
+
* <p>The connection is outbound, so nothing here listens on a port and no firewall rule is
|
|
23
|
+
* needed. Each forwarded call runs the same executeTool as the local MCP server, so a
|
|
24
|
+
* delegation behaves identically whether it arrived from a client on this machine or from
|
|
25
|
+
* one on the other side of the relay.
|
|
26
|
+
*/
|
|
27
|
+
export async function connectToRelay(options) {
|
|
28
|
+
const log = options.log ?? ((line) => process.stderr.write(`${line}\n`));
|
|
29
|
+
const url = toWebSocketUrl(options.relayUrl);
|
|
30
|
+
const device = (options.device ?? hostname()).slice(0, 80);
|
|
31
|
+
let backoff = MIN_BACKOFF_MS;
|
|
32
|
+
while (!options.signal?.aborted) {
|
|
33
|
+
const outcome = await runSession({ ...options, device, url, log });
|
|
34
|
+
if (outcome.stop || options.once)
|
|
35
|
+
return;
|
|
36
|
+
if (outcome.welcomed)
|
|
37
|
+
backoff = MIN_BACKOFF_MS;
|
|
38
|
+
const wait = backoff + Math.floor(Math.random() * 500);
|
|
39
|
+
log(`relay: disconnected (${outcome.reason}); reconnecting in ${Math.round(wait / 1000)}s`);
|
|
40
|
+
try {
|
|
41
|
+
await sleep(wait, undefined, { signal: options.signal });
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function runSession(options) {
|
|
50
|
+
const { context, log, device, url } = options;
|
|
51
|
+
const refreshMs = options.refreshMs ?? 60_000;
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
let welcomed = false;
|
|
54
|
+
let settled = false;
|
|
55
|
+
let refreshTimer;
|
|
56
|
+
const finish = (outcome) => {
|
|
57
|
+
if (settled)
|
|
58
|
+
return;
|
|
59
|
+
settled = true;
|
|
60
|
+
options.onState?.({ connected: false, reason: outcome.reason });
|
|
61
|
+
if (refreshTimer)
|
|
62
|
+
clearInterval(refreshTimer);
|
|
63
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
64
|
+
resolve(outcome);
|
|
65
|
+
};
|
|
66
|
+
const socket = new WebSocket(url, { headers: { Authorization: `Bearer ${options.token}` } });
|
|
67
|
+
const send = (message) => {
|
|
68
|
+
if (socket.readyState === WebSocket.OPEN)
|
|
69
|
+
socket.send(JSON.stringify(message));
|
|
70
|
+
};
|
|
71
|
+
const onAbort = () => {
|
|
72
|
+
socket.close(1000, 'shutting down');
|
|
73
|
+
finish({ reason: 'aborted', welcomed, stop: true });
|
|
74
|
+
};
|
|
75
|
+
options.signal?.addEventListener('abort', onAbort, { once: true });
|
|
76
|
+
socket.on('open', async () => {
|
|
77
|
+
const agents = await context.registry.statuses();
|
|
78
|
+
send({ type: 'hello', protocol: PROTOCOL_VERSION, agentVersion: options.agentVersion, device, agents });
|
|
79
|
+
refreshTimer = setInterval(async () => {
|
|
80
|
+
send({ type: 'agents', agents: await context.registry.statuses() });
|
|
81
|
+
}, refreshMs);
|
|
82
|
+
});
|
|
83
|
+
socket.on('message', async (data) => {
|
|
84
|
+
const message = parseRelayMessage(data.toString());
|
|
85
|
+
if (!message) {
|
|
86
|
+
log('relay: ignoring a message it could not parse');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
switch (message.type) {
|
|
90
|
+
case 'welcome':
|
|
91
|
+
welcomed = true;
|
|
92
|
+
log(`relay: connected as device "${message.device}"`);
|
|
93
|
+
options.onState?.({ connected: true, device: message.device });
|
|
94
|
+
return;
|
|
95
|
+
case 'goodbye':
|
|
96
|
+
log(`relay: ${message.reason}`);
|
|
97
|
+
finish({ reason: message.reason, welcomed, stop: !message.retry });
|
|
98
|
+
socket.close(1000);
|
|
99
|
+
return;
|
|
100
|
+
case 'call': {
|
|
101
|
+
// each call is independent; the concurrency limit inside executeTool is what
|
|
102
|
+
// keeps a burst of them from running every agent at once
|
|
103
|
+
try {
|
|
104
|
+
const payload = await executeTool(message.tool, message.args, context);
|
|
105
|
+
send({ type: 'result', id: message.id, ok: true, payload });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
send({ type: 'result', id: message.id, ok: false, payload: error.message });
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
socket.on('error', (error) => {
|
|
115
|
+
finish({ reason: error.message, welcomed, stop: false });
|
|
116
|
+
});
|
|
117
|
+
socket.on('close', (code, reasonBuffer) => {
|
|
118
|
+
const reason = reasonBuffer.toString() || `socket closed (${code})`;
|
|
119
|
+
// 4001 is the relay refusing the token: retrying with the same one is pointless
|
|
120
|
+
finish({ reason, welcomed, stop: code === 4001 });
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { createServer as createHttpServer } from 'node:http';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
6
|
+
import { AgentRegistry } from './agents/registry.js';
|
|
7
|
+
import { configPath, loadConfig } from './config.js';
|
|
8
|
+
import { connectToRelay } from './connect.js';
|
|
9
|
+
import { applySecretsToEnv, loadSecrets } from './secrets.js';
|
|
10
|
+
import { startUi } from './ui/server.js';
|
|
11
|
+
import { ConcurrencyLimit } from './limit.js';
|
|
12
|
+
import { createServer } from './server.js';
|
|
13
|
+
import { TaskStore } from './tasks.js';
|
|
14
|
+
const VERSION = '0.1.0';
|
|
15
|
+
function flag(argv, name) {
|
|
16
|
+
const index = argv.indexOf(name);
|
|
17
|
+
return index === -1 ? undefined : argv[index + 1];
|
|
18
|
+
}
|
|
19
|
+
const USAGE = `mcpbridgeapp - delegate work to another AI agent over MCP
|
|
20
|
+
|
|
21
|
+
mcpbridgeapp run as an MCP server over stdio (default)
|
|
22
|
+
mcpbridgeapp --http [port] run as an HTTP server on 127.0.0.1 (default port 8808)
|
|
23
|
+
mcpbridgeapp --agents print the configured agents and whether each is usable
|
|
24
|
+
mcpbridgeapp --ask <agent> <prompt>
|
|
25
|
+
delegate once from the terminal, to check an agent works
|
|
26
|
+
before wiring it into a client
|
|
27
|
+
mcpbridgeapp --example-config print a starter config; JSON on stdout, notes on stderr
|
|
28
|
+
mcpbridgeapp ui [--port N] [--no-open]
|
|
29
|
+
open a control panel on this computer: add agents and
|
|
30
|
+
their keys, test them, connect to the relay, all without
|
|
31
|
+
a terminal
|
|
32
|
+
mcpbridgeapp connect --relay <url> --token <token> [--device <name>]
|
|
33
|
+
keep this machine connected to a hosted relay, so clients
|
|
34
|
+
anywhere can delegate to the CLIs signed in here
|
|
35
|
+
mcpbridgeapp --help
|
|
36
|
+
|
|
37
|
+
Register it with a client once, e.g.
|
|
38
|
+
|
|
39
|
+
claude mcp add -s user mcpbridgeapp -- npx -y @mcpbridgeapp/cli
|
|
40
|
+
|
|
41
|
+
Agents come from ${configPath()} when it exists, otherwise from built-in defaults.
|
|
42
|
+
`;
|
|
43
|
+
async function main() {
|
|
44
|
+
const argv = process.argv.slice(2);
|
|
45
|
+
if (argv.includes('--help') || argv.includes('-h')) {
|
|
46
|
+
process.stdout.write(USAGE);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (argv.includes('--example-config')) {
|
|
50
|
+
printExampleConfig();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// keys and the relay token saved from `mcpbridgeapp ui` work in every command and window
|
|
54
|
+
let secrets = { keys: {} };
|
|
55
|
+
try {
|
|
56
|
+
secrets = loadSecrets();
|
|
57
|
+
applySecretsToEnv(secrets);
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.error(`ignoring saved keys: ${error.message}`);
|
|
61
|
+
}
|
|
62
|
+
if (argv[0] === 'ui') {
|
|
63
|
+
const portFlag = flag(argv, '--port');
|
|
64
|
+
const port = portFlag === undefined ? 8809 : Number(portFlag);
|
|
65
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
66
|
+
console.error(`not a usable port: ${portFlag}`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const ui = await startUi({ port, agentVersion: VERSION });
|
|
71
|
+
console.error(`mcpbridgeapp control panel: ${ui.url}`);
|
|
72
|
+
console.error('Keep this window open while you use it; Ctrl+C stops the page and the relay connection.');
|
|
73
|
+
if (!argv.includes('--no-open'))
|
|
74
|
+
openInBrowser(ui.url);
|
|
75
|
+
const stop = () => void ui.close().then(() => process.exit(0));
|
|
76
|
+
process.on('SIGINT', stop);
|
|
77
|
+
process.on('SIGTERM', stop);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const { config, source } = loadConfig();
|
|
81
|
+
const registry = new AgentRegistry(config);
|
|
82
|
+
const limit = new ConcurrencyLimit(config.maxConcurrent);
|
|
83
|
+
const tasks = new TaskStore(limit);
|
|
84
|
+
if (argv.includes('--agents')) {
|
|
85
|
+
process.stdout.write(`agents from ${source}\n\n`);
|
|
86
|
+
for (const status of await registry.statuses()) {
|
|
87
|
+
process.stdout.write(`${status.available ? '✓' : '✗'} ${status.name.padEnd(10)} ${status.detail}\n`);
|
|
88
|
+
// only meaningful for an agent that can actually be used
|
|
89
|
+
if (status.available && !status.readsFiles) {
|
|
90
|
+
process.stdout.write(`${''.padEnd(13)}cannot read files — inline context in the prompt\n`);
|
|
91
|
+
}
|
|
92
|
+
else if (status.available) {
|
|
93
|
+
const may = [status.writesFiles ? 'edit files' : '', status.runsCommands ? 'run commands' : ''].filter(Boolean);
|
|
94
|
+
process.stdout.write(`${''.padEnd(13)}${may.length ? `may ${may.join(' and ')}` : 'read-only: reads and reports, cannot edit or run anything'}\n`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const askIndex = argv.indexOf('--ask');
|
|
100
|
+
if (askIndex !== -1) {
|
|
101
|
+
const name = argv[askIndex + 1];
|
|
102
|
+
const prompt = argv.slice(askIndex + 2).join(' ');
|
|
103
|
+
if (!name || !prompt) {
|
|
104
|
+
console.error('usage: mcpbridgeapp --ask <agent> <prompt>');
|
|
105
|
+
process.exitCode = 1;
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const agent = registry.find(name);
|
|
109
|
+
if (!agent) {
|
|
110
|
+
console.error(`no agent named "${name}". Available: ${registry.names().join(', ')}`);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
process.stderr.write(`asking ${agent.name}...\n`);
|
|
115
|
+
const result = await limit.run(() => agent.run(prompt, { cwd: process.cwd() }));
|
|
116
|
+
if (result.output)
|
|
117
|
+
process.stdout.write(`${result.output}\n`);
|
|
118
|
+
if (result.notes)
|
|
119
|
+
process.stderr.write(`\nnote: ${result.notes}\n`);
|
|
120
|
+
if (!result.succeeded) {
|
|
121
|
+
process.stderr.write(`\nfailed after ${result.durationMs}ms: ${result.diagnostics}\n`);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
process.stderr.write(`\nok in ${result.durationMs}ms\n`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (argv[0] === 'connect') {
|
|
129
|
+
// flags, then the environment, then what `mcpbridgeapp ui` saved
|
|
130
|
+
const relay = flag(argv, '--relay') ?? process.env['MCPBRIDGE_RELAY'] ?? secrets.relay?.url;
|
|
131
|
+
const token = flag(argv, '--token') ?? process.env['MCPBRIDGE_TOKEN'] ?? secrets.relay?.token;
|
|
132
|
+
const device = flag(argv, '--device') ?? process.env['MCPBRIDGE_DEVICE'] ?? secrets.relay?.device;
|
|
133
|
+
if (!relay || !token) {
|
|
134
|
+
console.error('usage: mcpbridgeapp connect --relay <url> --token <token> [--device <name>]');
|
|
135
|
+
console.error(' (or set MCPBRIDGE_RELAY and MCPBRIDGE_TOKEN, or save them once in `mcpbridgeapp ui`)');
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const controller = new AbortController();
|
|
140
|
+
process.on('SIGINT', () => controller.abort());
|
|
141
|
+
process.on('SIGTERM', () => controller.abort());
|
|
142
|
+
console.error(`mcpbridgeapp connecting to ${relay}, agents from ${source}`);
|
|
143
|
+
await connectToRelay({
|
|
144
|
+
relayUrl: relay,
|
|
145
|
+
token,
|
|
146
|
+
...(device ? { device } : {}),
|
|
147
|
+
agentVersion: VERSION,
|
|
148
|
+
context: { registry, tasks, limit },
|
|
149
|
+
signal: controller.signal,
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const httpIndex = argv.indexOf('--http');
|
|
154
|
+
// anything left over is a mistake -- a typo, or a command this version does not have yet.
|
|
155
|
+
// Falling through to the stdio server would look like it worked while doing nothing asked.
|
|
156
|
+
const leftover = httpIndex === -1 ? argv : argv.filter((_, i) => i !== httpIndex && i !== httpIndex + 1);
|
|
157
|
+
if (leftover.length > 0) {
|
|
158
|
+
console.error(`mcpbridgeapp: unknown command or option: ${leftover.join(' ')}`);
|
|
159
|
+
console.error('Run `mcpbridgeapp --help` for the commands this version has. An older checkout may');
|
|
160
|
+
console.error('not have them yet: update it (git pull, then npm install) or use npx -y @mcpbridgeapp/cli.');
|
|
161
|
+
process.exitCode = 2;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (httpIndex === -1) {
|
|
165
|
+
// stdio: the transport owns stdout, so every diagnostic must go to stderr or it
|
|
166
|
+
// corrupts the protocol stream
|
|
167
|
+
console.error(`mcpbridgeapp on stdio, agents from ${source}`);
|
|
168
|
+
await createServer(registry, tasks, limit).connect(new StdioServerTransport());
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const port = Number(argv[httpIndex + 1] ?? 8808);
|
|
172
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
173
|
+
console.error(`not a usable port: ${argv[httpIndex + 1]}`);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// Stateless: sessionIdGenerator is omitted, so nothing is kept between requests and a
|
|
178
|
+
// fresh server per request is correct.
|
|
179
|
+
const http = createHttpServer((req, res) => {
|
|
180
|
+
void (async () => {
|
|
181
|
+
if (!req.url?.startsWith('/mcp')) {
|
|
182
|
+
res.writeHead(404).end();
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const transport = new StreamableHTTPServerTransport({
|
|
186
|
+
// Loopback binding alone does not protect this server: a web page the user
|
|
187
|
+
// visits can make their browser POST to 127.0.0.1, which would run ask_agent
|
|
188
|
+
// on their machine. Rejecting unexpected Host headers is what stops that.
|
|
189
|
+
enableDnsRebindingProtection: true,
|
|
190
|
+
allowedHosts: [`127.0.0.1:${port}`, `localhost:${port}`],
|
|
191
|
+
});
|
|
192
|
+
res.on('close', () => void transport.close());
|
|
193
|
+
await createServer(registry, tasks, limit).connect(transport);
|
|
194
|
+
await transport.handleRequest(req, res);
|
|
195
|
+
})().catch((error) => {
|
|
196
|
+
console.error('request failed:', error.message);
|
|
197
|
+
if (!res.headersSent)
|
|
198
|
+
res.writeHead(500).end();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
// Loopback only: reaching this server means running the configured commands, so a
|
|
202
|
+
// socket on 0.0.0.0 would hand that to the whole network.
|
|
203
|
+
http.listen(port, '127.0.0.1', () => {
|
|
204
|
+
console.error(`mcpbridgeapp on http://127.0.0.1:${port}/mcp, agents from ${source}`);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* JSON on stdout, guidance on stderr, so `mcpbridgeapp --example-config > config.json` writes
|
|
209
|
+
* a usable file while the person still sees what to fill in.
|
|
210
|
+
*/
|
|
211
|
+
function printExampleConfig() {
|
|
212
|
+
const example = {
|
|
213
|
+
maxConcurrent: 2,
|
|
214
|
+
maxOutputChars: 60_000,
|
|
215
|
+
agents: {
|
|
216
|
+
claude: { command: ['claude', '-p'], promptVia: 'stdin', timeoutMs: 300_000 },
|
|
217
|
+
gemini: { command: ['gemini', '-p', '{prompt}'], timeoutMs: 300_000 },
|
|
218
|
+
local: { type: 'ollama', description: 'A model running in Ollama' },
|
|
219
|
+
grok: {
|
|
220
|
+
type: 'openai',
|
|
221
|
+
description: 'Grok, via the xAI API — no CLI exists, so this is the only route',
|
|
222
|
+
baseUrl: 'https://api.x.ai/v1',
|
|
223
|
+
apiKeyEnv: 'XAI_API_KEY',
|
|
224
|
+
},
|
|
225
|
+
openrouter: {
|
|
226
|
+
type: 'openai',
|
|
227
|
+
description: 'One key, many providers',
|
|
228
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
229
|
+
apiKeyEnv: 'OPENROUTER_API_KEY',
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
process.stdout.write(`${JSON.stringify(example, null, 2)}\n`);
|
|
234
|
+
process.stderr.write([
|
|
235
|
+
'',
|
|
236
|
+
`Save this to ${configPath()} and edit it.`,
|
|
237
|
+
'',
|
|
238
|
+
'The CLI agents need nothing but the tool installed and signed in.',
|
|
239
|
+
'The "openai" agents need a key, exported under the name in apiKeyEnv — never put the',
|
|
240
|
+
'key in this file, which is easy to copy into a repo or an issue by accident.',
|
|
241
|
+
'',
|
|
242
|
+
'The "openai" agents have no model set, so they report unavailable until you add one.',
|
|
243
|
+
'With the key exported, `mcpbridgeapp --agents` lists the ids that endpoint offers, where',
|
|
244
|
+
'the provider exposes a listing; otherwise take one from its documentation.',
|
|
245
|
+
'',
|
|
246
|
+
].join('\n'));
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Best effort: the address is printed either way. On Windows this goes through the URL
|
|
250
|
+
* protocol handler rather than `cmd /c start`, so nothing in the address meets cmd.exe.
|
|
251
|
+
*/
|
|
252
|
+
function openInBrowser(url) {
|
|
253
|
+
const [command, args] = process.platform === 'win32' ? ['rundll32', ['url.dll,FileProtocolHandler', url]]
|
|
254
|
+
: process.platform === 'darwin' ? ['open', [url]]
|
|
255
|
+
: ['xdg-open', [url]];
|
|
256
|
+
try {
|
|
257
|
+
const child = spawn(command, args, { detached: true, stdio: 'ignore' });
|
|
258
|
+
child.on('error', () => { });
|
|
259
|
+
child.unref();
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// same
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
main().catch((error) => {
|
|
266
|
+
console.error(`mcpbridgeapp failed to start: ${error.message}`);
|
|
267
|
+
process.exitCode = 1;
|
|
268
|
+
});
|
|
269
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/limit.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caps how many delegations run at once. Each one is a full model doing real work, so an
|
|
3
|
+
* unbounded number of them saturates the machine and spends the quota of whatever account
|
|
4
|
+
* is behind them — and a caller that decides to ask five agents at once has no idea how
|
|
5
|
+
* expensive that is.
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConcurrencyLimit {
|
|
8
|
+
private readonly max;
|
|
9
|
+
private active;
|
|
10
|
+
private readonly waiting;
|
|
11
|
+
constructor(max: number);
|
|
12
|
+
get queueDepth(): number;
|
|
13
|
+
run<T>(work: () => Promise<T>): Promise<T>;
|
|
14
|
+
}
|
package/dist/limit.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caps how many delegations run at once. Each one is a full model doing real work, so an
|
|
3
|
+
* unbounded number of them saturates the machine and spends the quota of whatever account
|
|
4
|
+
* is behind them — and a caller that decides to ask five agents at once has no idea how
|
|
5
|
+
* expensive that is.
|
|
6
|
+
*/
|
|
7
|
+
export class ConcurrencyLimit {
|
|
8
|
+
max;
|
|
9
|
+
active = 0;
|
|
10
|
+
waiting = [];
|
|
11
|
+
constructor(max) {
|
|
12
|
+
this.max = max;
|
|
13
|
+
if (max < 1)
|
|
14
|
+
throw new Error('maxConcurrent must be at least 1');
|
|
15
|
+
}
|
|
16
|
+
get queueDepth() {
|
|
17
|
+
return this.waiting.length;
|
|
18
|
+
}
|
|
19
|
+
async run(work) {
|
|
20
|
+
if (this.active >= this.max) {
|
|
21
|
+
await new Promise((resolve) => this.waiting.push(resolve));
|
|
22
|
+
}
|
|
23
|
+
this.active += 1;
|
|
24
|
+
try {
|
|
25
|
+
return await work();
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
this.active -= 1;
|
|
29
|
+
this.waiting.shift()?.();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"limit.js","sourceRoot":"","sources":["../src/limit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,OAAO,gBAAgB;IAIE;IAHrB,MAAM,GAAG,CAAC,CAAC;IACF,OAAO,GAAmB,EAAE,CAAC;IAE9C,YAA6B,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QACtC,IAAI,GAAG,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAsB;QACjC,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The wire protocol between a local agent (`mcpbridgeapp connect`, running where the AI CLIs
|
|
4
|
+
* are signed in) and a relay (the hosted endpoint clients talk to). JSON messages over a
|
|
5
|
+
* WebSocket the agent opens outbound, so nothing on the user's machine listens.
|
|
6
|
+
*
|
|
7
|
+
* The relay only ever forwards: it never sees a credential, only prompts and answers.
|
|
8
|
+
*/
|
|
9
|
+
export declare const PROTOCOL_VERSION: 1;
|
|
10
|
+
export declare const AgentStatusSchema: z.ZodObject<{
|
|
11
|
+
name: z.ZodString;
|
|
12
|
+
description: z.ZodString;
|
|
13
|
+
requires: z.ZodString;
|
|
14
|
+
available: z.ZodBoolean;
|
|
15
|
+
readsFiles: z.ZodBoolean;
|
|
16
|
+
detail: z.ZodString;
|
|
17
|
+
status: z.ZodOptional<z.ZodString>;
|
|
18
|
+
writesFiles: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
runsCommands: z.ZodOptional<z.ZodBoolean>;
|
|
20
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
22
|
+
lastErrorAt: z.ZodOptional<z.ZodString>;
|
|
23
|
+
retryAt: z.ZodOptional<z.ZodString>;
|
|
24
|
+
lastSuccessAt: z.ZodOptional<z.ZodString>;
|
|
25
|
+
calls: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export type AgentStatus = z.infer<typeof AgentStatusSchema>;
|
|
28
|
+
export declare const TOOL_NAME: z.ZodEnum<{
|
|
29
|
+
list_agents: "list_agents";
|
|
30
|
+
ask_agent: "ask_agent";
|
|
31
|
+
start_task: "start_task";
|
|
32
|
+
get_task: "get_task";
|
|
33
|
+
}>;
|
|
34
|
+
/** First message after the socket opens. */
|
|
35
|
+
export declare const HelloMessage: z.ZodObject<{
|
|
36
|
+
type: z.ZodLiteral<"hello">;
|
|
37
|
+
protocol: z.ZodLiteral<1>;
|
|
38
|
+
agentVersion: z.ZodString;
|
|
39
|
+
device: z.ZodString;
|
|
40
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
41
|
+
name: z.ZodString;
|
|
42
|
+
description: z.ZodString;
|
|
43
|
+
requires: z.ZodString;
|
|
44
|
+
available: z.ZodBoolean;
|
|
45
|
+
readsFiles: z.ZodBoolean;
|
|
46
|
+
detail: z.ZodString;
|
|
47
|
+
status: z.ZodOptional<z.ZodString>;
|
|
48
|
+
writesFiles: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
runsCommands: z.ZodOptional<z.ZodBoolean>;
|
|
50
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
51
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
52
|
+
lastErrorAt: z.ZodOptional<z.ZodString>;
|
|
53
|
+
retryAt: z.ZodOptional<z.ZodString>;
|
|
54
|
+
lastSuccessAt: z.ZodOptional<z.ZodString>;
|
|
55
|
+
calls: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
}, z.core.$strip>>;
|
|
57
|
+
}, z.core.$strip>;
|
|
58
|
+
/** A refreshed agent list, so a dashboard can show what is installed without a call. */
|
|
59
|
+
export declare const AgentsMessage: z.ZodObject<{
|
|
60
|
+
type: z.ZodLiteral<"agents">;
|
|
61
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
62
|
+
name: z.ZodString;
|
|
63
|
+
description: z.ZodString;
|
|
64
|
+
requires: z.ZodString;
|
|
65
|
+
available: z.ZodBoolean;
|
|
66
|
+
readsFiles: z.ZodBoolean;
|
|
67
|
+
detail: z.ZodString;
|
|
68
|
+
status: z.ZodOptional<z.ZodString>;
|
|
69
|
+
writesFiles: z.ZodOptional<z.ZodBoolean>;
|
|
70
|
+
runsCommands: z.ZodOptional<z.ZodBoolean>;
|
|
71
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
72
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
73
|
+
lastErrorAt: z.ZodOptional<z.ZodString>;
|
|
74
|
+
retryAt: z.ZodOptional<z.ZodString>;
|
|
75
|
+
lastSuccessAt: z.ZodOptional<z.ZodString>;
|
|
76
|
+
calls: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
}, z.core.$strip>>;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
/** The answer to a call. `ok: false` means the tool itself threw; `payload` is the message. */
|
|
80
|
+
export declare const ResultMessage: z.ZodObject<{
|
|
81
|
+
type: z.ZodLiteral<"result">;
|
|
82
|
+
id: z.ZodString;
|
|
83
|
+
ok: z.ZodBoolean;
|
|
84
|
+
payload: z.ZodUnknown;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
export declare const AgentToRelay: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
87
|
+
type: z.ZodLiteral<"hello">;
|
|
88
|
+
protocol: z.ZodLiteral<1>;
|
|
89
|
+
agentVersion: z.ZodString;
|
|
90
|
+
device: z.ZodString;
|
|
91
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
92
|
+
name: z.ZodString;
|
|
93
|
+
description: z.ZodString;
|
|
94
|
+
requires: z.ZodString;
|
|
95
|
+
available: z.ZodBoolean;
|
|
96
|
+
readsFiles: z.ZodBoolean;
|
|
97
|
+
detail: z.ZodString;
|
|
98
|
+
status: z.ZodOptional<z.ZodString>;
|
|
99
|
+
writesFiles: z.ZodOptional<z.ZodBoolean>;
|
|
100
|
+
runsCommands: z.ZodOptional<z.ZodBoolean>;
|
|
101
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
102
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
103
|
+
lastErrorAt: z.ZodOptional<z.ZodString>;
|
|
104
|
+
retryAt: z.ZodOptional<z.ZodString>;
|
|
105
|
+
lastSuccessAt: z.ZodOptional<z.ZodString>;
|
|
106
|
+
calls: z.ZodOptional<z.ZodNumber>;
|
|
107
|
+
}, z.core.$strip>>;
|
|
108
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
109
|
+
type: z.ZodLiteral<"agents">;
|
|
110
|
+
agents: z.ZodArray<z.ZodObject<{
|
|
111
|
+
name: z.ZodString;
|
|
112
|
+
description: z.ZodString;
|
|
113
|
+
requires: z.ZodString;
|
|
114
|
+
available: z.ZodBoolean;
|
|
115
|
+
readsFiles: z.ZodBoolean;
|
|
116
|
+
detail: z.ZodString;
|
|
117
|
+
status: z.ZodOptional<z.ZodString>;
|
|
118
|
+
writesFiles: z.ZodOptional<z.ZodBoolean>;
|
|
119
|
+
runsCommands: z.ZodOptional<z.ZodBoolean>;
|
|
120
|
+
timeoutSeconds: z.ZodOptional<z.ZodNumber>;
|
|
121
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
122
|
+
lastErrorAt: z.ZodOptional<z.ZodString>;
|
|
123
|
+
retryAt: z.ZodOptional<z.ZodString>;
|
|
124
|
+
lastSuccessAt: z.ZodOptional<z.ZodString>;
|
|
125
|
+
calls: z.ZodOptional<z.ZodNumber>;
|
|
126
|
+
}, z.core.$strip>>;
|
|
127
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
128
|
+
type: z.ZodLiteral<"result">;
|
|
129
|
+
id: z.ZodString;
|
|
130
|
+
ok: z.ZodBoolean;
|
|
131
|
+
payload: z.ZodUnknown;
|
|
132
|
+
}, z.core.$strip>], "type">;
|
|
133
|
+
export type AgentToRelay = z.infer<typeof AgentToRelay>;
|
|
134
|
+
export declare const WelcomeMessage: z.ZodObject<{
|
|
135
|
+
type: z.ZodLiteral<"welcome">;
|
|
136
|
+
device: z.ZodString;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
export declare const CallMessage: z.ZodObject<{
|
|
139
|
+
type: z.ZodLiteral<"call">;
|
|
140
|
+
id: z.ZodString;
|
|
141
|
+
tool: z.ZodEnum<{
|
|
142
|
+
list_agents: "list_agents";
|
|
143
|
+
ask_agent: "ask_agent";
|
|
144
|
+
start_task: "start_task";
|
|
145
|
+
get_task: "get_task";
|
|
146
|
+
}>;
|
|
147
|
+
args: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
148
|
+
}, z.core.$strip>;
|
|
149
|
+
/** Sent before the relay closes the socket on purpose, so the agent knows not to retry. */
|
|
150
|
+
export declare const GoodbyeMessage: z.ZodObject<{
|
|
151
|
+
type: z.ZodLiteral<"goodbye">;
|
|
152
|
+
reason: z.ZodString;
|
|
153
|
+
retry: z.ZodBoolean;
|
|
154
|
+
}, z.core.$strip>;
|
|
155
|
+
export declare const RelayToAgent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
156
|
+
type: z.ZodLiteral<"welcome">;
|
|
157
|
+
device: z.ZodString;
|
|
158
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
159
|
+
type: z.ZodLiteral<"call">;
|
|
160
|
+
id: z.ZodString;
|
|
161
|
+
tool: z.ZodEnum<{
|
|
162
|
+
list_agents: "list_agents";
|
|
163
|
+
ask_agent: "ask_agent";
|
|
164
|
+
start_task: "start_task";
|
|
165
|
+
get_task: "get_task";
|
|
166
|
+
}>;
|
|
167
|
+
args: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
168
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
169
|
+
type: z.ZodLiteral<"goodbye">;
|
|
170
|
+
reason: z.ZodString;
|
|
171
|
+
retry: z.ZodBoolean;
|
|
172
|
+
}, z.core.$strip>], "type">;
|
|
173
|
+
export type RelayToAgent = z.infer<typeof RelayToAgent>;
|
|
174
|
+
export declare function parseAgentMessage(raw: string): AgentToRelay | null;
|
|
175
|
+
export declare function parseRelayMessage(raw: string): RelayToAgent | null;
|