@agimon-ai/mcp-proxy 0.10.0 → 0.10.2

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const require_src = require("./src-DIQjnEBk.cjs");
2
+ const require_src = require("./src-DMlOlvPm.cjs");
3
3
  let node_fs = require("node:fs");
4
4
  let node_fs_promises = require("node:fs/promises");
5
5
  let js_yaml = require("js-yaml");
@@ -7,18 +7,18 @@ js_yaml = require_src.__toESM(js_yaml);
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_src.__toESM(node_path);
10
+ let _agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
10
11
  let node_child_process = require("node:child_process");
11
12
  let liquidjs = require("liquidjs");
12
13
  let commander = require("commander");
13
14
  let node_url = require("node:url");
14
- let _agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
15
15
  let _agimon_ai_foundation_port_registry = require("@agimon-ai/foundation-port-registry");
16
- //#region src/commands/prestart-http.ts
16
+ //#region src/commands/http-runtime.ts
17
17
  /**
18
- * Prestart HTTP Command
18
+ * HTTP Runtime Helper
19
19
  *
20
20
  * Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
21
- * and then exits so the runtime can be reused by other commands.
21
+ * and returns the runtime details for callers that need to reuse it.
22
22
  */
23
23
  const WORKSPACE_MARKERS = [
24
24
  "pnpm-workspace.yaml",
@@ -26,7 +26,7 @@ const WORKSPACE_MARKERS = [
26
26
  ".git"
27
27
  ];
28
28
  const DEFAULT_HOST$1 = "localhost";
29
- const DEFAULT_TIMEOUT_MS = 12e4;
29
+ const DEFAULT_HTTP_RUNTIME_TIMEOUT_MS = 12e4;
30
30
  const POLL_INTERVAL_MS = 250;
31
31
  function resolveWorkspaceRoot(startPath = process.env.PROJECT_PATH || process.cwd()) {
32
32
  let current = node_path.default.resolve(startPath);
@@ -82,7 +82,7 @@ function buildCliCandidates() {
82
82
  throw new Error("Unable to locate mcp-proxy CLI entrypoint");
83
83
  }
84
84
  function parseTimeoutMs(value) {
85
- if (!value) return DEFAULT_TIMEOUT_MS;
85
+ if (!value) return DEFAULT_HTTP_RUNTIME_TIMEOUT_MS;
86
86
  const parsed = Number.parseInt(value, 10);
87
87
  if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
88
88
  return parsed;
@@ -208,17 +208,12 @@ async function prestartHttpRuntime(options) {
208
208
  throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
209
209
  }
210
210
  }
211
- 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) => {
212
- try {
213
- const { host, port, serverId, workspaceRoot } = await prestartHttpRuntime(options);
214
- process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
215
- process.stdout.write(`runtimeId=${serverId}\n`);
216
- process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
217
- process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
218
- } catch (error) {
219
- throw new Error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
220
- }
221
- });
211
+ function writePrestartHttpResult(result) {
212
+ process.stdout.write(`mcp-proxy HTTP runtime ready at http://${result.host}:${result.port} (${result.serverId})\n`);
213
+ process.stdout.write(`runtimeId=${result.serverId}\n`);
214
+ process.stdout.write(`runtimeUrl=http://${result.host}:${result.port}\n`);
215
+ process.stdout.write(`workspaceRoot=${result.workspaceRoot}\n`);
216
+ }
222
217
  //#endregion
223
218
  //#region src/commands/bootstrap.ts
224
219
  function toErrorMessage$9(error) {
@@ -1156,9 +1151,14 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
1156
1151
  console.error(`Runtime state: http://${runtimeRecord.host}:${runtimeRecord.port} (${runtimeRecord.serverId})`);
1157
1152
  }
1158
1153
  async function startStdioTransport(serverOptions) {
1154
+ let server;
1159
1155
  try {
1160
- await startServer(new require_src.StdioTransportHandler(await require_src.createServer(serverOptions), createStdioSafeLogger()));
1156
+ server = await require_src.createServer(serverOptions);
1157
+ await startServer(new require_src.StdioTransportHandler(server, createStdioSafeLogger()), async () => {
1158
+ await server?.dispose?.();
1159
+ });
1161
1160
  } catch (error) {
1161
+ await server?.dispose?.();
1162
1162
  throw new Error(`Failed to start stdio transport: ${toErrorMessage$3(error)}`);
1163
1163
  }
1164
1164
  }
