@winstonsayno/mcp-gateway 0.0.0-stage → 0.3.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/LICENSE +21 -0
  3. package/README.md +377 -2
  4. package/dashboard/README.md +27 -0
  5. package/dashboard/index.html +415 -0
  6. package/dist/auth/middleware.d.ts +24 -0
  7. package/dist/auth/middleware.d.ts.map +1 -0
  8. package/dist/auth/middleware.js +108 -0
  9. package/dist/auth/middleware.js.map +1 -0
  10. package/dist/auth/ratelimit.d.ts +19 -0
  11. package/dist/auth/ratelimit.d.ts.map +1 -0
  12. package/dist/auth/ratelimit.js +81 -0
  13. package/dist/auth/ratelimit.js.map +1 -0
  14. package/dist/cli.d.ts +6 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +129 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/config/loader.d.ts +13 -0
  19. package/dist/config/loader.d.ts.map +1 -0
  20. package/dist/config/loader.js +268 -0
  21. package/dist/config/loader.js.map +1 -0
  22. package/dist/config/watcher.d.ts +29 -0
  23. package/dist/config/watcher.d.ts.map +1 -0
  24. package/dist/config/watcher.js +96 -0
  25. package/dist/config/watcher.js.map +1 -0
  26. package/dist/gateway/api.d.ts +29 -0
  27. package/dist/gateway/api.d.ts.map +1 -0
  28. package/dist/gateway/api.js +280 -0
  29. package/dist/gateway/api.js.map +1 -0
  30. package/dist/gateway/index.d.ts +49 -0
  31. package/dist/gateway/index.d.ts.map +1 -0
  32. package/dist/gateway/index.js +260 -0
  33. package/dist/gateway/index.js.map +1 -0
  34. package/dist/gateway/supervisor.d.ts +58 -0
  35. package/dist/gateway/supervisor.d.ts.map +1 -0
  36. package/dist/gateway/supervisor.js +205 -0
  37. package/dist/gateway/supervisor.js.map +1 -0
  38. package/dist/index.d.ts +15 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +12 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/middleware/cors.d.ts +19 -0
  43. package/dist/middleware/cors.d.ts.map +1 -0
  44. package/dist/middleware/cors.js +65 -0
  45. package/dist/middleware/cors.js.map +1 -0
  46. package/dist/middleware/error-handler.d.ts +40 -0
  47. package/dist/middleware/error-handler.d.ts.map +1 -0
  48. package/dist/middleware/error-handler.js +98 -0
  49. package/dist/middleware/error-handler.js.map +1 -0
  50. package/dist/middleware/request-id.d.ts +23 -0
  51. package/dist/middleware/request-id.d.ts.map +1 -0
  52. package/dist/middleware/request-id.js +30 -0
  53. package/dist/middleware/request-id.js.map +1 -0
  54. package/dist/middleware/timeout.d.ts +12 -0
  55. package/dist/middleware/timeout.d.ts.map +1 -0
  56. package/dist/middleware/timeout.js +39 -0
  57. package/dist/middleware/timeout.js.map +1 -0
  58. package/dist/monitor/index.d.ts +49 -0
  59. package/dist/monitor/index.d.ts.map +1 -0
  60. package/dist/monitor/index.js +204 -0
  61. package/dist/monitor/index.js.map +1 -0
  62. package/dist/proxy/index.d.ts +86 -0
  63. package/dist/proxy/index.d.ts.map +1 -0
  64. package/dist/proxy/index.js +389 -0
  65. package/dist/proxy/index.js.map +1 -0
  66. package/dist/registry/index.d.ts +41 -0
  67. package/dist/registry/index.d.ts.map +1 -0
  68. package/dist/registry/index.js +157 -0
  69. package/dist/registry/index.js.map +1 -0
  70. package/dist/transport/channel.d.ts +61 -0
  71. package/dist/transport/channel.d.ts.map +1 -0
  72. package/dist/transport/channel.js +38 -0
  73. package/dist/transport/channel.js.map +1 -0
  74. package/dist/transport/sse-parser.d.ts +30 -0
  75. package/dist/transport/sse-parser.d.ts.map +1 -0
  76. package/dist/transport/sse-parser.js +107 -0
  77. package/dist/transport/sse-parser.js.map +1 -0
  78. package/dist/transport/sse.d.ts +39 -0
  79. package/dist/transport/sse.d.ts.map +1 -0
  80. package/dist/transport/sse.js +142 -0
  81. package/dist/transport/sse.js.map +1 -0
  82. package/dist/transport/stdio.d.ts +35 -0
  83. package/dist/transport/stdio.d.ts.map +1 -0
  84. package/dist/transport/stdio.js +149 -0
  85. package/dist/transport/stdio.js.map +1 -0
  86. package/dist/transport/streamable-http.d.ts +45 -0
  87. package/dist/transport/streamable-http.d.ts.map +1 -0
  88. package/dist/transport/streamable-http.js +183 -0
  89. package/dist/transport/streamable-http.js.map +1 -0
  90. package/dist/transport/websocket.d.ts +38 -0
  91. package/dist/transport/websocket.d.ts.map +1 -0
  92. package/dist/transport/websocket.js +172 -0
  93. package/dist/transport/websocket.js.map +1 -0
  94. package/dist/utils/logger.d.ts +16 -0
  95. package/dist/utils/logger.d.ts.map +1 -0
  96. package/dist/utils/logger.js +60 -0
  97. package/dist/utils/logger.js.map +1 -0
  98. package/dist/utils/mutex.d.ts +25 -0
  99. package/dist/utils/mutex.d.ts.map +1 -0
  100. package/dist/utils/mutex.js +62 -0
  101. package/dist/utils/mutex.js.map +1 -0
  102. package/dist/utils/semaphore.d.ts +16 -0
  103. package/dist/utils/semaphore.d.ts.map +1 -0
  104. package/dist/utils/semaphore.js +42 -0
  105. package/dist/utils/semaphore.js.map +1 -0
  106. package/dist/utils/types.d.ts +215 -0
  107. package/dist/utils/types.d.ts.map +1 -0
  108. package/dist/utils/types.js +5 -0
  109. package/dist/utils/types.js.map +1 -0
  110. package/dist/utils/version.d.ts +6 -0
  111. package/dist/utils/version.d.ts.map +1 -0
  112. package/dist/utils/version.js +18 -0
  113. package/dist/utils/version.js.map +1 -0
  114. package/package.json +78 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../src/middleware/timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,IACzC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAAI,CAiC/D"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Request Timeout Middleware
