@loop_ouroboros/mcp-hub-lite 1.2.7 → 1.2.8
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
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.8] - 2026-05-09
|
|
6
|
+
|
|
7
|
+
### Gateway
|
|
8
|
+
|
|
9
|
+
- prevent concurrent request counter drift from SSE timeout causing 503 for new clients
|
|
10
|
+
- add GET /health/connections diagnostic endpoint for connection stats
|
|
11
|
+
|
|
5
12
|
## [1.2.7] - 2026-05-09
|
|
6
13
|
|
|
7
14
|
### Gateway
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../../src/api/web/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../../../../src/api/web/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAG1C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,eAAe,iBAU7D"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getConnectionStats } from '../../app.js';
|
|
1
2
|
/**
|
|
2
3
|
* Health Check API Routes
|
|
3
4
|
*
|
|
@@ -21,4 +22,8 @@ export async function webHealthRoutes(fastify) {
|
|
|
21
22
|
fastify.get('/web/health', async () => {
|
|
22
23
|
return { status: 'ok', timestamp: new Date().toISOString() };
|
|
23
24
|
});
|
|
25
|
+
// GET /health/connections - diagnostic endpoint for connection counters
|
|
26
|
+
fastify.get('/health/connections', async () => {
|
|
27
|
+
return getConnectionStats();
|
|
28
|
+
});
|
|
24
29
|
}
|
package/dist/server/src/app.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/** Expose connection stats for diagnostic endpoints */
|
|
2
|
+
export declare function getConnectionStats(): {
|
|
3
|
+
currentConnections: number;
|
|
4
|
+
currentConcurrentRequests: number;
|
|
5
|
+
maxConnections: number;
|
|
6
|
+
maxConcurrentConnections: number;
|
|
7
|
+
};
|
|
1
8
|
/**
|
|
2
9
|
* Creates and configures a Fastify application instance for the MCP Hub Lite service.
|
|
3
10
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/app.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../src/app.ts"],"names":[],"mappings":"AAmCA,uDAAuD;AACvD,wBAAgB,kBAAkB;;;;;EAQjC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,QAAQ,mWAyJ7B"}
|
package/dist/server/src/app.js
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
import { configManager } from './config/config-manager.js';
|
|
6
6
|
import { setJsonPrettyConfigGetter } from './utils/json-utils.js';
|
|
7
7
|
import { isIpAllowed } from './utils/network-security.js';
|
|
8
|
+
import { logger, LOG_MODULES } from './utils/logger.js';
|
|
8
9
|
// MCP Protocol Routes
|
|
9
10
|
import { mcpGatewayRoutes } from './api/mcp/gateway.js';
|
|
10
11
|
// Web API Routes
|
|
@@ -24,6 +25,17 @@ const __dirname = path.dirname(__filename);
|
|
|
24
25
|
// Connection tracking counters (module-scoped, shared across all requests)
|
|
25
26
|
let currentConnections = 0;
|
|
26
27
|
let currentConcurrentRequests = 0;
|
|
28
|
+
const CONCURRENT_DECREMENTED = Symbol('concurrentDecremented');
|
|
29
|
+
/** Expose connection stats for diagnostic endpoints */
|
|
30
|
+
export function getConnectionStats() {
|
|
31
|
+
const cfg = configManager.getConfig().security;
|
|
32
|
+
return {
|
|
33
|
+
currentConnections,
|
|
34
|
+
currentConcurrentRequests,
|
|
35
|
+
maxConnections: cfg.maxConnections,
|
|
36
|
+
maxConcurrentConnections: cfg.maxConcurrentConnections
|
|
37
|
+
};
|
|
38
|
+
}
|
|
27
39
|
/**
|
|
28
40
|
* Creates and configures a Fastify application instance for the MCP Hub Lite service.
|
|
29
41
|
*
|
|
@@ -69,6 +81,9 @@ export async function buildApp() {
|
|
|
69
81
|
socket.on('close', () => {
|
|
70
82
|
currentConnections--;
|
|
71
83
|
});
|
|
84
|
+
socket.on('error', (err) => {
|
|
85
|
+
logger.debug(`Socket error (will be closed): ${err.message}`, LOG_MODULES.SERVER);
|
|
86
|
+
});
|
|
72
87
|
if (currentConnections > config.security.maxConnections) {
|
|
73
88
|
socket.destroy();
|
|
74
89
|
}
|
|
@@ -95,10 +110,36 @@ export async function buildApp() {
|
|
|
95
110
|
return;
|
|
96
111
|
}
|
|
97
112
|
currentConcurrentRequests++;
|
|
113
|
+
// Safety net: decrement on premature connection close (e.g. SSE timeout).
|
|
114
|
+
// Prevents counter drift for hijacked long-lived connections whose
|
|
115
|
+
// onResponse hook may not fire when the socket is destroyed by timeout.
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
117
|
+
reply.raw[CONCURRENT_DECREMENTED] = false;
|
|
118
|
+
reply.raw.on('close', () => {
|
|
119
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
120
|
+
if (!reply.raw[CONCURRENT_DECREMENTED]) {
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
122
|
+
reply.raw[CONCURRENT_DECREMENTED] = true;
|
|
123
|
+
currentConcurrentRequests--;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
// Warn when approaching the configured limit
|
|
127
|
+
if (currentConcurrentRequests > config.security.maxConcurrentConnections * 0.8) {
|
|
128
|
+
logger.warn(`High concurrent requests: ${currentConcurrentRequests}/${config.security.maxConcurrentConnections}`, LOG_MODULES.SERVER);
|
|
129
|
+
}
|
|
98
130
|
done();
|
|
99
131
|
});
|
|
100
|
-
fastify.addHook('onResponse', (_request,
|
|
101
|
-
|
|
132
|
+
fastify.addHook('onResponse', (_request, reply, done) => {
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
|
+
if (!reply.raw[CONCURRENT_DECREMENTED]) {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
+
reply.raw[CONCURRENT_DECREMENTED] = true;
|
|
137
|
+
currentConcurrentRequests--;
|
|
138
|
+
if (currentConcurrentRequests < 0) {
|
|
139
|
+
logger.warn('currentConcurrentRequests went negative in onResponse, resetting to 0', LOG_MODULES.SERVER);
|
|
140
|
+
currentConcurrentRequests = 0;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
102
143
|
done();
|
|
103
144
|
});
|
|
104
145
|
// Simple CORS for dev
|