@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/dist/cli.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { randomUUID } from 'crypto';
|
|
3
3
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
4
4
|
import { createServer } from 'http';
|
|
5
|
+
import { SUPPORTED_PROTOCOL_VERSIONS as SUPPORTED_PROTOCOL_VERSIONS$1 } from '@modelcontextprotocol/sdk/types.js';
|
|
5
6
|
import { stat, realpath, readFile, mkdir, writeFile, rm, mkdtemp, rename, lstat } from 'fs/promises';
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import { z } from 'zod';
|
|
@@ -28,7 +29,7 @@ var SERVER_NAME, SERVER_VERSION, MCP_PROTOCOL_VERSION;
|
|
|
28
29
|
var init_constants = __esm({
|
|
29
30
|
"src/infra/constants.ts"() {
|
|
30
31
|
SERVER_NAME = "peac-mcp-server";
|
|
31
|
-
SERVER_VERSION = "0.16.
|
|
32
|
+
SERVER_VERSION = "0.16.5";
|
|
32
33
|
MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
33
34
|
}
|
|
34
35
|
});
|
|
@@ -93,6 +94,11 @@ var init_session_manager = __esm({
|
|
|
93
94
|
}
|
|
94
95
|
return entry;
|
|
95
96
|
}
|
|
97
|
+
/** Whether an unexpired session exists; unlike getSession(), does not refresh lastSeen. */
|
|
98
|
+
hasSession(sessionId) {
|
|
99
|
+
const entry = this.sessions.get(sessionId);
|
|
100
|
+
return entry !== void 0 && Date.now() - entry.lastSeen <= this.ttlMs;
|
|
101
|
+
}
|
|
96
102
|
/** Terminate and clean up a specific session */
|
|
97
103
|
async terminateSession(sessionId) {
|
|
98
104
|
const entry = this.sessions.get(sessionId);
|
|
@@ -159,8 +165,17 @@ var init_session_manager = __esm({
|
|
|
159
165
|
// src/http-transport.ts
|
|
160
166
|
var http_transport_exports = {};
|
|
161
167
|
__export(http_transport_exports, {
|
|
162
|
-
|
|
168
|
+
MAX_RATE_LIMIT_KEYS: () => MAX_RATE_LIMIT_KEYS,
|
|
169
|
+
createHttpTransport: () => createHttpTransport,
|
|
170
|
+
rateLimitKeyFor: () => rateLimitKeyFor
|
|
163
171
|
});
|
|
172
|
+
function checkProtocolVersion(req) {
|
|
173
|
+
const protocolVersion = req.headers["mcp-protocol-version"];
|
|
174
|
+
if (protocolVersion && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
|
|
175
|
+
return `Unsupported MCP protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`;
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
164
179
|
function isValidSessionId(id) {
|
|
165
180
|
if (id.length === 0 || id.length > MAX_SESSION_ID_LENGTH) return false;
|
|
166
181
|
for (let i = 0; i < id.length; i++) {
|
|
@@ -169,6 +184,9 @@ function isValidSessionId(id) {
|
|
|
169
184
|
}
|
|
170
185
|
return true;
|
|
171
186
|
}
|
|
187
|
+
function rateLimitKeyFor(sessionId, clientIp, isLiveSession) {
|
|
188
|
+
return sessionId !== void 0 && isValidSessionId(sessionId) && isLiveSession(sessionId) ? `session:${sessionId}` : `ip:${clientIp}`;
|
|
189
|
+
}
|
|
172
190
|
function isLoopbackAddr(addr) {
|
|
173
191
|
return addr.startsWith("127.") || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
174
192
|
}
|
|
@@ -223,7 +241,12 @@ async function createHttpTransport(options) {
|
|
|
223
241
|
const now = Date.now();
|
|
224
242
|
let entry = rateLimits.get(key);
|
|
225
243
|
if (!entry || now - entry.windowStart > ONE_MINUTE_MS) {
|
|
244
|
+
if (!entry && rateLimits.size >= MAX_RATE_LIMIT_KEYS) {
|
|
245
|
+
const oldest = rateLimits.keys().next().value;
|
|
246
|
+
if (oldest !== void 0) rateLimits.delete(oldest);
|
|
247
|
+
}
|
|
226
248
|
entry = { count: 0, windowStart: now };
|
|
249
|
+
rateLimits.delete(key);
|
|
227
250
|
rateLimits.set(key, entry);
|
|
228
251
|
}
|
|
229
252
|
entry.count++;
|
|
@@ -402,7 +425,11 @@ async function createHttpTransport(options) {
|
|
|
402
425
|
}
|
|
403
426
|
if (req.method === "POST") {
|
|
404
427
|
const sessionId = req.headers["mcp-session-id"];
|
|
405
|
-
const rateLimitKey =
|
|
428
|
+
const rateLimitKey = rateLimitKeyFor(
|
|
429
|
+
sessionId,
|
|
430
|
+
getClientIp(req),
|
|
431
|
+
(id) => sessionManager.hasSession(id)
|
|
432
|
+
);
|
|
406
433
|
if (!checkRateLimit(rateLimitKey)) {
|
|
407
434
|
res.writeHead(429, { "Content-Type": "application/json", "Retry-After": "60" });
|
|
408
435
|
res.end(JSON.stringify({ error: "Rate limit exceeded" }));
|
|
@@ -419,9 +446,9 @@ async function createHttpTransport(options) {
|
|
|
419
446
|
}
|
|
420
447
|
const isInit = typeof body === "object" && body !== null && "method" in body && body.method === "initialize";
|
|
421
448
|
if (isInit) {
|
|
422
|
-
const
|
|
423
|
-
if (
|
|
424
|
-
sendJson(res, 400, { error:
|
|
449
|
+
const versionError2 = checkProtocolVersion(req);
|
|
450
|
+
if (versionError2) {
|
|
451
|
+
sendJson(res, 400, { error: versionError2 });
|
|
425
452
|
return;
|
|
426
453
|
}
|
|
427
454
|
const accept = req.headers.accept;
|
|
@@ -442,6 +469,11 @@ async function createHttpTransport(options) {
|
|
|
442
469
|
await entry2.transport.handleRequest(req, res, body);
|
|
443
470
|
return;
|
|
444
471
|
}
|
|
472
|
+
const versionError = checkProtocolVersion(req);
|
|
473
|
+
if (versionError) {
|
|
474
|
+
sendJson(res, 400, { error: versionError });
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
445
477
|
if (!sessionId) {
|
|
446
478
|
sendJson(res, 400, { error: "Missing Mcp-Session-Id header" });
|
|
447
479
|
return;
|
|
@@ -495,26 +527,27 @@ async function createHttpTransport(options) {
|
|
|
495
527
|
` Sessions: max ${options.maxSessions ?? 100} (${options.maxSessionsPerIp ?? 10}/IP), TTL ${(options.sessionTtlMs ?? 18e5) / 1e3}s
|
|
496
528
|
`
|
|
497
529
|
);
|
|
498
|
-
process.stderr.write(` Rate limit: ${rateLimitRpm} req/min per session
|
|
530
|
+
process.stderr.write(` Rate limit: ${rateLimitRpm} req/min per session or client address
|
|
499
531
|
`);
|
|
500
532
|
process.stderr.write(
|
|
501
533
|
` CORS: ${corsOrigins.size > 0 ? [...corsOrigins].join(", ") : "deny all"}
|
|
502
534
|
`
|
|
503
535
|
);
|
|
504
536
|
process.stderr.write(
|
|
505
|
-
` Mode: unprotected (token validation
|
|
537
|
+
` Mode: unprotected (no token validation; deploy behind an authenticating reverse proxy)
|
|
506
538
|
`
|
|
507
539
|
);
|
|
508
540
|
resolve2({
|
|
509
541
|
cleanup: async () => {
|
|
510
542
|
await sessionManager.cleanup();
|
|
511
543
|
await new Promise((res) => server.close(() => res()));
|
|
512
|
-
}
|
|
544
|
+
},
|
|
545
|
+
rateLimitKeyCount: () => rateLimits.size
|
|
513
546
|
});
|
|
514
547
|
});
|
|
515
548
|
});
|
|
516
549
|
}
|
|
517
|
-
var ONE_MINUTE_MS, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_RATE_LIMIT_RPM, MAX_SESSION_ID_LENGTH;
|
|
550
|
+
var ONE_MINUTE_MS, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_RATE_LIMIT_RPM, MAX_SESSION_ID_LENGTH, MAX_RATE_LIMIT_KEYS, SUPPORTED_PROTOCOL_VERSIONS;
|
|
518
551
|
var init_http_transport = __esm({
|
|
519
552
|
"src/http-transport.ts"() {
|
|
520
553
|
init_session_manager();
|
|
@@ -523,6 +556,8 @@ var init_http_transport = __esm({
|
|
|
523
556
|
DEFAULT_MAX_REQUEST_BYTES = 1048576;
|
|
524
557
|
DEFAULT_RATE_LIMIT_RPM = 100;
|
|
525
558
|
MAX_SESSION_ID_LENGTH = 128;
|
|
559
|
+
MAX_RATE_LIMIT_KEYS = 1e4;
|
|
560
|
+
SUPPORTED_PROTOCOL_VERSIONS = SUPPORTED_PROTOCOL_VERSIONS$1;
|
|
526
561
|
}
|
|
527
562
|
});
|
|
528
563
|
|
|
@@ -1969,6 +2004,7 @@ var BUNDLE_TOOL_ANNOTATIONS = {
|
|
|
1969
2004
|
openWorldHint: true
|
|
1970
2005
|
};
|
|
1971
2006
|
var MAX_INPUT_DEPTH = 10;
|
|
2007
|
+
var MAX_TOOL_INPUT_ELEMENTS = 1024;
|
|
1972
2008
|
function errorCallToolResult(meta, code, message) {
|
|
1973
2009
|
const errorDef = ERRORS[code];
|
|
1974
2010
|
return {
|
|
@@ -2077,7 +2113,10 @@ function createPeacMcpServer(options) {
|
|
|
2077
2113
|
{ name: SERVER_NAME, version },
|
|
2078
2114
|
// listChanged: false -- tool set is static per server instance (determined
|
|
2079
2115
|
// at startup from CLI flags). The server never emits notifications/tools/list_changed.
|
|
2080
|
-
{
|
|
2116
|
+
{
|
|
2117
|
+
capabilities: { tools: { listChanged: false } },
|
|
2118
|
+
maxToolInputElements: MAX_TOOL_INPUT_ELEMENTS
|
|
2119
|
+
}
|
|
2081
2120
|
);
|
|
2082
2121
|
const register = server.registerTool.bind(server);
|
|
2083
2122
|
register(
|