3
+ *
4
+ * Bug fix (v0.1.0): tool-call requests to slow or unresponsive MCP servers
5
+ * could hang indefinitely, exhausting the Node.js event loop.
6
+ * This middleware enforces a per-request deadline and returns a 504 response.
7
+ *
8
+ * @module middleware/timeout
9
+ */
10
+ import { GatewayError, ErrorCodes } from './error-handler.js';
11
+ export function timeoutMiddleware(timeoutMs) {
12
+ return (req, res, next) => {
13
+ // Skip timeout for SSE streaming endpoints
14
+ if (req.path.endsWith('/stream')) {
15
+ next();
16
+ return;
17
+ }
18
+ let timedOut = false;
19
+ const timer = setTimeout(() => {
20
+ timedOut = true;
21
+ // The handler may have started streaming; nothing safe to send then.
22
+ if (res.headersSent)
23
+ return;
24
+ res.set('Retry-After', String(Math.max(1, Math.ceil(timeoutMs / 1000))));
25
+ next(new GatewayError(504, ErrorCodes.TIMEOUT, `Request timed out after ${timeoutMs}ms`, { path: req.path, method: req.method }));
26
+ }, timeoutMs);
27
+ // Clear the timer once the response is sent
28
+ res.on('finish', () => {
29
+ if (!timedOut)
30
+ clearTimeout(timer);
31
+ });
32
+ res.on('close', () => {
33
+ if (!timedOut)
34
+ clearTimeout(timer);
35
+ });
36
+ next();
37
+ };
38
+ }
39
+ //# sourceMappingURL=timeout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.js","sourceRoot":"","sources":["../../src/middleware/timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE9D,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;QAC/D,2CAA2C;QAC3C,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QAED,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,QAAQ,GAAG,IAAI,CAAC;YAChB,qEAAqE;YACrE,IAAI,GAAG,CAAC,WAAW;gBAAE,OAAO;YAC5B,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACzE,IAAI,CACF,IAAI,YAAY,CACd,GAAG,EACH,UAAU,CAAC,OAAO,EAClB,2BAA2B,SAAS,IAAI,EACxC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CACvC,CACF,CAAC;QACJ,CAAC,EAAE,SAAS,CAAC,CAAC;QAEd,4CAA4C;QAC5C,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACpB,IAAI,CAAC,QAAQ;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,IAAI,CAAC,QAAQ;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Metrics collection and aggregation for mcp-gateway
3
+ *
4
+ * Audit fixes:
5
+ * - Prometheus `*_total` series were the count of the *last minute*, which
6
+ * goes down over time and breaks `rate()`; they are now real monotonic
7
+ * counters kept independently of the retention window.
8
+ * - Label values are escaped per the exposition format.
9
+ * - Percentiles use the nearest-rank method; `requestsPerMinute` without a
10
+ * window is computed from the actual time span instead of request count.
11
+ * - The in-memory log is capped (`maxEntries`) so high traffic within the
12
+ * retention window cannot exhaust memory; cleanup timer is unref()'d.
13
+ */
14
+ import { EventEmitter } from 'events';
15
+ import type { RequestMetric, AggregatedMetrics, MonitorConfig } from '../utils/types.js';
16
+ export interface MetricsOptions {
17
+ /** Hard cap on retained request records (oldest dropped first). Default 100k. */
18
+ maxEntries?: number;
19
+ }
20
+ /** Per-server connection state exported as Prometheus gauges / counters. */
21
+ export interface ServerStateSample {
22
+ id: string;
23
+ status: string;
24
+ /** 1 when connected (online or degraded), else 0. */
25
+ up: number;
26
+ /** Successful automatic reconnects since start (monotonic). */
27
+ reconnects: number;
28
+ /** Consecutive failed reconnect attempts right now. */
29
+ reconnectAttempt: number;
30
+ latencyMs?: number;
31
+ }
32
+ export declare class MetricsCollector extends EventEmitter {
33
+ private metrics;
34
+ private readonly retentionMs;
35
+ private readonly maxEntries;
36
+ private cleanupInterval?;
37
+ private readonly counters;
38
+ constructor(config?: MonitorConfig, options?: MetricsOptions);
39
+ record(metric: Omit<RequestMetric, 'id' | 'timestamp'>): RequestMetric;
40
+ aggregate(windowMs?: number): AggregatedMetrics;
41
+ toPrometheusText(servers?: ServerStateSample[]): string;
42
+ start(): void;
43
+ /** Drop records older than the retention period. */
44
+ prune(now?: number): number;
45
+ stop(): void;
46
+ getRecent(limit?: number): RequestMetric[];
47
+ clear(): void;
48
+ }
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEzF,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,eAAe,CAAC,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;gBAElD,MAAM,CAAC,EAAE,aAAa,EAAE,OAAO,GAAE,cAAmB;IAQhE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,aAAa;IAwBtE,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,iBAAiB;IAsD/C,gBAAgB,CAAC,OAAO,GAAE,iBAAiB,EAAO,GAAG,MAAM;IAkG3D,KAAK,IAAI,IAAI;IAMb,oDAAoD;IACpD,KAAK,CAAC,GAAG,SAAa,GAAG,MAAM;IAS/B,IAAI,IAAI,IAAI;IAOZ,SAAS,CAAC,KAAK,SAAM,GAAG,aAAa,EAAE;IAKvC,KAAK,IAAI,IAAI;CAId"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Metrics collection and aggregation for mcp-gateway
3
+ *
4
+ * Audit fixes:
5
+ * - Prometheus `*_total` series were the count of the *last minute*, which
6
+ * goes down over time and breaks `rate()`; they are now real monotonic
7
+ * counters kept independently of the retention window.
8
+ * - Label values are escaped per the exposition format.
9
+ * - Percentiles use the nearest-rank method; `requestsPerMinute` without a
10
+ * window is computed from the actual time span instead of request count.
11
+ * - The in-memory log is capped (`maxEntries`) so high traffic within the
12
+ * retention window cannot exhaust memory; cleanup timer is unref()'d.
13
+ */
14
+ import { EventEmitter } from 'events';
15
+ import { randomUUID } from 'crypto';
16
+ const SERVER_STATUSES = ['online', 'degraded', 'reconnecting', 'offline', 'unknown'];
17
+ export class MetricsCollector extends EventEmitter {
18
+ metrics = [];
19
+ retentionMs;
20
+ maxEntries;
21
+ cleanupInterval;
22
+ counters = new Map();
23
+ constructor(config, options = {}) {
24
+ super();
25
+ this.retentionMs = (config?.retentionHours ?? 24) * 60 * 60 * 1000;
26
+ this.maxEntries = Math.max(1, options.maxEntries ?? 100_000);
27
+ }
28
+ // ─── Recording ──────────────────────────────────────────────────────────────
29
+ record(metric) {
30
+ const full = {
31
+ ...metric,
32
+ id: randomUUID(),
33
+ timestamp: new Date(),
34
+ };
35
+ this.metrics.push(full);
36
+ // Trim in batches to keep this amortised O(1).
37
+ if (this.metrics.length > this.maxEntries * 1.1) {
38
+ this.metrics.splice(0, this.metrics.length - this.maxEntries);
39
+ }
40
+ const c = this.counters.get(metric.serverId) ?? { requests: 0, errors: 0, durationMsSum: 0 };
41
+ c.requests++;
42
+ if (!metric.success)
43
+ c.errors++;
44
+ c.durationMsSum += metric.durationMs;
45
+ this.counters.set(metric.serverId, c);
46
+ this.emit('metric', full);
47
+ return full;
48
+ }
49
+ // ─── Aggregation ────────────────────────────────────────────────────────────
50
+ aggregate(windowMs) {
51
+ const now = Date.now();
52
+ const validWindow = windowMs !== undefined && Number.isFinite(windowMs) && windowMs > 0;
53
+ const cutoff = validWindow ? now - windowMs : 0;
54
+ const recent = cutoff > 0 ? this.metrics.filter((m) => m.timestamp.getTime() >= cutoff) : this.metrics;
55
+ if (recent.length === 0) {
56
+ return {
57
+ totalRequests: 0,
58
+ successRate: 1,
59
+ avgLatencyMs: 0,
60
+ p95LatencyMs: 0,
61
+ p99LatencyMs: 0,
62
+ requestsPerMinute: 0,
63
+ topTools: [],
64
+ topServers: [],
65
+ errorsByServer: {},
66
+ };
67
+ }
68
+ let successCount = 0;
69
+ let latencySum = 0;
70
+ const latencies = new Array(recent.length);
71
+ const toolCounts = new Map();
72
+ const serverCounts = new Map();
73
+ const errorsByServer = {};
74
+ recent.forEach((m, i) => {
75
+ latencies[i] = m.durationMs;
76
+ latencySum += m.durationMs;
77
+ if (m.success)
78
+ successCount++;
79
+ else
80
+ errorsByServer[m.serverId] = (errorsByServer[m.serverId] ?? 0) + 1;
81
+ toolCounts.set(m.toolName, (toolCounts.get(m.toolName) ?? 0) + 1);
82
+ serverCounts.set(m.serverId, (serverCounts.get(m.serverId) ?? 0) + 1);
83
+ });
84
+ latencies.sort((a, b) => a - b);
85
+ const spanMs = validWindow ? windowMs : Math.max(60_000, now - recent[0].timestamp.getTime());
86
+ return {
87
+ totalRequests: recent.length,
88
+ successRate: successCount / recent.length,
89
+ avgLatencyMs: latencySum / recent.length,
90
+ p95LatencyMs: percentile(latencies, 0.95),
91
+ p99LatencyMs: percentile(latencies, 0.99),
92
+ requestsPerMinute: recent.length / (spanMs / 60_000),
93
+ topTools: topN(toolCounts).map(([name, count]) => ({ name, count })),
94
+ topServers: topN(serverCounts).map(([id, count]) => ({ id, count })),
95
+ errorsByServer,
96
+ };
97
+ }
98
+ // ─── Prometheus Format ──────────────────────────────────────────────────────
99
+ toPrometheusText(servers = []) {
100
+ const agg = this.aggregate(60_000); // gauges over the last minute
101
+ let total = 0;
102
+ let errors = 0;
103
+ for (const c of this.counters.values()) {
104
+ total += c.requests;
105
+ errors += c.errors;
106
+ }
107
+ const lines = [
108
+ '# HELP mcp_gateway_requests_total Total number of tool calls since start',
109
+ '# TYPE mcp_gateway_requests_total counter',
110
+ `mcp_gateway_requests_total ${total}`,
111
+ '# HELP mcp_gateway_errors_total Total number of failed tool calls since start',
112
+ '# TYPE mcp_gateway_errors_total counter',
113
+ `mcp_gateway_errors_total ${errors}`,
114
+ '# HELP mcp_gateway_server_requests_total Tool calls per server since start',
115
+ '# TYPE mcp_gateway_server_requests_total counter',
116
+ ];
117
+ for (const [id, c] of this.counters) {
118
+ lines.push(`mcp_gateway_server_requests_total{server="${escapeLabel(id)}"} ${c.requests}`);
119
+ }
120
+ lines.push('# HELP mcp_gateway_server_errors_total Failed tool calls per server since start', '# TYPE mcp_gateway_server_errors_total counter');
121
+ for (const [id, c] of this.counters) {
122
+ lines.push(`mcp_gateway_server_errors_total{server="${escapeLabel(id)}"} ${c.errors}`);
123
+ }
124
+ lines.push('# HELP mcp_gateway_server_duration_ms_sum Sum of tool call latency per server since start (ms)', '# TYPE mcp_gateway_server_duration_ms_sum counter');
125
+ for (const [id, c] of this.counters) {
126
+ lines.push(`mcp_gateway_server_duration_ms_sum{server="${escapeLabel(id)}"} ${c.durationMsSum}`);
127
+ }
128
+ lines.push('# HELP mcp_gateway_success_rate Request success rate over the last minute (0-1)', '# TYPE mcp_gateway_success_rate gauge', `mcp_gateway_success_rate ${agg.successRate.toFixed(4)}`, '# HELP mcp_gateway_latency_avg_ms Average latency over the last minute (ms)', '# TYPE mcp_gateway_latency_avg_ms gauge', `mcp_gateway_latency_avg_ms ${agg.avgLatencyMs.toFixed(2)}`, '# HELP mcp_gateway_latency_p95_ms P95 latency over the last minute (ms)', '# TYPE mcp_gateway_latency_p95_ms gauge', `mcp_gateway_latency_p95_ms ${agg.p95LatencyMs.toFixed(2)}`, '# HELP mcp_gateway_latency_p99_ms P99 latency over the last minute (ms)', '# TYPE mcp_gateway_latency_p99_ms gauge', `mcp_gateway_latency_p99_ms ${agg.p99LatencyMs.toFixed(2)}`);
129
+ if (servers.length > 0) {
130
+ lines.push('# HELP mcp_gateway_server_up Whether the gateway currently has a session with the server (1/0)', '# TYPE mcp_gateway_server_up gauge');
131
+ for (const s of servers)
132
+ lines.push(`mcp_gateway_server_up{server="${escapeLabel(s.id)}"} ${s.up}`);
133
+ lines.push('# HELP mcp_gateway_server_status Current server status (1 for the active status label)', '# TYPE mcp_gateway_server_status gauge');
134
+ for (const s of servers) {
135
+ for (const st of SERVER_STATUSES) {
136
+ lines.push(`mcp_gateway_server_status{server="${escapeLabel(s.id)}",status="${st}"} ${s.status === st ? 1 : 0}`);
137
+ }
138
+ }
139
+ lines.push('# HELP mcp_gateway_server_reconnects_total Successful automatic reconnects per server since start', '# TYPE mcp_gateway_server_reconnects_total counter');
140
+ for (const s of servers) {
141
+ lines.push(`mcp_gateway_server_reconnects_total{server="${escapeLabel(s.id)}"} ${s.reconnects}`);
142
+ }
143
+ lines.push('# HELP mcp_gateway_server_reconnect_attempt Consecutive failed reconnect attempts (0 when healthy)', '# TYPE mcp_gateway_server_reconnect_attempt gauge');
144
+ for (const s of servers) {
145
+ lines.push(`mcp_gateway_server_reconnect_attempt{server="${escapeLabel(s.id)}"} ${s.reconnectAttempt}`);
146
+ }
147
+ const pinged = servers.filter((s) => typeof s.latencyMs === 'number');
148
+ if (pinged.length > 0) {
149
+ lines.push('# HELP mcp_gateway_server_ping_ms Latency of the last health ping (ms)', '# TYPE mcp_gateway_server_ping_ms gauge');
150
+ for (const s of pinged)
151
+ lines.push(`mcp_gateway_server_ping_ms{server="${escapeLabel(s.id)}"} ${s.latencyMs}`);
152
+ }
153
+ }
154
+ lines.push('');
155
+ return lines.join('\n');
156
+ }
157
+ // ─── Lifecycle ──────────────────────────────────────────────────────────────
158
+ start() {
159
+ this.stop();
160
+ this.cleanupInterval = setInterval(() => this.prune(), 60_000);
161
+ this.cleanupInterval.unref();
162
+ }
163
+ /** Drop records older than the retention period. */
164
+ prune(now = Date.now()) {
165
+ const cutoff = now - this.retentionMs;
166
+ // Records are appended in time order: find the first one to keep.
167
+ let i = 0;
168
+ while (i < this.metrics.length && this.metrics[i].timestamp.getTime() < cutoff)
169
+ i++;
170
+ if (i > 0)
171
+ this.metrics.splice(0, i);
172
+ return i;
173
+ }
174
+ stop() {
175
+ if (this.cleanupInterval) {
176
+ clearInterval(this.cleanupInterval);
177
+ this.cleanupInterval = undefined;
178
+ }
179
+ }
180
+ getRecent(limit = 100) {
181
+ if (!Number.isFinite(limit) || limit <= 0)
182
+ return [];
183
+ return this.metrics.slice(-Math.floor(limit)).reverse();
184
+ }
185
+ clear() {
186
+ this.metrics = [];
187
+ this.counters.clear();
188
+ }
189
+ }
190
+ function percentile(sorted, p) {
191
+ if (sorted.length === 0)
192
+ return 0;
193
+ const idx = Math.min(sorted.length - 1, Math.max(0, Math.ceil(p * sorted.length) - 1));
194
+ return sorted[idx];
195
+ }
196
+ function topN(counts, n = 10) {
197
+ return Array.from(counts.entries())
198
+ .sort((a, b) => b[1] - a[1])
199
+ .slice(0, n);
200
+ }
201
+ function escapeLabel(v) {
202
+ return v.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/"/g, '\\"');
203
+ }
204
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/monitor/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * MCP Proxy
3
+ * Routes tool-call requests to the appropriate upstream MCP server over any
4
+ * supported transport: `stdio`, `sse` (HTTP+SSE, 2024-11-05), `websocket`
5
+ * and `streamable-http` (2025-03-26+).
6
+ *
7
+ * The proxy is split in two layers:
8
+ * - a *channel* per transport (`src/transport/*`) that only moves JSON-RPC
9
+ * messages, and
10
+ * - this transport-independent *session* layer: MCP handshake, request/
11
+ * response correlation, timeouts + upstream cancellation, `maxConcurrency`,
12
+ * answering server→client requests (`ping`), `tools/list` pagination and
13
+ * `notifications/tools/list_changed`.
14
+ *
15
+ * Events:
16
+ * - `disconnected` (serverId, error) — a session was lost unexpectedly
17
+ * (process exit, socket/stream closed, session expired). Not emitted for
18
+ * `disconnect()`. The gateway supervisor uses it to reconnect.
19
+ * - `tools-changed` (serverId, tools) — the server announced a new tool list.
20
+ *
21
+ * Fixes kept from v0.2.0 / the audit: per-server connect mutex (BUG-001),
22
+ * monotonic ids (BUG-002), no leaked sessions on failed `initialize`, an old
23
+ * session's exit can never remove a newer one, server requests with colliding
24
+ * ids are answered instead of mistaken for responses.
25
+ *
26
+ * @module proxy
27
+ */
28
+ import { EventEmitter } from 'events';
29
+ import type { McpServerConfig, ProxyResponse, ToolInfo } from '../utils/types.js';
30
+ import type { ChannelFactory } from '../transport/channel.js';
31
+ /** Protocol version the gateway asks for in `initialize`. */
32
+ export declare const MCP_PROTOCOL_VERSION = "2025-06-18";
33
+ /** Versions the gateway understands; servers may answer with any of them. */
34
+ export declare const SUPPORTED_PROTOCOL_VERSIONS: string[];
35
+ export declare const ERR_NOT_CONNECTED = -32000;
36
+ export declare const ERR_TIMEOUT = -32001;
37
+ /** Default channel per transport. */
38
+ export declare const defaultChannelFactory: ChannelFactory;
39
+ export interface SessionInfo {
40
+ transport: string;
41
+ protocolVersion?: string;
42
+ serverInfo?: {
43
+ name?: string;
44
+ version?: string;
45
+ };
46
+ connectedAt?: Date;
47
+ }
48
+ export interface ProxyOptions {
49
+ /** Grace period between closing stdin / SIGTERM / SIGKILL (and for WS/HTTP close). */
50
+ killGraceMs?: number;
51
+ /** Override how channels are created (for tests or custom transports). */
52
+ channelFactory?: ChannelFactory;
53
+ }
54
+ export declare class McpProxy extends EventEmitter {
55
+ private sessions;
56
+ private spawnLocks;
57
+ private readonly killGraceMs;
58
+ private readonly channelFactory;
59
+ constructor(options?: ProxyOptions);
60
+ private getSpawnLock;
61
+ connect(config: McpServerConfig): Promise<ToolInfo[]>;
62
+ private _handshake;
63
+ private _listTools;
64
+ disconnect(serverId: string): Promise<void>;
65
+ private _disconnectUnlocked;
66
+ disconnectAll(): Promise<void>;
67
+ callTool(serverId: string, toolName: string, args: Record<string, unknown>, timeout?: number): Promise<ProxyResponse>;
68
+ /** MCP `ping`: resolves with the round-trip latency (ms), or rejects if the server does not answer. */
69
+ ping(serverId: string, timeout?: number): Promise<number>;
70
+ isConnected(serverId: string): boolean;
71
+ /** Negotiated session details (for /servers). */
72
+ getSessionInfo(serverId: string): SessionInfo | undefined;
73
+ /** In-flight and queued tool calls for a server (for monitoring). */
74
+ getLoad(serverId: string): {
75
+ inFlight: number;
76
+ queued: number;
77
+ } | undefined;
78
+ private _onChannelLost;
79
+ private _rejectAll;
80
+ private _onMessage;
81
+ private _refreshTools;
82
+ private _answerServerRequest;
83
+ private _notify;
84
+ private _sendRequest;
85
+ }
86
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/proxy/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAKlF,OAAO,KAAK,EAAE,cAAc,EAA8D,MAAM,yBAAyB,CAAC;AAM1H,6DAA6D;AAC7D,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,UAA6C,CAAC;AAMtF,eAAO,MAAM,iBAAiB,SAAS,CAAC;AACxC,eAAO,MAAM,WAAW,SAAS,CAAC;AAQlC,qCAAqC;AACrC,eAAO,MAAM,qBAAqB,EAAE,cAanC,CAAC;AAqBF,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,qBAAa,QAAS,SAAQ,YAAY;IACxC,OAAO,CAAC,QAAQ,CAA8B;IAE9C,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;gBAEpC,OAAO,GAAE,YAAiB;IAMtC,OAAO,CAAC,YAAY;IAWd,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;YA0C7C,UAAU;YAoCV,UAAU;IAgClB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAInC,mBAAmB;IAY3B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAM9B,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,CAAC;IAkBzB,uGAAuG;IACjG,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAY9D,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAKtC,iDAAiD;IACjD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAWzD,qEAAqE;IACrE,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAO3E,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,oBAAoB;YAQd,OAAO;YAOP,YAAY;CA+E3B"}