@peac/mcp-server 0.16.3 → 0.16.5
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/README.md +1 -1
- package/dist/cli.cjs +50 -11
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +50 -11
- package/dist/cli.mjs.map +1 -1
- package/dist/http-transport.d.ts +7 -1
- package/dist/http-transport.d.ts.map +1 -1
- package/dist/index.cjs +6 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +6 -2
- package/dist/index.mjs.map +1 -1
- package/dist/infra/constants.d.ts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/session-manager.d.ts +2 -0
- package/dist/session-manager.d.ts.map +1 -1
- package/manifest.json +1 -1
- package/package.json +7 -7
- package/server.json +2 -11
- package/smithery.yaml +1 -1
package/README.md
CHANGED
package/dist/cli.cjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
var crypto$1 = require('crypto');
|
|
5
5
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
6
6
|
var http = require('http');
|
|
7
|
+
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
7
8
|
var promises = require('fs/promises');
|
|
8
9
|
var commander = require('commander');
|
|
9
10
|
var zod = require('zod');
|
|
@@ -49,7 +50,7 @@ var SERVER_NAME, SERVER_VERSION, MCP_PROTOCOL_VERSION;
|
|
|
49
50
|
var init_constants = __esm({
|
|
50
51
|
"src/infra/constants.ts"() {
|
|
51
52
|
SERVER_NAME = "peac-mcp-server";
|
|
52
|
-
SERVER_VERSION = "0.16.
|
|
53
|
+
SERVER_VERSION = "0.16.5";
|
|
53
54
|
MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
54
55
|
}
|
|
55
56
|
});
|
|
@@ -114,6 +115,11 @@ var init_session_manager = __esm({
|
|
|
114
115
|
}
|
|
115
116
|
return entry;
|
|
116
117
|
}
|
|
118
|
+
/** Whether an unexpired session exists; unlike getSession(), does not refresh lastSeen. */
|
|
119
|
+
hasSession(sessionId) {
|
|
120
|
+
const entry = this.sessions.get(sessionId);
|
|
121
|
+
return entry !== void 0 && Date.now() - entry.lastSeen <= this.ttlMs;
|
|
122
|
+
}
|
|
117
123
|
/** Terminate and clean up a specific session */
|
|
118
124
|
async terminateSession(sessionId) {
|
|
119
125
|
const entry = this.sessions.get(sessionId);
|
|
@@ -180,8 +186,17 @@ var init_session_manager = __esm({
|
|
|
180
186
|
// src/http-transport.ts
|
|
181
187
|
var http_transport_exports = {};
|
|
182
188
|
__export(http_transport_exports, {
|
|
183
|
-
|
|
189
|
+
MAX_RATE_LIMIT_KEYS: () => MAX_RATE_LIMIT_KEYS,
|
|
190
|
+
createHttpTransport: () => createHttpTransport,
|
|
191
|
+
rateLimitKeyFor: () => rateLimitKeyFor
|
|
184
192
|
});
|
|
193
|
+
function checkProtocolVersion(req) {
|
|
194
|
+
const protocolVersion = req.headers["mcp-protocol-version"];
|
|
195
|
+
if (protocolVersion && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
|
|
196
|
+
return `Unsupported MCP protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`;
|
|
197
|
+
}
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
185
200
|
function isValidSessionId(id) {
|
|
186
201
|
if (id.length === 0 || id.length > MAX_SESSION_ID_LENGTH) return false;
|
|
187
202
|
for (let i = 0; i < id.length; i++) {
|
|
@@ -190,6 +205,9 @@ function isValidSessionId(id) {
|
|
|
190
205
|
}
|
|
191
206
|
return true;
|
|
192
207
|
}
|
|
208
|
+
function rateLimitKeyFor(sessionId, clientIp, isLiveSession) {
|
|
209
|
+
return sessionId !== void 0 && isValidSessionId(sessionId) && isLiveSession(sessionId) ? `session:${sessionId}` : `ip:${clientIp}`;
|
|
210
|
+
}
|
|
193
211
|
function isLoopbackAddr(addr) {
|
|
194
212
|
return addr.startsWith("127.") || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
195
213
|
}
|
|
@@ -244,7 +262,12 @@ async function createHttpTransport(options) {
|
|
|
244
262
|
const now = Date.now();
|
|
245
263
|
let entry = rateLimits.get(key);
|
|
246
264
|
if (!entry || now - entry.windowStart > ONE_MINUTE_MS) {
|
|
265
|
+
if (!entry && rateLimits.size >= MAX_RATE_LIMIT_KEYS) {
|
|
266
|
+
const oldest = rateLimits.keys().next().value;
|
|
267
|
+
if (oldest !== void 0) rateLimits.delete(oldest);
|
|
268
|
+
}
|
|
247
269
|
entry = { count: 0, windowStart: now };
|
|
270
|
+
rateLimits.delete(key);
|
|
248
271
|
rateLimits.set(key, entry);
|
|
249
272
|
}
|
|
250
273
|
entry.count++;
|
|
@@ -423,7 +446,11 @@ async function createHttpTransport(options) {
|
|
|
423
446
|
}
|
|
424
447
|
if (req.method === "POST") {
|
|
425
448
|
const sessionId = req.headers["mcp-session-id"];
|
|
426
|
-
const rateLimitKey =
|
|
449
|
+
const rateLimitKey = rateLimitKeyFor(
|
|
450
|
+
sessionId,
|
|
451
|
+
getClientIp(req),
|
|
452
|
+
(id) => sessionManager.hasSession(id)
|
|
453
|
+
);
|
|
427
454
|
if (!checkRateLimit(rateLimitKey)) {
|
|
428
455
|
res.writeHead(429, { "Content-Type": "application/json", "Retry-After": "60" });
|
|
429
456
|
res.end(JSON.stringify({ error: "Rate limit exceeded" }));
|
|
@@ -440,9 +467,9 @@ async function createHttpTransport(options) {
|
|
|
440
467
|
}
|
|
441
468
|
const isInit = typeof body === "object" && body !== null && "method" in body && body.method === "initialize";
|
|
442
469
|
if (isInit) {
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
-
sendJson(res, 400, { error:
|
|
470
|
+
const versionError2 = checkProtocolVersion(req);
|
|
471
|
+
if (versionError2) {
|
|
472
|
+
sendJson(res, 400, { error: versionError2 });
|
|
446
473
|
return;
|
|
447
474
|
}
|
|
448
475
|
const accept = req.headers.accept;
|
|
@@ -463,6 +490,11 @@ async function createHttpTransport(options) {
|
|
|
463
490
|
await entry2.transport.handleRequest(req, res, body);
|
|
464
491
|
return;
|
|
465
492
|
}
|
|
493
|
+
const versionError = checkProtocolVersion(req);
|
|
494
|
+
if (versionError) {
|
|
495
|
+
sendJson(res, 400, { error: versionError });
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
466
498
|
if (!sessionId) {
|
|
467
499
|
sendJson(res, 400, { error: "Missing Mcp-Session-Id header" });
|
|
468
500
|
return;
|
|
@@ -516,26 +548,27 @@ async function createHttpTransport(options) {
|
|
|
516
548
|
` Sessions: max ${options.maxSessions ?? 100} (${options.maxSessionsPerIp ?? 10}/IP), TTL ${(options.sessionTtlMs ?? 18e5) / 1e3}s
|
|
517
549
|
`
|
|
518
550
|
);
|
|
519
|
-
process.stderr.write(` Rate limit: ${rateLimitRpm} req/min per session
|
|
551
|
+
process.stderr.write(` Rate limit: ${rateLimitRpm} req/min per session or client address
|
|
520
552
|
`);
|
|
521
553
|
process.stderr.write(
|
|
522
554
|
` CORS: ${corsOrigins.size > 0 ? [...corsOrigins].join(", ") : "deny all"}
|
|
523
555
|
`
|
|
524
556
|
);
|
|
525
557
|
process.stderr.write(
|
|
526
|
-
` Mode: unprotected (token validation
|
|
558
|
+
` Mode: unprotected (no token validation; deploy behind an authenticating reverse proxy)
|
|
527
559
|
`
|
|
528
560
|
);
|
|
529
561
|
resolve2({
|
|
530
562
|
cleanup: async () => {
|
|
531
563
|
await sessionManager.cleanup();
|
|
532
564
|
await new Promise((res) => server.close(() => res()));
|
|
533
|
-
}
|
|
565
|
+
},
|
|
566
|
+
rateLimitKeyCount: () => rateLimits.size
|
|
534
567
|
});
|
|
535
568
|
});
|
|
536
569
|
});
|
|
537
570
|
}
|
|
538
|
-
var ONE_MINUTE_MS, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_RATE_LIMIT_RPM, MAX_SESSION_ID_LENGTH;
|
|
571
|
+
var ONE_MINUTE_MS, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_RATE_LIMIT_RPM, MAX_SESSION_ID_LENGTH, MAX_RATE_LIMIT_KEYS, SUPPORTED_PROTOCOL_VERSIONS;
|
|
539
572
|
var init_http_transport = __esm({
|
|
540
573
|
"src/http-transport.ts"() {
|
|
541
574
|
init_session_manager();
|
|
@@ -544,6 +577,8 @@ var init_http_transport = __esm({
|
|
|
544
577
|
DEFAULT_MAX_REQUEST_BYTES = 1048576;
|
|
545
578
|
DEFAULT_RATE_LIMIT_RPM = 100;
|
|
546
579
|
MAX_SESSION_ID_LENGTH = 128;
|
|
580
|
+
MAX_RATE_LIMIT_KEYS = 1e4;
|
|
581
|
+
SUPPORTED_PROTOCOL_VERSIONS = types_js.SUPPORTED_PROTOCOL_VERSIONS;
|
|
547
582
|
}
|
|
548
583
|
});
|
|
549
584
|
|
|
@@ -1990,6 +2025,7 @@ var BUNDLE_TOOL_ANNOTATIONS = {
|
|
|
1990
2025
|
openWorldHint: true
|
|
1991
2026
|
};
|
|
1992
2027
|
var MAX_INPUT_DEPTH = 10;
|
|
2028
|
+
var MAX_TOOL_INPUT_ELEMENTS = 1024;
|
|
1993
2029
|
function errorCallToolResult(meta, code, message) {
|
|
1994
2030
|
const errorDef = kernel.ERRORS[code];
|
|
1995
2031
|
return {
|
|
@@ -2098,7 +2134,10 @@ function createPeacMcpServer(options) {
|
|
|
2098
2134
|
{ name: SERVER_NAME, version },
|
|
2099
2135
|
// listChanged: false -- tool set is static per server instance (determined
|
|
2100
2136
|
// at startup from CLI flags). The server never emits notifications/tools/list_changed.
|
|
2101
|
-
{
|
|
2137
|
+
{
|
|
2138
|
+
capabilities: { tools: { listChanged: false } },
|
|
2139
|
+
maxToolInputElements: MAX_TOOL_INPUT_ELEMENTS
|
|
2140
|
+
}
|
|
2102
2141
|
);
|
|
2103
2142
|
const register = server.registerTool.bind(server);
|
|
2104
2143
|
register(
|