@agimon-ai/mcp-proxy 0.4.4 → 0.4.6
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/dist/cli.cjs +215 -173
- package/dist/cli.mjs +215 -173
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-G1hs2GLZ.cjs → src-B2m53VQ1.cjs} +1 -1
- package/dist/{src-0OJqEpGA.mjs → src-DCIv5S_2.mjs} +1 -1
- package/package.json +4 -4
package/dist/cli.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_src = require('./src-
|
|
2
|
+
const require_src = require('./src-B2m53VQ1.cjs');
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_fs_promises = require("node:fs/promises");
|
|
5
5
|
let node_path = require("node:path");
|
|
@@ -8,8 +8,8 @@ let node_fs = require("node:fs");
|
|
|
8
8
|
let liquidjs = require("liquidjs");
|
|
9
9
|
let node_child_process = require("node:child_process");
|
|
10
10
|
let commander = require("commander");
|
|
11
|
-
let __agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
|
|
12
11
|
let __agimon_ai_foundation_port_registry = require("@agimon-ai/foundation-port-registry");
|
|
12
|
+
let __agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
|
|
13
13
|
let node_url = require("node:url");
|
|
14
14
|
|
|
15
15
|
//#region src/utils/output.ts
|
|
@@ -113,6 +113,169 @@ const initCommand = new commander.Command("init").description("Initialize MCP co
|
|
|
113
113
|
}
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
//#endregion
|
|
117
|
+
//#region src/commands/prestart-http.ts
|
|
118
|
+
/**
|
|
119
|
+
* Prestart HTTP Command
|
|
120
|
+
*
|
|
121
|
+
* Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
|
|
122
|
+
* and then exits so the runtime can be reused by other commands.
|
|
123
|
+
*/
|
|
124
|
+
const WORKSPACE_MARKERS = [
|
|
125
|
+
"pnpm-workspace.yaml",
|
|
126
|
+
"nx.json",
|
|
127
|
+
".git"
|
|
128
|
+
];
|
|
129
|
+
const DEFAULT_HOST$1 = "localhost";
|
|
130
|
+
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
131
|
+
const POLL_INTERVAL_MS = 250;
|
|
132
|
+
function resolveWorkspaceRoot(startPath = process.env.PROJECT_PATH || process.cwd()) {
|
|
133
|
+
let current = node_path.default.resolve(startPath);
|
|
134
|
+
while (true) {
|
|
135
|
+
for (const marker of WORKSPACE_MARKERS) if ((0, node_fs.existsSync)(node_path.default.join(current, marker))) return current;
|
|
136
|
+
const parent = node_path.default.dirname(current);
|
|
137
|
+
if (parent === current) return process.cwd();
|
|
138
|
+
current = parent;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function resolveSiblingRegistryPath(registryPath, fileName) {
|
|
142
|
+
if (!registryPath) return;
|
|
143
|
+
const resolved = node_path.default.resolve(registryPath);
|
|
144
|
+
if (node_path.default.extname(resolved) === ".json") return node_path.default.join(node_path.default.dirname(resolved), fileName);
|
|
145
|
+
return node_path.default.join(resolved, fileName);
|
|
146
|
+
}
|
|
147
|
+
function buildCliCandidates() {
|
|
148
|
+
const __filename$1 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
149
|
+
const __dirname$1 = node_path.default.dirname(__filename$1);
|
|
150
|
+
const distCandidates = [
|
|
151
|
+
node_path.default.resolve(__dirname$1, "cli.mjs"),
|
|
152
|
+
node_path.default.resolve(__dirname$1, "..", "dist", "cli.mjs"),
|
|
153
|
+
node_path.default.resolve(__dirname$1, "..", "..", "dist", "cli.mjs")
|
|
154
|
+
];
|
|
155
|
+
const srcCandidates = [node_path.default.resolve(__dirname$1, "..", "cli.ts"), node_path.default.resolve(__dirname$1, "..", "..", "src", "cli.ts")];
|
|
156
|
+
for (const candidate of distCandidates) if ((0, node_fs.existsSync)(candidate)) return {
|
|
157
|
+
command: process.execPath,
|
|
158
|
+
args: [candidate]
|
|
159
|
+
};
|
|
160
|
+
for (const candidate of srcCandidates) if ((0, node_fs.existsSync)(candidate)) return {
|
|
161
|
+
command: process.execPath,
|
|
162
|
+
args: [
|
|
163
|
+
"--import",
|
|
164
|
+
"tsx",
|
|
165
|
+
candidate
|
|
166
|
+
]
|
|
167
|
+
};
|
|
168
|
+
throw new Error("Unable to locate mcp-proxy CLI entrypoint");
|
|
169
|
+
}
|
|
170
|
+
function parseTimeoutMs(value) {
|
|
171
|
+
if (!value) return DEFAULT_TIMEOUT_MS;
|
|
172
|
+
const parsed = Number.parseInt(value, 10);
|
|
173
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
|
|
174
|
+
return parsed;
|
|
175
|
+
}
|
|
176
|
+
async function waitForFile(filePath, timeoutMs) {
|
|
177
|
+
const deadline = Date.now() + timeoutMs;
|
|
178
|
+
while (Date.now() < deadline) {
|
|
179
|
+
try {
|
|
180
|
+
await (0, node_fs_promises.access)(filePath);
|
|
181
|
+
return;
|
|
182
|
+
} catch {}
|
|
183
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, POLL_INTERVAL_MS));
|
|
184
|
+
}
|
|
185
|
+
throw new Error(`Timed out waiting for runtime state file: ${filePath}`);
|
|
186
|
+
}
|
|
187
|
+
async function waitForHealthyRuntime(serverId, timeoutMs) {
|
|
188
|
+
const runtimeStateService = new require_src.RuntimeStateService();
|
|
189
|
+
const deadline = Date.now() + timeoutMs;
|
|
190
|
+
while (Date.now() < deadline) {
|
|
191
|
+
const record = await runtimeStateService.read(serverId);
|
|
192
|
+
if (record) {
|
|
193
|
+
const healthUrl = `http://${record.host}:${record.port}/health`;
|
|
194
|
+
try {
|
|
195
|
+
const response = await fetch(healthUrl);
|
|
196
|
+
if (response.ok) {
|
|
197
|
+
const payload = await response.json().catch(() => null);
|
|
198
|
+
if (!payload || payload.transport === "http") return {
|
|
199
|
+
host: record.host,
|
|
200
|
+
port: record.port
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
} catch {}
|
|
204
|
+
}
|
|
205
|
+
await new Promise((resolve$2) => setTimeout(resolve$2, POLL_INTERVAL_MS));
|
|
206
|
+
}
|
|
207
|
+
throw new Error(`Timed out waiting for HTTP runtime '${serverId}' to become healthy`);
|
|
208
|
+
}
|
|
209
|
+
function spawnBackgroundRuntime(args, env, cwd) {
|
|
210
|
+
const { command, args: baseArgs } = buildCliCandidates();
|
|
211
|
+
const child = (0, node_child_process.spawn)(command, [...baseArgs, ...args], {
|
|
212
|
+
detached: true,
|
|
213
|
+
cwd,
|
|
214
|
+
stdio: "ignore",
|
|
215
|
+
env
|
|
216
|
+
});
|
|
217
|
+
child.unref();
|
|
218
|
+
return child;
|
|
219
|
+
}
|
|
220
|
+
async function prestartHttpRuntime(options) {
|
|
221
|
+
const serverId = options.id || require_src.generateServerId();
|
|
222
|
+
const timeoutMs = parseTimeoutMs(options.timeoutMs);
|
|
223
|
+
const registryPath = options.registryPath || options.registryDir;
|
|
224
|
+
const workspaceRoot = resolveWorkspaceRoot();
|
|
225
|
+
const childEnv = {
|
|
226
|
+
...process.env,
|
|
227
|
+
...registryPath ? {
|
|
228
|
+
PORT_REGISTRY_PATH: registryPath,
|
|
229
|
+
PROCESS_REGISTRY_PATH: resolveSiblingRegistryPath(registryPath, "processes.json")
|
|
230
|
+
} : {}
|
|
231
|
+
};
|
|
232
|
+
const child = spawnBackgroundRuntime([
|
|
233
|
+
"mcp-serve",
|
|
234
|
+
"--type",
|
|
235
|
+
"http",
|
|
236
|
+
"--id",
|
|
237
|
+
serverId,
|
|
238
|
+
"--host",
|
|
239
|
+
options.host || DEFAULT_HOST$1,
|
|
240
|
+
...options.port !== void 0 ? ["--port", String(options.port)] : [],
|
|
241
|
+
...options.config ? ["--config", options.config] : [],
|
|
242
|
+
...options.cache === false ? ["--no-cache"] : [],
|
|
243
|
+
...options.definitionsCache ? ["--definitions-cache", options.definitionsCache] : [],
|
|
244
|
+
...options.clearDefinitionsCache ? ["--clear-definitions-cache"] : [],
|
|
245
|
+
"--proxy-mode",
|
|
246
|
+
options.proxyMode
|
|
247
|
+
], childEnv, workspaceRoot);
|
|
248
|
+
const childExit = new Promise((_, reject) => {
|
|
249
|
+
child.once("exit", (code, signal) => {
|
|
250
|
+
reject(/* @__PURE__ */ new Error(`Background runtime exited before becoming healthy (code=${code ?? "null"}, signal=${signal ?? "null"})`));
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
const runtimeFile = node_path.default.join(require_src.RuntimeStateService.getDefaultRuntimeDir(), `${serverId}.runtime.json`);
|
|
254
|
+
try {
|
|
255
|
+
await Promise.race([waitForFile(runtimeFile, timeoutMs), childExit]);
|
|
256
|
+
const { host, port } = await Promise.race([waitForHealthyRuntime(serverId, timeoutMs), childExit]);
|
|
257
|
+
return {
|
|
258
|
+
host,
|
|
259
|
+
port,
|
|
260
|
+
serverId,
|
|
261
|
+
workspaceRoot
|
|
262
|
+
};
|
|
263
|
+
} catch (error) {
|
|
264
|
+
throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const prestartHttpCommand = new commander.Command("prestart-http").description("Start an mcp-proxy HTTP runtime in the background and wait until it is healthy").option("--id <id>", "Server identifier to assign to the runtime").option("--host <host>", "Host to bind to", DEFAULT_HOST$1).option("-p, --port <port>", "Preferred HTTP port for the runtime", (value) => Number.parseInt(value, 10)).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--registry-path <path>", "Custom registry path or directory for service discovery").option("--registry-dir <path>", "Custom registry directory for service discovery").option("--timeout-ms <ms>", "How long to wait for the runtime to become healthy", String(DEFAULT_TIMEOUT_MS)).action(async (options) => {
|
|
268
|
+
try {
|
|
269
|
+
const { host, port, serverId, workspaceRoot } = await prestartHttpRuntime(options);
|
|
270
|
+
process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
|
|
271
|
+
process.stdout.write(`runtimeId=${serverId}\n`);
|
|
272
|
+
process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
|
|
273
|
+
process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
throw new Error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${error instanceof Error ? error.message : String(error)}`);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
116
279
|
//#endregion
|
|
117
280
|
//#region src/commands/mcp-serve.ts
|
|
118
281
|
/**
|
|
@@ -141,7 +304,7 @@ const CONFIG_FILE_NAMES = [
|
|
|
141
304
|
"mcp-config.json"
|
|
142
305
|
];
|
|
143
306
|
const MCP_ENDPOINT_PATH = "/mcp";
|
|
144
|
-
const DEFAULT_HOST
|
|
307
|
+
const DEFAULT_HOST = "localhost";
|
|
145
308
|
const TRANSPORT_TYPE_STDIO = "stdio";
|
|
146
309
|
const TRANSPORT_TYPE_HTTP = "http";
|
|
147
310
|
const TRANSPORT_TYPE_SSE = "sse";
|
|
@@ -149,10 +312,14 @@ const TRANSPORT_TYPE_STDIO_HTTP = "stdio-http";
|
|
|
149
312
|
const RUNTIME_TRANSPORT = TRANSPORT_TYPE_HTTP;
|
|
150
313
|
const PORT_REGISTRY_SERVICE_HTTP = "mcp-proxy-http";
|
|
151
314
|
const PORT_REGISTRY_SERVICE_TYPE = "service";
|
|
152
|
-
|
|
315
|
+
function getWorkspaceRoot() {
|
|
316
|
+
return resolveWorkspaceRoot();
|
|
317
|
+
}
|
|
153
318
|
const PROCESS_REGISTRY_SERVICE_HTTP = "mcp-proxy-http";
|
|
154
319
|
const PROCESS_REGISTRY_SERVICE_TYPE = "service";
|
|
155
|
-
|
|
320
|
+
function getRegistryRepositoryPath() {
|
|
321
|
+
return getWorkspaceRoot();
|
|
322
|
+
}
|
|
156
323
|
function toErrorMessage$9(error) {
|
|
157
324
|
return error instanceof Error ? error.message : String(error);
|
|
158
325
|
}
|
|
@@ -213,7 +380,23 @@ function createTransportConfig(options, mode) {
|
|
|
213
380
|
return {
|
|
214
381
|
mode,
|
|
215
382
|
port: options.port ?? (Number.isFinite(envPort) ? envPort : void 0),
|
|
216
|
-
host: options.host || process.env.MCP_HOST || DEFAULT_HOST
|
|
383
|
+
host: options.host || process.env.MCP_HOST || DEFAULT_HOST
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function createStdioSafeLogger() {
|
|
387
|
+
const logToStderr = (message, data) => {
|
|
388
|
+
if (data === void 0) {
|
|
389
|
+
console.error(message);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
console.error(message, data);
|
|
393
|
+
};
|
|
394
|
+
return {
|
|
395
|
+
trace: logToStderr,
|
|
396
|
+
debug: logToStderr,
|
|
397
|
+
info: logToStderr,
|
|
398
|
+
warn: logToStderr,
|
|
399
|
+
error: logToStderr
|
|
217
400
|
};
|
|
218
401
|
}
|
|
219
402
|
function createServerOptions(options, resolvedConfigPath, serverId) {
|
|
@@ -234,7 +417,7 @@ function formatStartError(type, host, port, error) {
|
|
|
234
417
|
function createRuntimeRecord(serverId, config, port, shutdownToken, configPath) {
|
|
235
418
|
return {
|
|
236
419
|
serverId,
|
|
237
|
-
host: config.host ?? DEFAULT_HOST
|
|
420
|
+
host: config.host ?? DEFAULT_HOST,
|
|
238
421
|
port,
|
|
239
422
|
transport: RUNTIME_TRANSPORT,
|
|
240
423
|
shutdownToken,
|
|
@@ -258,7 +441,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
258
441
|
} : __agimon_ai_foundation_port_registry.DEFAULT_PORT_RANGE) {
|
|
259
442
|
const portRegistry = createPortRegistryService();
|
|
260
443
|
const result = await portRegistry.reservePort({
|
|
261
|
-
repositoryPath:
|
|
444
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
262
445
|
serviceName,
|
|
263
446
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
264
447
|
environment: getRegistryEnvironment(),
|
|
@@ -284,7 +467,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
284
467
|
if (released) return;
|
|
285
468
|
released = true;
|
|
286
469
|
const releaseResult = await portRegistry.releasePort({
|
|
287
|
-
repositoryPath:
|
|
470
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
288
471
|
serviceName,
|
|
289
472
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
290
473
|
pid: process.pid,
|
|
@@ -298,7 +481,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
298
481
|
async function createProcessRegistryLease(serviceName, host, port, serverId, transport, configPath) {
|
|
299
482
|
const processRegistry = createProcessRegistryService();
|
|
300
483
|
const result = await processRegistry.registerProcess({
|
|
301
|
-
repositoryPath:
|
|
484
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
302
485
|
serviceName,
|
|
303
486
|
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
304
487
|
environment: getRegistryEnvironment(),
|
|
@@ -319,7 +502,7 @@ async function createProcessRegistryLease(serviceName, host, port, serverId, tra
|
|
|
319
502
|
if (released) return;
|
|
320
503
|
released = true;
|
|
321
504
|
const releaseResult = await processRegistry.releaseProcess({
|
|
322
|
-
repositoryPath:
|
|
505
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
323
506
|
serviceName,
|
|
324
507
|
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
325
508
|
pid: process.pid,
|
|
@@ -420,13 +603,13 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
420
603
|
min: requestedPort,
|
|
421
604
|
max: requestedPort
|
|
422
605
|
} : __agimon_ai_foundation_port_registry.DEFAULT_PORT_RANGE;
|
|
423
|
-
const portLease = await createPortRegistryLease(PORT_REGISTRY_SERVICE_HTTP, config.host ?? DEFAULT_HOST
|
|
606
|
+
const portLease = await createPortRegistryLease(PORT_REGISTRY_SERVICE_HTTP, config.host ?? DEFAULT_HOST, requestedPort, runtimeServerId, TRANSPORT_TYPE_HTTP, resolvedConfigPath, portRange);
|
|
424
607
|
const runtimePort = portLease.port;
|
|
425
608
|
const runtimeConfig = {
|
|
426
609
|
...config,
|
|
427
610
|
port: runtimePort
|
|
428
611
|
};
|
|
429
|
-
const processLease = await createProcessRegistryLease(PROCESS_REGISTRY_SERVICE_HTTP, runtimeConfig.host ?? DEFAULT_HOST
|
|
612
|
+
const processLease = await createProcessRegistryLease(PROCESS_REGISTRY_SERVICE_HTTP, runtimeConfig.host ?? DEFAULT_HOST, runtimePort, runtimeServerId, TRANSPORT_TYPE_HTTP, resolvedConfigPath);
|
|
430
613
|
let releasePort = async () => {
|
|
431
614
|
await releasePortLease(portLease ?? null);
|
|
432
615
|
releasePort = async () => void 0;
|
|
@@ -482,7 +665,7 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
482
665
|
}
|
|
483
666
|
async function startStdioTransport(serverOptions) {
|
|
484
667
|
try {
|
|
485
|
-
await startServer(new require_src.StdioTransportHandler(await require_src.createServer(serverOptions)));
|
|
668
|
+
await startServer(new require_src.StdioTransportHandler(await require_src.createServer(serverOptions), createStdioSafeLogger()));
|
|
486
669
|
} catch (error) {
|
|
487
670
|
throw new Error(`Failed to start stdio transport: ${toErrorMessage$9(error)}`);
|
|
488
671
|
}
|
|
@@ -494,20 +677,29 @@ async function startSseTransport(serverOptions, config) {
|
|
|
494
677
|
throw new Error(`Failed to start SSE transport: ${toErrorMessage$9(error)}`);
|
|
495
678
|
}
|
|
496
679
|
}
|
|
497
|
-
async function resolveStdioHttpEndpoint(config) {
|
|
498
|
-
|
|
680
|
+
async function resolveStdioHttpEndpoint(config, options, resolvedConfigPath) {
|
|
681
|
+
const repositoryPath = getRegistryRepositoryPath();
|
|
682
|
+
if (config.port !== void 0) return new URL(`http://${config.host ?? DEFAULT_HOST}:${config.port}${MCP_ENDPOINT_PATH}`);
|
|
499
683
|
const result = await createPortRegistryService().getPort({
|
|
500
|
-
repositoryPath
|
|
684
|
+
repositoryPath,
|
|
501
685
|
serviceName: PORT_REGISTRY_SERVICE_HTTP,
|
|
502
686
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
503
687
|
environment: getRegistryEnvironment()
|
|
504
688
|
});
|
|
505
|
-
if (
|
|
506
|
-
|
|
689
|
+
if (result.success && result.record) return new URL(`http://${config.host ?? result.record.host}:${result.record.port}${MCP_ENDPOINT_PATH}`);
|
|
690
|
+
const runtime = await prestartHttpRuntime({
|
|
691
|
+
host: config.host ?? DEFAULT_HOST,
|
|
692
|
+
config: options.config || resolvedConfigPath,
|
|
693
|
+
cache: options.cache,
|
|
694
|
+
definitionsCache: options.definitionsCache,
|
|
695
|
+
clearDefinitionsCache: options.clearDefinitionsCache,
|
|
696
|
+
proxyMode: options.proxyMode
|
|
697
|
+
});
|
|
698
|
+
return new URL(`http://${runtime.host}:${runtime.port}${MCP_ENDPOINT_PATH}`);
|
|
507
699
|
}
|
|
508
|
-
async function startStdioHttpTransport(config) {
|
|
700
|
+
async function startStdioHttpTransport(config, options, resolvedConfigPath) {
|
|
509
701
|
try {
|
|
510
|
-
await startServer(new require_src.StdioHttpTransportHandler({ endpoint: await resolveStdioHttpEndpoint(config) }));
|
|
702
|
+
await startServer(new require_src.StdioHttpTransportHandler({ endpoint: await resolveStdioHttpEndpoint(config, options, resolvedConfigPath) }, createStdioSafeLogger()));
|
|
511
703
|
} catch (error) {
|
|
512
704
|
throw new Error(`Failed to start stdio-http transport: ${toErrorMessage$9(error)}`);
|
|
513
705
|
}
|
|
@@ -526,7 +718,7 @@ async function startTransport(transportType, options, resolvedConfigPath, server
|
|
|
526
718
|
await startSseTransport(serverOptions, createTransportConfig(options, require_src.TRANSPORT_MODE.SSE));
|
|
527
719
|
return;
|
|
528
720
|
}
|
|
529
|
-
await startStdioHttpTransport(createTransportConfig(options, require_src.TRANSPORT_MODE.HTTP));
|
|
721
|
+
await startStdioHttpTransport(createTransportConfig(options, require_src.TRANSPORT_MODE.HTTP), options, resolvedConfigPath);
|
|
530
722
|
} catch (error) {
|
|
531
723
|
throw new Error(`Failed to start transport '${transportType}': ${toErrorMessage$9(error)}`);
|
|
532
724
|
}
|
|
@@ -534,7 +726,7 @@ async function startTransport(transportType, options, resolvedConfigPath, server
|
|
|
534
726
|
/**
|
|
535
727
|
* MCP Serve command
|
|
536
728
|
*/
|
|
537
|
-
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`, TRANSPORT_TYPE_STDIO).option("-p, --port <port>", "Port to listen on (http/sse) or backend port for stdio-http", (val) => parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse) or backend host for stdio-http", DEFAULT_HOST
|
|
729
|
+
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`, TRANSPORT_TYPE_STDIO).option("-p, --port <port>", "Port to listen on (http/sse) or backend port for stdio-http", (val) => Number.parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse) or backend host for stdio-http", DEFAULT_HOST).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--id <id>", "Unique server identifier (overrides config file id, auto-generated if not provided)").action(async (options) => {
|
|
538
730
|
try {
|
|
539
731
|
const transportType = validateTransportType(options.type.toLowerCase());
|
|
540
732
|
validateProxyMode(options.proxyMode);
|
|
@@ -550,156 +742,6 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
|
|
|
550
742
|
}
|
|
551
743
|
});
|
|
552
744
|
|
|
553
|
-
//#endregion
|
|
554
|
-
//#region src/commands/prestart-http.ts
|
|
555
|
-
/**
|
|
556
|
-
* Prestart HTTP Command
|
|
557
|
-
*
|
|
558
|
-
* Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
|
|
559
|
-
* and then exits so the runtime can be reused by other commands.
|
|
560
|
-
*/
|
|
561
|
-
const WORKSPACE_MARKERS = [
|
|
562
|
-
"pnpm-workspace.yaml",
|
|
563
|
-
"nx.json",
|
|
564
|
-
".git"
|
|
565
|
-
];
|
|
566
|
-
const DEFAULT_HOST = "localhost";
|
|
567
|
-
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
568
|
-
const POLL_INTERVAL_MS = 250;
|
|
569
|
-
function resolveWorkspaceRoot(startPath = process.cwd()) {
|
|
570
|
-
let current = node_path.default.resolve(startPath);
|
|
571
|
-
while (true) {
|
|
572
|
-
for (const marker of WORKSPACE_MARKERS) if ((0, node_fs.existsSync)(node_path.default.join(current, marker))) return current;
|
|
573
|
-
const parent = node_path.default.dirname(current);
|
|
574
|
-
if (parent === current) return process.cwd();
|
|
575
|
-
current = parent;
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
function resolveSiblingRegistryPath(registryPath, fileName) {
|
|
579
|
-
if (!registryPath) return;
|
|
580
|
-
const resolved = node_path.default.resolve(registryPath);
|
|
581
|
-
if (node_path.default.extname(resolved) === ".json") return node_path.default.join(node_path.default.dirname(resolved), fileName);
|
|
582
|
-
return node_path.default.join(resolved, fileName);
|
|
583
|
-
}
|
|
584
|
-
function buildCliCandidates() {
|
|
585
|
-
const __filename$1 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
586
|
-
const __dirname$1 = node_path.default.dirname(__filename$1);
|
|
587
|
-
const distCandidates = [
|
|
588
|
-
node_path.default.resolve(__dirname$1, "cli.mjs"),
|
|
589
|
-
node_path.default.resolve(__dirname$1, "..", "dist", "cli.mjs"),
|
|
590
|
-
node_path.default.resolve(__dirname$1, "..", "..", "dist", "cli.mjs")
|
|
591
|
-
];
|
|
592
|
-
const srcCandidates = [node_path.default.resolve(__dirname$1, "..", "cli.ts"), node_path.default.resolve(__dirname$1, "..", "..", "src", "cli.ts")];
|
|
593
|
-
for (const candidate of distCandidates) if ((0, node_fs.existsSync)(candidate)) return {
|
|
594
|
-
command: process.execPath,
|
|
595
|
-
args: [candidate]
|
|
596
|
-
};
|
|
597
|
-
for (const candidate of srcCandidates) if ((0, node_fs.existsSync)(candidate)) return {
|
|
598
|
-
command: process.execPath,
|
|
599
|
-
args: [
|
|
600
|
-
"--import",
|
|
601
|
-
"tsx",
|
|
602
|
-
candidate
|
|
603
|
-
]
|
|
604
|
-
};
|
|
605
|
-
throw new Error("Unable to locate mcp-proxy CLI entrypoint");
|
|
606
|
-
}
|
|
607
|
-
function parseTimeoutMs(value) {
|
|
608
|
-
if (!value) return DEFAULT_TIMEOUT_MS;
|
|
609
|
-
const parsed = Number.parseInt(value, 10);
|
|
610
|
-
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
|
|
611
|
-
return parsed;
|
|
612
|
-
}
|
|
613
|
-
async function waitForFile(filePath, timeoutMs) {
|
|
614
|
-
const deadline = Date.now() + timeoutMs;
|
|
615
|
-
while (Date.now() < deadline) {
|
|
616
|
-
try {
|
|
617
|
-
await (0, node_fs_promises.access)(filePath);
|
|
618
|
-
return;
|
|
619
|
-
} catch {}
|
|
620
|
-
await new Promise((resolve$2) => setTimeout(resolve$2, POLL_INTERVAL_MS));
|
|
621
|
-
}
|
|
622
|
-
throw new Error(`Timed out waiting for runtime state file: ${filePath}`);
|
|
623
|
-
}
|
|
624
|
-
async function waitForHealthyRuntime(serverId, timeoutMs) {
|
|
625
|
-
const runtimeStateService = new require_src.RuntimeStateService();
|
|
626
|
-
const deadline = Date.now() + timeoutMs;
|
|
627
|
-
while (Date.now() < deadline) {
|
|
628
|
-
const record = await runtimeStateService.read(serverId);
|
|
629
|
-
if (record) {
|
|
630
|
-
const healthUrl = `http://${record.host}:${record.port}/health`;
|
|
631
|
-
try {
|
|
632
|
-
const response = await fetch(healthUrl);
|
|
633
|
-
if (response.ok) {
|
|
634
|
-
const payload = await response.json().catch(() => null);
|
|
635
|
-
if (!payload || payload.transport === "http") return {
|
|
636
|
-
host: record.host,
|
|
637
|
-
port: record.port
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
} catch {}
|
|
641
|
-
}
|
|
642
|
-
await new Promise((resolve$2) => setTimeout(resolve$2, POLL_INTERVAL_MS));
|
|
643
|
-
}
|
|
644
|
-
throw new Error(`Timed out waiting for HTTP runtime '${serverId}' to become healthy`);
|
|
645
|
-
}
|
|
646
|
-
function spawnBackgroundRuntime(args, env) {
|
|
647
|
-
const { command, args: baseArgs } = buildCliCandidates();
|
|
648
|
-
const child = (0, node_child_process.spawn)(command, [...baseArgs, ...args], {
|
|
649
|
-
detached: true,
|
|
650
|
-
stdio: "ignore",
|
|
651
|
-
env
|
|
652
|
-
});
|
|
653
|
-
child.unref();
|
|
654
|
-
return child;
|
|
655
|
-
}
|
|
656
|
-
const prestartHttpCommand = new commander.Command("prestart-http").description("Start an mcp-proxy HTTP runtime in the background and wait until it is healthy").option("--id <id>", "Server identifier to assign to the runtime").option("--host <host>", "Host to bind to", DEFAULT_HOST).option("-p, --port <port>", "Preferred HTTP port for the runtime", (value) => Number.parseInt(value, 10)).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--registry-path <path>", "Custom registry path or directory for service discovery").option("--registry-dir <path>", "Custom registry directory for service discovery").option("--timeout-ms <ms>", "How long to wait for the runtime to become healthy", String(DEFAULT_TIMEOUT_MS)).action(async (options) => {
|
|
657
|
-
const serverId = options.id || require_src.generateServerId();
|
|
658
|
-
const timeoutMs = parseTimeoutMs(options.timeoutMs);
|
|
659
|
-
const registryPath = options.registryPath || options.registryDir;
|
|
660
|
-
new require_src.RuntimeStateService();
|
|
661
|
-
const workspaceRoot = resolveWorkspaceRoot(process.cwd());
|
|
662
|
-
const childEnv = {
|
|
663
|
-
...process.env,
|
|
664
|
-
...registryPath ? {
|
|
665
|
-
PORT_REGISTRY_PATH: registryPath,
|
|
666
|
-
PROCESS_REGISTRY_PATH: resolveSiblingRegistryPath(registryPath, "processes.json")
|
|
667
|
-
} : {}
|
|
668
|
-
};
|
|
669
|
-
const child = spawnBackgroundRuntime([
|
|
670
|
-
"mcp-serve",
|
|
671
|
-
"--type",
|
|
672
|
-
"http",
|
|
673
|
-
"--id",
|
|
674
|
-
serverId,
|
|
675
|
-
"--host",
|
|
676
|
-
options.host || DEFAULT_HOST,
|
|
677
|
-
...options.port !== void 0 ? ["--port", String(options.port)] : [],
|
|
678
|
-
...options.config ? ["--config", options.config] : [],
|
|
679
|
-
...options.cache === false ? ["--no-cache"] : [],
|
|
680
|
-
...options.definitionsCache ? ["--definitions-cache", options.definitionsCache] : [],
|
|
681
|
-
...options.clearDefinitionsCache ? ["--clear-definitions-cache"] : [],
|
|
682
|
-
"--proxy-mode",
|
|
683
|
-
options.proxyMode
|
|
684
|
-
], childEnv);
|
|
685
|
-
const childExit = new Promise((_, reject) => {
|
|
686
|
-
child.once("exit", (code, signal) => {
|
|
687
|
-
reject(/* @__PURE__ */ new Error(`Background runtime exited before becoming healthy (code=${code ?? "null"}, signal=${signal ?? "null"})`));
|
|
688
|
-
});
|
|
689
|
-
});
|
|
690
|
-
const runtimeFile = node_path.default.join(require_src.RuntimeStateService.getDefaultRuntimeDir(), `${serverId}.runtime.json`);
|
|
691
|
-
try {
|
|
692
|
-
await Promise.race([waitForFile(runtimeFile, timeoutMs), childExit]);
|
|
693
|
-
const { host, port } = await Promise.race([waitForHealthyRuntime(serverId, timeoutMs), childExit]);
|
|
694
|
-
process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
|
|
695
|
-
process.stdout.write(`runtimeId=${serverId}\n`);
|
|
696
|
-
process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
|
|
697
|
-
process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
|
|
698
|
-
} catch (error) {
|
|
699
|
-
throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
700
|
-
}
|
|
701
|
-
});
|
|
702
|
-
|
|
703
745
|
//#endregion
|
|
704
746
|
//#region src/commands/bootstrap.ts
|
|
705
747
|
function toErrorMessage$8(error) {
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { D as findConfigFile, E as generateServerId, T as DefinitionsCacheService, d as version, f as StdioHttpTransportHandler, h as HttpTransportHandler, m as SseTransportHandler, n as createServer, o as createProxyIoCContainer, p as StdioTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, v as RuntimeStateService } from "./src-
|
|
2
|
+
import { D as findConfigFile, E as generateServerId, T as DefinitionsCacheService, d as version, f as StdioHttpTransportHandler, h as HttpTransportHandler, m as SseTransportHandler, n as createServer, o as createProxyIoCContainer, p as StdioTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, v as RuntimeStateService } from "./src-DCIv5S_2.mjs";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { access, writeFile } from "node:fs/promises";
|
|
5
5
|
import path, { join, resolve } from "node:path";
|
|
@@ -7,8 +7,8 @@ import { constants, existsSync } from "node:fs";
|
|
|
7
7
|
import { Liquid } from "liquidjs";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import { Command } from "commander";
|
|
10
|
-
import { ProcessRegistryService } from "@agimon-ai/foundation-process-registry";
|
|
11
10
|
import { DEFAULT_PORT_RANGE, PortRegistryService } from "@agimon-ai/foundation-port-registry";
|
|
11
|
+
import { ProcessRegistryService } from "@agimon-ai/foundation-process-registry";
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
|
|
14
14
|
//#region src/utils/output.ts
|
|
@@ -112,6 +112,169 @@ const initCommand = new Command("init").description("Initialize MCP configuratio
|
|
|
112
112
|
}
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/commands/prestart-http.ts
|
|
117
|
+
/**
|
|
118
|
+
* Prestart HTTP Command
|
|
119
|
+
*
|
|
120
|
+
* Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
|
|
121
|
+
* and then exits so the runtime can be reused by other commands.
|
|
122
|
+
*/
|
|
123
|
+
const WORKSPACE_MARKERS = [
|
|
124
|
+
"pnpm-workspace.yaml",
|
|
125
|
+
"nx.json",
|
|
126
|
+
".git"
|
|
127
|
+
];
|
|
128
|
+
const DEFAULT_HOST$1 = "localhost";
|
|
129
|
+
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
130
|
+
const POLL_INTERVAL_MS = 250;
|
|
131
|
+
function resolveWorkspaceRoot(startPath = process.env.PROJECT_PATH || process.cwd()) {
|
|
132
|
+
let current = path.resolve(startPath);
|
|
133
|
+
while (true) {
|
|
134
|
+
for (const marker of WORKSPACE_MARKERS) if (existsSync(path.join(current, marker))) return current;
|
|
135
|
+
const parent = path.dirname(current);
|
|
136
|
+
if (parent === current) return process.cwd();
|
|
137
|
+
current = parent;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function resolveSiblingRegistryPath(registryPath, fileName) {
|
|
141
|
+
if (!registryPath) return;
|
|
142
|
+
const resolved = path.resolve(registryPath);
|
|
143
|
+
if (path.extname(resolved) === ".json") return path.join(path.dirname(resolved), fileName);
|
|
144
|
+
return path.join(resolved, fileName);
|
|
145
|
+
}
|
|
146
|
+
function buildCliCandidates() {
|
|
147
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
148
|
+
const __dirname = path.dirname(__filename);
|
|
149
|
+
const distCandidates = [
|
|
150
|
+
path.resolve(__dirname, "cli.mjs"),
|
|
151
|
+
path.resolve(__dirname, "..", "dist", "cli.mjs"),
|
|
152
|
+
path.resolve(__dirname, "..", "..", "dist", "cli.mjs")
|
|
153
|
+
];
|
|
154
|
+
const srcCandidates = [path.resolve(__dirname, "..", "cli.ts"), path.resolve(__dirname, "..", "..", "src", "cli.ts")];
|
|
155
|
+
for (const candidate of distCandidates) if (existsSync(candidate)) return {
|
|
156
|
+
command: process.execPath,
|
|
157
|
+
args: [candidate]
|
|
158
|
+
};
|
|
159
|
+
for (const candidate of srcCandidates) if (existsSync(candidate)) return {
|
|
160
|
+
command: process.execPath,
|
|
161
|
+
args: [
|
|
162
|
+
"--import",
|
|
163
|
+
"tsx",
|
|
164
|
+
candidate
|
|
165
|
+
]
|
|
166
|
+
};
|
|
167
|
+
throw new Error("Unable to locate mcp-proxy CLI entrypoint");
|
|
168
|
+
}
|
|
169
|
+
function parseTimeoutMs(value) {
|
|
170
|
+
if (!value) return DEFAULT_TIMEOUT_MS;
|
|
171
|
+
const parsed = Number.parseInt(value, 10);
|
|
172
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
|
|
173
|
+
return parsed;
|
|
174
|
+
}
|
|
175
|
+
async function waitForFile(filePath, timeoutMs) {
|
|
176
|
+
const deadline = Date.now() + timeoutMs;
|
|
177
|
+
while (Date.now() < deadline) {
|
|
178
|
+
try {
|
|
179
|
+
await access(filePath);
|
|
180
|
+
return;
|
|
181
|
+
} catch {}
|
|
182
|
+
await new Promise((resolve$1) => setTimeout(resolve$1, POLL_INTERVAL_MS));
|
|
183
|
+
}
|
|
184
|
+
throw new Error(`Timed out waiting for runtime state file: ${filePath}`);
|
|
185
|
+
}
|
|
186
|
+
async function waitForHealthyRuntime(serverId, timeoutMs) {
|
|
187
|
+
const runtimeStateService = new RuntimeStateService();
|
|
188
|
+
const deadline = Date.now() + timeoutMs;
|
|
189
|
+
while (Date.now() < deadline) {
|
|
190
|
+
const record = await runtimeStateService.read(serverId);
|
|
191
|
+
if (record) {
|
|
192
|
+
const healthUrl = `http://${record.host}:${record.port}/health`;
|
|
193
|
+
try {
|
|
194
|
+
const response = await fetch(healthUrl);
|
|
195
|
+
if (response.ok) {
|
|
196
|
+
const payload = await response.json().catch(() => null);
|
|
197
|
+
if (!payload || payload.transport === "http") return {
|
|
198
|
+
host: record.host,
|
|
199
|
+
port: record.port
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
} catch {}
|
|
203
|
+
}
|
|
204
|
+
await new Promise((resolve$1) => setTimeout(resolve$1, POLL_INTERVAL_MS));
|
|
205
|
+
}
|
|
206
|
+
throw new Error(`Timed out waiting for HTTP runtime '${serverId}' to become healthy`);
|
|
207
|
+
}
|
|
208
|
+
function spawnBackgroundRuntime(args, env, cwd) {
|
|
209
|
+
const { command, args: baseArgs } = buildCliCandidates();
|
|
210
|
+
const child = spawn(command, [...baseArgs, ...args], {
|
|
211
|
+
detached: true,
|
|
212
|
+
cwd,
|
|
213
|
+
stdio: "ignore",
|
|
214
|
+
env
|
|
215
|
+
});
|
|
216
|
+
child.unref();
|
|
217
|
+
return child;
|
|
218
|
+
}
|
|
219
|
+
async function prestartHttpRuntime(options) {
|
|
220
|
+
const serverId = options.id || generateServerId();
|
|
221
|
+
const timeoutMs = parseTimeoutMs(options.timeoutMs);
|
|
222
|
+
const registryPath = options.registryPath || options.registryDir;
|
|
223
|
+
const workspaceRoot = resolveWorkspaceRoot();
|
|
224
|
+
const childEnv = {
|
|
225
|
+
...process.env,
|
|
226
|
+
...registryPath ? {
|
|
227
|
+
PORT_REGISTRY_PATH: registryPath,
|
|
228
|
+
PROCESS_REGISTRY_PATH: resolveSiblingRegistryPath(registryPath, "processes.json")
|
|
229
|
+
} : {}
|
|
230
|
+
};
|
|
231
|
+
const child = spawnBackgroundRuntime([
|
|
232
|
+
"mcp-serve",
|
|
233
|
+
"--type",
|
|
234
|
+
"http",
|
|
235
|
+
"--id",
|
|
236
|
+
serverId,
|
|
237
|
+
"--host",
|
|
238
|
+
options.host || DEFAULT_HOST$1,
|
|
239
|
+
...options.port !== void 0 ? ["--port", String(options.port)] : [],
|
|
240
|
+
...options.config ? ["--config", options.config] : [],
|
|
241
|
+
...options.cache === false ? ["--no-cache"] : [],
|
|
242
|
+
...options.definitionsCache ? ["--definitions-cache", options.definitionsCache] : [],
|
|
243
|
+
...options.clearDefinitionsCache ? ["--clear-definitions-cache"] : [],
|
|
244
|
+
"--proxy-mode",
|
|
245
|
+
options.proxyMode
|
|
246
|
+
], childEnv, workspaceRoot);
|
|
247
|
+
const childExit = new Promise((_, reject) => {
|
|
248
|
+
child.once("exit", (code, signal) => {
|
|
249
|
+
reject(/* @__PURE__ */ new Error(`Background runtime exited before becoming healthy (code=${code ?? "null"}, signal=${signal ?? "null"})`));
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
const runtimeFile = path.join(RuntimeStateService.getDefaultRuntimeDir(), `${serverId}.runtime.json`);
|
|
253
|
+
try {
|
|
254
|
+
await Promise.race([waitForFile(runtimeFile, timeoutMs), childExit]);
|
|
255
|
+
const { host, port } = await Promise.race([waitForHealthyRuntime(serverId, timeoutMs), childExit]);
|
|
256
|
+
return {
|
|
257
|
+
host,
|
|
258
|
+
port,
|
|
259
|
+
serverId,
|
|
260
|
+
workspaceRoot
|
|
261
|
+
};
|
|
262
|
+
} catch (error) {
|
|
263
|
+
throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
const prestartHttpCommand = new Command("prestart-http").description("Start an mcp-proxy HTTP runtime in the background and wait until it is healthy").option("--id <id>", "Server identifier to assign to the runtime").option("--host <host>", "Host to bind to", DEFAULT_HOST$1).option("-p, --port <port>", "Preferred HTTP port for the runtime", (value) => Number.parseInt(value, 10)).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--registry-path <path>", "Custom registry path or directory for service discovery").option("--registry-dir <path>", "Custom registry directory for service discovery").option("--timeout-ms <ms>", "How long to wait for the runtime to become healthy", String(DEFAULT_TIMEOUT_MS)).action(async (options) => {
|
|
267
|
+
try {
|
|
268
|
+
const { host, port, serverId, workspaceRoot } = await prestartHttpRuntime(options);
|
|
269
|
+
process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
|
|
270
|
+
process.stdout.write(`runtimeId=${serverId}\n`);
|
|
271
|
+
process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
|
|
272
|
+
process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new Error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${error instanceof Error ? error.message : String(error)}`);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
115
278
|
//#endregion
|
|
116
279
|
//#region src/commands/mcp-serve.ts
|
|
117
280
|
/**
|
|
@@ -140,7 +303,7 @@ const CONFIG_FILE_NAMES = [
|
|
|
140
303
|
"mcp-config.json"
|
|
141
304
|
];
|
|
142
305
|
const MCP_ENDPOINT_PATH = "/mcp";
|
|
143
|
-
const DEFAULT_HOST
|
|
306
|
+
const DEFAULT_HOST = "localhost";
|
|
144
307
|
const TRANSPORT_TYPE_STDIO = "stdio";
|
|
145
308
|
const TRANSPORT_TYPE_HTTP = "http";
|
|
146
309
|
const TRANSPORT_TYPE_SSE = "sse";
|
|
@@ -148,10 +311,14 @@ const TRANSPORT_TYPE_STDIO_HTTP = "stdio-http";
|
|
|
148
311
|
const RUNTIME_TRANSPORT = TRANSPORT_TYPE_HTTP;
|
|
149
312
|
const PORT_REGISTRY_SERVICE_HTTP = "mcp-proxy-http";
|
|
150
313
|
const PORT_REGISTRY_SERVICE_TYPE = "service";
|
|
151
|
-
|
|
314
|
+
function getWorkspaceRoot() {
|
|
315
|
+
return resolveWorkspaceRoot();
|
|
316
|
+
}
|
|
152
317
|
const PROCESS_REGISTRY_SERVICE_HTTP = "mcp-proxy-http";
|
|
153
318
|
const PROCESS_REGISTRY_SERVICE_TYPE = "service";
|
|
154
|
-
|
|
319
|
+
function getRegistryRepositoryPath() {
|
|
320
|
+
return getWorkspaceRoot();
|
|
321
|
+
}
|
|
155
322
|
function toErrorMessage$9(error) {
|
|
156
323
|
return error instanceof Error ? error.message : String(error);
|
|
157
324
|
}
|
|
@@ -212,7 +379,23 @@ function createTransportConfig(options, mode) {
|
|
|
212
379
|
return {
|
|
213
380
|
mode,
|
|
214
381
|
port: options.port ?? (Number.isFinite(envPort) ? envPort : void 0),
|
|
215
|
-
host: options.host || process.env.MCP_HOST || DEFAULT_HOST
|
|
382
|
+
host: options.host || process.env.MCP_HOST || DEFAULT_HOST
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function createStdioSafeLogger() {
|
|
386
|
+
const logToStderr = (message, data) => {
|
|
387
|
+
if (data === void 0) {
|
|
388
|
+
console.error(message);
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
console.error(message, data);
|
|
392
|
+
};
|
|
393
|
+
return {
|
|
394
|
+
trace: logToStderr,
|
|
395
|
+
debug: logToStderr,
|
|
396
|
+
info: logToStderr,
|
|
397
|
+
warn: logToStderr,
|
|
398
|
+
error: logToStderr
|
|
216
399
|
};
|
|
217
400
|
}
|
|
218
401
|
function createServerOptions(options, resolvedConfigPath, serverId) {
|
|
@@ -233,7 +416,7 @@ function formatStartError(type, host, port, error) {
|
|
|
233
416
|
function createRuntimeRecord(serverId, config, port, shutdownToken, configPath) {
|
|
234
417
|
return {
|
|
235
418
|
serverId,
|
|
236
|
-
host: config.host ?? DEFAULT_HOST
|
|
419
|
+
host: config.host ?? DEFAULT_HOST,
|
|
237
420
|
port,
|
|
238
421
|
transport: RUNTIME_TRANSPORT,
|
|
239
422
|
shutdownToken,
|
|
@@ -257,7 +440,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
257
440
|
} : DEFAULT_PORT_RANGE) {
|
|
258
441
|
const portRegistry = createPortRegistryService();
|
|
259
442
|
const result = await portRegistry.reservePort({
|
|
260
|
-
repositoryPath:
|
|
443
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
261
444
|
serviceName,
|
|
262
445
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
263
446
|
environment: getRegistryEnvironment(),
|
|
@@ -283,7 +466,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
283
466
|
if (released) return;
|
|
284
467
|
released = true;
|
|
285
468
|
const releaseResult = await portRegistry.releasePort({
|
|
286
|
-
repositoryPath:
|
|
469
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
287
470
|
serviceName,
|
|
288
471
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
289
472
|
pid: process.pid,
|
|
@@ -297,7 +480,7 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
297
480
|
async function createProcessRegistryLease(serviceName, host, port, serverId, transport, configPath) {
|
|
298
481
|
const processRegistry = createProcessRegistryService();
|
|
299
482
|
const result = await processRegistry.registerProcess({
|
|
300
|
-
repositoryPath:
|
|
483
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
301
484
|
serviceName,
|
|
302
485
|
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
303
486
|
environment: getRegistryEnvironment(),
|
|
@@ -318,7 +501,7 @@ async function createProcessRegistryLease(serviceName, host, port, serverId, tra
|
|
|
318
501
|
if (released) return;
|
|
319
502
|
released = true;
|
|
320
503
|
const releaseResult = await processRegistry.releaseProcess({
|
|
321
|
-
repositoryPath:
|
|
504
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
322
505
|
serviceName,
|
|
323
506
|
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
324
507
|
pid: process.pid,
|
|
@@ -419,13 +602,13 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
419
602
|
min: requestedPort,
|
|
420
603
|
max: requestedPort
|
|
421
604
|
} : DEFAULT_PORT_RANGE;
|
|
422
|
-
const portLease = await createPortRegistryLease(PORT_REGISTRY_SERVICE_HTTP, config.host ?? DEFAULT_HOST
|
|
605
|
+
const portLease = await createPortRegistryLease(PORT_REGISTRY_SERVICE_HTTP, config.host ?? DEFAULT_HOST, requestedPort, runtimeServerId, TRANSPORT_TYPE_HTTP, resolvedConfigPath, portRange);
|
|
423
606
|
const runtimePort = portLease.port;
|
|
424
607
|
const runtimeConfig = {
|
|
425
608
|
...config,
|
|
426
609
|
port: runtimePort
|
|
427
610
|
};
|
|
428
|
-
const processLease = await createProcessRegistryLease(PROCESS_REGISTRY_SERVICE_HTTP, runtimeConfig.host ?? DEFAULT_HOST
|
|
611
|
+
const processLease = await createProcessRegistryLease(PROCESS_REGISTRY_SERVICE_HTTP, runtimeConfig.host ?? DEFAULT_HOST, runtimePort, runtimeServerId, TRANSPORT_TYPE_HTTP, resolvedConfigPath);
|
|
429
612
|
let releasePort = async () => {
|
|
430
613
|
await releasePortLease(portLease ?? null);
|
|
431
614
|
releasePort = async () => void 0;
|
|
@@ -481,7 +664,7 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
481
664
|
}
|
|
482
665
|
async function startStdioTransport(serverOptions) {
|
|
483
666
|
try {
|
|
484
|
-
await startServer(new StdioTransportHandler(await createServer(serverOptions)));
|
|
667
|
+
await startServer(new StdioTransportHandler(await createServer(serverOptions), createStdioSafeLogger()));
|
|
485
668
|
} catch (error) {
|
|
486
669
|
throw new Error(`Failed to start stdio transport: ${toErrorMessage$9(error)}`);
|
|
487
670
|
}
|
|
@@ -493,20 +676,29 @@ async function startSseTransport(serverOptions, config) {
|
|
|
493
676
|
throw new Error(`Failed to start SSE transport: ${toErrorMessage$9(error)}`);
|
|
494
677
|
}
|
|
495
678
|
}
|
|
496
|
-
async function resolveStdioHttpEndpoint(config) {
|
|
497
|
-
|
|
679
|
+
async function resolveStdioHttpEndpoint(config, options, resolvedConfigPath) {
|
|
680
|
+
const repositoryPath = getRegistryRepositoryPath();
|
|
681
|
+
if (config.port !== void 0) return new URL(`http://${config.host ?? DEFAULT_HOST}:${config.port}${MCP_ENDPOINT_PATH}`);
|
|
498
682
|
const result = await createPortRegistryService().getPort({
|
|
499
|
-
repositoryPath
|
|
683
|
+
repositoryPath,
|
|
500
684
|
serviceName: PORT_REGISTRY_SERVICE_HTTP,
|
|
501
685
|
serviceType: PORT_REGISTRY_SERVICE_TYPE,
|
|
502
686
|
environment: getRegistryEnvironment()
|
|
503
687
|
});
|
|
504
|
-
if (
|
|
505
|
-
|
|
688
|
+
if (result.success && result.record) return new URL(`http://${config.host ?? result.record.host}:${result.record.port}${MCP_ENDPOINT_PATH}`);
|
|
689
|
+
const runtime = await prestartHttpRuntime({
|
|
690
|
+
host: config.host ?? DEFAULT_HOST,
|
|
691
|
+
config: options.config || resolvedConfigPath,
|
|
692
|
+
cache: options.cache,
|
|
693
|
+
definitionsCache: options.definitionsCache,
|
|
694
|
+
clearDefinitionsCache: options.clearDefinitionsCache,
|
|
695
|
+
proxyMode: options.proxyMode
|
|
696
|
+
});
|
|
697
|
+
return new URL(`http://${runtime.host}:${runtime.port}${MCP_ENDPOINT_PATH}`);
|
|
506
698
|
}
|
|
507
|
-
async function startStdioHttpTransport(config) {
|
|
699
|
+
async function startStdioHttpTransport(config, options, resolvedConfigPath) {
|
|
508
700
|
try {
|
|
509
|
-
await startServer(new StdioHttpTransportHandler({ endpoint: await resolveStdioHttpEndpoint(config) }));
|
|
701
|
+
await startServer(new StdioHttpTransportHandler({ endpoint: await resolveStdioHttpEndpoint(config, options, resolvedConfigPath) }, createStdioSafeLogger()));
|
|
510
702
|
} catch (error) {
|
|
511
703
|
throw new Error(`Failed to start stdio-http transport: ${toErrorMessage$9(error)}`);
|
|
512
704
|
}
|
|
@@ -525,7 +717,7 @@ async function startTransport(transportType, options, resolvedConfigPath, server
|
|
|
525
717
|
await startSseTransport(serverOptions, createTransportConfig(options, TRANSPORT_MODE.SSE));
|
|
526
718
|
return;
|
|
527
719
|
}
|
|
528
|
-
await startStdioHttpTransport(createTransportConfig(options, TRANSPORT_MODE.HTTP));
|
|
720
|
+
await startStdioHttpTransport(createTransportConfig(options, TRANSPORT_MODE.HTTP), options, resolvedConfigPath);
|
|
529
721
|
} catch (error) {
|
|
530
722
|
throw new Error(`Failed to start transport '${transportType}': ${toErrorMessage$9(error)}`);
|
|
531
723
|
}
|
|
@@ -533,7 +725,7 @@ async function startTransport(transportType, options, resolvedConfigPath, server
|
|
|
533
725
|
/**
|
|
534
726
|
* MCP Serve command
|
|
535
727
|
*/
|
|
536
|
-
const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`, TRANSPORT_TYPE_STDIO).option("-p, --port <port>", "Port to listen on (http/sse) or backend port for stdio-http", (val) => parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse) or backend host for stdio-http", DEFAULT_HOST
|
|
728
|
+
const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`, TRANSPORT_TYPE_STDIO).option("-p, --port <port>", "Port to listen on (http/sse) or backend port for stdio-http", (val) => Number.parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse) or backend host for stdio-http", DEFAULT_HOST).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--id <id>", "Unique server identifier (overrides config file id, auto-generated if not provided)").action(async (options) => {
|
|
537
729
|
try {
|
|
538
730
|
const transportType = validateTransportType(options.type.toLowerCase());
|
|
539
731
|
validateProxyMode(options.proxyMode);
|
|
@@ -549,156 +741,6 @@ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server w
|
|
|
549
741
|
}
|
|
550
742
|
});
|
|
551
743
|
|
|
552
|
-
//#endregion
|
|
553
|
-
//#region src/commands/prestart-http.ts
|
|
554
|
-
/**
|
|
555
|
-
* Prestart HTTP Command
|
|
556
|
-
*
|
|
557
|
-
* Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
|
|
558
|
-
* and then exits so the runtime can be reused by other commands.
|
|
559
|
-
*/
|
|
560
|
-
const WORKSPACE_MARKERS = [
|
|
561
|
-
"pnpm-workspace.yaml",
|
|
562
|
-
"nx.json",
|
|
563
|
-
".git"
|
|
564
|
-
];
|
|
565
|
-
const DEFAULT_HOST = "localhost";
|
|
566
|
-
const DEFAULT_TIMEOUT_MS = 12e4;
|
|
567
|
-
const POLL_INTERVAL_MS = 250;
|
|
568
|
-
function resolveWorkspaceRoot(startPath = process.cwd()) {
|
|
569
|
-
let current = path.resolve(startPath);
|
|
570
|
-
while (true) {
|
|
571
|
-
for (const marker of WORKSPACE_MARKERS) if (existsSync(path.join(current, marker))) return current;
|
|
572
|
-
const parent = path.dirname(current);
|
|
573
|
-
if (parent === current) return process.cwd();
|
|
574
|
-
current = parent;
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
function resolveSiblingRegistryPath(registryPath, fileName) {
|
|
578
|
-
if (!registryPath) return;
|
|
579
|
-
const resolved = path.resolve(registryPath);
|
|
580
|
-
if (path.extname(resolved) === ".json") return path.join(path.dirname(resolved), fileName);
|
|
581
|
-
return path.join(resolved, fileName);
|
|
582
|
-
}
|
|
583
|
-
function buildCliCandidates() {
|
|
584
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
585
|
-
const __dirname = path.dirname(__filename);
|
|
586
|
-
const distCandidates = [
|
|
587
|
-
path.resolve(__dirname, "cli.mjs"),
|
|
588
|
-
path.resolve(__dirname, "..", "dist", "cli.mjs"),
|
|
589
|
-
path.resolve(__dirname, "..", "..", "dist", "cli.mjs")
|
|
590
|
-
];
|
|
591
|
-
const srcCandidates = [path.resolve(__dirname, "..", "cli.ts"), path.resolve(__dirname, "..", "..", "src", "cli.ts")];
|
|
592
|
-
for (const candidate of distCandidates) if (existsSync(candidate)) return {
|
|
593
|
-
command: process.execPath,
|
|
594
|
-
args: [candidate]
|
|
595
|
-
};
|
|
596
|
-
for (const candidate of srcCandidates) if (existsSync(candidate)) return {
|
|
597
|
-
command: process.execPath,
|
|
598
|
-
args: [
|
|
599
|
-
"--import",
|
|
600
|
-
"tsx",
|
|
601
|
-
candidate
|
|
602
|
-
]
|
|
603
|
-
};
|
|
604
|
-
throw new Error("Unable to locate mcp-proxy CLI entrypoint");
|
|
605
|
-
}
|
|
606
|
-
function parseTimeoutMs(value) {
|
|
607
|
-
if (!value) return DEFAULT_TIMEOUT_MS;
|
|
608
|
-
const parsed = Number.parseInt(value, 10);
|
|
609
|
-
if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
|
|
610
|
-
return parsed;
|
|
611
|
-
}
|
|
612
|
-
async function waitForFile(filePath, timeoutMs) {
|
|
613
|
-
const deadline = Date.now() + timeoutMs;
|
|
614
|
-
while (Date.now() < deadline) {
|
|
615
|
-
try {
|
|
616
|
-
await access(filePath);
|
|
617
|
-
return;
|
|
618
|
-
} catch {}
|
|
619
|
-
await new Promise((resolve$1) => setTimeout(resolve$1, POLL_INTERVAL_MS));
|
|
620
|
-
}
|
|
621
|
-
throw new Error(`Timed out waiting for runtime state file: ${filePath}`);
|
|
622
|
-
}
|
|
623
|
-
async function waitForHealthyRuntime(serverId, timeoutMs) {
|
|
624
|
-
const runtimeStateService = new RuntimeStateService();
|
|
625
|
-
const deadline = Date.now() + timeoutMs;
|
|
626
|
-
while (Date.now() < deadline) {
|
|
627
|
-
const record = await runtimeStateService.read(serverId);
|
|
628
|
-
if (record) {
|
|
629
|
-
const healthUrl = `http://${record.host}:${record.port}/health`;
|
|
630
|
-
try {
|
|
631
|
-
const response = await fetch(healthUrl);
|
|
632
|
-
if (response.ok) {
|
|
633
|
-
const payload = await response.json().catch(() => null);
|
|
634
|
-
if (!payload || payload.transport === "http") return {
|
|
635
|
-
host: record.host,
|
|
636
|
-
port: record.port
|
|
637
|
-
};
|
|
638
|
-
}
|
|
639
|
-
} catch {}
|
|
640
|
-
}
|
|
641
|
-
await new Promise((resolve$1) => setTimeout(resolve$1, POLL_INTERVAL_MS));
|
|
642
|
-
}
|
|
643
|
-
throw new Error(`Timed out waiting for HTTP runtime '${serverId}' to become healthy`);
|
|
644
|
-
}
|
|
645
|
-
function spawnBackgroundRuntime(args, env) {
|
|
646
|
-
const { command, args: baseArgs } = buildCliCandidates();
|
|
647
|
-
const child = spawn(command, [...baseArgs, ...args], {
|
|
648
|
-
detached: true,
|
|
649
|
-
stdio: "ignore",
|
|
650
|
-
env
|
|
651
|
-
});
|
|
652
|
-
child.unref();
|
|
653
|
-
return child;
|
|
654
|
-
}
|
|
655
|
-
const prestartHttpCommand = new Command("prestart-http").description("Start an mcp-proxy HTTP runtime in the background and wait until it is healthy").option("--id <id>", "Server identifier to assign to the runtime").option("--host <host>", "Host to bind to", DEFAULT_HOST).option("-p, --port <port>", "Preferred HTTP port for the runtime", (value) => Number.parseInt(value, 10)).option("-c, --config <path>", "Path to MCP server configuration file").option("--no-cache", "Disable configuration caching, always reload from config file").option("--definitions-cache <path>", "Path to prefetched tool/prompt/skill definitions cache file").option("--clear-definitions-cache", "Delete definitions cache before startup", false).option("--proxy-mode <mode>", "How mcp-proxy exposes downstream tools: meta, flat, or search", "meta").option("--registry-path <path>", "Custom registry path or directory for service discovery").option("--registry-dir <path>", "Custom registry directory for service discovery").option("--timeout-ms <ms>", "How long to wait for the runtime to become healthy", String(DEFAULT_TIMEOUT_MS)).action(async (options) => {
|
|
656
|
-
const serverId = options.id || generateServerId();
|
|
657
|
-
const timeoutMs = parseTimeoutMs(options.timeoutMs);
|
|
658
|
-
const registryPath = options.registryPath || options.registryDir;
|
|
659
|
-
new RuntimeStateService();
|
|
660
|
-
const workspaceRoot = resolveWorkspaceRoot(process.cwd());
|
|
661
|
-
const childEnv = {
|
|
662
|
-
...process.env,
|
|
663
|
-
...registryPath ? {
|
|
664
|
-
PORT_REGISTRY_PATH: registryPath,
|
|
665
|
-
PROCESS_REGISTRY_PATH: resolveSiblingRegistryPath(registryPath, "processes.json")
|
|
666
|
-
} : {}
|
|
667
|
-
};
|
|
668
|
-
const child = spawnBackgroundRuntime([
|
|
669
|
-
"mcp-serve",
|
|
670
|
-
"--type",
|
|
671
|
-
"http",
|
|
672
|
-
"--id",
|
|
673
|
-
serverId,
|
|
674
|
-
"--host",
|
|
675
|
-
options.host || DEFAULT_HOST,
|
|
676
|
-
...options.port !== void 0 ? ["--port", String(options.port)] : [],
|
|
677
|
-
...options.config ? ["--config", options.config] : [],
|
|
678
|
-
...options.cache === false ? ["--no-cache"] : [],
|
|
679
|
-
...options.definitionsCache ? ["--definitions-cache", options.definitionsCache] : [],
|
|
680
|
-
...options.clearDefinitionsCache ? ["--clear-definitions-cache"] : [],
|
|
681
|
-
"--proxy-mode",
|
|
682
|
-
options.proxyMode
|
|
683
|
-
], childEnv);
|
|
684
|
-
const childExit = new Promise((_, reject) => {
|
|
685
|
-
child.once("exit", (code, signal) => {
|
|
686
|
-
reject(/* @__PURE__ */ new Error(`Background runtime exited before becoming healthy (code=${code ?? "null"}, signal=${signal ?? "null"})`));
|
|
687
|
-
});
|
|
688
|
-
});
|
|
689
|
-
const runtimeFile = path.join(RuntimeStateService.getDefaultRuntimeDir(), `${serverId}.runtime.json`);
|
|
690
|
-
try {
|
|
691
|
-
await Promise.race([waitForFile(runtimeFile, timeoutMs), childExit]);
|
|
692
|
-
const { host, port } = await Promise.race([waitForHealthyRuntime(serverId, timeoutMs), childExit]);
|
|
693
|
-
process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
|
|
694
|
-
process.stdout.write(`runtimeId=${serverId}\n`);
|
|
695
|
-
process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
|
|
696
|
-
process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
|
|
697
|
-
} catch (error) {
|
|
698
|
-
throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`);
|
|
699
|
-
}
|
|
700
|
-
});
|
|
701
|
-
|
|
702
744
|
//#endregion
|
|
703
745
|
//#region src/commands/bootstrap.ts
|
|
704
746
|
function toErrorMessage$8(error) {
|
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { C as SearchListToolsTool, D as findConfigFile, E as generateServerId, S as UseToolTool, T as DefinitionsCacheService, _ as StopServerService, a as createProxyContainer, b as createProxyLogger, c as createStdioHttpTransportHandler, f as StdioHttpTransportHandler, g as SkillService, h as HttpTransportHandler, i as createHttpTransportHandler, l as createStdioTransportHandler, m as SseTransportHandler, n as createServer, p as StdioTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as RuntimeStateService, w as DescribeToolsTool, x as ConfigFetcherService, y as McpClientManagerService } from "./src-
|
|
1
|
+
import { C as SearchListToolsTool, D as findConfigFile, E as generateServerId, S as UseToolTool, T as DefinitionsCacheService, _ as StopServerService, a as createProxyContainer, b as createProxyLogger, c as createStdioHttpTransportHandler, f as StdioHttpTransportHandler, g as SkillService, h as HttpTransportHandler, i as createHttpTransportHandler, l as createStdioTransportHandler, m as SseTransportHandler, n as createServer, p as StdioTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as RuntimeStateService, w as DescribeToolsTool, x as ConfigFetcherService, y as McpClientManagerService } from "./src-DCIv5S_2.mjs";
|
|
2
2
|
|
|
3
3
|
export { ConfigFetcherService, DefinitionsCacheService, DescribeToolsTool, HttpTransportHandler, McpClientManagerService, RuntimeStateService, SearchListToolsTool, SkillService, SseTransportHandler, StdioHttpTransportHandler, StdioTransportHandler, StopServerService, TRANSPORT_MODE, UseToolTool, createHttpTransportHandler, createProxyContainer, createProxyLogger, createServer, createSessionServer, createSseTransportHandler, createStdioHttpTransportHandler, createStdioTransportHandler, findConfigFile, generateServerId, initializeSharedServices };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/mcp-proxy",
|
|
3
3
|
"description": "MCP proxy server package",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.6",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mcp",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"js-yaml": "^4.1.0",
|
|
28
28
|
"liquidjs": "^10.21.0",
|
|
29
29
|
"zod": "^3.24.1",
|
|
30
|
-
"@agimon-ai/foundation-process-registry": "0.2.
|
|
31
|
-
"@agimon-ai/
|
|
32
|
-
"@agimon-ai/
|
|
30
|
+
"@agimon-ai/foundation-process-registry": "0.2.4",
|
|
31
|
+
"@agimon-ai/foundation-port-registry": "0.2.8",
|
|
32
|
+
"@agimon-ai/log-sink-mcp": "0.2.8"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/express": "^5.0.0",
|