@@ -1272,11 +1272,33 @@ async function startTransport(transportType, options, resolvedConfigPath, server
1272
1272
  throw new Error(`Failed to start transport '${transportType}': ${toErrorMessage$3(error)}`);
1273
1273
  }
1274
1274
  }
1275
+ async function prestartHttpRuntimeCommand(options, resolvedConfigPath) {
1276
+ try {
1277
+ writePrestartHttpResult(await prestartHttpRuntime({
1278
+ id: options.id,
1279
+ host: options.host ?? DEFAULT_HOST,
1280
+ port: options.port,
1281
+ config: options.config || resolvedConfigPath,
1282
+ cache: options.cache,
1283
+ definitionsCache: options.definitionsCache,
1284
+ clearDefinitionsCache: options.clearDefinitionsCache,
1285
+ proxyMode: options.proxyMode,
1286
+ timeoutMs: options.timeoutMs
1287
+ }));
1288
+ } catch (error) {
1289
+ console.error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${toErrorMessage$3(error)}`);
1290
+ process.exit(1);
1291
+ }
1292
+ }
1275
1293
  /**
1276
1294
  * MCP Serve command
1277
1295
  */
1278
- 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}`).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").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) => {
1296
+ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport or prestart the HTTP runtime in the background").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`).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").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)").option("--prestart-http", "Prestart the HTTP runtime in the background and exit after it becomes healthy", false).option("--timeout-ms <ms>", "How long to wait for the HTTP runtime to become healthy", String(DEFAULT_HTTP_RUNTIME_TIMEOUT_MS)).action(async (options) => {
1279
1297
  try {
1298
+ if (options.prestartHttp) {
1299
+ await prestartHttpRuntimeCommand(options, options.config || await findConfigFileAsync() || void 0);
1300
+ return;
1301
+ }
1280
1302
  const resolvedConfigPath = options.config || await findConfigFileAsync() || void 0;
1281
1303
  const proxyDefaults = resolvedConfigPath ? loadProxyDefaults(resolvedConfigPath) : {};
1282
1304
  const transportType = validateTransportType((options.type ?? proxyDefaults.type ?? TRANSPORT_TYPE_STDIO).toLowerCase());
@@ -1703,7 +1725,6 @@ async function main() {
1703
1725
  program.name("mcp-proxy").description("MCP proxy server package").version(require_src.version);
1704
1726
  program.addCommand(initCommand);
1705
1727
  program.addCommand(mcpServeCommand);
1706
- program.addCommand(prestartHttpCommand);
1707
1728
  program.addCommand(searchToolsCommand);
1708
1729
  program.addCommand(describeToolsCommand);
1709
1730
  program.addCommand(useToolCommand);
package/dist/cli.mjs CHANGED
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { C as DefinitionsCacheService, D as version, T as findConfigFile, b as RuntimeStateService, d as StdioHttpTransportHandler, f as StdioTransportHandler, m as HttpTransportHandler, n as createServer, o as createProxyIoCContainer, p as SseTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, v as StopServerService, w as generateServerId } from "./src-9L_ccN5I.mjs";
2
+ import { C as DefinitionsCacheService, D as version, T as findConfigFile, b as RuntimeStateService, d as StdioHttpTransportHandler, f as StdioTransportHandler, m as HttpTransportHandler, n as createServer, o as createProxyIoCContainer, p as SseTransportHandler, r as createSessionServer, t as TRANSPORT_MODE, u as initializeSharedServices, v as StopServerService, w as generateServerId } from "./src-pCtALj-B.mjs";
3
3
  import { constants, existsSync, readFileSync } from "node:fs";
4
4
  import { access, writeFile } from "node:fs/promises";
5
5
  import yaml from "js-yaml";
6
6
  import { randomUUID } from "node:crypto";
7
7
  import path, { dirname, join, resolve } from "node:path";
8
+ import { ProcessRegistryService, createProcessLease, resolveSiblingRegistryPath } from "@agimon-ai/foundation-process-registry";
8
9
  import { spawn } from "node:child_process";
9
10
  import { Liquid } from "liquidjs";
10
11
  import { Command } from "commander";
11
12
  import { fileURLToPath } from "node:url";
12
- import { ProcessRegistryService, createProcessLease, resolveSiblingRegistryPath } from "@agimon-ai/foundation-process-registry";
13
13
  import { DEFAULT_PORT_RANGE, PortRegistryService } from "@agimon-ai/foundation-port-registry";
14
- //#region src/commands/prestart-http.ts
14
+ //#region src/commands/http-runtime.ts
15
15
  /**
16
- * Prestart HTTP Command
16
+ * HTTP Runtime Helper
17
17
  *
18
18
  * Starts an mcp-proxy HTTP runtime in the background, waits until it is healthy,
19
- * and then exits so the runtime can be reused by other commands.
19
+ * and returns the runtime details for callers that need to reuse it.
20
20
  */
21
21
  const WORKSPACE_MARKERS = [
22
22
  "pnpm-workspace.yaml",
@@ -24,7 +24,7 @@ const WORKSPACE_MARKERS = [
24
24
  ".git"
25
25
  ];
26
26
  const DEFAULT_HOST$1 = "localhost";
27
- const DEFAULT_TIMEOUT_MS = 12e4;
27
+ const DEFAULT_HTTP_RUNTIME_TIMEOUT_MS = 12e4;
28
28
  const POLL_INTERVAL_MS = 250;
29
29
  function resolveWorkspaceRoot(startPath = process.env.PROJECT_PATH || process.cwd()) {
30
30
  let current = path.resolve(startPath);
@@ -80,7 +80,7 @@ function buildCliCandidates() {
80
80
  throw new Error("Unable to locate mcp-proxy CLI entrypoint");
81
81
  }
82
82
  function parseTimeoutMs(value) {
83
- if (!value) return DEFAULT_TIMEOUT_MS;
83
+ if (!value) return DEFAULT_HTTP_RUNTIME_TIMEOUT_MS;
84
84
  const parsed = Number.parseInt(value, 10);
85
85
  if (!Number.isInteger(parsed) || parsed <= 0) throw new Error(`Invalid timeout value: ${value}`);
86
86
  return parsed;
@@ -206,17 +206,12 @@ async function prestartHttpRuntime(options) {
206
206
  throw new Error(`Failed to prestart HTTP runtime '${serverId}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
207
207
  }
208
208
  }
209
- 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) => {
210
- try {
211
- const { host, port, serverId, workspaceRoot } = await prestartHttpRuntime(options);
212
- process.stdout.write(`mcp-proxy HTTP runtime ready at http://${host}:${port} (${serverId})\n`);
213
- process.stdout.write(`runtimeId=${serverId}\n`);
214
- process.stdout.write(`runtimeUrl=http://${host}:${port}\n`);
215
- process.stdout.write(`workspaceRoot=${workspaceRoot}\n`);
216
- } catch (error) {
217
- throw new Error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${error instanceof Error ? error.message : String(error)}`, { cause: error });
218
- }
219
- });
209
+ function writePrestartHttpResult(result) {
210
+ process.stdout.write(`mcp-proxy HTTP runtime ready at http://${result.host}:${result.port} (${result.serverId})\n`);
211
+ process.stdout.write(`runtimeId=${result.serverId}\n`);
212
+ process.stdout.write(`runtimeUrl=http://${result.host}:${result.port}\n`);
213
+ process.stdout.write(`workspaceRoot=${result.workspaceRoot}\n`);
214
+ }
220
215
  //#endregion
221
216
  //#region src/commands/bootstrap.ts
222
217
  function toErrorMessage$9(error) {
@@ -1154,9 +1149,14 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
1154
1149
  console.error(`Runtime state: http://${runtimeRecord.host}:${runtimeRecord.port} (${runtimeRecord.serverId})`);
1155
1150
  }
1156
1151
  async function startStdioTransport(serverOptions) {
1152
+ let server;
1157
1153
  try {
1158
- await startServer(new StdioTransportHandler(await createServer(serverOptions), createStdioSafeLogger()));
1154
+ server = await createServer(serverOptions);
1155
+ await startServer(new StdioTransportHandler(server, createStdioSafeLogger()), async () => {
1156
+ await server?.dispose?.();
1157
+ });
1159
1158
  } catch (error) {
1159
+ await server?.dispose?.();
1160
1160
  throw new Error(`Failed to start stdio transport: ${toErrorMessage$3(error)}`);
1161
1161
  }
1162
1162
  }
@@ -1270,11 +1270,33 @@ async function startTransport(transportType, options, resolvedConfigPath, server
1270
1270
  throw new Error(`Failed to start transport '${transportType}': ${toErrorMessage$3(error)}`);
1271
1271
  }
1272
1272
  }
1273
+ async function prestartHttpRuntimeCommand(options, resolvedConfigPath) {
1274
+ try {
1275
+ writePrestartHttpResult(await prestartHttpRuntime({
1276
+ id: options.id,
1277
+ host: options.host ?? DEFAULT_HOST,
1278
+ port: options.port,
1279
+ config: options.config || resolvedConfigPath,
1280
+ cache: options.cache,
1281
+ definitionsCache: options.definitionsCache,
1282
+ clearDefinitionsCache: options.clearDefinitionsCache,
1283
+ proxyMode: options.proxyMode,
1284
+ timeoutMs: options.timeoutMs
1285
+ }));
1286
+ } catch (error) {
1287
+ console.error(`Failed to prestart HTTP runtime '${options.id || "generated-server-id"}': ${toErrorMessage$3(error)}`);
1288
+ process.exit(1);
1289
+ }
1290
+ }
1273
1291
  /**
1274
1292
  * MCP Serve command
1275
1293
  */
1276
- 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}`).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").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) => {
1294
+ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport or prestart the HTTP runtime in the background").option("-t, --type <type>", `Transport type: ${TRANSPORT_TYPE_STDIO}, ${TRANSPORT_TYPE_HTTP}, ${TRANSPORT_TYPE_SSE}, or ${TRANSPORT_TYPE_STDIO_HTTP}`).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").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)").option("--prestart-http", "Prestart the HTTP runtime in the background and exit after it becomes healthy", false).option("--timeout-ms <ms>", "How long to wait for the HTTP runtime to become healthy", String(DEFAULT_HTTP_RUNTIME_TIMEOUT_MS)).action(async (options) => {
1277
1295
  try {
1296
+ if (options.prestartHttp) {
1297
+ await prestartHttpRuntimeCommand(options, options.config || await findConfigFileAsync() || void 0);
1298
+ return;
1299
+ }
1278
1300
  const resolvedConfigPath = options.config || await findConfigFileAsync() || void 0;
1279
1301
  const proxyDefaults = resolvedConfigPath ? loadProxyDefaults(resolvedConfigPath) : {};
1280
1302
  const transportType = validateTransportType((options.type ?? proxyDefaults.type ?? TRANSPORT_TYPE_STDIO).toLowerCase());
@@ -1701,7 +1723,6 @@ async function main() {
1701
1723
  program.name("mcp-proxy").description("MCP proxy server package").version(version);
1702
1724
  program.addCommand(initCommand);
1703
1725
  program.addCommand(mcpServeCommand);
1704
- program.addCommand(prestartHttpCommand);
1705
1726
  program.addCommand(searchToolsCommand);
1706
1727
  program.addCommand(describeToolsCommand);
1707
1728
  program.addCommand(useToolCommand);
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_src = require("./src-DIQjnEBk.cjs");
2
+ const require_src = require("./src-DMlOlvPm.cjs");
3
3
  exports.ConfigFetcherService = require_src.ConfigFetcherService;
4
4
  exports.DefinitionsCacheService = require_src.DefinitionsCacheService;
5
5
  exports.DescribeToolsTool = require_src.DescribeToolsTool;
package/dist/index.d.cts CHANGED
@@ -525,12 +525,12 @@ declare class McpClientManagerService {
525
525
  private serverConfigs;
526
526
  private connectionPromises;
527
527
  private logger;
528
- constructor(logger?: LoggerLike);
528
+ private readonly repositoryPath;
529
+ constructor(logger?: LoggerLike, repositoryPath?: string);
529
530
  /**
530
531
  * Kill all stdio MCP server child processes.
531
- * Sends SIGTERM first, then SIGKILL after 1s if the process hasn't exited.
532
- * Must be called by the owner (e.g. transport/command layer) during shutdown.
533
- * Awaiting the returned promise ensures force-kill timers complete before process.exit().
532
+ * Delegates to disconnectAll() so each client closes its child process and
533
+ * releases the corresponding process-registry lease before shutdown exits.
534
534
  */
535
535
  cleanupChildProcesses(): Promise<void>;
536
536
  /**
package/dist/index.d.mts CHANGED
@@ -525,12 +525,12 @@ declare class McpClientManagerService {
525
525
  private serverConfigs;
526
526
  private connectionPromises;
527
527
  private logger;
528
- constructor(logger?: LoggerLike);
528
+ private readonly repositoryPath;
529
+ constructor(logger?: LoggerLike, repositoryPath?: string);
529
530
  /**
530
531
  * Kill all stdio MCP server child processes.
531
- * Sends SIGTERM first, then SIGKILL after 1s if the process hasn't exited.
532
- * Must be called by the owner (e.g. transport/command layer) during shutdown.
533
- * Awaiting the returned promise ensures force-kill timers complete before process.exit().
532
+ * Delegates to disconnectAll() so each client closes its child process and
533
+ * releases the corresponding process-registry lease before shutdown exits.
534
534
  */
535
535
  cleanupChildProcesses(): Promise<void>;
536
536
  /**
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { C as DefinitionsCacheService, E as ConfigFetcherService, S as createProxyLogger, T as findConfigFile, _ as DescribeToolsTool, a as createProxyContainer, b as RuntimeStateService, c as createStdioHttpTransportHandler, d as StdioHttpTransportHandler, f as StdioTransportHandler, g as SearchListToolsTool, h as UseToolTool, i as createHttpTransportHandler, l as createStdioTransportHandler, m as HttpTransportHandler, n as createServer, p as SseTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as StopServerService, w as generateServerId, x as McpClientManagerService, y as SkillService } from "./src-9L_ccN5I.mjs";
1
+ import { C as DefinitionsCacheService, E as ConfigFetcherService, S as createProxyLogger, T as findConfigFile, _ as DescribeToolsTool, a as createProxyContainer, b as RuntimeStateService, c as createStdioHttpTransportHandler, d as StdioHttpTransportHandler, f as StdioTransportHandler, g as SearchListToolsTool, h as UseToolTool, i as createHttpTransportHandler, l as createStdioTransportHandler, m as HttpTransportHandler, n as createServer, p as SseTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as StopServerService, w as generateServerId, x as McpClientManagerService, y as SkillService } from "./src-pCtALj-B.mjs";
2
2
  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 };
@@ -33,6 +33,7 @@ let _modelcontextprotocol_sdk_client_index_js = require("@modelcontextprotocol/s
33
33
  let _modelcontextprotocol_sdk_client_sse_js = require("@modelcontextprotocol/sdk/client/sse.js");
34
34
  let _modelcontextprotocol_sdk_client_stdio_js = require("@modelcontextprotocol/sdk/client/stdio.js");
35
35
  let _modelcontextprotocol_sdk_client_streamableHttp_js = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
36
+ let _agimon_ai_foundation_process_registry = require("@agimon-ai/foundation-process-registry");
36
37
  let node_child_process = require("node:child_process");
37
38
  let liquidjs = require("liquidjs");
38
39
  let _agimon_ai_foundation_validator = require("@agimon-ai/foundation-validator");
@@ -47,7 +48,7 @@ let _modelcontextprotocol_sdk_server_sse_js = require("@modelcontextprotocol/sdk
47
48
  let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
48
49
  let _modelcontextprotocol_sdk_server_index_js = require("@modelcontextprotocol/sdk/server/index.js");
49
50
  //#region package.json
50
- var version = "0.9.1";
51
+ var version = "0.10.1";
51
52
  //#endregion
52
53
  //#region src/utils/mcpConfigSchema.ts
53
54
  /**
@@ -1538,6 +1539,7 @@ async function createProxyLogger(options = {}) {
1538
1539
  //#region src/services/McpClientManagerService.ts
1539
1540
  /** Default connection timeout in milliseconds (30 seconds) */
1540
1541
  const DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
1542
+ const PROCESS_REGISTRY_SERVICE_TYPE = "tool";
1541
1543
  /**
1542
1544
  * Checks if an error is a session-related error from an HTTP backend
1543
1545
  * (e.g., downstream server restarted and no longer recognizes the session ID).
@@ -1592,6 +1594,7 @@ var McpClient = class {
1592
1594
  logger;
1593
1595
  client;
1594
1596
  childProcess;
1597
+ processLease;
1595
1598
  connected = false;
1596
1599
  reconnectFn;
1597
1600
  reconnectPromise;
@@ -1608,6 +1611,9 @@ var McpClient = class {
1608
1611
  setChildProcess(process) {
1609
1612
  this.childProcess = process;
1610
1613
  }
1614
+ setProcessLease(processLease) {
1615
+ this.processLease = processLease;
1616
+ }
1611
1617
  setConnected(connected) {
1612
1618
  this.connected = connected;
1613
1619
  }
@@ -1706,9 +1712,20 @@ var McpClient = class {
1706
1712
  });
1707
1713
  }
1708
1714
  async close() {
1709
- if (this.childProcess) this.childProcess.kill();
1710
- await this.client.close();
1715
+ const childProcess = this.childProcess;
1716
+ const processLease = this.processLease;
1717
+ this.childProcess = void 0;
1718
+ this.processLease = void 0;
1711
1719
  this.connected = false;
1720
+ try {
1721
+ if (childProcess) childProcess.kill();
1722
+ await this.client.close();
1723
+ } finally {
1724
+ await processLease?.release({
1725
+ kill: false,
1726
+ releasePort: false
1727
+ });
1728
+ }
1712
1729
  }
1713
1730
  };
1714
1731
  /**
@@ -1719,38 +1736,18 @@ var McpClientManagerService = class {
1719
1736
  serverConfigs = /* @__PURE__ */ new Map();
1720
1737
  connectionPromises = /* @__PURE__ */ new Map();
1721
1738
  logger;
1722
- constructor(logger = console) {
1739
+ repositoryPath;
1740
+ constructor(logger = console, repositoryPath = process.cwd()) {
1723
1741
  this.logger = logger;
1742
+ this.repositoryPath = repositoryPath;
1724
1743
  }
1725
1744
  /**
1726
1745
  * Kill all stdio MCP server child processes.
1727
- * Sends SIGTERM first, then SIGKILL after 1s if the process hasn't exited.
1728
- * Must be called by the owner (e.g. transport/command layer) during shutdown.
1729
- * Awaiting the returned promise ensures force-kill timers complete before process.exit().
1746
+ * Delegates to disconnectAll() so each client closes its child process and
1747
+ * releases the corresponding process-registry lease before shutdown exits.
1730
1748
  */
1731
1749
  async cleanupChildProcesses() {
1732
- const killPromises = [];
1733
- for (const [serverName, client] of this.clients) try {
1734
- const childProcess = client["childProcess"];
1735
- if (childProcess && !childProcess.killed) {
1736
- this.logger.info(`Killing stdio MCP server: ${serverName} (PID: ${childProcess.pid})`);
1737
- childProcess.kill("SIGTERM");
1738
- killPromises.push(new Promise((resolve) => {
1739
- setTimeout(() => {
1740
- try {
1741
- if (!childProcess.killed) {
1742
- this.logger.warn(`Force killing stdio MCP server: ${serverName} (PID: ${childProcess.pid})`);
1743
- childProcess.kill("SIGKILL");
1744
- }
1745
- } catch {}
1746
- resolve();
1747
- }, 1e3);
1748
- }));
1749
- }
1750
- } catch (error) {
1751
- this.logger.warn(`Failed to kill child process for ${serverName}`, error);
1752
- }
1753
- await Promise.all(killPromises);
1750
+ await this.disconnectAll();
1754
1751
  }
1755
1752
  /**
1756
1753
  * Connect to an MCP server based on its configuration with timeout
@@ -1846,7 +1843,22 @@ var McpClientManagerService = class {
1846
1843
  });
1847
1844
  await mcpClient["client"].connect(transport);
1848
1845
  const childProcess = transport["_process"];
1849
- if (childProcess) mcpClient.setChildProcess(childProcess);
1846
+ if (childProcess) {
1847
+ if (typeof childProcess.pid !== "number" || childProcess.pid <= 0) throw new Error(`Failed to capture pid for stdio child process on server "${mcpClient.serverName}"`);
1848
+ mcpClient.setChildProcess(childProcess);
1849
+ const processLease = await (0, _agimon_ai_foundation_process_registry.createProcessLease)({
1850
+ repositoryPath: this.repositoryPath,
1851
+ serviceName: mcpClient.serverName,
1852
+ serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
1853
+ pid: childProcess.pid,
1854
+ command: config.command,
1855
+ args: config.args,
1856
+ metadata: { transport: "stdio" }
1857
+ });
1858
+ mcpClient.setProcessLease(processLease);
1859
+ return;
1860
+ }
1861
+ throw new Error(`Failed to capture stdio child process for server "${mcpClient.serverName}"`);
1850
1862
  }
1851
1863
  async connectHttpClient(mcpClient, config) {
1852
1864
  const transport = new _modelcontextprotocol_sdk_client_streamableHttp_js.StreamableHTTPClientTransport(new URL(config.url), { requestInit: config.headers ? { headers: config.headers } : void 0 });
@@ -4938,7 +4950,10 @@ async function createSessionServer(shared) {
4938
4950
  * For multi-session HTTP transport, use createProxyContainer() + createSessionServer() instead.
4939
4951
  */
4940
4952
  async function createServer(options) {
4941
- return createSessionServer(await createProxyContainer(options));
4953
+ const shared = await createProxyContainer(options);
4954
+ const server = await createSessionServer(shared);
4955
+ Object.assign(server, { dispose: shared.dispose });
4956
+ return server;
4942
4957
  }
4943
4958
  //#endregion
4944
4959
  //#region src/types/index.ts
@@ -10,6 +10,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
10
10
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
11
11
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
12
12
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
13
+ import { createProcessLease } from "@agimon-ai/foundation-process-registry";
13
14
  import { spawn } from "node:child_process";
14
15
  import { Liquid } from "liquidjs";
15
16
  import { coerceArgs, formatZodError, jsonSchemaToZod } from "@agimon-ai/foundation-validator";
@@ -24,7 +25,7 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
24
25
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
26
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
26
27
  //#region package.json
27
- var version = "0.9.1";
28
+ var version = "0.10.1";
28
29
  //#endregion
29
30
  //#region src/utils/mcpConfigSchema.ts
30
31
  /**
@@ -1515,6 +1516,7 @@ async function createProxyLogger(options = {}) {
1515
1516
  //#region src/services/McpClientManagerService.ts
1516
1517
  /** Default connection timeout in milliseconds (30 seconds) */
1517
1518
  const DEFAULT_CONNECTION_TIMEOUT_MS = 3e4;
1519
+ const PROCESS_REGISTRY_SERVICE_TYPE = "tool";
1518
1520
  /**
1519
1521
  * Checks if an error is a session-related error from an HTTP backend
1520
1522
  * (e.g., downstream server restarted and no longer recognizes the session ID).
@@ -1569,6 +1571,7 @@ var McpClient = class {
1569
1571
  logger;
1570
1572
  client;
1571
1573
  childProcess;
1574
+ processLease;
1572
1575
  connected = false;
1573
1576
  reconnectFn;
1574
1577
  reconnectPromise;
@@ -1585,6 +1588,9 @@ var McpClient = class {
1585
1588
  setChildProcess(process) {
1586
1589
  this.childProcess = process;
1587
1590
  }
1591
+ setProcessLease(processLease) {
1592
+ this.processLease = processLease;
1593
+ }
1588
1594
  setConnected(connected) {
1589
1595
  this.connected = connected;
1590
1596
  }
@@ -1683,9 +1689,20 @@ var McpClient = class {
1683
1689
  });
1684
1690
  }
1685
1691
  async close() {
1686
- if (this.childProcess) this.childProcess.kill();
1687
- await this.client.close();
1692
+ const childProcess = this.childProcess;
1693
+ const processLease = this.processLease;
1694
+ this.childProcess = void 0;
1695
+ this.processLease = void 0;
1688
1696
  this.connected = false;
1697
+ try {
1698
+ if (childProcess) childProcess.kill();
1699
+ await this.client.close();
1700
+ } finally {
1701
+ await processLease?.release({
1702
+ kill: false,
1703
+ releasePort: false
1704
+ });
1705
+ }
1689
1706
  }
1690
1707
  };
1691
1708
  /**
@@ -1696,38 +1713,18 @@ var McpClientManagerService = class {
1696
1713
  serverConfigs = /* @__PURE__ */ new Map();
1697
1714
  connectionPromises = /* @__PURE__ */ new Map();
1698
1715
  logger;
1699
- constructor(logger = console) {
1716
+ repositoryPath;
1717
+ constructor(logger = console, repositoryPath = process.cwd()) {
1700
1718
  this.logger = logger;
1719
+ this.repositoryPath = repositoryPath;
1701
1720
  }
1702
1721
  /**
1703
1722
  * Kill all stdio MCP server child processes.
1704
- * Sends SIGTERM first, then SIGKILL after 1s if the process hasn't exited.
1705
- * Must be called by the owner (e.g. transport/command layer) during shutdown.
1706
- * Awaiting the returned promise ensures force-kill timers complete before process.exit().
1723
+ * Delegates to disconnectAll() so each client closes its child process and
1724
+ * releases the corresponding process-registry lease before shutdown exits.
1707
1725
  */
1708
1726
  async cleanupChildProcesses() {
1709
- const killPromises = [];
1710
- for (const [serverName, client] of this.clients) try {
1711
- const childProcess = client["childProcess"];
1712
- if (childProcess && !childProcess.killed) {
1713
- this.logger.info(`Killing stdio MCP server: ${serverName} (PID: ${childProcess.pid})`);
1714
- childProcess.kill("SIGTERM");
1715
- killPromises.push(new Promise((resolve) => {
1716
- setTimeout(() => {
1717
- try {
1718
- if (!childProcess.killed) {
1719
- this.logger.warn(`Force killing stdio MCP server: ${serverName} (PID: ${childProcess.pid})`);
1720
- childProcess.kill("SIGKILL");
1721
- }
1722
- } catch {}
1723
- resolve();
1724
- }, 1e3);
1725
- }));
1726
- }
1727
- } catch (error) {
1728
- this.logger.warn(`Failed to kill child process for ${serverName}`, error);
1729
- }
1730
- await Promise.all(killPromises);
1727
+ await this.disconnectAll();
1731
1728
  }
1732
1729
  /**
1733
1730
  * Connect to an MCP server based on its configuration with timeout
@@ -1823,7 +1820,22 @@ var McpClientManagerService = class {
1823
1820
  });
1824
1821
  await mcpClient["client"].connect(transport);
1825
1822
  const childProcess = transport["_process"];
1826
- if (childProcess) mcpClient.setChildProcess(childProcess);
1823
+ if (childProcess) {
1824
+ if (typeof childProcess.pid !== "number" || childProcess.pid <= 0) throw new Error(`Failed to capture pid for stdio child process on server "${mcpClient.serverName}"`);
1825
+ mcpClient.setChildProcess(childProcess);
1826
+ const processLease = await createProcessLease({
1827
+ repositoryPath: this.repositoryPath,
1828
+ serviceName: mcpClient.serverName,
1829
+ serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
1830
+ pid: childProcess.pid,
1831
+ command: config.command,
1832
+ args: config.args,
1833
+ metadata: { transport: "stdio" }
1834
+ });
1835
+ mcpClient.setProcessLease(processLease);
1836
+ return;
1837
+ }
1838
+ throw new Error(`Failed to capture stdio child process for server "${mcpClient.serverName}"`);
1827
1839
  }
1828
1840
  async connectHttpClient(mcpClient, config) {
1829
1841
  const transport = new StreamableHTTPClientTransport(new URL(config.url), { requestInit: config.headers ? { headers: config.headers } : void 0 });
@@ -4915,7 +4927,10 @@ async function createSessionServer(shared) {
4915
4927
  * For multi-session HTTP transport, use createProxyContainer() + createSessionServer() instead.
4916
4928
  */
4917
4929
  async function createServer$1(options) {
4918
- return createSessionServer(await createProxyContainer(options));
4930
+ const shared = await createProxyContainer(options);
4931
+ const server = await createSessionServer(shared);
4932
+ Object.assign(server, { dispose: shared.dispose });
4933
+ return server;
4919
4934
  }
4920
4935
  //#endregion
4921
4936
  //#region src/types/index.ts
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.10.0",
4
+ "version": "0.10.2",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",