@winstonsayno/mcp-gateway 0.0.0-stage → 0.4.0
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/CHANGELOG.md +130 -0
- package/LICENSE +21 -0
- package/README.md +432 -2
- package/dashboard/README.md +27 -0
- package/dashboard/index.html +415 -0
- package/dist/auth/middleware.d.ts +24 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +108 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/ratelimit.d.ts +19 -0
- package/dist/auth/ratelimit.d.ts.map +1 -0
- package/dist/auth/ratelimit.js +81 -0
- package/dist/auth/ratelimit.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +129 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/loader.d.ts +13 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +276 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/watcher.d.ts +29 -0
- package/dist/config/watcher.d.ts.map +1 -0
- package/dist/config/watcher.js +96 -0
- package/dist/config/watcher.js.map +1 -0
- package/dist/gateway/api.d.ts +47 -0
- package/dist/gateway/api.d.ts.map +1 -0
- package/dist/gateway/api.js +324 -0
- package/dist/gateway/api.js.map +1 -0
- package/dist/gateway/index.d.ts +49 -0
- package/dist/gateway/index.d.ts.map +1 -0
- package/dist/gateway/index.js +261 -0
- package/dist/gateway/index.js.map +1 -0
- package/dist/gateway/supervisor.d.ts +58 -0
- package/dist/gateway/supervisor.d.ts.map +1 -0
- package/dist/gateway/supervisor.js +205 -0
- package/dist/gateway/supervisor.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/cors.d.ts +19 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +65 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +40 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +98 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/request-id.d.ts +23 -0
- package/dist/middleware/request-id.d.ts.map +1 -0
- package/dist/middleware/request-id.js +30 -0
- package/dist/middleware/request-id.js.map +1 -0
- package/dist/middleware/timeout.d.ts +12 -0
- package/dist/middleware/timeout.d.ts.map +1 -0
- package/dist/middleware/timeout.js +39 -0
- package/dist/middleware/timeout.js.map +1 -0
- package/dist/monitor/index.d.ts +49 -0
- package/dist/monitor/index.d.ts.map +1 -0
- package/dist/monitor/index.js +204 -0
- package/dist/monitor/index.js.map +1 -0
- package/dist/proxy/index.d.ts +86 -0
- package/dist/proxy/index.d.ts.map +1 -0
- package/dist/proxy/index.js +389 -0
- package/dist/proxy/index.js.map +1 -0
- package/dist/registry/index.d.ts +48 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +171 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/transport/channel.d.ts +61 -0
- package/dist/transport/channel.d.ts.map +1 -0
- package/dist/transport/channel.js +38 -0
- package/dist/transport/channel.js.map +1 -0
- package/dist/transport/sse-parser.d.ts +30 -0
- package/dist/transport/sse-parser.d.ts.map +1 -0
- package/dist/transport/sse-parser.js +107 -0
- package/dist/transport/sse-parser.js.map +1 -0
- package/dist/transport/sse.d.ts +39 -0
- package/dist/transport/sse.d.ts.map +1 -0
- package/dist/transport/sse.js +142 -0
- package/dist/transport/sse.js.map +1 -0
- package/dist/transport/stdio.d.ts +35 -0
- package/dist/transport/stdio.d.ts.map +1 -0
- package/dist/transport/stdio.js +149 -0
- package/dist/transport/stdio.js.map +1 -0
- package/dist/transport/streamable-http.d.ts +45 -0
- package/dist/transport/streamable-http.d.ts.map +1 -0
- package/dist/transport/streamable-http.js +183 -0
- package/dist/transport/streamable-http.js.map +1 -0
- package/dist/transport/websocket.d.ts +38 -0
- package/dist/transport/websocket.d.ts.map +1 -0
- package/dist/transport/websocket.js +172 -0
- package/dist/transport/websocket.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +60 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/mutex.d.ts +25 -0
- package/dist/utils/mutex.d.ts.map +1 -0
- package/dist/utils/mutex.js +62 -0
- package/dist/utils/mutex.js.map +1 -0
- package/dist/utils/semaphore.d.ts +16 -0
- package/dist/utils/semaphore.d.ts.map +1 -0
- package/dist/utils/semaphore.js +42 -0
- package/dist/utils/semaphore.js.map +1 -0
- package/dist/utils/tool-filter.d.ts +24 -0
- package/dist/utils/tool-filter.d.ts.map +1 -0
- package/dist/utils/tool-filter.js +48 -0
- package/dist/utils/tool-filter.js.map +1 -0
- package/dist/utils/types.d.ts +223 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +5 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/utils/version.d.ts +6 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +18 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +79 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ratelimit.js","sourceRoot":"","sources":["../../src/auth/ratelimit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAc5C,MAAM,UAAU,iBAAiB,CAC/B,MAAwB,EACxB,MAAoB,IAAI,CAAC,GAAG;IAE5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,WAAW,GAAG,CAAC,CAAC,IAAa,EAAE,IAAc,EAAE,IAAkB,EAAE,EAAE,CAAC,IAAI,EAAE,CAAgB,CAAC;QACnG,WAAW,CAAC,KAAK,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;QAC7B,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;IACvD,MAAM,QAAQ,GAAG,aAAa,GAAG,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAE7C,4EAA4E;IAC5E,wEAAwE;IACxE,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE;QAC/B,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,QAAQ;gBAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7B,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,MAAM,OAAO,GAAG,CAAC,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACnE,MAAM,QAAQ,GAAG,MAAM;YACrB,CAAC,CAAC,CAAE,GAAuC,CAAC,QAAQ,IAAI,GAAG,CAAC,EAAE,IAAI,WAAW,CAAC;YAC9E,CAAC,CAAC,QAAQ,CAAC;QAEb,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC;QACxD,IAAI,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;aAAM,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YAC7C,mEAAmE;YACnE,4BAA4B;YAC5B,KAAK,CAAC,QAAQ,GAAG,WAAW,GAAG,KAAK,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAClF,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YAClB,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;QAClC,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,GAAG,QAAQ,CAAC;QACjD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,QAAQ,GAAG,OAAO,CAAC;QAC3D,MAAM,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;QAEvC,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YAChE,MAAM,CAAC,IAAI,CAAC,2BAA2B,QAAQ,EAAE,CAAC,CAAC;YACnD,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC1D,KAAK,EAAE,mBAAmB;gBAC1B,OAAO,EAAE,iBAAiB,KAAK,iBAAiB,aAAa,YAAY;gBACzE,UAAU;aACX,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,KAAK,CAAC,OAAO,EAAE,CAAC;QAChB,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,SAAS,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC5E,IAAI,EAAE,CAAC;IACT,CAAC,CAAgB,CAAC;IAElB,OAAO,CAAC,KAAK,GAAG,GAAG,EAAE;QACnB,aAAa,CAAC,OAAO,CAAC,CAAC;QACvB,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,mBAAmB,CAC1B,GAAa,EACb,KAAa,EACb,SAAiB,EACjB,OAAe;IAEf,GAAG,CAAC,GAAG,CAAC;QACN,mBAAmB,EAAE,MAAM,CAAC,KAAK,CAAC;QAClC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACvD,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;KACvD,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,eAAe,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* mcp-gateway CLI
|
|
4
|
+
*/
|
|
5
|
+
import 'dotenv/config';
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { existsSync } from 'fs';
|
|
8
|
+
import { writeFile } from 'fs/promises';
|
|
9
|
+
import { loadConfig, generateDefaultConfig, resolveConfigPath } from './config/loader.js';
|
|
10
|
+
import { ConfigWatcher } from './config/watcher.js';
|
|
11
|
+
import { Gateway } from './gateway/index.js';
|
|
12
|
+
import { logger } from './utils/logger.js';
|
|
13
|
+
import { VERSION } from './utils/version.js';
|
|
14
|
+
const LOG_LEVELS = ['debug', 'info', 'warn', 'error'];
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('mcp-gateway')
|
|
18
|
+
.description('A lightweight gateway for managing multiple MCP servers')
|
|
19
|
+
.version(VERSION);
|
|
20
|
+
// ─── start ────────────────────────────────────────────────────────────────────
|
|
21
|
+
program
|
|
22
|
+
.command('start')
|
|
23
|
+
.description('Start the MCP gateway server')
|
|
24
|
+
.option('-c, --config <path>', 'Path to config file')
|
|
25
|
+
.option('-p, --port <number>', 'Override port from config')
|
|
26
|
+
.option('--log-level <level>', 'Log level (debug|info|warn|error)')
|
|
27
|
+
.option('--no-watch', 'Disable config hot reload')
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
let gateway;
|
|
30
|
+
let watcher;
|
|
31
|
+
try {
|
|
32
|
+
const config = await loadConfig(options.config);
|
|
33
|
+
if (options.port !== undefined) {
|
|
34
|
+
const port = Number(options.port);
|
|
35
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
36
|
+
throw new Error(`Invalid --port "${options.port}"`);
|
|
37
|
+
}
|
|
38
|
+
config.port = port;
|
|
39
|
+
}
|
|
40
|
+
if (options.logLevel) {
|
|
41
|
+
if (!LOG_LEVELS.includes(options.logLevel)) {
|
|
42
|
+
throw new Error(`Invalid --log-level "${options.logLevel}" (expected ${LOG_LEVELS.join('|')})`);
|
|
43
|
+
}
|
|
44
|
+
config.logLevel = options.logLevel;
|
|
45
|
+
}
|
|
46
|
+
const gw = new Gateway(config);
|
|
47
|
+
gateway = gw;
|
|
48
|
+
// Graceful shutdown (idempotent; a second signal forces exit)
|
|
49
|
+
let shuttingDown = false;
|
|
50
|
+
const shutdown = (signal) => {
|
|
51
|
+
if (shuttingDown) {
|
|
52
|
+
logger.warn(`Received ${signal} again, forcing exit`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
shuttingDown = true;
|
|
56
|
+
logger.info(`Received ${signal}, shutting down gracefully...`);
|
|
57
|
+
watcher?.stop();
|
|
58
|
+
gw.stop().then(() => process.exit(0), (err) => {
|
|
59
|
+
logger.error(`Error during shutdown: ${err instanceof Error ? err.message : String(err)}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
64
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
65
|
+
await gw.start();
|
|
66
|
+
const configPath = resolveConfigPath(options.config);
|
|
67
|
+
if (options.watch && configPath) {
|
|
68
|
+
const w = new ConfigWatcher(configPath, logger);
|
|
69
|
+
watcher = w;
|
|
70
|
+
w.on('reload', (next) => {
|
|
71
|
+
// CLI overrides keep precedence over the file
|
|
72
|
+
if (options.logLevel)
|
|
73
|
+
next.logLevel = options.logLevel;
|
|
74
|
+
if (options.port !== undefined)
|
|
75
|
+
next.port = config.port;
|
|
76
|
+
gw.reload(next).catch((err) => {
|
|
77
|
+
logger.error(`Hot reload failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
w.start();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
logger.error(`Failed to start gateway: ${err instanceof Error ? err.message : String(err)}`);
|
|
85
|
+
watcher?.stop();
|
|
86
|
+
await gateway?.stop().catch(() => { });
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// ─── init ─────────────────────────────────────────────────────────────────────
|
|
91
|
+
program
|
|
92
|
+
.command('init')
|
|
93
|
+
.description('Generate a default configuration file')
|
|
94
|
+
.option('-o, --output <path>', 'Output path', 'mcp-gateway.yml')
|
|
95
|
+
.option('--force', 'Overwrite existing file')
|
|
96
|
+
.action(async (options) => {
|
|
97
|
+
if (existsSync(options.output) && !options.force) {
|
|
98
|
+
logger.error(`File "${options.output}" already exists. Use --force to overwrite.`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
await writeFile(options.output, generateDefaultConfig(), 'utf-8');
|
|
102
|
+
logger.info(`Created ${options.output}`);
|
|
103
|
+
console.log('\nNext steps:');
|
|
104
|
+
console.log(` 1. Edit ${options.output} to configure your MCP servers`);
|
|
105
|
+
console.log(' 2. Run: mcp-gateway start\n');
|
|
106
|
+
});
|
|
107
|
+
// ─── validate ─────────────────────────────────────────────────────────────────
|
|
108
|
+
program
|
|
109
|
+
.command('validate')
|
|
110
|
+
.description('Validate a configuration file')
|
|
111
|
+
.option('-c, --config <path>', 'Path to config file')
|
|
112
|
+
.action(async (options) => {
|
|
113
|
+
try {
|
|
114
|
+
const config = await loadConfig(options.config);
|
|
115
|
+
console.log(`✓ Configuration is valid`);
|
|
116
|
+
console.log(` Port: ${config.port}`);
|
|
117
|
+
console.log(` Servers: ${config.servers.length}`);
|
|
118
|
+
console.log(` Auth: ${config.auth?.strategy ?? 'none'}`);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
logger.error(`Invalid configuration: ${err instanceof Error ? err.message : String(err)}`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
program.parse(process.argv);
|
|
126
|
+
if (!process.argv.slice(2).length) {
|
|
127
|
+
program.outputHelp();
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration loader
|
|
3
|
+
* Supports YAML, JSON, and environment variable overrides
|
|
4
|
+
*/
|
|
5
|
+
import type { GatewayConfig } from '../utils/types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the config file that `loadConfig` would read: the explicit path if
|
|
8
|
+
* given, otherwise the first match in the default search paths.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveConfigPath(configPath?: string): string | undefined;
|
|
11
|
+
export declare function loadConfig(configPath?: string): Promise<GatewayConfig>;
|
|
12
|
+
export declare function generateDefaultConfig(): string;
|
|
13
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AA0IvD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMzE;AAED,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAsB5E;AAkCD,wBAAgB,qBAAqB,IAAI,MAAM,CA8E9C"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration loader
|
|
3
|
+
* Supports YAML, JSON, and environment variable overrides
|
|
4
|
+
*/
|
|
5
|
+
import { readFile } from 'fs/promises';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { resolve } from 'path';
|
|
8
|
+
import { parse as parseYaml } from 'yaml';
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
// ─── Zod Schema ───────────────────────────────────────────────────────────────
|
|
11
|
+
const ReconnectSchema = z.object({
|
|
12
|
+
enabled: z.boolean().optional(),
|
|
13
|
+
initialDelayMs: z.number().int().positive().optional(),
|
|
14
|
+
maxDelayMs: z.number().int().positive().optional(),
|
|
15
|
+
multiplier: z.number().min(1).optional(),
|
|
16
|
+
jitter: z.number().min(0).max(1).optional(),
|
|
17
|
+
maxAttempts: z.number().int().min(0).optional(),
|
|
18
|
+
});
|
|
19
|
+
const URL_PROTOCOLS = {
|
|
20
|
+
sse: ['http:', 'https:'],
|
|
21
|
+
'streamable-http': ['http:', 'https:'],
|
|
22
|
+
websocket: ['ws:', 'wss:'],
|
|
23
|
+
};
|
|
24
|
+
function safeProtocol(url) {
|
|
25
|
+
try {
|
|
26
|
+
return new URL(url).protocol;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const ToolPatternList = z.array(z.string().min(1, 'patterns must be non-empty'));
|
|
33
|
+
const ToolFilterSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
allow: ToolPatternList.optional(),
|
|
36
|
+
deny: ToolPatternList.optional(),
|
|
37
|
+
})
|
|
38
|
+
.strict();
|
|
39
|
+
const McpServerSchema = z.object({
|
|
40
|
+
id: z.string().min(1),
|
|
41
|
+
name: z.string().min(1),
|
|
42
|
+
description: z.string().optional(),
|
|
43
|
+
transport: z.enum(['stdio', 'sse', 'websocket', 'streamable-http']),
|
|
44
|
+
command: z.string().optional(),
|
|
45
|
+
args: z.array(z.string()).optional(),
|
|
46
|
+
url: z.string().url().optional(),
|
|
47
|
+
env: z.record(z.string()).optional(),
|
|
48
|
+
headers: z.record(z.string()).optional(),
|
|
49
|
+
subprotocol: z.string().optional(),
|
|
50
|
+
reconnect: ReconnectSchema.optional(),
|
|
51
|
+
tags: z.array(z.string()).optional(),
|
|
52
|
+
enabled: z.boolean().default(true),
|
|
53
|
+
timeout: z.number().positive().default(30000),
|
|
54
|
+
maxConcurrency: z.number().int().positive().default(10),
|
|
55
|
+
tools: ToolFilterSchema.optional(),
|
|
56
|
+
}).superRefine((s, ctx) => {
|
|
57
|
+
if (s.transport === 'stdio' && !s.command) {
|
|
58
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['command'], message: 'required for stdio transport' });
|
|
59
|
+
}
|
|
60
|
+
const protocols = URL_PROTOCOLS[s.transport];
|
|
61
|
+
if (protocols) {
|
|
62
|
+
if (!s.url) {
|
|
63
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['url'], message: `required for ${s.transport} transport` });
|
|
64
|
+
}
|
|
65
|
+
else if (!protocols.includes(safeProtocol(s.url))) {
|
|
66
|
+
ctx.addIssue({
|
|
67
|
+
code: z.ZodIssueCode.custom,
|
|
68
|
+
path: ['url'],
|
|
69
|
+
message: `${s.transport} transport needs a ${protocols.map((p) => p.replace(':', '://')).join(' or ')} URL`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
const GatewayConfigSchema = z.object({
|
|
75
|
+
port: z.number().int().min(1).max(65535).default(4000),
|
|
76
|
+
host: z.string().default('0.0.0.0'),
|
|
77
|
+
auth: z
|
|
78
|
+
.object({
|
|
79
|
+
strategy: z.enum(['none', 'api-key', 'jwt', 'oauth2']).default('none'),
|
|
80
|
+
apiKeys: z.array(z.string()).optional(),
|
|
81
|
+
jwtSecret: z.string().optional(),
|
|
82
|
+
protect: z
|
|
83
|
+
.object({
|
|
84
|
+
health: z.boolean().default(false),
|
|
85
|
+
metrics: z.boolean().default(false),
|
|
86
|
+
})
|
|
87
|
+
.optional(),
|
|
88
|
+
})
|
|
89
|
+
.superRefine((a, ctx) => {
|
|
90
|
+
if (a.strategy === 'api-key' && !(a.apiKeys ?? []).some((k) => k.length > 0)) {
|
|
91
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['apiKeys'], message: 'at least one key is required for api-key strategy' });
|
|
92
|
+
}
|
|
93
|
+
if (a.strategy === 'jwt' && !a.jwtSecret) {
|
|
94
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['jwtSecret'], message: 'required for jwt strategy' });
|
|
95
|
+
}
|
|
96
|
+
if (a.strategy === 'oauth2') {
|
|
97
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['strategy'], message: 'oauth2 is not implemented yet (refusing to start without auth)' });
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
.optional(),
|
|
101
|
+
rateLimit: z
|
|
102
|
+
.object({
|
|
103
|
+
limit: z.number().int().positive().default(100),
|
|
104
|
+
windowSeconds: z.number().positive().default(60),
|
|
105
|
+
perKey: z.boolean().default(true),
|
|
106
|
+
})
|
|
107
|
+
.optional(),
|
|
108
|
+
monitor: z
|
|
109
|
+
.object({
|
|
110
|
+
prometheus: z.boolean().default(false),
|
|
111
|
+
requestLog: z.boolean().default(true),
|
|
112
|
+
retentionHours: z.number().positive().default(24),
|
|
113
|
+
})
|
|
114
|
+
.optional(),
|
|
115
|
+
servers: z.array(McpServerSchema).default([]),
|
|
116
|
+
corsOrigins: z.array(z.string()).optional(),
|
|
117
|
+
logLevel: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
|
|
118
|
+
reconnect: ReconnectSchema.optional(),
|
|
119
|
+
healthCheckIntervalMs: z.number().int().min(1000).default(30_000),
|
|
120
|
+
dashboard: z.object({ enabled: z.boolean().default(true) }).optional(),
|
|
121
|
+
}).superRefine((c, ctx) => {
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
c.servers.forEach((s, i) => {
|
|
124
|
+
if (seen.has(s.id)) {
|
|
125
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ['servers', i, 'id'], message: `duplicate server id "${s.id}"` });
|
|
126
|
+
}
|
|
127
|
+
seen.add(s.id);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
// ─── Loader ───────────────────────────────────────────────────────────────────
|
|
131
|
+
const CONFIG_SEARCH_PATHS = [
|
|
132
|
+
'mcp-gateway.yml',
|
|
133
|
+
'mcp-gateway.yaml',
|
|
134
|
+
'mcp-gateway.json',
|
|
135
|
+
'.mcp-gateway.yml',
|
|
136
|
+
'.mcp-gateway.yaml',
|
|
137
|
+
];
|
|
138
|
+
/**
|
|
139
|
+
* Resolve the config file that `loadConfig` would read: the explicit path if
|
|
140
|
+
* given, otherwise the first match in the default search paths.
|
|
141
|
+
*/
|
|
142
|
+
export function resolveConfigPath(configPath) {
|
|
143
|
+
if (configPath)
|
|
144
|
+
return resolve(configPath);
|
|
145
|
+
for (const searchPath of CONFIG_SEARCH_PATHS) {
|
|
146
|
+
if (existsSync(searchPath))
|
|
147
|
+
return resolve(searchPath);
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
export async function loadConfig(configPath) {
|
|
152
|
+
const filePath = resolveConfigPath(configPath);
|
|
153
|
+
let raw = filePath ? await readConfigFile(filePath) : {};
|
|
154
|
+
// An empty YAML file parses to null
|
|
155
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
156
|
+
if (raw !== null && raw !== undefined) {
|
|
157
|
+
throw new Error(`Invalid configuration: ${filePath} must contain a mapping/object at the top level`);
|
|
158
|
+
}
|
|
159
|
+
raw = {};
|
|
160
|
+
}
|
|
161
|
+
// Apply environment variable overrides
|
|
162
|
+
raw = applyEnvOverrides(raw);
|
|
163
|
+
const result = GatewayConfigSchema.safeParse(raw);
|
|
164
|
+
if (!result.success) {
|
|
165
|
+
throw new Error(`Invalid configuration:\n${result.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`).join('\n')}`);
|
|
166
|
+
}
|
|
167
|
+
return result.data;
|
|
168
|
+
}
|
|
169
|
+
async function readConfigFile(filePath) {
|
|
170
|
+
const content = await readFile(filePath, 'utf-8');
|
|
171
|
+
if (filePath.endsWith('.json')) {
|
|
172
|
+
return JSON.parse(content);
|
|
173
|
+
}
|
|
174
|
+
return parseYaml(content);
|
|
175
|
+
}
|
|
176
|
+
function applyEnvOverrides(config) {
|
|
177
|
+
const overrides = { ...config };
|
|
178
|
+
if (process.env.MCP_GATEWAY_PORT) {
|
|
179
|
+
overrides.port = parseInt(process.env.MCP_GATEWAY_PORT, 10);
|
|
180
|
+
}
|
|
181
|
+
if (process.env.MCP_GATEWAY_HOST) {
|
|
182
|
+
overrides.host = process.env.MCP_GATEWAY_HOST;
|
|
183
|
+
}
|
|
184
|
+
if (process.env.MCP_GATEWAY_LOG_LEVEL) {
|
|
185
|
+
overrides.logLevel = process.env.MCP_GATEWAY_LOG_LEVEL;
|
|
186
|
+
}
|
|
187
|
+
if (process.env.MCP_GATEWAY_API_KEYS) {
|
|
188
|
+
// Keeps other auth settings (e.g. auth.protect) from the file.
|
|
189
|
+
overrides.auth = {
|
|
190
|
+
...(overrides.auth ?? {}),
|
|
191
|
+
strategy: 'api-key',
|
|
192
|
+
apiKeys: process.env.MCP_GATEWAY_API_KEYS.split(',').map((k) => k.trim()).filter(Boolean),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return overrides;
|
|
196
|
+
}
|
|
197
|
+
export function generateDefaultConfig() {
|
|
198
|
+
return `# mcp-gateway configuration
|
|
199
|
+
# Documentation: https://github.com/HarrisonCN/mcp-gateway/docs
|
|
200
|
+
|
|
201
|
+
port: 4000
|
|
202
|
+
host: 0.0.0.0
|
|
203
|
+
logLevel: info
|
|
204
|
+
|
|
205
|
+
# Authentication (optional; keys can be changed without a restart)
|
|
206
|
+
# auth:
|
|
207
|
+
# strategy: api-key
|
|
208
|
+
# apiKeys:
|
|
209
|
+
# - your-secret-key-here
|
|
210
|
+
# protect:
|
|
211
|
+
# health: false # true = /api/v1/health requires a key (/health/live stays public)
|
|
212
|
+
# metrics: false # true = /api/v1/metrics requires a key (configure your scraper)
|
|
213
|
+
|
|
214
|
+
# Automatic reconnect of crashed / disconnected servers (defaults shown)
|
|
215
|
+
# reconnect:
|
|
216
|
+
# enabled: true
|
|
217
|
+
# initialDelayMs: 1000
|
|
218
|
+
# maxDelayMs: 60000
|
|
219
|
+
# multiplier: 2
|
|
220
|
+
# jitter: 0.2
|
|
221
|
+
# maxAttempts: 0 # 0 = retry forever
|
|
222
|
+
|
|
223
|
+
# Rate limiting (optional)
|
|
224
|
+
# rateLimit:
|
|
225
|
+
# limit: 100
|
|
226
|
+
# windowSeconds: 60
|
|
227
|
+
# perKey: true
|
|
228
|
+
|
|
229
|
+
# Monitoring
|
|
230
|
+
monitor:
|
|
231
|
+
requestLog: true
|
|
232
|
+
prometheus: false
|
|
233
|
+
retentionHours: 24
|
|
234
|
+
|
|
235
|
+
# MCP Servers to manage
|
|
236
|
+
servers:
|
|
237
|
+
- id: filesystem
|
|
238
|
+
name: Filesystem Server
|
|
239
|
+
description: Access local files and directories
|
|
240
|
+
transport: stdio
|
|
241
|
+
command: npx
|
|
242
|
+
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
|
|
243
|
+
tags: [files, local]
|
|
244
|
+
enabled: true
|
|
245
|
+
|
|
246
|
+
- id: github
|
|
247
|
+
name: GitHub Server
|
|
248
|
+
description: Interact with GitHub repositories
|
|
249
|
+
transport: stdio
|
|
250
|
+
command: npx
|
|
251
|
+
args: ["-y", "@modelcontextprotocol/server-github"]
|
|
252
|
+
env:
|
|
253
|
+
GITHUB_PERSONAL_ACCESS_TOKEN: \${GITHUB_TOKEN}
|
|
254
|
+
tags: [github, vcs]
|
|
255
|
+
enabled: true
|
|
256
|
+
|
|
257
|
+
# Remote servers
|
|
258
|
+
# - id: remote-http
|
|
259
|
+
# name: Remote (Streamable HTTP)
|
|
260
|
+
# transport: streamable-http
|
|
261
|
+
# url: https://mcp.example.com/mcp
|
|
262
|
+
# headers:
|
|
263
|
+
# Authorization: "Bearer \${REMOTE_MCP_TOKEN}"
|
|
264
|
+
#
|
|
265
|
+
# - id: legacy-sse
|
|
266
|
+
# name: Legacy SSE server
|
|
267
|
+
# transport: sse
|
|
268
|
+
# url: http://localhost:8080/sse
|
|
269
|
+
#
|
|
270
|
+
# - id: websocket
|
|
271
|
+
# name: WebSocket server
|
|
272
|
+
# transport: websocket
|
|
273
|
+
# url: ws://localhost:8081
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config File Watcher — Hot Reload Support
|
|
3
|
+
*
|
|
4
|
+
* Watches the active config file for changes and emits a 'reload' event
|
|
5
|
+
* so the gateway can apply new server registrations without restarting.
|
|
6
|
+
*
|
|
7
|
+
* Many editors save atomically (write temp file + rename), which surfaces as a
|
|
8
|
+
* 'rename' event and silently detaches an fs.watch handle from the path. The
|
|
9
|
+
* watcher therefore treats 'rename' as a change and re-attaches itself.
|
|
10
|
+
*
|
|
11
|
+
* @module config/watcher
|
|
12
|
+
*/
|
|
13
|
+
import { EventEmitter } from 'events';
|
|
14
|
+
import type { Logger } from '../utils/logger.js';
|
|
15
|
+
export declare class ConfigWatcher extends EventEmitter {
|
|
16
|
+
private configPath;
|
|
17
|
+
private logger;
|
|
18
|
+
private watcher;
|
|
19
|
+
private debounceTimer;
|
|
20
|
+
private debounceMs;
|
|
21
|
+
private stopped;
|
|
22
|
+
constructor(configPath: string, logger: Logger, debounceMs?: number);
|
|
23
|
+
start(): void;
|
|
24
|
+
private _attach;
|
|
25
|
+
private _schedule;
|
|
26
|
+
private _reload;
|
|
27
|
+
stop(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/config/watcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAIjD,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAQ;gBAEX,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,SAAM;IAOhE,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,SAAS;YAUH,OAAO;IAerB,IAAI,IAAI,IAAI;CAQb"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config File Watcher — Hot Reload Support
|
|
3
|
+
*
|
|
4
|
+
* Watches the active config file for changes and emits a 'reload' event
|
|
5
|
+
* so the gateway can apply new server registrations without restarting.
|
|
6
|
+
*
|
|
7
|
+
* Many editors save atomically (write temp file + rename), which surfaces as a
|
|
8
|
+
* 'rename' event and silently detaches an fs.watch handle from the path. The
|
|
9
|
+
* watcher therefore treats 'rename' as a change and re-attaches itself.
|
|
10
|
+
*
|
|
11
|
+
* @module config/watcher
|
|
12
|
+
*/
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { EventEmitter } from 'events';
|
|
16
|
+
import { loadConfig } from './loader.js';
|
|
17
|
+
export class ConfigWatcher extends EventEmitter {
|
|
18
|
+
configPath;
|
|
19
|
+
logger;
|
|
20
|
+
watcher = null;
|
|
21
|
+
debounceTimer = null;
|
|
22
|
+
debounceMs;
|
|
23
|
+
stopped = true;
|
|
24
|
+
constructor(configPath, logger, debounceMs = 500) {
|
|
25
|
+
super();
|
|
26
|
+
this.configPath = path.resolve(configPath);
|
|
27
|
+
this.logger = logger;
|
|
28
|
+
this.debounceMs = debounceMs;
|
|
29
|
+
}
|
|
30
|
+
start() {
|
|
31
|
+
if (this.watcher)
|
|
32
|
+
return;
|
|
33
|
+
this.stopped = false;
|
|
34
|
+
this._attach();
|
|
35
|
+
this.logger.info(`Config hot-reload enabled — watching ${this.configPath}`);
|
|
36
|
+
}
|
|
37
|
+
_attach() {
|
|
38
|
+
try {
|
|
39
|
+
this.watcher = fs.watch(this.configPath, (eventType) => {
|
|
40
|
+
if (eventType === 'rename') {
|
|
41
|
+
// File was replaced; the old handle is now stale.
|
|
42
|
+
this.watcher?.close();
|
|
43
|
+
this.watcher = null;
|
|
44
|
+
}
|
|
45
|
+
this._schedule();
|
|
46
|
+
});
|
|
47
|
+
this.watcher.on('error', (err) => {
|
|
48
|
+
this.logger.warn(`Config watcher error: ${err.message}`);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53
|
+
this.logger.warn(`Cannot watch ${this.configPath}: ${msg}`);
|
|
54
|
+
this.watcher = null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
_schedule() {
|
|
58
|
+
if (this.debounceTimer)
|
|
59
|
+
clearTimeout(this.debounceTimer);
|
|
60
|
+
this.debounceTimer = setTimeout(() => {
|
|
61
|
+
this.debounceTimer = null;
|
|
62
|
+
if (this.stopped)
|
|
63
|
+
return;
|
|
64
|
+
if (!this.watcher)
|
|
65
|
+
this._attach();
|
|
66
|
+
void this._reload();
|
|
67
|
+
}, this.debounceMs);
|
|
68
|
+
}
|
|
69
|
+
async _reload() {
|
|
70
|
+
try {
|
|
71
|
+
const newConfig = await loadConfig(this.configPath);
|
|
72
|
+
if (this.stopped)
|
|
73
|
+
return;
|
|
74
|
+
this.logger.info('Config file changed — applying hot reload');
|
|
75
|
+
this.emit('reload', newConfig);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
+
this.logger.error(`Config reload failed (keeping current config): ${msg}`);
|
|
80
|
+
// Only emit when someone listens: an 'error'-like event without a
|
|
81
|
+
// listener is fine for custom names, but keep it explicit.
|
|
82
|
+
if (this.listenerCount('reload-error') > 0)
|
|
83
|
+
this.emit('reload-error', err);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
stop() {
|
|
87
|
+
this.stopped = true;
|
|
88
|
+
if (this.debounceTimer)
|
|
89
|
+
clearTimeout(this.debounceTimer);
|
|
90
|
+
this.debounceTimer = null;
|
|
91
|
+
this.watcher?.close();
|
|
92
|
+
this.watcher = null;
|
|
93
|
+
this.logger.debug('Config watcher stopped');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/config/watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gateway HTTP API
|
|
3
|
+
* Exposes REST endpoints for tool invocation, server management, and monitoring
|
|
4
|
+
*/
|
|
5
|
+
import express from 'express';
|
|
6
|
+
import type { GatewayConfig, McpServerConfig } from '../utils/types.js';
|
|
7
|
+
import type { ServerRegistry } from '../registry/index.js';
|
|
8
|
+
import { type McpProxy } from '../proxy/index.js';
|
|
9
|
+
import type { MetricsCollector, ServerStateSample } from '../monitor/index.js';
|
|
10
|
+
import type { ServerSupervisor } from './supervisor.js';
|
|
11
|
+
export type ApiRouter = express.Router & {
|
|
12
|
+
close(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Apply hot-reloadable settings from a new config: auth (strategy, keys,
|
|
15
|
+
* secret, protect flags), rate limits and monitor flags. Invalid auth keeps
|
|
16
|
+
* the current middleware (fail safe).
|
|
17
|
+
*/
|
|
18
|
+
update(next: GatewayConfig): void;
|
|
19
|
+
};
|
|
20
|
+
export interface ApiRouterOptions {
|
|
21
|
+
/** Enables POST /servers/:id/reconnect and reconnect info. */
|
|
22
|
+
supervisor?: ServerSupervisor;
|
|
23
|
+
/** Makes GET /health/ready answer 503 while the gateway is shutting down. */
|
|
24
|
+
isShuttingDown?: () => boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface Readiness {
|
|
27
|
+
ready: boolean;
|
|
28
|
+
/** Enabled servers that are connected and not `degraded`. */
|
|
29
|
+
readyServers: number;
|
|
30
|
+
/** Enabled servers. */
|
|
31
|
+
totalServers: number;
|
|
32
|
+
/** Servers that must be ready (`?min=`, default: all of them). */
|
|
33
|
+
required: number;
|
|
34
|
+
shuttingDown: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Readiness for load balancers / Kubernetes: ready when at least `min`
|
|
38
|
+
* enabled servers (default: every one) are connected and answering pings.
|
|
39
|
+
* A gateway with no enabled servers is ready; a shutting-down one never is.
|
|
40
|
+
*/
|
|
41
|
+
export declare function computeReadiness(registry: ServerRegistry, proxy: McpProxy, min?: number, shuttingDown?: boolean): Readiness;
|
|
42
|
+
/** Never expose env values (tokens are commonly configured there). */
|
|
43
|
+
export declare function redactServer(server: McpServerConfig): McpServerConfig;
|
|
44
|
+
/** Per-server state for /metrics and Prometheus. */
|
|
45
|
+
export declare function serverStateSamples(registry: ServerRegistry, proxy: McpProxy): ServerStateSample[];
|
|
46
|
+
export declare function createApiRouter(config: GatewayConfig, registry: ServerRegistry, proxy: McpProxy, metrics: MetricsCollector, options?: ApiRouterOptions): ApiRouter;
|
|
47
|
+
//# sourceMappingURL=api.d.ts.map
|