@j0hanz/fetch-url-mcp 1.12.13 → 2.0.1
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/LICENSE +21 -21
- package/README.md +815 -809
- package/dist/assets/logo.svg +53 -53
- package/dist/http/auth.d.ts +7 -3
- package/dist/http/auth.d.ts.map +1 -1
- package/dist/http/auth.js +65 -37
- package/dist/http/helpers.d.ts +21 -0
- package/dist/http/helpers.d.ts.map +1 -0
- package/dist/http/helpers.js +31 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +1 -0
- package/dist/http/native.d.ts +6 -24
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +141 -86
- package/dist/http/rate-limit.d.ts +1 -1
- package/dist/http/rate-limit.d.ts.map +1 -1
- package/dist/http/rate-limit.js +3 -9
- package/dist/index.js +0 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +1 -0
- package/dist/lib/core.d.ts +4 -3
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +4 -1
- package/dist/lib/error/classify.d.ts.map +1 -1
- package/dist/lib/error/classify.js +27 -6
- package/dist/lib/error/payload.d.ts +2 -2
- package/dist/lib/error/payload.d.ts.map +1 -1
- package/dist/lib/error/payload.js +2 -2
- package/dist/lib/mcp-interop.d.ts +9 -108
- package/dist/lib/mcp-interop.d.ts.map +1 -1
- package/dist/lib/mcp-interop.js +39 -240
- package/dist/lib/net/http.d.ts.map +1 -1
- package/dist/lib/net/http.js +4 -17
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +67 -60
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -34
- package/dist/tasks/adapter.d.ts +15 -0
- package/dist/tasks/adapter.d.ts.map +1 -0
- package/dist/tasks/adapter.js +138 -0
- package/dist/tasks/manager.d.ts +14 -82
- package/dist/tasks/manager.d.ts.map +1 -1
- package/dist/tasks/manager.js +48 -607
- package/dist/tasks/store.d.ts +33 -19
- package/dist/tasks/store.d.ts.map +1 -1
- package/dist/tasks/store.js +143 -80
- package/dist/tools/index.d.ts +7 -13
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +153 -58
- package/dist/transform/index.js +1 -1
- package/package.json +110 -108
package/dist/http/native.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
2
|
+
import { isInitializeRequest, ProtocolErrorCode, } from '@modelcontextprotocol/server';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { once } from 'node:events';
|
|
5
5
|
import { readFileSync } from 'node:fs';
|
|
6
6
|
import { createServer, } from 'node:http';
|
|
7
7
|
import { createServer as createHttpsServer, } from 'node:https';
|
|
8
|
+
import { SocketAddress } from 'node:net';
|
|
8
9
|
import { freemem, hostname, totalmem } from 'node:os';
|
|
9
10
|
import { monitorEventLoopDelay, performance } from 'node:perf_hooks';
|
|
10
11
|
import process from 'node:process';
|
|
@@ -13,14 +14,16 @@ import { pipeline } from 'node:stream/promises';
|
|
|
13
14
|
import { config, enableHttpMode, serverVersion } from '../lib/config.js';
|
|
14
15
|
import { composeCloseHandlers, createSessionStore, createSlotTracker, ensureSessionCapacity, logDebug, logError, Loggers, logInfo, logWarn, registerMcpSessionOwnerKey, registerMcpSessionServer, reserveSessionSlot, resolveMcpSessionIdByServer, runWithRequestContext, runWithTraceContext, startSessionCleanupLoop, unregisterMcpSessionServer, unregisterMcpSessionServerByServer, } from '../lib/core.js';
|
|
15
16
|
import { getErrorMessage, toError } from '../lib/error/index.js';
|
|
16
|
-
import { acceptsEventStream, acceptsJsonAndEventStream,
|
|
17
|
+
import { acceptsEventStream, acceptsJsonAndEventStream, isJsonRpcBatchRequest, isMcpRequestBody, } from '../lib/mcp-interop.js';
|
|
17
18
|
import { createDefaultBlockList, normalizeIpForBlockList, } from '../lib/net/index.js';
|
|
18
19
|
import { isObject } from '../lib/utils.js';
|
|
19
20
|
import { createMcpServerForHttpSession } from '../server.js';
|
|
20
21
|
import { buildAuthenticatedOwnerKey } from '../tasks/index.js';
|
|
21
22
|
import { getTransformPoolStats } from '../transform/index.js';
|
|
22
23
|
import { applyInsufficientScopeAuthHeaders, applyUnauthorizedAuthHeaders, assertHttpModeConfiguration, authService, buildAuthFingerprint, buildProtectedResourceMetadataDocument, corsPolicy, ensureMcpProtocolVersion, hostOriginPolicy, isInsufficientScopeError, isOAuthMetadataEnabled, isProtectedResourceMetadataPath, SUPPORTED_MCP_PROTOCOL_VERSIONS, } from './auth.js';
|
|
24
|
+
import { getHeaderValue, sendEmpty, sendError, sendJson, } from './helpers.js';
|
|
23
25
|
import { RateLimiter } from './rate-limit.js';
|
|
26
|
+
export { getHeaderValue, sendEmpty, sendError, sendJson, setNoStoreHeaders, } from './helpers.js';
|
|
24
27
|
const DROP_LOG_INTERVAL_MS = 10_000;
|
|
25
28
|
const MISSING_SESSION_ID_MESSAGE = "We couldn't find a session ID for your request. Please ensure you have an active session.";
|
|
26
29
|
const SESSION_NOT_INITIALIZED_MESSAGE = "Your session hasn't been initialized yet. Please wait a moment and try again.";
|
|
@@ -79,39 +82,17 @@ function drainConnectionsOnShutdown(server) {
|
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
// ---------------------------------------------------------------------------
|
|
82
|
-
// Response helpers
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
function setNoStoreHeaders(res) {
|
|
85
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
86
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
87
|
-
}
|
|
88
|
-
export function sendJson(res, status, body) {
|
|
89
|
-
res.statusCode = status;
|
|
90
|
-
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
91
|
-
setNoStoreHeaders(res);
|
|
92
|
-
res.end(JSON.stringify(body));
|
|
93
|
-
}
|
|
94
|
-
export function sendEmpty(res, status) {
|
|
95
|
-
res.statusCode = status;
|
|
96
|
-
res.setHeader('Content-Length', '0');
|
|
97
|
-
res.end();
|
|
98
|
-
}
|
|
99
|
-
export function sendError(res, code, message, status = 400, id) {
|
|
100
|
-
sendJsonRpcError(res, status, code, message, id ?? null);
|
|
101
|
-
}
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
85
|
// Request helpers
|
|
104
86
|
// ---------------------------------------------------------------------------
|
|
105
|
-
export function getHeaderValue(req, name) {
|
|
106
|
-
const val = req.headers[name];
|
|
107
|
-
if (!val)
|
|
108
|
-
return null;
|
|
109
|
-
return Array.isArray(val) ? (val[0] ?? null) : val;
|
|
110
|
-
}
|
|
111
87
|
export function getMcpSessionId(req) {
|
|
112
88
|
return (getHeaderValue(req, 'mcp-session-id') ??
|
|
113
89
|
getHeaderValue(req, 'x-mcp-session-id'));
|
|
114
90
|
}
|
|
91
|
+
function attachAuthInfoToRequest(req, auth) {
|
|
92
|
+
const requestWithAuth = req;
|
|
93
|
+
requestWithAuth.auth = auth;
|
|
94
|
+
return requestWithAuth;
|
|
95
|
+
}
|
|
115
96
|
const SINGLE_VALUE_HEADER_NAMES = [
|
|
116
97
|
'authorization',
|
|
117
98
|
'x-api-key',
|
|
@@ -197,9 +178,84 @@ function normalizeRemoteAddress(address) {
|
|
|
197
178
|
return normalized.ip;
|
|
198
179
|
return trimmed;
|
|
199
180
|
}
|
|
181
|
+
function trimMatchingQuotes(value) {
|
|
182
|
+
return value.length >= 2 &&
|
|
183
|
+
((value.startsWith('"') && value.endsWith('"')) ||
|
|
184
|
+
(value.startsWith("'") && value.endsWith("'")))
|
|
185
|
+
? value.slice(1, -1)
|
|
186
|
+
: value;
|
|
187
|
+
}
|
|
188
|
+
function parseForwardedAddressToken(token) {
|
|
189
|
+
const trimmed = trimMatchingQuotes(token.trim());
|
|
190
|
+
if (!trimmed)
|
|
191
|
+
return null;
|
|
192
|
+
const lowered = trimmed.toLowerCase();
|
|
193
|
+
if (lowered === 'unknown' || lowered.startsWith('_'))
|
|
194
|
+
return null;
|
|
195
|
+
if (trimmed.startsWith('[')) {
|
|
196
|
+
const endBracket = trimmed.indexOf(']');
|
|
197
|
+
if (endBracket === -1)
|
|
198
|
+
return null;
|
|
199
|
+
return normalizeRemoteAddress(trimmed.slice(1, endBracket));
|
|
200
|
+
}
|
|
201
|
+
const socketAddress = SocketAddress.parse(trimmed);
|
|
202
|
+
if (socketAddress) {
|
|
203
|
+
return normalizeRemoteAddress(socketAddress.address);
|
|
204
|
+
}
|
|
205
|
+
const normalized = normalizeRemoteAddress(trimmed);
|
|
206
|
+
if (normalized)
|
|
207
|
+
return normalized;
|
|
208
|
+
const firstColon = trimmed.indexOf(':');
|
|
209
|
+
const lastColon = trimmed.lastIndexOf(':');
|
|
210
|
+
if (firstColon !== -1 && firstColon === lastColon) {
|
|
211
|
+
return normalizeRemoteAddress(trimmed.slice(0, firstColon));
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
function resolveXForwardedForIp(headerValue) {
|
|
216
|
+
for (const part of headerValue.split(',')) {
|
|
217
|
+
const resolved = parseForwardedAddressToken(part);
|
|
218
|
+
if (resolved)
|
|
219
|
+
return resolved;
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
function resolveForwardedHeaderIp(headerValue) {
|
|
224
|
+
for (const element of headerValue.split(',')) {
|
|
225
|
+
for (const part of element.split(';')) {
|
|
226
|
+
const separatorIndex = part.indexOf('=');
|
|
227
|
+
if (separatorIndex === -1)
|
|
228
|
+
continue;
|
|
229
|
+
const key = part.slice(0, separatorIndex).trim().toLowerCase();
|
|
230
|
+
if (key !== 'for')
|
|
231
|
+
continue;
|
|
232
|
+
const resolved = parseForwardedAddressToken(part.slice(separatorIndex + 1));
|
|
233
|
+
if (resolved)
|
|
234
|
+
return resolved;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
export function resolveClientIp(req) {
|
|
240
|
+
if (config.server.http.trustProxy) {
|
|
241
|
+
const xForwardedFor = getHeaderValue(req, 'x-forwarded-for');
|
|
242
|
+
const forwardedForIp = xForwardedFor
|
|
243
|
+
? resolveXForwardedForIp(xForwardedFor)
|
|
244
|
+
: null;
|
|
245
|
+
if (forwardedForIp)
|
|
246
|
+
return forwardedForIp;
|
|
247
|
+
const forwarded = getHeaderValue(req, 'forwarded');
|
|
248
|
+
const forwardedIp = forwarded ? resolveForwardedHeaderIp(forwarded) : null;
|
|
249
|
+
if (forwardedIp)
|
|
250
|
+
return forwardedIp;
|
|
251
|
+
}
|
|
252
|
+
return normalizeRemoteAddress(req.socket.remoteAddress);
|
|
253
|
+
}
|
|
200
254
|
export function registerInboundBlockList(server) {
|
|
201
|
-
if (!config.server.http.blockPrivateConnections
|
|
255
|
+
if (!config.server.http.blockPrivateConnections ||
|
|
256
|
+
config.server.http.trustProxy) {
|
|
202
257
|
return;
|
|
258
|
+
}
|
|
203
259
|
const blockList = createDefaultBlockList();
|
|
204
260
|
server.on('connection', (socket) => {
|
|
205
261
|
const raw = socket.remoteAddress?.trim();
|
|
@@ -231,7 +287,7 @@ export function buildRequestContext(req, res, signal) {
|
|
|
231
287
|
res,
|
|
232
288
|
url,
|
|
233
289
|
method: req.method,
|
|
234
|
-
ip:
|
|
290
|
+
ip: resolveClientIp(req),
|
|
235
291
|
body: undefined,
|
|
236
292
|
...(signal ? { signal } : {}),
|
|
237
293
|
};
|
|
@@ -255,41 +311,6 @@ export async function closeMcpServerBestEffort(server, context) {
|
|
|
255
311
|
logWarn('MCP server close failed', { context, error }, Loggers.LOG_HTTP);
|
|
256
312
|
}
|
|
257
313
|
}
|
|
258
|
-
export function createTransportAdapter(transportImpl) {
|
|
259
|
-
const noopOnClose = () => { };
|
|
260
|
-
const noopOnError = () => { };
|
|
261
|
-
const noopOnMessage = () => { };
|
|
262
|
-
const baseOnClose = transportImpl.onclose;
|
|
263
|
-
let oncloseHandler = noopOnClose;
|
|
264
|
-
let onerrorHandler = noopOnError;
|
|
265
|
-
let onmessageHandler = noopOnMessage;
|
|
266
|
-
return {
|
|
267
|
-
start: () => transportImpl.start(),
|
|
268
|
-
send: (message, options) => transportImpl.send(message, options),
|
|
269
|
-
close: () => transportImpl.close(),
|
|
270
|
-
get onclose() {
|
|
271
|
-
return oncloseHandler;
|
|
272
|
-
},
|
|
273
|
-
set onclose(handler) {
|
|
274
|
-
oncloseHandler = handler;
|
|
275
|
-
transportImpl.onclose = composeCloseHandlers(baseOnClose, handler);
|
|
276
|
-
},
|
|
277
|
-
get onerror() {
|
|
278
|
-
return onerrorHandler;
|
|
279
|
-
},
|
|
280
|
-
set onerror(handler) {
|
|
281
|
-
onerrorHandler = handler;
|
|
282
|
-
transportImpl.onerror = handler;
|
|
283
|
-
},
|
|
284
|
-
get onmessage() {
|
|
285
|
-
return onmessageHandler;
|
|
286
|
-
},
|
|
287
|
-
set onmessage(handler) {
|
|
288
|
-
onmessageHandler = handler;
|
|
289
|
-
transportImpl.onmessage = handler;
|
|
290
|
-
},
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
314
|
export class JsonBodyError extends Error {
|
|
294
315
|
kind;
|
|
295
316
|
constructor(kind, message) {
|
|
@@ -744,7 +765,7 @@ class McpSessionGateway {
|
|
|
744
765
|
const transport = await this.getOrCreateTransport(ctx, requestId);
|
|
745
766
|
if (!transport)
|
|
746
767
|
return;
|
|
747
|
-
await transport.handleRequest(ctx.req, ctx.res, body);
|
|
768
|
+
await transport.handleRequest(attachAuthInfoToRequest(ctx.req, ctx.auth), ctx.res, body);
|
|
748
769
|
}
|
|
749
770
|
async handleGet(ctx) {
|
|
750
771
|
const sessionState = this.getRequiredAuthenticatedSession(ctx, null, {
|
|
@@ -763,12 +784,12 @@ class McpSessionGateway {
|
|
|
763
784
|
status: 406,
|
|
764
785
|
sessionId,
|
|
765
786
|
});
|
|
766
|
-
sendError(ctx.res,
|
|
787
|
+
sendError(ctx.res, ProtocolErrorCode.InvalidRequest, 'We need you to use "text/event-stream" for this connection.', 406);
|
|
767
788
|
return;
|
|
768
789
|
}
|
|
769
790
|
logDebug('MCP GET received', { sessionId }, Loggers.LOG_HTTP);
|
|
770
791
|
this.store.touch(sessionId);
|
|
771
|
-
await session.transport.handleRequest(ctx.req, ctx.res);
|
|
792
|
+
await session.transport.handleRequest(attachAuthInfoToRequest(ctx.req, ctx.auth), ctx.res);
|
|
772
793
|
}
|
|
773
794
|
async handleDelete(ctx) {
|
|
774
795
|
const sessionState = this.getRequiredAuthenticatedSession(ctx, null, {
|
|
@@ -791,14 +812,47 @@ class McpSessionGateway {
|
|
|
791
812
|
reason: 'accept_missing_json_or_event_stream',
|
|
792
813
|
status: 406,
|
|
793
814
|
});
|
|
794
|
-
sendError(ctx.res,
|
|
815
|
+
sendError(ctx.res, ProtocolErrorCode.InvalidRequest, 'We need the request to accept both "application/json" and "text/event-stream".', 406);
|
|
795
816
|
return null;
|
|
796
817
|
}
|
|
797
818
|
const { body } = ctx;
|
|
798
|
-
if (
|
|
819
|
+
if (body === undefined) {
|
|
820
|
+
logGatewayRejection({
|
|
821
|
+
message: 'Rejected MCP POST request',
|
|
822
|
+
method: ctx.method,
|
|
823
|
+
path: ctx.url.pathname,
|
|
824
|
+
reason: 'missing_json_body',
|
|
825
|
+
status: 400,
|
|
826
|
+
mcpCode: -32600,
|
|
827
|
+
});
|
|
828
|
+
sendError(ctx.res, ProtocolErrorCode.InvalidRequest, 'We need a valid JSON object in the request body for MCP POST requests.', 400);
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
831
|
+
if (isJsonRpcBatchRequest(body)) {
|
|
832
|
+
logGatewayRejection({
|
|
833
|
+
message: 'Rejected MCP POST request',
|
|
834
|
+
method: ctx.method,
|
|
835
|
+
path: ctx.url.pathname,
|
|
836
|
+
reason: 'jsonrpc_batch_unsupported',
|
|
837
|
+
status: 400,
|
|
838
|
+
mcpCode: -32600,
|
|
839
|
+
});
|
|
840
|
+
sendError(ctx.res, ProtocolErrorCode.InvalidRequest, 'JSON-RPC batch requests are not supported on this endpoint.', 400);
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
if (isObject(body)) {
|
|
799
844
|
return body;
|
|
800
845
|
}
|
|
801
|
-
|
|
846
|
+
logGatewayRejection({
|
|
847
|
+
message: 'Rejected MCP POST request',
|
|
848
|
+
method: ctx.method,
|
|
849
|
+
path: ctx.url.pathname,
|
|
850
|
+
reason: 'invalid_json_body',
|
|
851
|
+
status: 400,
|
|
852
|
+
mcpCode: -32600,
|
|
853
|
+
});
|
|
854
|
+
sendError(ctx.res, ProtocolErrorCode.InvalidRequest, 'We need a valid JSON object in the request body for MCP POST requests.', 400);
|
|
855
|
+
return null;
|
|
802
856
|
}
|
|
803
857
|
resolvePostRequestState(ctx, body) {
|
|
804
858
|
const requestId = body.id ?? null;
|
|
@@ -1060,8 +1114,9 @@ class McpSessionGateway {
|
|
|
1060
1114
|
tracker.releaseSlot();
|
|
1061
1115
|
};
|
|
1062
1116
|
try {
|
|
1063
|
-
const
|
|
1064
|
-
await sessionServer.connect(
|
|
1117
|
+
const preConnectOnClose = transportImpl.onclose;
|
|
1118
|
+
await sessionServer.connect(transportImpl);
|
|
1119
|
+
transportImpl.onclose = composeCloseHandlers(preConnectOnClose, transportImpl.onclose);
|
|
1065
1120
|
}
|
|
1066
1121
|
catch (err) {
|
|
1067
1122
|
logWarn('Session transport connect failed', {
|
|
@@ -1107,7 +1162,7 @@ class McpSessionGateway {
|
|
|
1107
1162
|
tracker.releaseSlot();
|
|
1108
1163
|
throw error;
|
|
1109
1164
|
}
|
|
1110
|
-
const transportImpl = new
|
|
1165
|
+
const transportImpl = new NodeStreamableHTTPServerTransport({
|
|
1111
1166
|
sessionIdGenerator: () => newSessionId,
|
|
1112
1167
|
});
|
|
1113
1168
|
const unpublishedSession = {
|
|
@@ -1345,22 +1400,22 @@ class HttpRequestPipeline {
|
|
|
1345
1400
|
const { signal, cleanup } = createRequestAbortSignal(rawReq);
|
|
1346
1401
|
const path = resolveRequestPath(rawReq);
|
|
1347
1402
|
const startTime = performance.now();
|
|
1348
|
-
rawRes.once('finish', () => {
|
|
1349
|
-
logRequestCompletion({
|
|
1350
|
-
path,
|
|
1351
|
-
statusCode: rawRes.statusCode,
|
|
1352
|
-
durationMs: performance.now() - startTime,
|
|
1353
|
-
requestId,
|
|
1354
|
-
...(rawReq.method ? { method: rawReq.method } : {}),
|
|
1355
|
-
...(sessionId ? { sessionId } : {}),
|
|
1356
|
-
});
|
|
1357
|
-
});
|
|
1358
1403
|
try {
|
|
1359
1404
|
await runWithRequestContext({
|
|
1360
1405
|
requestId,
|
|
1361
1406
|
operationId: requestId,
|
|
1362
1407
|
...(sessionId ? { sessionId } : {}),
|
|
1363
1408
|
}, async () => {
|
|
1409
|
+
rawRes.once('finish', () => {
|
|
1410
|
+
logRequestCompletion({
|
|
1411
|
+
path,
|
|
1412
|
+
statusCode: rawRes.statusCode,
|
|
1413
|
+
durationMs: performance.now() - startTime,
|
|
1414
|
+
requestId,
|
|
1415
|
+
...(rawReq.method ? { method: rawReq.method } : {}),
|
|
1416
|
+
...(sessionId ? { sessionId } : {}),
|
|
1417
|
+
});
|
|
1418
|
+
});
|
|
1364
1419
|
if (this.rejectDuplicateHeaders(rawReq, rawRes))
|
|
1365
1420
|
return;
|
|
1366
1421
|
const ctx = this.buildContext(rawReq, rawRes, signal);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/http/rate-limit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/http/rate-limit.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,cAAc,EAAY,MAAM,cAAc,CAAC;AAY7D,UAAU,eAAe;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;gBAEpB,OAAO,EAAE,eAAe;IAIrD,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,WAAW;IAQnB,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO;IAyCnC,IAAI,IAAI,IAAI;CAGb"}
|
package/dist/http/rate-limit.js
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
2
2
|
import { Loggers, logWarn } from '../lib/core.js';
|
|
3
3
|
import { isAbortError } from '../lib/error/index.js';
|
|
4
4
|
import { sendJsonRpcError } from '../lib/mcp-interop.js';
|
|
5
5
|
import { startAbortableIntervalLoop } from '../lib/utils.js';
|
|
6
|
-
|
|
7
|
-
res.statusCode = status;
|
|
8
|
-
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
9
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
10
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
11
|
-
res.end(JSON.stringify(body));
|
|
12
|
-
}
|
|
6
|
+
import { sendJson } from './helpers.js';
|
|
13
7
|
function isMcpEndpoint(pathname) {
|
|
14
8
|
return pathname === '/mcp' || pathname === '/mcp/';
|
|
15
9
|
}
|
|
@@ -83,7 +77,7 @@ export class RateLimiter {
|
|
|
83
77
|
const retryAfter = Math.max(1, Math.ceil((entry.resetTime - now) / 1000));
|
|
84
78
|
ctx.res.setHeader('Retry-After', String(retryAfter));
|
|
85
79
|
if (isMcpEndpoint(ctx.url.pathname)) {
|
|
86
|
-
sendJsonRpcError(ctx.res, 429,
|
|
80
|
+
sendJsonRpcError(ctx.res, 429, ProtocolErrorCode.InvalidRequest, 'Rate limit exceeded', null, { retryAfter });
|
|
87
81
|
}
|
|
88
82
|
else {
|
|
89
83
|
sendJson(ctx.res, 429, { error: 'Rate limit exceeded', retryAfter });
|
package/dist/index.js
CHANGED
|
File without changes
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ interface AppServerHttpConfig {
|
|
|
40
40
|
keepAliveTimeoutBufferMs: number | undefined;
|
|
41
41
|
maxHeadersCount: number | undefined;
|
|
42
42
|
maxConnections: number;
|
|
43
|
+
trustProxy: boolean;
|
|
43
44
|
blockPrivateConnections: boolean;
|
|
44
45
|
shutdownCloseIdleConnections: boolean;
|
|
45
46
|
shutdownCloseAllConnections: boolean;
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AA4CA,eAAO,MAAM,aAAa,EAAE,MAA2C,CAAC;AAIxE,MAAM,MAAM,QAAQ,GAChB,OAAO,GACP,MAAM,GACN,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,CAAC;AAkCf,KAAK,mBAAmB,GAAG,SAAS,GAAG,SAAS,CAAC;AACjD,KAAK,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAqQnC,UAAU,oBAAoB;IAC5B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAyCD,UAAU,UAAU;IAClB,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,GAAG,GAAG,SAAS,CAAC;IAC3B,gBAAgB,EAAE,GAAG,GAAG,SAAS,CAAC;IAClC,QAAQ,EAAE,GAAG,GAAG,SAAS,CAAC;IAC1B,aAAa,EAAE,GAAG,GAAG,SAAS,CAAC;IAC/B,eAAe,EAAE,GAAG,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,GAAG,GAAG,SAAS,CAAC;IAClC,aAAa,EAAE,GAAG,GAAG,SAAS,CAAC;IAC/B,WAAW,EAAE,GAAG,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,UAAU,WAAW;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAuGD,UAAU,YAAY;IACpB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAQD,UAAU,mBAAmB;IAC3B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,OAAO,CAAC;IACjC,4BAA4B,EAAE,OAAO,CAAC;IACtC,2BAA2B,EAAE,OAAO,CAAC;CACtC;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,mBAAmB,CAAC;CAC3B;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.js
CHANGED
|
@@ -390,6 +390,7 @@ function buildServerConfig() {
|
|
|
390
390
|
min: 0,
|
|
391
391
|
envName: 'SERVER_MAX_CONNECTIONS',
|
|
392
392
|
}),
|
|
393
|
+
trustProxy: EnvParser.boolean(env['SERVER_TRUST_PROXY'], false, 'SERVER_TRUST_PROXY'),
|
|
393
394
|
blockPrivateConnections: EnvParser.boolean(env['SERVER_BLOCK_PRIVATE_CONNECTIONS'], false, 'SERVER_BLOCK_PRIVATE_CONNECTIONS'),
|
|
394
395
|
shutdownCloseIdleConnections: true,
|
|
395
396
|
shutdownCloseAllConnections: false,
|
package/dist/lib/core.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import type { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
2
|
+
import { type McpServer } from '@modelcontextprotocol/server';
|
|
3
3
|
type LogMetadata = Record<string, unknown>;
|
|
4
4
|
export interface TraceContext {
|
|
5
5
|
readonly traceparent?: string;
|
|
@@ -21,6 +21,7 @@ export declare function unregisterMcpSessionServer(sessionId: string): void;
|
|
|
21
21
|
export declare function unregisterMcpSessionServerByServer(server: McpServer): void;
|
|
22
22
|
export declare function resolveMcpSessionOwnerKey(sessionId: string): string | undefined;
|
|
23
23
|
export declare function resolveMcpSessionIdByServer(server: McpServer): string | undefined;
|
|
24
|
+
export declare function resolveMcpSessionServer(sessionId: string): McpServer | undefined;
|
|
24
25
|
export declare function runWithRequestContext<T>(context: RequestContext, fn: () => T): T;
|
|
25
26
|
export declare function extractTraceContext(meta: unknown): TraceContext | undefined;
|
|
26
27
|
export declare function runWithTraceContext<T>(meta: unknown, fn: () => T): T;
|
|
@@ -56,7 +57,7 @@ export declare const Loggers: {
|
|
|
56
57
|
};
|
|
57
58
|
export interface SessionEntry {
|
|
58
59
|
readonly server: McpServer;
|
|
59
|
-
readonly transport:
|
|
60
|
+
readonly transport: NodeStreamableHTTPServerTransport;
|
|
60
61
|
createdAt: number;
|
|
61
62
|
lastSeen: number;
|
|
62
63
|
protocolInitialized: boolean;
|
package/dist/lib/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/lib/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/lib/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AACpF,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAoC9D,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC3C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AACD,UAAU,cAAc;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AA4CD,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAKpD;AACD,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,SAAS,GAChB,IAAI,CAGN;AACD,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,IAAI,CAGN;AACD,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAGlE;AACD,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAK1E;AACD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAEpB;AACD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,SAAS,GAChB,MAAM,GAAG,SAAS,CAEpB;AACD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAChB,SAAS,GAAG,SAAS,CAEvB;AACD,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,cAAc,EACvB,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAEH;AAMD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAuB3E;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAcpE;AAKD,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAGjD;AACD,wBAAgB,YAAY,IAAI,MAAM,GAAG,SAAS,CAEjD;AACD,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAEnD;AACD,wBAAgB,eAAe,IAAI,YAAY,GAAG,SAAS,CAY1D;AAmfD,wBAAgB,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,WAAW,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AACD,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,WAAW,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AACD,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,WAAW,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AACD,wBAAgB,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,WAAW,EAClB,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AAcD,wBAAgB,QAAQ,CACtB,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,KAAK,GAAG,WAAW,EAC3B,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAIN;AACD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAUnE;AACD,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQhD;AA8KD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,YAAY,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IACR,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACjE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GACA,eAAe,CAQjB;AACD;;GAEG;AACH,eAAO,MAAM,OAAO;;;;;;;;;;;CAWV,CAAC;AAMX,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,iCAAiC,CAAC;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,yBAAyB,EAAE,MAAM,CAAC;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC;IACrD,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,GAAG,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACtD,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,GAAG,SAAS,CAAC;IACxD,IAAI,EAAE,MAAM,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,KAAK,EAAE,MAAM,YAAY,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,YAAY,CAAA;KAAE,EAAE,CAAC;IAC1D,WAAW,EAAE,MAAM,YAAY,GAAG,SAAS,CAAC;CAC7C;AAED,UAAU,WAAW;IACnB,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,OAAO,CAAC;CACvC;AAMD,KAAK,YAAY,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;AAE7C,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,YAAY,GACnB,YAAY,CAWd;AA0FD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAGrE;AAMD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,WAAW,CAiBlE;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAMT;AAED,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,WAAW,EACX,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,YAAY,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;CAC/C,GAAG,OAAO,CAUV"}
|
package/dist/lib/core.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {} from '@modelcontextprotocol/
|
|
1
|
+
import {} from '@modelcontextprotocol/server';
|
|
2
2
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import process from 'node:process';
|
|
@@ -80,6 +80,9 @@ export function resolveMcpSessionOwnerKey(sessionId) {
|
|
|
80
80
|
export function resolveMcpSessionIdByServer(server) {
|
|
81
81
|
return findSessionIdByServer(server);
|
|
82
82
|
}
|
|
83
|
+
export function resolveMcpSessionServer(sessionId) {
|
|
84
|
+
return sessionServers.get(sessionId);
|
|
85
|
+
}
|
|
83
86
|
export function runWithRequestContext(context, fn) {
|
|
84
87
|
return requestContext.run(context, fn);
|
|
85
88
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/lib/error/classify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/lib/error/classify.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,gBAAgB,EAErB,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAsLtB,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,MAAM,EACX,eAAe,SAAqB,GACnC,iBAAiB,CAInB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,gBAAgB,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,iBAAiB,CAuCnB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolError, ProtocolErrorCode, SdkError, SdkErrorCode, } from '@modelcontextprotocol/server';
|
|
2
2
|
import { logError, logWarn } from '../core.js';
|
|
3
3
|
import { FetchError, isAbortError, isSystemError } from './classes.js';
|
|
4
4
|
import { ErrorCategory, SystemErrors } from './codes.js';
|
|
5
|
-
import { createToolErrorResponse, sanitizeToolErrorDetails,
|
|
5
|
+
import { createToolErrorResponse, sanitizeToolErrorDetails, stripProtocolErrorPrefix, } from './payload.js';
|
|
6
6
|
function toToolErrorResponse(payload) {
|
|
7
7
|
return createToolErrorResponse(payload.error, payload.url, payload);
|
|
8
8
|
}
|
|
@@ -111,7 +111,7 @@ function mapGenericToolError(error, url, fallbackMessage) {
|
|
|
111
111
|
}
|
|
112
112
|
function mapMcpToolError(error, url) {
|
|
113
113
|
return {
|
|
114
|
-
error:
|
|
114
|
+
error: stripProtocolErrorPrefix(error.message),
|
|
115
115
|
url,
|
|
116
116
|
category: ErrorCategory.MCP_ERROR,
|
|
117
117
|
code: error.code,
|
|
@@ -119,21 +119,42 @@ function mapMcpToolError(error, url) {
|
|
|
119
119
|
...(error.data !== undefined ? { data: error.data } : {}),
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
|
+
function resolveSdkErrorCategory(code) {
|
|
123
|
+
switch (code) {
|
|
124
|
+
case SdkErrorCode.ConnectionClosed:
|
|
125
|
+
return ErrorCategory.UPSTREAM_ABORTED;
|
|
126
|
+
case SdkErrorCode.RequestTimeout:
|
|
127
|
+
return ErrorCategory.UPSTREAM_TIMEOUT;
|
|
128
|
+
case SdkErrorCode.SendFailed:
|
|
129
|
+
return ErrorCategory.FETCH_ERROR;
|
|
130
|
+
default:
|
|
131
|
+
return ErrorCategory.MCP_ERROR;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
122
134
|
function resolveToolErrorPayload(error, url, fallbackMessage) {
|
|
123
135
|
if (error instanceof FetchError) {
|
|
124
136
|
return mapFetchToolError(error, url);
|
|
125
137
|
}
|
|
126
|
-
if (error instanceof
|
|
138
|
+
if (error instanceof ProtocolError) {
|
|
127
139
|
return mapMcpToolError(error, url);
|
|
128
140
|
}
|
|
141
|
+
if (error instanceof SdkError) {
|
|
142
|
+
return {
|
|
143
|
+
error: error.message,
|
|
144
|
+
url,
|
|
145
|
+
category: resolveSdkErrorCategory(error.code),
|
|
146
|
+
code: error.code,
|
|
147
|
+
...(error.data !== undefined ? { data: error.data } : {}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
129
150
|
return mapGenericToolError(error, url, fallbackMessage);
|
|
130
151
|
}
|
|
131
152
|
export function handleToolError(error, url, fallbackMessage = 'Operation failed') {
|
|
132
153
|
return toToolErrorResponse(resolveToolErrorPayload(error, url, fallbackMessage));
|
|
133
154
|
}
|
|
134
155
|
export function classifyAndLogToolError(error, meta, loggerName, toolName, fallbackMessage) {
|
|
135
|
-
if (error instanceof
|
|
136
|
-
if (error.code ===
|
|
156
|
+
if (error instanceof ProtocolError) {
|
|
157
|
+
if (error.code === ProtocolErrorCode.MethodNotFound) {
|
|
137
158
|
logError(`${toolName} tool protocol error`, { url: meta.url, durationMs: meta.durationMs, error }, loggerName);
|
|
138
159
|
throw error;
|
|
139
160
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CallToolResult } from '@modelcontextprotocol/
|
|
1
|
+
import { type CallToolResult } from '@modelcontextprotocol/server';
|
|
2
2
|
export type ToolErrorResponse = CallToolResult & {
|
|
3
3
|
isError: true;
|
|
4
4
|
};
|
|
@@ -29,5 +29,5 @@ export declare function createToolErrorResponse(message: string, url: string, ex
|
|
|
29
29
|
export declare function createToolErrorPayload(message: string, url: string, extra?: ToolErrorExtra): ToolErrorPayload;
|
|
30
30
|
export declare function tryReadToolErrorPayload(value: unknown): ToolErrorPayload | undefined;
|
|
31
31
|
export declare function tryReadToolErrorMessage(value: unknown): string | undefined;
|
|
32
|
-
export declare function
|
|
32
|
+
export declare function stripProtocolErrorPrefix(message: string): string;
|
|
33
33
|
//# sourceMappingURL=payload.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/lib/error/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/lib/error/payload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAOnE,MAAM,MAAM,iBAAiB,GAAG,cAAc,GAAG;IAC/C,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAmBD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACzC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAqBrC;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,cAAc,GACrB,iBAAiB,CAOnB;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,cAAc,GACrB,gBAAgB,CAgBlB;AAiBD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb,gBAAgB,GAAG,SAAS,CA2B9B;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAE1E;AAID,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhE"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {} from '@modelcontextprotocol/
|
|
1
|
+
import {} from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { isObject } from '../utils.js';
|
|
4
4
|
import { SystemErrors } from './codes.js';
|
|
@@ -103,6 +103,6 @@ export function tryReadToolErrorMessage(value) {
|
|
|
103
103
|
return tryReadToolErrorPayload(value)?.error;
|
|
104
104
|
}
|
|
105
105
|
const mcpErrorPrefixPattern = /^MCP error -?\d+:\s*/;
|
|
106
|
-
export function
|
|
106
|
+
export function stripProtocolErrorPrefix(message) {
|
|
107
107
|
return message.replace(mcpErrorPrefixPattern, '');
|
|
108
108
|
}
|