@agimon-ai/mcp-proxy 0.4.11 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +146 -105
- package/dist/cli.mjs +146 -106
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +74 -60
- package/dist/index.d.mts +74 -60
- package/dist/index.mjs +1 -1
- package/dist/{src-DwErnAUn.cjs → src-B5N-kt9Y.cjs} +2965 -2802
- package/dist/{src-Cp1GdSlN.mjs → src-DQSfFKFP.mjs} +2968 -2804
- package/package.json +9 -6
package/dist/cli.mjs
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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, w as generateServerId, y as StopServerService } from "./src-DQSfFKFP.mjs";
|
|
3
|
+
import { constants, existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { access, writeFile } from "node:fs/promises";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import yaml from "js-yaml";
|
|
6
|
+
import { randomUUID } from "node:crypto";
|
|
7
|
+
import path, { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
|
+
import { Liquid } from "liquidjs";
|
|
9
10
|
import { Command } from "commander";
|
|
10
11
|
import { DEFAULT_PORT_RANGE, PortRegistryService } from "@agimon-ai/foundation-port-registry";
|
|
11
|
-
import { ProcessRegistryService } from "@agimon-ai/foundation-process-registry";
|
|
12
|
+
import { ProcessRegistryService, createProcessLease, resolveSiblingRegistryPath } from "@agimon-ai/foundation-process-registry";
|
|
12
13
|
import { fileURLToPath } from "node:url";
|
|
13
14
|
|
|
15
|
+
//#region src/templates/mcp-config.json?raw
|
|
16
|
+
var mcp_config_default = "{\n \"_comment\": \"MCP Server Configuration - Use ${VAR_NAME} syntax for environment variable interpolation\",\n \"_instructions\": \"config.instruction: Server's default instruction | instruction: User override (takes precedence)\",\n \"mcpServers\": {\n \"example-server\": {\n \"command\": \"node\",\n \"args\": [\"/path/to/mcp-server/build/index.js\"],\n \"env\": {\n \"LOG_LEVEL\": \"info\",\n \"_comment\": \"You can use environment variable interpolation:\",\n \"_example_DATABASE_URL\": \"${DATABASE_URL}\",\n \"_example_API_KEY\": \"${MY_API_KEY}\"\n },\n \"config\": {\n \"instruction\": \"Use this server for...\"\n },\n \"_instruction_override\": \"Optional user override - takes precedence over config.instruction\"\n }\n }\n}\n";
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/templates/mcp-config.yaml.liquid?raw
|
|
20
|
+
var mcp_config_yaml_default = "# MCP Server Configuration\n# This file configures the MCP servers that mcp-proxy will connect to\n#\n# Environment Variable Interpolation:\n# Use ${VAR_NAME} syntax to reference environment variables\n# Example: ${HOME}, ${API_KEY}, ${DATABASE_URL}\n#\n# Instructions:\n# - config.instruction: Server's default instruction (from server documentation)\n# - instruction: User override (optional, takes precedence over config.instruction)\n# - config.toolBlacklist: Array of tool names to hide/block from this server\n# - config.omitToolDescription: Boolean to show only tool names without descriptions (saves tokens)\n\n# Remote Configuration Sources (OPTIONAL)\n# Fetch and merge configurations from remote URLs\n# Remote configs are merged with local configs based on merge strategy\n#\n# SECURITY: SSRF Protection is ENABLED by default\n# - Only HTTPS URLs are allowed (set security.enforceHttps: false to allow HTTP)\n# - Private IPs and localhost are blocked (set security.allowPrivateIPs: true for internal networks)\n# - Blocked ranges: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16\nremoteConfigs:\n # Example 1: Basic remote config with default security\n # - url: ${AGIFLOW_URL}/api/v1/mcp-configs\n # headers:\n # Authorization: Bearer ${AGIFLOW_API_KEY}\n # mergeStrategy: local-priority # Options: local-priority (default), remote-priority, merge-deep\n #\n # Example 2: Remote config with custom security settings (for internal networks)\n # - url: ${INTERNAL_URL}/mcp-configs\n # headers:\n # Authorization: Bearer ${INTERNAL_TOKEN}\n # security:\n # allowPrivateIPs: true # Allow internal IPs (default: false)\n # enforceHttps: false # Allow HTTP (default: true, HTTPS only)\n # mergeStrategy: local-priority\n #\n # Example 3: Remote config with additional validation (OPTIONAL)\n # - url: ${AGIFLOW_URL}/api/v1/mcp-configs\n # headers:\n # Authorization: Bearer ${AGIFLOW_API_KEY}\n # X-API-Key: ${AGIFLOW_API_KEY}\n # security:\n # enforceHttps: true # Require HTTPS (default: true)\n # allowPrivateIPs: false # Block private IPs (default: false)\n # validation: # OPTIONAL: Additional regex validation on top of security checks\n # url: ^https://.*\\.agiflow\\.io/.* # OPTIONAL: Regex pattern to validate URL format\n # headers: # OPTIONAL: Regex patterns to validate header values\n # Authorization: ^Bearer [A-Za-z0-9_-]+$\n # X-API-Key: ^[A-Za-z0-9_-]{32,}$\n # mergeStrategy: local-priority\n\nmcpServers:\n{%- if mcpServers %}{% for server in mcpServers %}\n {{ server.name }}:\n command: {{ server.command }}\n args:{% for arg in server.args %}\n - '{{ arg }}'{% endfor %}\n # env:\n # LOG_LEVEL: info\n # # API_KEY: ${MY_API_KEY}\n # config:\n # instruction: Use this server for...\n # # toolBlacklist:\n # # - tool_to_block\n # # omitToolDescription: true\n{% endfor %}\n # Example MCP server using SSE transport\n # remote-server:\n # url: https://example.com/mcp\n # type: sse\n # headers:\n # Authorization: Bearer ${API_KEY}\n # config:\n # instruction: This server provides tools for...\n{% else %}\n # Example MCP server using stdio transport\n example-server:\n command: node\n args:\n - /path/to/mcp-server/build/index.js\n env:\n # Environment variables for the MCP server\n LOG_LEVEL: info\n # You can use environment variable interpolation:\n # DATABASE_URL: ${DATABASE_URL}\n # API_KEY: ${MY_API_KEY}\n config:\n # Server's default instruction (from server documentation)\n instruction: Use this server for...\n # Optional: Block specific tools from being listed or executed\n # toolBlacklist:\n # - dangerous_tool_name\n # - another_blocked_tool\n # Optional: Omit tool descriptions to save tokens (default: false)\n # omitToolDescription: true\n # instruction: Optional user override - takes precedence over config.instruction\n\n # Example MCP server using SSE transport with environment variables\n # remote-server:\n # url: https://example.com/mcp\n # type: sse\n # headers:\n # # Use ${VAR_NAME} to interpolate environment variables\n # Authorization: Bearer ${API_KEY}\n # config:\n # instruction: This server provides tools for...\n # # Optional: Block specific tools from being listed or executed\n # # toolBlacklist:\n # # - tool_to_block\n # # Optional: Omit tool descriptions to save tokens (default: false)\n # # omitToolDescription: true\n # # instruction: Optional user override\n{% endif %}\n";
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
14
23
|
//#region src/utils/output.ts
|
|
15
24
|
function writeLine(message = "") {
|
|
16
25
|
console.log(message);
|
|
@@ -34,14 +43,6 @@ const print = {
|
|
|
34
43
|
indent: (message) => writeLine(` ${message}`)
|
|
35
44
|
};
|
|
36
45
|
|
|
37
|
-
//#endregion
|
|
38
|
-
//#region src/templates/mcp-config.yaml.liquid?raw
|
|
39
|
-
var mcp_config_yaml_default = "# MCP Server Configuration\n# This file configures the MCP servers that mcp-proxy will connect to\n#\n# Environment Variable Interpolation:\n# Use ${VAR_NAME} syntax to reference environment variables\n# Example: ${HOME}, ${API_KEY}, ${DATABASE_URL}\n#\n# Instructions:\n# - config.instruction: Server's default instruction (from server documentation)\n# - instruction: User override (optional, takes precedence over config.instruction)\n# - config.toolBlacklist: Array of tool names to hide/block from this server\n# - config.omitToolDescription: Boolean to show only tool names without descriptions (saves tokens)\n\n# Remote Configuration Sources (OPTIONAL)\n# Fetch and merge configurations from remote URLs\n# Remote configs are merged with local configs based on merge strategy\n#\n# SECURITY: SSRF Protection is ENABLED by default\n# - Only HTTPS URLs are allowed (set security.enforceHttps: false to allow HTTP)\n# - Private IPs and localhost are blocked (set security.allowPrivateIPs: true for internal networks)\n# - Blocked ranges: 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16\nremoteConfigs:\n # Example 1: Basic remote config with default security\n # - url: ${AGIFLOW_URL}/api/v1/mcp-configs\n # headers:\n # Authorization: Bearer ${AGIFLOW_API_KEY}\n # mergeStrategy: local-priority # Options: local-priority (default), remote-priority, merge-deep\n #\n # Example 2: Remote config with custom security settings (for internal networks)\n # - url: ${INTERNAL_URL}/mcp-configs\n # headers:\n # Authorization: Bearer ${INTERNAL_TOKEN}\n # security:\n # allowPrivateIPs: true # Allow internal IPs (default: false)\n # enforceHttps: false # Allow HTTP (default: true, HTTPS only)\n # mergeStrategy: local-priority\n #\n # Example 3: Remote config with additional validation (OPTIONAL)\n # - url: ${AGIFLOW_URL}/api/v1/mcp-configs\n # headers:\n # Authorization: Bearer ${AGIFLOW_API_KEY}\n # X-API-Key: ${AGIFLOW_API_KEY}\n # security:\n # enforceHttps: true # Require HTTPS (default: true)\n # allowPrivateIPs: false # Block private IPs (default: false)\n # validation: # OPTIONAL: Additional regex validation on top of security checks\n # url: ^https://.*\\.agiflow\\.io/.* # OPTIONAL: Regex pattern to validate URL format\n # headers: # OPTIONAL: Regex patterns to validate header values\n # Authorization: ^Bearer [A-Za-z0-9_-]+$\n # X-API-Key: ^[A-Za-z0-9_-]{32,}$\n # mergeStrategy: local-priority\n\nmcpServers:\n{%- if mcpServers %}{% for server in mcpServers %}\n {{ server.name }}:\n command: {{ server.command }}\n args:{% for arg in server.args %}\n - '{{ arg }}'{% endfor %}\n # env:\n # LOG_LEVEL: info\n # # API_KEY: ${MY_API_KEY}\n # config:\n # instruction: Use this server for...\n # # toolBlacklist:\n # # - tool_to_block\n # # omitToolDescription: true\n{% endfor %}\n # Example MCP server using SSE transport\n # remote-server:\n # url: https://example.com/mcp\n # type: sse\n # headers:\n # Authorization: Bearer ${API_KEY}\n # config:\n # instruction: This server provides tools for...\n{% else %}\n # Example MCP server using stdio transport\n example-server:\n command: node\n args:\n - /path/to/mcp-server/build/index.js\n env:\n # Environment variables for the MCP server\n LOG_LEVEL: info\n # You can use environment variable interpolation:\n # DATABASE_URL: ${DATABASE_URL}\n # API_KEY: ${MY_API_KEY}\n config:\n # Server's default instruction (from server documentation)\n instruction: Use this server for...\n # Optional: Block specific tools from being listed or executed\n # toolBlacklist:\n # - dangerous_tool_name\n # - another_blocked_tool\n # Optional: Omit tool descriptions to save tokens (default: false)\n # omitToolDescription: true\n # instruction: Optional user override - takes precedence over config.instruction\n\n # Example MCP server using SSE transport with environment variables\n # remote-server:\n # url: https://example.com/mcp\n # type: sse\n # headers:\n # # Use ${VAR_NAME} to interpolate environment variables\n # Authorization: Bearer ${API_KEY}\n # config:\n # instruction: This server provides tools for...\n # # Optional: Block specific tools from being listed or executed\n # # toolBlacklist:\n # # - tool_to_block\n # # Optional: Omit tool descriptions to save tokens (default: false)\n # # omitToolDescription: true\n # # instruction: Optional user override\n{% endif %}\n";
|
|
40
|
-
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region src/templates/mcp-config.json?raw
|
|
43
|
-
var mcp_config_default = "{\n \"_comment\": \"MCP Server Configuration - Use ${VAR_NAME} syntax for environment variable interpolation\",\n \"_instructions\": \"config.instruction: Server's default instruction | instruction: User override (takes precedence)\",\n \"mcpServers\": {\n \"example-server\": {\n \"command\": \"node\",\n \"args\": [\"/path/to/mcp-server/build/index.js\"],\n \"env\": {\n \"LOG_LEVEL\": \"info\",\n \"_comment\": \"You can use environment variable interpolation:\",\n \"_example_DATABASE_URL\": \"${DATABASE_URL}\",\n \"_example_API_KEY\": \"${MY_API_KEY}\"\n },\n \"config\": {\n \"instruction\": \"Use this server for...\"\n },\n \"_instruction_override\": \"Optional user override - takes precedence over config.instruction\"\n }\n }\n}\n";
|
|
44
|
-
|
|
45
46
|
//#endregion
|
|
46
47
|
//#region src/commands/init.ts
|
|
47
48
|
/**
|
|
@@ -158,12 +159,6 @@ async function findExistingHealthyRuntime(workspaceRoot) {
|
|
|
158
159
|
} catch {}
|
|
159
160
|
return null;
|
|
160
161
|
}
|
|
161
|
-
function resolveSiblingRegistryPath(registryPath, fileName) {
|
|
162
|
-
if (!registryPath) return;
|
|
163
|
-
const resolved = path.resolve(registryPath);
|
|
164
|
-
if (path.extname(resolved) === ".json") return path.join(path.dirname(resolved), fileName);
|
|
165
|
-
return path.join(resolved, fileName);
|
|
166
|
-
}
|
|
167
162
|
function buildCliCandidates() {
|
|
168
163
|
const __filename = fileURLToPath(import.meta.url);
|
|
169
164
|
const __dirname = path.dirname(__filename);
|
|
@@ -386,16 +381,37 @@ async function findConfigFileAsync() {
|
|
|
386
381
|
const configPath = resolve(projectPath, fileName);
|
|
387
382
|
if (await pathExists(configPath)) return configPath;
|
|
388
383
|
}
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
384
|
+
const MAX_PARENT_LEVELS = 3;
|
|
385
|
+
let searchDir = process.cwd();
|
|
386
|
+
for (let level = 0; level <= MAX_PARENT_LEVELS; level++) {
|
|
387
|
+
for (const fileName of CONFIG_FILE_NAMES) {
|
|
388
|
+
const configPath = join(searchDir, fileName);
|
|
389
|
+
if (await pathExists(configPath)) return configPath;
|
|
390
|
+
}
|
|
391
|
+
const parentDir = dirname(searchDir);
|
|
392
|
+
if (parentDir === searchDir) break;
|
|
393
|
+
searchDir = parentDir;
|
|
393
394
|
}
|
|
394
395
|
return null;
|
|
395
396
|
} catch (error) {
|
|
396
397
|
throw new Error(`Failed to discover MCP config file: ${toErrorMessage$9(error)}`);
|
|
397
398
|
}
|
|
398
399
|
}
|
|
400
|
+
function loadProxyDefaults(configPath) {
|
|
401
|
+
try {
|
|
402
|
+
const content = readFileSync(configPath, "utf-8");
|
|
403
|
+
const proxy = (configPath.endsWith(".yaml") || configPath.endsWith(".yml") ? yaml.load(content) : JSON.parse(content))?.proxy;
|
|
404
|
+
if (!proxy || typeof proxy !== "object") return {};
|
|
405
|
+
const p = proxy;
|
|
406
|
+
return {
|
|
407
|
+
type: typeof p.type === "string" ? p.type : void 0,
|
|
408
|
+
port: typeof p.port === "number" && Number.isInteger(p.port) && p.port > 0 ? p.port : void 0,
|
|
409
|
+
host: typeof p.host === "string" ? p.host : void 0
|
|
410
|
+
};
|
|
411
|
+
} catch {
|
|
412
|
+
return {};
|
|
413
|
+
}
|
|
414
|
+
}
|
|
399
415
|
async function resolveServerId(options, resolvedConfigPath) {
|
|
400
416
|
const container = createProxyIoCContainer();
|
|
401
417
|
if (options.id) return options.id;
|
|
@@ -417,12 +433,12 @@ function validateTransportType(type) {
|
|
|
417
433
|
function validateProxyMode(mode) {
|
|
418
434
|
if (!isValidProxyMode(mode)) throw new Error(`Unknown proxy mode: '${mode}'. Valid options: meta, flat, search`);
|
|
419
435
|
}
|
|
420
|
-
function createTransportConfig(options, mode) {
|
|
436
|
+
function createTransportConfig(options, mode, proxyDefaults) {
|
|
421
437
|
const envPort = process.env.MCP_PORT ? Number(process.env.MCP_PORT) : void 0;
|
|
422
438
|
return {
|
|
423
439
|
mode,
|
|
424
|
-
port: options.port ?? (Number.isFinite(envPort) ? envPort : void 0),
|
|
425
|
-
host: options.host
|
|
440
|
+
port: options.port ?? (Number.isFinite(envPort) ? envPort : void 0) ?? proxyDefaults?.port,
|
|
441
|
+
host: options.host ?? process.env.MCP_HOST ?? proxyDefaults?.host ?? DEFAULT_HOST
|
|
426
442
|
};
|
|
427
443
|
}
|
|
428
444
|
function createStdioSafeLogger() {
|
|
@@ -471,9 +487,6 @@ function createRuntimeRecord(serverId, config, port, shutdownToken, configPath)
|
|
|
471
487
|
function createPortRegistryService() {
|
|
472
488
|
return new PortRegistryService(process.env.PORT_REGISTRY_PATH);
|
|
473
489
|
}
|
|
474
|
-
function createProcessRegistryService() {
|
|
475
|
-
return new ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH);
|
|
476
|
-
}
|
|
477
490
|
function getRegistryEnvironment() {
|
|
478
491
|
return process.env.NODE_ENV ?? "development";
|
|
479
492
|
}
|
|
@@ -520,41 +533,6 @@ async function createPortRegistryLease(serviceName, host, preferredPort, serverI
|
|
|
520
533
|
}
|
|
521
534
|
};
|
|
522
535
|
}
|
|
523
|
-
async function createProcessRegistryLease(serviceName, host, port, serverId, transport, configPath) {
|
|
524
|
-
const processRegistry = createProcessRegistryService();
|
|
525
|
-
const result = await processRegistry.registerProcess({
|
|
526
|
-
repositoryPath: getRegistryRepositoryPath(),
|
|
527
|
-
serviceName,
|
|
528
|
-
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
529
|
-
environment: getRegistryEnvironment(),
|
|
530
|
-
pid: process.pid,
|
|
531
|
-
host,
|
|
532
|
-
port,
|
|
533
|
-
command: process.argv[1],
|
|
534
|
-
args: process.argv.slice(2),
|
|
535
|
-
metadata: {
|
|
536
|
-
transport,
|
|
537
|
-
serverId,
|
|
538
|
-
...configPath ? { configPath } : {}
|
|
539
|
-
}
|
|
540
|
-
});
|
|
541
|
-
if (!result.success || !result.record) throw new Error(result.error || `Failed to register process for ${serviceName}`);
|
|
542
|
-
let released = false;
|
|
543
|
-
return { release: async (options) => {
|
|
544
|
-
if (released) return;
|
|
545
|
-
released = true;
|
|
546
|
-
const releaseResult = await processRegistry.releaseProcess({
|
|
547
|
-
repositoryPath: getRegistryRepositoryPath(),
|
|
548
|
-
serviceName,
|
|
549
|
-
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
550
|
-
pid: process.pid,
|
|
551
|
-
environment: getRegistryEnvironment(),
|
|
552
|
-
kill: options?.kill ?? false,
|
|
553
|
-
releasePort: options?.releasePort ?? false
|
|
554
|
-
});
|
|
555
|
-
if (!releaseResult.success && releaseResult.error && !releaseResult.error.includes("No matching process entry")) throw new Error(releaseResult.error || `Failed to release process for ${serviceName}`);
|
|
556
|
-
} };
|
|
557
|
-
}
|
|
558
536
|
async function releasePortLease(lease) {
|
|
559
537
|
if (!lease) return;
|
|
560
538
|
await lease.release();
|
|
@@ -588,13 +566,19 @@ async function stopOwnedHttpTransport(handler, runtimeStateService, serverId, pr
|
|
|
588
566
|
throw new Error(`Failed to stop owned HTTP transport '${serverId}': ${toErrorMessage$9(error)}`);
|
|
589
567
|
}
|
|
590
568
|
} finally {
|
|
591
|
-
await processLease?.release({
|
|
592
|
-
kill: false,
|
|
593
|
-
releasePort: false
|
|
594
|
-
});
|
|
569
|
+
await processLease?.release({ kill: false });
|
|
595
570
|
await removeRuntimeRecord(runtimeStateService, serverId);
|
|
596
571
|
}
|
|
597
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Run post-stop cleanup for an HTTP runtime (release port, dispose services, remove state).
|
|
575
|
+
* This is the subset of stopOwnedHttpTransport that runs AFTER handler.stop() has already
|
|
576
|
+
* been called by startServer()'s signal handler — avoids double-stopping the transport.
|
|
577
|
+
*/
|
|
578
|
+
async function cleanupHttpRuntime(runtimeStateService, serverId, processLease) {
|
|
579
|
+
await processLease?.release({ kill: false });
|
|
580
|
+
await removeRuntimeRecord(runtimeStateService, serverId);
|
|
581
|
+
}
|
|
598
582
|
async function cleanupFailedRuntimeStartup(handler, runtimeStateService, serverId, processLease) {
|
|
599
583
|
try {
|
|
600
584
|
try {
|
|
@@ -603,10 +587,7 @@ async function cleanupFailedRuntimeStartup(handler, runtimeStateService, serverI
|
|
|
603
587
|
throw new Error(`Failed to stop HTTP transport during cleanup for '${serverId}': ${toErrorMessage$9(error)}`);
|
|
604
588
|
}
|
|
605
589
|
} finally {
|
|
606
|
-
await processLease?.release({
|
|
607
|
-
kill: false,
|
|
608
|
-
releasePort: false
|
|
609
|
-
});
|
|
590
|
+
await processLease?.release({ kill: false });
|
|
610
591
|
await removeRuntimeRecord(runtimeStateService, serverId);
|
|
611
592
|
}
|
|
612
593
|
}
|
|
@@ -651,7 +632,21 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
651
632
|
...config,
|
|
652
633
|
port: runtimePort
|
|
653
634
|
};
|
|
654
|
-
const processLease = await
|
|
635
|
+
const processLease = await createProcessLease({
|
|
636
|
+
repositoryPath: getRegistryRepositoryPath(),
|
|
637
|
+
serviceName: PROCESS_REGISTRY_SERVICE_HTTP,
|
|
638
|
+
serviceType: PROCESS_REGISTRY_SERVICE_TYPE,
|
|
639
|
+
environment: getRegistryEnvironment(),
|
|
640
|
+
host: runtimeConfig.host ?? DEFAULT_HOST,
|
|
641
|
+
port: runtimePort,
|
|
642
|
+
command: process.argv[1],
|
|
643
|
+
args: process.argv.slice(2),
|
|
644
|
+
metadata: {
|
|
645
|
+
transport: TRANSPORT_TYPE_HTTP,
|
|
646
|
+
serverId: runtimeServerId,
|
|
647
|
+
...resolvedConfigPath ? { configPath: resolvedConfigPath } : {}
|
|
648
|
+
}
|
|
649
|
+
});
|
|
655
650
|
let releasePort = async () => {
|
|
656
651
|
await releasePortLease(portLease ?? null);
|
|
657
652
|
releasePort = async () => void 0;
|
|
@@ -675,10 +670,7 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
675
670
|
handler = new HttpTransportHandler(() => createSessionServer(sharedServices), runtimeConfig, createHttpAdminOptions(runtimeRecord.serverId, shutdownToken, stopHandler));
|
|
676
671
|
} catch (error) {
|
|
677
672
|
await releasePort();
|
|
678
|
-
await processLease.release({
|
|
679
|
-
kill: false,
|
|
680
|
-
releasePort: false
|
|
681
|
-
});
|
|
673
|
+
await processLease.release({ kill: false });
|
|
682
674
|
await sharedServices.dispose();
|
|
683
675
|
throw new Error(`Failed to create HTTP runtime server: ${toErrorMessage$9(error)}`);
|
|
684
676
|
}
|
|
@@ -686,19 +678,11 @@ async function createAndStartHttpRuntime(serverOptions, config, resolvedConfigPa
|
|
|
686
678
|
await startServer(handler, async () => {
|
|
687
679
|
await releasePort();
|
|
688
680
|
await sharedServices.dispose();
|
|
689
|
-
await processLease
|
|
690
|
-
kill: false,
|
|
691
|
-
releasePort: false
|
|
692
|
-
});
|
|
693
|
-
await removeRuntimeRecord(runtimeStateService, runtimeRecord.serverId);
|
|
681
|
+
await cleanupHttpRuntime(runtimeStateService, runtimeRecord.serverId, processLease);
|
|
694
682
|
});
|
|
695
683
|
await writeRuntimeRecord(runtimeStateService, runtimeRecord);
|
|
696
684
|
} catch (error) {
|
|
697
685
|
await releasePort();
|
|
698
|
-
await processLease.release({
|
|
699
|
-
kill: false,
|
|
700
|
-
releasePort: false
|
|
701
|
-
});
|
|
702
686
|
await sharedServices.dispose();
|
|
703
687
|
await cleanupFailedRuntimeStartup(handler, runtimeStateService, runtimeRecord.serverId, processLease);
|
|
704
688
|
throw new Error(`Failed to start HTTP runtime '${runtimeRecord.serverId}': ${toErrorMessage$9(error)}`);
|
|
@@ -778,21 +762,21 @@ async function startStdioHttpTransport(config, options, resolvedConfigPath) {
|
|
|
778
762
|
throw new Error(`Failed to start stdio-http transport: ${toErrorMessage$9(error)}`);
|
|
779
763
|
}
|
|
780
764
|
}
|
|
781
|
-
async function startTransport(transportType, options, resolvedConfigPath, serverOptions) {
|
|
765
|
+
async function startTransport(transportType, options, resolvedConfigPath, serverOptions, proxyDefaults) {
|
|
782
766
|
try {
|
|
783
767
|
if (transportType === TRANSPORT_TYPE_STDIO) {
|
|
784
768
|
await startStdioTransport(serverOptions);
|
|
785
769
|
return;
|
|
786
770
|
}
|
|
787
771
|
if (transportType === TRANSPORT_TYPE_HTTP) {
|
|
788
|
-
await createAndStartHttpRuntime(serverOptions, createTransportConfig(options, TRANSPORT_MODE.HTTP), resolvedConfigPath);
|
|
772
|
+
await createAndStartHttpRuntime(serverOptions, createTransportConfig(options, TRANSPORT_MODE.HTTP, proxyDefaults), resolvedConfigPath);
|
|
789
773
|
return;
|
|
790
774
|
}
|
|
791
775
|
if (transportType === TRANSPORT_TYPE_SSE) {
|
|
792
|
-
await startSseTransport(serverOptions, createTransportConfig(options, TRANSPORT_MODE.SSE));
|
|
776
|
+
await startSseTransport(serverOptions, createTransportConfig(options, TRANSPORT_MODE.SSE, proxyDefaults));
|
|
793
777
|
return;
|
|
794
778
|
}
|
|
795
|
-
await startStdioHttpTransport(createTransportConfig(options, TRANSPORT_MODE.HTTP), options, resolvedConfigPath);
|
|
779
|
+
await startStdioHttpTransport(createTransportConfig(options, TRANSPORT_MODE.HTTP, proxyDefaults), options, resolvedConfigPath);
|
|
796
780
|
} catch (error) {
|
|
797
781
|
throw new Error(`Failed to start transport '${transportType}': ${toErrorMessage$9(error)}`);
|
|
798
782
|
}
|
|
@@ -800,18 +784,19 @@ async function startTransport(transportType, options, resolvedConfigPath, server
|
|
|
800
784
|
/**
|
|
801
785
|
* MCP Serve command
|
|
802
786
|
*/
|
|
803
|
-
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}
|
|
787
|
+
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) => {
|
|
804
788
|
try {
|
|
805
|
-
const transportType = validateTransportType(options.type.toLowerCase());
|
|
806
|
-
validateProxyMode(options.proxyMode);
|
|
807
789
|
const resolvedConfigPath = options.config || await findConfigFileAsync() || void 0;
|
|
808
|
-
|
|
790
|
+
const proxyDefaults = resolvedConfigPath ? loadProxyDefaults(resolvedConfigPath) : {};
|
|
791
|
+
const transportType = validateTransportType((options.type ?? proxyDefaults.type ?? TRANSPORT_TYPE_STDIO).toLowerCase());
|
|
792
|
+
validateProxyMode(options.proxyMode);
|
|
793
|
+
await startTransport(transportType, options, resolvedConfigPath, createServerOptions(options, resolvedConfigPath, await resolveServerId(options, resolvedConfigPath)), proxyDefaults);
|
|
809
794
|
} catch (error) {
|
|
810
|
-
const rawTransportType = options.type.toLowerCase();
|
|
795
|
+
const rawTransportType = (options.type ?? TRANSPORT_TYPE_STDIO).toLowerCase();
|
|
811
796
|
const transportType = isValidTransportType(rawTransportType) ? rawTransportType : TRANSPORT_TYPE_STDIO;
|
|
812
797
|
const envPort = process.env.MCP_PORT ? Number(process.env.MCP_PORT) : void 0;
|
|
813
798
|
const requestedPort = options.port ?? (Number.isFinite(envPort) ? envPort : void 0);
|
|
814
|
-
console.error(formatStartError(transportType, options.host, requestedPort, error));
|
|
799
|
+
console.error(formatStartError(transportType, options.host ?? DEFAULT_HOST, requestedPort, error));
|
|
815
800
|
process.exit(1);
|
|
816
801
|
}
|
|
817
802
|
});
|
|
@@ -821,14 +806,58 @@ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server w
|
|
|
821
806
|
function toErrorMessage$8(error) {
|
|
822
807
|
return error instanceof Error ? error.message : String(error);
|
|
823
808
|
}
|
|
824
|
-
async function
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
809
|
+
async function checkHealth(host, port) {
|
|
810
|
+
try {
|
|
811
|
+
return (await fetch(`http://${host}:${port}/health`, { signal: AbortSignal.timeout(3e3) })).ok;
|
|
812
|
+
} catch {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Proxy mode: connect to a running HTTP server instead of downstream servers directly.
|
|
818
|
+
* Auto-starts the server if not running.
|
|
819
|
+
*/
|
|
820
|
+
async function withProxiedContext(container, config, configFilePath, options, run) {
|
|
821
|
+
const host = config.proxy?.host ?? "localhost";
|
|
822
|
+
const port = config.proxy?.port;
|
|
823
|
+
const endpoint = `http://${host}:${port}/mcp`;
|
|
824
|
+
if (!await checkHealth(host, port)) {
|
|
825
|
+
if (!options.json) console.error("Starting HTTP proxy server in background...");
|
|
826
|
+
await prestartHttpRuntime({
|
|
827
|
+
host,
|
|
828
|
+
port,
|
|
829
|
+
config: configFilePath,
|
|
830
|
+
cache: options.useCache !== false,
|
|
831
|
+
clearDefinitionsCache: false,
|
|
832
|
+
proxyMode: "flat"
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
const clientManager = container.createClientManagerService();
|
|
836
|
+
try {
|
|
837
|
+
await clientManager.connectToServer("proxy", {
|
|
838
|
+
name: "proxy",
|
|
839
|
+
transport: "http",
|
|
840
|
+
config: { url: endpoint }
|
|
841
|
+
});
|
|
842
|
+
if (!options.json) console.error(`✓ Connected to proxy at ${endpoint}`);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
throw new Error(`Failed to connect to proxy server at ${endpoint}: ${toErrorMessage$8(error)}`);
|
|
845
|
+
}
|
|
846
|
+
try {
|
|
847
|
+
return await run({
|
|
848
|
+
container,
|
|
849
|
+
configFilePath,
|
|
850
|
+
config,
|
|
851
|
+
clientManager
|
|
852
|
+
});
|
|
853
|
+
} finally {
|
|
854
|
+
await clientManager.disconnectAll();
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Direct mode: connect to all downstream MCP servers individually.
|
|
859
|
+
*/
|
|
860
|
+
async function withDirectContext(container, config, configFilePath, options, run) {
|
|
832
861
|
const clientManager = container.createClientManagerService();
|
|
833
862
|
await Promise.all(Object.entries(config.mcpServers).map(async ([serverName, serverConfig]) => {
|
|
834
863
|
try {
|
|
@@ -850,6 +879,17 @@ async function withConnectedCommandContext(options, run) {
|
|
|
850
879
|
await clientManager.disconnectAll();
|
|
851
880
|
}
|
|
852
881
|
}
|
|
882
|
+
async function withConnectedCommandContext(options, run) {
|
|
883
|
+
const container = createProxyIoCContainer();
|
|
884
|
+
const configFilePath = options.config || findConfigFile();
|
|
885
|
+
if (!configFilePath) throw new Error("No config file found. Use --config or create mcp-config.yaml");
|
|
886
|
+
const config = await container.createConfigFetcherService({
|
|
887
|
+
configFilePath,
|
|
888
|
+
useCache: options.useCache
|
|
889
|
+
}).fetchConfiguration();
|
|
890
|
+
if (config.proxy?.port) return await withProxiedContext(container, config, configFilePath, options, run);
|
|
891
|
+
return await withDirectContext(container, config, configFilePath, options, run);
|
|
892
|
+
}
|
|
853
893
|
|
|
854
894
|
//#endregion
|
|
855
895
|
//#region src/commands/list-tools.ts
|
|
@@ -1092,7 +1132,7 @@ function toErrorMessage$5(error) {
|
|
|
1092
1132
|
/**
|
|
1093
1133
|
* Execute an MCP tool with arguments
|
|
1094
1134
|
*/
|
|
1095
|
-
const useToolCommand = new Command("use-tool").description("Execute an MCP tool with arguments").argument("<toolName>", "Tool name to execute").option("-c, --config <path>", "Path to MCP server configuration file").option("-s, --server <name>", "Server name (required if tool exists on multiple servers)").option("-a, --args <json>", "Tool arguments as JSON string", "{}").option("-t, --timeout <ms>", "Request timeout in milliseconds for tool execution (default: 60000)", parseInt).option("-j, --json", "Output as JSON", false).action(async (toolName, options) => {
|
|
1135
|
+
const useToolCommand = new Command("use-tool").description("Execute an MCP tool with arguments").argument("<toolName>", "Tool name to execute").option("-c, --config <path>", "Path to MCP server configuration file").option("-s, --server <name>", "Server name (required if tool exists on multiple servers)").option("-a, --args <json>", "Tool arguments as JSON string", "{}").option("-t, --timeout <ms>", "Request timeout in milliseconds for tool execution (default: 60000)", Number.parseInt).option("-j, --json", "Output as JSON", false).action(async (toolName, options) => {
|
|
1096
1136
|
try {
|
|
1097
1137
|
let toolArgs = {};
|
|
1098
1138
|
try {
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -260,6 +260,11 @@ interface PromptConfig {
|
|
|
260
260
|
*/
|
|
261
261
|
interface RemoteMcpConfiguration {
|
|
262
262
|
id?: string;
|
|
263
|
+
proxy?: {
|
|
264
|
+
type?: string;
|
|
265
|
+
port?: number;
|
|
266
|
+
host?: string;
|
|
267
|
+
};
|
|
263
268
|
mcpServers: Record<string, McpServerConfig>;
|
|
264
269
|
skills?: SkillsConfig;
|
|
265
270
|
}
|
|
@@ -515,6 +520,62 @@ declare class ConfigFetcherService {
|
|
|
515
520
|
isCacheValid(): boolean;
|
|
516
521
|
}
|
|
517
522
|
//#endregion
|
|
523
|
+
//#region src/services/McpClientManagerService.d.ts
|
|
524
|
+
/**
|
|
525
|
+
* Service for managing MCP client connections to remote servers
|
|
526
|
+
*/
|
|
527
|
+
declare class McpClientManagerService {
|
|
528
|
+
private clients;
|
|
529
|
+
private serverConfigs;
|
|
530
|
+
private connectionPromises;
|
|
531
|
+
private logger;
|
|
532
|
+
constructor(logger?: LoggerLike);
|
|
533
|
+
/**
|
|
534
|
+
* Kill all stdio MCP server child processes.
|
|
535
|
+
* Sends SIGTERM first, then SIGKILL after 1s if the process hasn't exited.
|
|
536
|
+
* Must be called by the owner (e.g. transport/command layer) during shutdown.
|
|
537
|
+
* Awaiting the returned promise ensures force-kill timers complete before process.exit().
|
|
538
|
+
*/
|
|
539
|
+
cleanupChildProcesses(): Promise<void>;
|
|
540
|
+
/**
|
|
541
|
+
* Connect to an MCP server based on its configuration with timeout
|
|
542
|
+
* Uses the timeout from server config, falling back to default (30s)
|
|
543
|
+
*/
|
|
544
|
+
connectToServer(serverName: string, config: McpServerConfig): Promise<void>;
|
|
545
|
+
registerServerConfigs(configs: Record<string, McpServerConfig>): void;
|
|
546
|
+
getKnownServerNames(): string[];
|
|
547
|
+
getServerRequestTimeout(serverName: string): number | undefined;
|
|
548
|
+
ensureConnected(serverName: string): Promise<McpClientConnection>;
|
|
549
|
+
private createConnection;
|
|
550
|
+
/**
|
|
551
|
+
* Perform the actual connection to MCP server
|
|
552
|
+
*/
|
|
553
|
+
private performConnection;
|
|
554
|
+
private connectStdioClient;
|
|
555
|
+
private connectHttpClient;
|
|
556
|
+
private connectSseClient;
|
|
557
|
+
/**
|
|
558
|
+
* Get a connected client by server name
|
|
559
|
+
*/
|
|
560
|
+
getClient(serverName: string): McpClientConnection | undefined;
|
|
561
|
+
/**
|
|
562
|
+
* Get all connected clients
|
|
563
|
+
*/
|
|
564
|
+
getAllClients(): McpClientConnection[];
|
|
565
|
+
/**
|
|
566
|
+
* Disconnect from a specific server
|
|
567
|
+
*/
|
|
568
|
+
disconnectServer(serverName: string): Promise<void>;
|
|
569
|
+
/**
|
|
570
|
+
* Disconnect from all servers
|
|
571
|
+
*/
|
|
572
|
+
disconnectAll(): Promise<void>;
|
|
573
|
+
/**
|
|
574
|
+
* Check if a server is connected
|
|
575
|
+
*/
|
|
576
|
+
isConnected(serverName: string): boolean;
|
|
577
|
+
}
|
|
578
|
+
//#endregion
|
|
518
579
|
//#region src/services/SkillService.d.ts
|
|
519
580
|
/**
|
|
520
581
|
* Service for loading and managing skills from configured skill directories.
|
|
@@ -643,60 +704,6 @@ declare class SkillService {
|
|
|
643
704
|
private loadSkillFile;
|
|
644
705
|
}
|
|
645
706
|
//#endregion
|
|
646
|
-
//#region src/services/McpClientManagerService.d.ts
|
|
647
|
-
/**
|
|
648
|
-
* Service for managing MCP client connections to remote servers
|
|
649
|
-
*/
|
|
650
|
-
declare class McpClientManagerService {
|
|
651
|
-
private clients;
|
|
652
|
-
private serverConfigs;
|
|
653
|
-
private connectionPromises;
|
|
654
|
-
private logger;
|
|
655
|
-
constructor(logger?: LoggerLike);
|
|
656
|
-
/**
|
|
657
|
-
* Synchronously kill all stdio MCP server child processes.
|
|
658
|
-
* Must be called by the owner (e.g. transport/command layer) during shutdown.
|
|
659
|
-
*/
|
|
660
|
-
cleanupChildProcesses(): void;
|
|
661
|
-
/**
|
|
662
|
-
* Connect to an MCP server based on its configuration with timeout
|
|
663
|
-
* Uses the timeout from server config, falling back to default (30s)
|
|
664
|
-
*/
|
|
665
|
-
connectToServer(serverName: string, config: McpServerConfig): Promise<void>;
|
|
666
|
-
registerServerConfigs(configs: Record<string, McpServerConfig>): void;
|
|
667
|
-
getKnownServerNames(): string[];
|
|
668
|
-
getServerRequestTimeout(serverName: string): number | undefined;
|
|
669
|
-
ensureConnected(serverName: string): Promise<McpClientConnection>;
|
|
670
|
-
private createConnection;
|
|
671
|
-
/**
|
|
672
|
-
* Perform the actual connection to MCP server
|
|
673
|
-
*/
|
|
674
|
-
private performConnection;
|
|
675
|
-
private connectStdioClient;
|
|
676
|
-
private connectHttpClient;
|
|
677
|
-
private connectSseClient;
|
|
678
|
-
/**
|
|
679
|
-
* Get a connected client by server name
|
|
680
|
-
*/
|
|
681
|
-
getClient(serverName: string): McpClientConnection | undefined;
|
|
682
|
-
/**
|
|
683
|
-
* Get all connected clients
|
|
684
|
-
*/
|
|
685
|
-
getAllClients(): McpClientConnection[];
|
|
686
|
-
/**
|
|
687
|
-
* Disconnect from a specific server
|
|
688
|
-
*/
|
|
689
|
-
disconnectServer(serverName: string): Promise<void>;
|
|
690
|
-
/**
|
|
691
|
-
* Disconnect from all servers
|
|
692
|
-
*/
|
|
693
|
-
disconnectAll(): Promise<void>;
|
|
694
|
-
/**
|
|
695
|
-
* Check if a server is connected
|
|
696
|
-
*/
|
|
697
|
-
isConnected(serverName: string): boolean;
|
|
698
|
-
}
|
|
699
|
-
//#endregion
|
|
700
707
|
//#region src/services/DefinitionsCacheService.d.ts
|
|
701
708
|
interface DefinitionsCacheServiceOptions {
|
|
702
709
|
cacheData?: DefinitionsCacheFile;
|
|
@@ -1115,10 +1122,14 @@ declare class UseToolTool implements Tool<UseToolToolInput> {
|
|
|
1115
1122
|
/**
|
|
1116
1123
|
* HTTP transport handler using Streamable HTTP (protocol version 2025-03-26)
|
|
1117
1124
|
* Provides stateful session management with resumability support
|
|
1125
|
+
*
|
|
1126
|
+
* Uses a hybrid server architecture:
|
|
1127
|
+
* - Raw Node.js createServer for /mcp routes (MCP SDK needs native req/res)
|
|
1128
|
+
* - Hono for REST routes (/health, /admin/shutdown)
|
|
1118
1129
|
*/
|
|
1119
1130
|
declare class HttpTransportHandler implements HttpTransportHandler$1 {
|
|
1120
1131
|
private serverFactory;
|
|
1121
|
-
private
|
|
1132
|
+
private honoApp;
|
|
1122
1133
|
private server;
|
|
1123
1134
|
private sessionManager;
|
|
1124
1135
|
private config;
|
|
@@ -1126,10 +1137,14 @@ declare class HttpTransportHandler implements HttpTransportHandler$1 {
|
|
|
1126
1137
|
private adminRateLimiter;
|
|
1127
1138
|
private logger;
|
|
1128
1139
|
constructor(serverFactory: () => Server | Promise<Server>, config: TransportConfig, adminOptions?: HttpTransportAdminOptions, logger?: LoggerLike);
|
|
1129
|
-
private
|
|
1130
|
-
private setupRoutes;
|
|
1140
|
+
private setupHonoRoutes;
|
|
1131
1141
|
private isAuthorizedShutdownRequest;
|
|
1132
1142
|
private handleAdminShutdownRequest;
|
|
1143
|
+
/**
|
|
1144
|
+
* Handle MCP protocol requests (POST/GET/DELETE /mcp)
|
|
1145
|
+
* Uses raw Node.js req/res as required by MCP SDK
|
|
1146
|
+
*/
|
|
1147
|
+
private handleMcpRequest;
|
|
1133
1148
|
private handlePostRequest;
|
|
1134
1149
|
private handleGetRequest;
|
|
1135
1150
|
private handleDeleteRequest;
|
|
@@ -1147,14 +1162,13 @@ declare class HttpTransportHandler implements HttpTransportHandler$1 {
|
|
|
1147
1162
|
*/
|
|
1148
1163
|
declare class SseTransportHandler implements HttpTransportHandler$1 {
|
|
1149
1164
|
private serverFactory;
|
|
1150
|
-
private
|
|
1165
|
+
private honoApp;
|
|
1151
1166
|
private server;
|
|
1152
1167
|
private sessionManager;
|
|
1153
1168
|
private config;
|
|
1154
1169
|
private logger;
|
|
1155
1170
|
constructor(serverFactory: Server | (() => Server), config: TransportConfig, logger?: LoggerLike);
|
|
1156
|
-
private
|
|
1157
|
-
private setupRoutes;
|
|
1171
|
+
private setupHonoRoutes;
|
|
1158
1172
|
private handleSseConnection;
|
|
1159
1173
|
private handlePostMessage;
|
|
1160
1174
|
start(): Promise<void>;
|