@j0hanz/fetch-url-mcp 1.2.0 → 1.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 (184) hide show
  1. package/dist/cache.d.ts +9 -3
  2. package/dist/cache.d.ts.map +1 -0
  3. package/dist/cache.js +44 -110
  4. package/dist/cache.js.map +1 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +9 -4
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config.d.ts +2 -3
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +18 -25
  12. package/dist/config.js.map +1 -0
  13. package/dist/crypto.d.ts +1 -0
  14. package/dist/crypto.d.ts.map +1 -0
  15. package/dist/crypto.js +1 -0
  16. package/dist/crypto.js.map +1 -0
  17. package/dist/dom-noise-removal.d.ts +2 -1
  18. package/dist/dom-noise-removal.d.ts.map +1 -0
  19. package/dist/dom-noise-removal.js +8 -4
  20. package/dist/dom-noise-removal.js.map +1 -0
  21. package/dist/download.d.ts +4 -0
  22. package/dist/download.d.ts.map +1 -0
  23. package/dist/download.js +106 -0
  24. package/dist/download.js.map +1 -0
  25. package/dist/errors.d.ts +1 -0
  26. package/dist/errors.d.ts.map +1 -0
  27. package/dist/errors.js +1 -0
  28. package/dist/errors.js.map +1 -0
  29. package/dist/examples/mcp-fetch-url-client.js +19 -3
  30. package/dist/examples/mcp-fetch-url-client.js.map +1 -1
  31. package/dist/fetch-content.d.ts +1 -0
  32. package/dist/fetch-content.d.ts.map +1 -0
  33. package/dist/fetch-content.js +14 -14
  34. package/dist/fetch-content.js.map +1 -0
  35. package/dist/fetch-stream.d.ts +1 -0
  36. package/dist/fetch-stream.d.ts.map +1 -0
  37. package/dist/fetch-stream.js +6 -3
  38. package/dist/fetch-stream.js.map +1 -0
  39. package/dist/fetch.d.ts +1 -0
  40. package/dist/fetch.d.ts.map +1 -0
  41. package/dist/fetch.js +120 -51
  42. package/dist/fetch.js.map +1 -0
  43. package/dist/host-normalization.d.ts +1 -0
  44. package/dist/host-normalization.d.ts.map +1 -0
  45. package/dist/host-normalization.js +19 -6
  46. package/dist/host-normalization.js.map +1 -0
  47. package/dist/http/auth.d.ts +35 -0
  48. package/dist/http/auth.d.ts.map +1 -0
  49. package/dist/http/auth.js +283 -0
  50. package/dist/http/auth.js.map +1 -0
  51. package/dist/http/health.d.ts +7 -0
  52. package/dist/http/health.d.ts.map +1 -0
  53. package/dist/http/health.js +166 -0
  54. package/dist/http/health.js.map +1 -0
  55. package/dist/http/helpers.d.ts +58 -0
  56. package/dist/http/helpers.d.ts.map +1 -0
  57. package/dist/http/helpers.js +372 -0
  58. package/dist/http/helpers.js.map +1 -0
  59. package/dist/{http-native.d.ts → http/native.d.ts} +1 -0
  60. package/dist/http/native.d.ts.map +1 -0
  61. package/dist/http/native.js +529 -0
  62. package/dist/http/native.js.map +1 -0
  63. package/dist/http/rate-limit.d.ts +13 -0
  64. package/dist/http/rate-limit.d.ts.map +1 -0
  65. package/dist/http/rate-limit.js +81 -0
  66. package/dist/http/rate-limit.js.map +1 -0
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +2 -1
  70. package/dist/index.js.map +1 -0
  71. package/dist/instructions.d.ts +2 -0
  72. package/dist/instructions.d.ts.map +1 -0
  73. package/dist/instructions.js +108 -0
  74. package/dist/instructions.js.map +1 -0
  75. package/dist/ip-blocklist.d.ts +1 -0
  76. package/dist/ip-blocklist.d.ts.map +1 -0
  77. package/dist/ip-blocklist.js +2 -0
  78. package/dist/ip-blocklist.js.map +1 -0
  79. package/dist/json.d.ts +2 -1
  80. package/dist/json.d.ts.map +1 -0
  81. package/dist/json.js +19 -6
  82. package/dist/json.js.map +1 -0
  83. package/dist/language-detection.d.ts +1 -0
  84. package/dist/language-detection.d.ts.map +1 -0
  85. package/dist/language-detection.js +1 -0
  86. package/dist/language-detection.js.map +1 -0
  87. package/dist/markdown-cleanup.d.ts +2 -1
  88. package/dist/markdown-cleanup.d.ts.map +1 -0
  89. package/dist/markdown-cleanup.js +51 -52
  90. package/dist/markdown-cleanup.js.map +1 -0
  91. package/dist/mcp-validator.d.ts +1 -0
  92. package/dist/mcp-validator.d.ts.map +1 -0
  93. package/dist/mcp-validator.js +16 -8
  94. package/dist/mcp-validator.js.map +1 -0
  95. package/dist/mcp.d.ts +2 -2
  96. package/dist/mcp.d.ts.map +1 -0
  97. package/dist/mcp.js +17 -333
  98. package/dist/mcp.js.map +1 -0
  99. package/dist/observability.d.ts +2 -0
  100. package/dist/observability.d.ts.map +1 -0
  101. package/dist/observability.js +30 -5
  102. package/dist/observability.js.map +1 -0
  103. package/dist/prompts.d.ts +1 -0
  104. package/dist/prompts.d.ts.map +1 -0
  105. package/dist/prompts.js +15 -3
  106. package/dist/prompts.js.map +1 -0
  107. package/dist/resources.d.ts +1 -0
  108. package/dist/resources.d.ts.map +1 -0
  109. package/dist/resources.js +30 -23
  110. package/dist/resources.js.map +1 -0
  111. package/dist/server-tuning.d.ts +1 -0
  112. package/dist/server-tuning.d.ts.map +1 -0
  113. package/dist/server-tuning.js +11 -15
  114. package/dist/server-tuning.js.map +1 -0
  115. package/dist/server.d.ts +1 -0
  116. package/dist/server.d.ts.map +1 -0
  117. package/dist/server.js +23 -23
  118. package/dist/server.js.map +1 -0
  119. package/dist/session.d.ts +1 -0
  120. package/dist/session.d.ts.map +1 -0
  121. package/dist/session.js +55 -28
  122. package/dist/session.js.map +1 -0
  123. package/dist/tasks/execution.d.ts +42 -0
  124. package/dist/tasks/execution.d.ts.map +1 -0
  125. package/dist/tasks/execution.js +232 -0
  126. package/dist/tasks/execution.js.map +1 -0
  127. package/dist/{tasks.d.ts → tasks/manager.d.ts} +6 -0
  128. package/dist/tasks/manager.d.ts.map +1 -0
  129. package/dist/{tasks.js → tasks/manager.js} +86 -37
  130. package/dist/tasks/manager.js.map +1 -0
  131. package/dist/tasks/owner.d.ts +33 -0
  132. package/dist/tasks/owner.d.ts.map +1 -0
  133. package/dist/tasks/owner.js +99 -0
  134. package/dist/tasks/owner.js.map +1 -0
  135. package/dist/timer-utils.d.ts +1 -0
  136. package/dist/timer-utils.d.ts.map +1 -0
  137. package/dist/timer-utils.js +12 -5
  138. package/dist/timer-utils.js.map +1 -0
  139. package/dist/tool-errors.d.ts +12 -0
  140. package/dist/tool-errors.d.ts.map +1 -0
  141. package/dist/tool-errors.js +52 -0
  142. package/dist/tool-errors.js.map +1 -0
  143. package/dist/tool-pipeline.d.ts +72 -0
  144. package/dist/tool-pipeline.d.ts.map +1 -0
  145. package/dist/tool-pipeline.js +407 -0
  146. package/dist/tool-pipeline.js.map +1 -0
  147. package/dist/tool-progress.d.ts +32 -0
  148. package/dist/tool-progress.d.ts.map +1 -0
  149. package/dist/tool-progress.js +123 -0
  150. package/dist/tool-progress.js.map +1 -0
  151. package/dist/tools.d.ts +35 -111
  152. package/dist/tools.d.ts.map +1 -0
  153. package/dist/tools.js +93 -566
  154. package/dist/tools.js.map +1 -0
  155. package/dist/{transform.d.ts → transform/transform.d.ts} +2 -1
  156. package/dist/transform/transform.d.ts.map +1 -0
  157. package/dist/{transform.js → transform/transform.js} +73 -769
  158. package/dist/transform/transform.js.map +1 -0
  159. package/dist/{transform-types.d.ts → transform/types.d.ts} +1 -0
  160. package/dist/transform/types.d.ts.map +1 -0
  161. package/dist/{transform-types.js → transform/types.js} +1 -0
  162. package/dist/transform/types.js.map +1 -0
  163. package/dist/transform/worker-pool.d.ts +93 -0
  164. package/dist/transform/worker-pool.d.ts.map +1 -0
  165. package/dist/transform/worker-pool.js +759 -0
  166. package/dist/transform/worker-pool.js.map +1 -0
  167. package/dist/transform/workers/transform-child.d.ts +2 -0
  168. package/dist/transform/workers/transform-child.d.ts.map +1 -0
  169. package/dist/{workers → transform/workers}/transform-child.js +3 -1
  170. package/dist/transform/workers/transform-child.js.map +1 -0
  171. package/dist/transform/workers/transform-worker.d.ts +2 -0
  172. package/dist/transform/workers/transform-worker.d.ts.map +1 -0
  173. package/dist/{workers → transform/workers}/transform-worker.js +2 -1
  174. package/dist/transform/workers/transform-worker.js.map +1 -0
  175. package/dist/type-guards.d.ts +1 -0
  176. package/dist/type-guards.d.ts.map +1 -0
  177. package/dist/type-guards.js +1 -0
  178. package/dist/type-guards.js.map +1 -0
  179. package/package.json +6 -7
  180. package/dist/AGENTS.md +0 -152
  181. package/dist/http-native.js +0 -1320
  182. package/dist/instructions.md +0 -113
  183. package/dist/workers/transform-child.d.ts +0 -1
  184. package/dist/workers/transform-worker.d.ts +0 -1
@@ -0,0 +1,529 @@
1
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
2
+ import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { readFileSync } from 'node:fs';
5
+ import { createServer, } from 'node:http';
6
+ import { createServer as createHttpsServer, } from 'node:https';
7
+ import { hostname } from 'node:os';
8
+ import process from 'node:process';
9
+ import { config, enableHttpMode } from '../config.js';
10
+ import { handleDownload } from '../download.js';
11
+ import { acceptsEventStream, acceptsJsonAndEventStream, isJsonRpcBatchRequest, isMcpRequestBody, } from '../mcp-validator.js';
12
+ import { cancelTasksForOwner } from '../mcp.js';
13
+ import { logError, logInfo, registerMcpSessionServer, resolveMcpSessionIdByServer, runWithRequestContext, unregisterMcpSessionServer, unregisterMcpSessionServerByServer, } from '../observability.js';
14
+ import { applyHttpServerTuning, drainConnectionsOnShutdown, } from '../server-tuning.js';
15
+ import { createMcpServerForHttpSession } from '../server.js';
16
+ import { composeCloseHandlers, createSessionStore, createSlotTracker, ensureSessionCapacity, reserveSessionSlot, startSessionCleanupLoop, } from '../session.js';
17
+ import { assertHttpModeConfiguration, authService, buildAuthFingerprint, corsPolicy, ensureMcpProtocolVersion, hostOriginPolicy, } from './auth.js';
18
+ import { disableEventLoopMonitoring, resetEventLoopMonitoring, sendHealthRouteResponse, shouldHandleHealthRoute, } from './health.js';
19
+ import { buildRequestContext, closeMcpServerBestEffort, closeTransportBestEffort, createRequestAbortSignal, createTransportAdapter, DEFAULT_BODY_LIMIT_BYTES, drainRequest, findDuplicateSingleValueHeader, getHeaderValue, getMcpSessionId, jsonBodyReader, registerInboundBlockList, sendError, sendJson, sendText, } from './helpers.js';
20
+ import { createRateLimitManagerImpl, } from './rate-limit.js';
21
+ // ---------------------------------------------------------------------------
22
+ // MCP session gateway
23
+ // ---------------------------------------------------------------------------
24
+ class McpSessionGateway {
25
+ store;
26
+ createSessionServer;
27
+ constructor(store, createSessionServer) {
28
+ this.store = store;
29
+ this.createSessionServer = createSessionServer;
30
+ }
31
+ async handlePost(ctx) {
32
+ if (!ensureMcpProtocolVersion(ctx.req, ctx.res))
33
+ return;
34
+ if (!acceptsJsonAndEventStream(getHeaderValue(ctx.req, 'accept'))) {
35
+ sendJson(ctx.res, 400, {
36
+ error: 'Accept header must include application/json and text/event-stream',
37
+ });
38
+ return;
39
+ }
40
+ const { body } = ctx;
41
+ if (isJsonRpcBatchRequest(body)) {
42
+ sendError(ctx.res, -32600, 'Batch requests not supported');
43
+ return;
44
+ }
45
+ if (!isMcpRequestBody(body)) {
46
+ sendError(ctx.res, -32600, 'Invalid request body');
47
+ return;
48
+ }
49
+ const requestId = body.id ?? null;
50
+ logInfo('[MCP POST]', {
51
+ method: body.method,
52
+ id: body.id,
53
+ sessionId: getMcpSessionId(ctx.req),
54
+ });
55
+ const transport = await this.getOrCreateTransport(ctx, requestId);
56
+ if (!transport)
57
+ return;
58
+ await transport.handleRequest(ctx.req, ctx.res, body);
59
+ }
60
+ async handleGet(ctx) {
61
+ if (!ensureMcpProtocolVersion(ctx.req, ctx.res))
62
+ return;
63
+ const sessionId = getMcpSessionId(ctx.req);
64
+ if (!sessionId) {
65
+ sendError(ctx.res, -32600, 'Missing session ID');
66
+ return;
67
+ }
68
+ const session = this.store.get(sessionId);
69
+ if (!session) {
70
+ sendError(ctx.res, -32600, 'Session not found', 404);
71
+ return;
72
+ }
73
+ const acceptHeader = getHeaderValue(ctx.req, 'accept');
74
+ if (!acceptsEventStream(acceptHeader)) {
75
+ sendJson(ctx.res, 405, { error: 'Method Not Allowed' });
76
+ return;
77
+ }
78
+ this.store.touch(sessionId);
79
+ await session.transport.handleRequest(ctx.req, ctx.res);
80
+ }
81
+ async handleDelete(ctx) {
82
+ if (!ensureMcpProtocolVersion(ctx.req, ctx.res))
83
+ return;
84
+ const sessionId = getMcpSessionId(ctx.req);
85
+ if (!sessionId) {
86
+ sendError(ctx.res, -32600, 'Missing session ID');
87
+ return;
88
+ }
89
+ const session = this.store.get(sessionId);
90
+ if (session) {
91
+ await session.transport.close();
92
+ this.cleanupSessionRecord(sessionId, 'session-delete');
93
+ }
94
+ sendText(ctx.res, 200, 'Session closed');
95
+ }
96
+ async getOrCreateTransport(ctx, requestId) {
97
+ const sessionId = getMcpSessionId(ctx.req);
98
+ if (sessionId) {
99
+ const fingerprint = buildAuthFingerprint(ctx.auth);
100
+ return this.getExistingTransport(sessionId, fingerprint, ctx.res, requestId);
101
+ }
102
+ if (!isInitializeRequest(ctx.body)) {
103
+ sendError(ctx.res, -32600, 'Missing session ID', 400, requestId);
104
+ return null;
105
+ }
106
+ return this.createNewSession(ctx, requestId);
107
+ }
108
+ getExistingTransport(sessionId, authFingerprint, res, requestId) {
109
+ const session = this.store.get(sessionId);
110
+ if (!session) {
111
+ sendError(res, -32600, 'Session not found', 404, requestId);
112
+ return null;
113
+ }
114
+ if (!authFingerprint || session.authFingerprint !== authFingerprint) {
115
+ sendError(res, -32600, 'Session not found', 404, requestId);
116
+ return null;
117
+ }
118
+ this.store.touch(sessionId);
119
+ return session.transport;
120
+ }
121
+ async createNewSession(ctx, requestId) {
122
+ const authFingerprint = buildAuthFingerprint(ctx.auth);
123
+ if (!authFingerprint) {
124
+ sendError(ctx.res, -32603, 'Missing auth context', 500, requestId);
125
+ return null;
126
+ }
127
+ if (!this.reserveCapacity(ctx.res, requestId))
128
+ return null;
129
+ const tracker = createSlotTracker(this.store);
130
+ const newSessionId = randomUUID();
131
+ let sessionServer;
132
+ try {
133
+ sessionServer = await this.createSessionServer();
134
+ }
135
+ catch (error) {
136
+ tracker.releaseSlot();
137
+ throw error;
138
+ }
139
+ const transportImpl = new StreamableHTTPServerTransport({
140
+ sessionIdGenerator: () => newSessionId,
141
+ });
142
+ const initTimeout = setTimeout(() => {
143
+ if (!tracker.isInitialized()) {
144
+ tracker.releaseSlot();
145
+ void closeTransportBestEffort(transportImpl, 'session-init-timeout');
146
+ void closeMcpServerBestEffort(sessionServer, 'session-init-timeout');
147
+ }
148
+ }, config.server.sessionInitTimeoutMs);
149
+ initTimeout.unref();
150
+ transportImpl.onclose = () => {
151
+ clearTimeout(initTimeout);
152
+ if (!tracker.isInitialized())
153
+ tracker.releaseSlot();
154
+ };
155
+ try {
156
+ const transport = createTransportAdapter(transportImpl);
157
+ await sessionServer.connect(transport);
158
+ }
159
+ catch (err) {
160
+ clearTimeout(initTimeout);
161
+ tracker.releaseSlot();
162
+ void closeTransportBestEffort(transportImpl, 'session-connect-failed');
163
+ void closeMcpServerBestEffort(sessionServer, 'session-connect-failed');
164
+ throw err;
165
+ }
166
+ tracker.markInitialized();
167
+ tracker.releaseSlot();
168
+ this.store.set(newSessionId, {
169
+ server: sessionServer,
170
+ transport: transportImpl,
171
+ createdAt: Date.now(),
172
+ lastSeen: Date.now(),
173
+ protocolInitialized: false,
174
+ authFingerprint,
175
+ });
176
+ registerMcpSessionServer(newSessionId, sessionServer);
177
+ transportImpl.onclose = composeCloseHandlers(transportImpl.onclose, () => {
178
+ this.cleanupSessionRecord(newSessionId, 'session-close');
179
+ });
180
+ return transportImpl;
181
+ }
182
+ cleanupSessionRecord(sessionId, context) {
183
+ const session = this.store.remove(sessionId);
184
+ if (!session)
185
+ return;
186
+ cancelTasksForOwner(`session:${sessionId}`, 'The task was cancelled because the MCP session ended.');
187
+ unregisterMcpSessionServer(sessionId);
188
+ void closeMcpServerBestEffort(session.server, `${context}-server`);
189
+ }
190
+ reserveCapacity(res, requestId) {
191
+ const allowed = ensureSessionCapacity({
192
+ store: this.store,
193
+ maxSessions: config.server.maxSessions,
194
+ evictOldest: (store) => {
195
+ const evicted = store.evictOldest();
196
+ if (evicted) {
197
+ const sessionId = resolveMcpSessionIdByServer(evicted.server);
198
+ if (sessionId) {
199
+ cancelTasksForOwner(`session:${sessionId}`, 'The task was cancelled because the MCP session was evicted.');
200
+ unregisterMcpSessionServer(sessionId);
201
+ }
202
+ unregisterMcpSessionServerByServer(evicted.server);
203
+ void closeTransportBestEffort(evicted.transport, 'session-eviction');
204
+ void closeMcpServerBestEffort(evicted.server, 'session-eviction');
205
+ return true;
206
+ }
207
+ return false;
208
+ },
209
+ });
210
+ if (!allowed) {
211
+ sendError(res, -32000, 'Server busy', 503, requestId);
212
+ return false;
213
+ }
214
+ if (!reserveSessionSlot(this.store, config.server.maxSessions)) {
215
+ sendError(res, -32000, 'Server busy', 503, requestId);
216
+ return false;
217
+ }
218
+ return true;
219
+ }
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // Download route
223
+ // ---------------------------------------------------------------------------
224
+ function checkDownloadRoute(path) {
225
+ const downloadMatch = /^\/mcp\/downloads\/([^/]+)\/([^/]+)$/.exec(path);
226
+ if (!downloadMatch)
227
+ return null;
228
+ const namespace = downloadMatch[1];
229
+ const hash = downloadMatch[2];
230
+ if (!namespace || !hash)
231
+ return null;
232
+ return { namespace, hash };
233
+ }
234
+ // ---------------------------------------------------------------------------
235
+ // HTTP dispatcher
236
+ // ---------------------------------------------------------------------------
237
+ class HttpDispatcher {
238
+ store;
239
+ mcpGateway;
240
+ constructor(store, mcpGateway) {
241
+ this.store = store;
242
+ this.mcpGateway = mcpGateway;
243
+ }
244
+ async tryHandleHealthRoute(ctx) {
245
+ if (!shouldHandleHealthRoute(ctx))
246
+ return false;
247
+ const requiresAuthForVerbose = isVerboseHealthRequest(ctx) && config.security.allowRemote;
248
+ if (!requiresAuthForVerbose) {
249
+ sendHealthRouteResponse(this.store, ctx, false);
250
+ return true;
251
+ }
252
+ const healthAuth = await this.authenticateRequest(ctx);
253
+ if (!healthAuth)
254
+ return true;
255
+ sendHealthRouteResponse(this.store, ctx, true);
256
+ return true;
257
+ }
258
+ tryHandleDownloadRoute(ctx) {
259
+ if (ctx.method !== 'GET')
260
+ return false;
261
+ const download = checkDownloadRoute(ctx.url.pathname);
262
+ if (!download)
263
+ return false;
264
+ handleDownload(ctx.res, download.namespace, download.hash);
265
+ return true;
266
+ }
267
+ async dispatch(ctx) {
268
+ try {
269
+ if (await this.tryHandleHealthRoute(ctx))
270
+ return;
271
+ const auth = await this.authenticateRequest(ctx);
272
+ if (!auth)
273
+ return;
274
+ const authCtx = { ...ctx, auth };
275
+ if (this.tryHandleDownloadRoute(ctx))
276
+ return;
277
+ if (ctx.url.pathname === '/mcp') {
278
+ const handled = await this.handleMcpRoutes(authCtx);
279
+ if (handled)
280
+ return;
281
+ }
282
+ sendJson(ctx.res, 404, { error: 'Not Found' });
283
+ }
284
+ catch (err) {
285
+ const error = err instanceof Error ? err : new Error(String(err));
286
+ logError('Request failed', error);
287
+ if (!ctx.res.writableEnded) {
288
+ sendJson(ctx.res, 500, { error: 'Internal Server Error' });
289
+ }
290
+ }
291
+ }
292
+ async handleMcpRoutes(ctx) {
293
+ switch (ctx.method) {
294
+ case 'POST':
295
+ await this.mcpGateway.handlePost(ctx);
296
+ return true;
297
+ case 'GET':
298
+ await this.mcpGateway.handleGet(ctx);
299
+ return true;
300
+ case 'DELETE':
301
+ await this.mcpGateway.handleDelete(ctx);
302
+ return true;
303
+ default:
304
+ return false;
305
+ }
306
+ }
307
+ async authenticateRequest(ctx) {
308
+ try {
309
+ return await authService.authenticate(ctx.req, ctx.signal);
310
+ }
311
+ catch (err) {
312
+ sendJson(ctx.res, 401, {
313
+ error: err instanceof Error ? err.message : 'Unauthorized',
314
+ });
315
+ return null;
316
+ }
317
+ }
318
+ }
319
+ // ---------------------------------------------------------------------------
320
+ // Verbose health helper (local to dispatcher)
321
+ // ---------------------------------------------------------------------------
322
+ function isVerboseHealthRequest(ctx) {
323
+ const value = ctx.url.searchParams.get('verbose');
324
+ if (!value)
325
+ return false;
326
+ const normalized = value.trim().toLowerCase();
327
+ return normalized === '1' || normalized === 'true';
328
+ }
329
+ // ---------------------------------------------------------------------------
330
+ // Request pipeline
331
+ // ---------------------------------------------------------------------------
332
+ class HttpRequestPipeline {
333
+ rateLimiter;
334
+ dispatcher;
335
+ constructor(rateLimiter, dispatcher) {
336
+ this.rateLimiter = rateLimiter;
337
+ this.dispatcher = dispatcher;
338
+ }
339
+ async handle(rawReq, rawRes) {
340
+ const requestId = getHeaderValue(rawReq, 'x-request-id') ?? randomUUID();
341
+ const sessionId = getMcpSessionId(rawReq) ?? undefined;
342
+ const { signal, cleanup } = createRequestAbortSignal(rawReq);
343
+ try {
344
+ await runWithRequestContext({
345
+ requestId,
346
+ operationId: requestId,
347
+ ...(sessionId ? { sessionId } : {}),
348
+ }, async () => {
349
+ const duplicateHeader = findDuplicateSingleValueHeader(rawReq);
350
+ if (duplicateHeader) {
351
+ sendJson(rawRes, 400, {
352
+ error: `Duplicate ${duplicateHeader} header is not allowed`,
353
+ });
354
+ drainRequest(rawReq);
355
+ return;
356
+ }
357
+ const ctx = buildRequestContext(rawReq, rawRes, signal);
358
+ if (!ctx) {
359
+ drainRequest(rawReq);
360
+ return;
361
+ }
362
+ if (!hostOriginPolicy.validate(ctx)) {
363
+ drainRequest(rawReq);
364
+ return;
365
+ }
366
+ if (corsPolicy.handle(ctx)) {
367
+ drainRequest(rawReq);
368
+ return;
369
+ }
370
+ if (!this.rateLimiter.check(ctx)) {
371
+ drainRequest(rawReq);
372
+ return;
373
+ }
374
+ if (ctx.method === 'POST') {
375
+ try {
376
+ ctx.body = await jsonBodyReader.read(ctx.req, DEFAULT_BODY_LIMIT_BYTES, ctx.signal);
377
+ }
378
+ catch {
379
+ if (ctx.url.pathname === '/mcp') {
380
+ sendError(ctx.res, -32700, 'Parse error', 400, null);
381
+ }
382
+ else {
383
+ sendJson(ctx.res, 400, {
384
+ error: 'Invalid JSON or Payload too large',
385
+ });
386
+ }
387
+ drainRequest(rawReq);
388
+ return;
389
+ }
390
+ }
391
+ else {
392
+ const contentLengthHeader = getHeaderValue(rawReq, 'content-length');
393
+ const transferEncodingHeader = getHeaderValue(rawReq, 'transfer-encoding');
394
+ const hasRequestBody = (contentLengthHeader !== null &&
395
+ Number.parseInt(contentLengthHeader, 10) > 0) ||
396
+ transferEncodingHeader !== null;
397
+ if (hasRequestBody) {
398
+ drainRequest(rawReq);
399
+ }
400
+ ctx.body = undefined;
401
+ }
402
+ await this.dispatcher.dispatch(ctx);
403
+ });
404
+ }
405
+ finally {
406
+ cleanup();
407
+ }
408
+ }
409
+ }
410
+ // ---------------------------------------------------------------------------
411
+ // Server bootstrap
412
+ // ---------------------------------------------------------------------------
413
+ function handlePipelineError(error, res) {
414
+ logError('Request pipeline failed', error instanceof Error ? error : new Error(String(error)));
415
+ if (res.writableEnded)
416
+ return;
417
+ if (!res.headersSent) {
418
+ sendJson(res, 500, { error: 'Internal Server Error' });
419
+ return;
420
+ }
421
+ res.end();
422
+ }
423
+ function createNetworkServer(listener) {
424
+ const { https } = config.server;
425
+ if (!https.enabled) {
426
+ return createServer(listener);
427
+ }
428
+ const { keyFile, certFile, caFile } = https;
429
+ if (!keyFile || !certFile) {
430
+ throw new Error('HTTPS enabled but SERVER_TLS_KEY_FILE / SERVER_TLS_CERT_FILE are missing');
431
+ }
432
+ const tlsOptions = {
433
+ key: readFileSync(keyFile),
434
+ cert: readFileSync(certFile),
435
+ };
436
+ if (caFile) {
437
+ tlsOptions.ca = readFileSync(caFile);
438
+ }
439
+ return createHttpsServer(tlsOptions, listener);
440
+ }
441
+ async function listen(server, host, port) {
442
+ await new Promise((resolve, reject) => {
443
+ function onError(err) {
444
+ server.off('error', onError);
445
+ reject(err);
446
+ }
447
+ server.once('error', onError);
448
+ server.listen(port, host, () => {
449
+ server.off('error', onError);
450
+ resolve();
451
+ });
452
+ });
453
+ }
454
+ function resolveListeningPort(server, fallback) {
455
+ const addr = server.address();
456
+ if (addr && typeof addr === 'object')
457
+ return addr.port;
458
+ return fallback;
459
+ }
460
+ function createShutdownHandler(options) {
461
+ const closeBatchSize = 10;
462
+ return async (signal) => {
463
+ logInfo(`Stopping HTTP server (${signal})...`);
464
+ options.rateLimiter.stop();
465
+ options.sessionCleanup.abort();
466
+ drainConnectionsOnShutdown(options.server);
467
+ disableEventLoopMonitoring();
468
+ const sessions = options.sessionStore.clear();
469
+ for (let i = 0; i < sessions.length; i += closeBatchSize) {
470
+ const batch = sessions.slice(i, i + closeBatchSize);
471
+ await Promise.all(batch.map(async (session) => {
472
+ const sessionId = resolveMcpSessionIdByServer(session.server);
473
+ if (sessionId) {
474
+ cancelTasksForOwner(`session:${sessionId}`, 'The task was cancelled because the HTTP server is shutting down.');
475
+ unregisterMcpSessionServer(sessionId);
476
+ }
477
+ unregisterMcpSessionServerByServer(session.server);
478
+ await closeTransportBestEffort(session.transport, 'shutdown-session-close');
479
+ await closeMcpServerBestEffort(session.server, 'shutdown-session-close');
480
+ }));
481
+ }
482
+ await new Promise((resolve, reject) => {
483
+ options.server.close((err) => {
484
+ if (err)
485
+ reject(err);
486
+ else
487
+ resolve();
488
+ });
489
+ });
490
+ };
491
+ }
492
+ export async function startHttpServer() {
493
+ assertHttpModeConfiguration();
494
+ enableHttpMode();
495
+ resetEventLoopMonitoring();
496
+ const rateLimiter = createRateLimitManagerImpl(config.rateLimit);
497
+ const sessionStore = createSessionStore(config.server.sessionTtlMs);
498
+ const sessionCleanup = startSessionCleanupLoop(sessionStore, config.server.sessionTtlMs);
499
+ const mcpGateway = new McpSessionGateway(sessionStore, createMcpServerForHttpSession);
500
+ const dispatcher = new HttpDispatcher(sessionStore, mcpGateway);
501
+ const pipeline = new HttpRequestPipeline(rateLimiter, dispatcher);
502
+ const server = createNetworkServer((req, res) => {
503
+ void pipeline.handle(req, res).catch((error) => {
504
+ handlePipelineError(error, res);
505
+ });
506
+ });
507
+ registerInboundBlockList(server);
508
+ applyHttpServerTuning(server);
509
+ await listen(server, config.server.host, config.server.port);
510
+ const port = resolveListeningPort(server, config.server.port);
511
+ const protocol = config.server.https.enabled ? 'https' : 'http';
512
+ logInfo(`${protocol.toUpperCase()} server listening on port ${port}`, {
513
+ platform: process.platform,
514
+ arch: process.arch,
515
+ hostname: hostname(),
516
+ nodeVersion: process.version,
517
+ });
518
+ return {
519
+ port,
520
+ host: config.server.host,
521
+ shutdown: createShutdownHandler({
522
+ server,
523
+ rateLimiter,
524
+ sessionCleanup,
525
+ sessionStore,
526
+ }),
527
+ };
528
+ }
529
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../../src/http/native.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type RequestContext } from './helpers.js';
2
+ export interface RateLimitConfig {
3
+ maxRequests: number;
4
+ windowMs: number;
5
+ cleanupIntervalMs: number;
6
+ enabled: boolean;
7
+ }
8
+ export interface RateLimitManagerImpl {
9
+ check(ctx: RequestContext): boolean;
10
+ stop(): void;
11
+ }
12
+ export declare function createRateLimitManagerImpl(options: RateLimitConfig): RateLimitManagerImpl;
13
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/http/rate-limit.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAY,MAAM,cAAc,CAAC;AAY7D,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC;IACpC,IAAI,IAAI,IAAI,CAAC;CACd;AAmFD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,eAAe,GACvB,oBAAoB,CAEtB"}
@@ -0,0 +1,81 @@
1
+ import { setInterval as setIntervalPromise } from 'node:timers/promises';
2
+ import { logWarn } from '../observability.js';
3
+ import { sendJson } from './helpers.js';
4
+ function isAbortError(error) {
5
+ return error instanceof Error && error.name === 'AbortError';
6
+ }
7
+ // ---------------------------------------------------------------------------
8
+ // Rate limiter
9
+ // ---------------------------------------------------------------------------
10
+ class RateLimiter {
11
+ options;
12
+ store = new Map();
13
+ cleanup = new AbortController();
14
+ constructor(options) {
15
+ this.options = options;
16
+ this.startCleanupLoop();
17
+ }
18
+ startCleanupLoop() {
19
+ const interval = setIntervalPromise(this.options.cleanupIntervalMs, Date.now, { signal: this.cleanup.signal, ref: false });
20
+ void (async () => {
21
+ try {
22
+ for await (const getNow of interval) {
23
+ this.cleanupEntries(getNow());
24
+ }
25
+ }
26
+ catch (err) {
27
+ if (!isAbortError(err)) {
28
+ logWarn('Rate limit cleanup failed', { error: err });
29
+ }
30
+ }
31
+ })();
32
+ }
33
+ cleanupEntries(now) {
34
+ const maxIdle = this.options.windowMs * 2;
35
+ for (const [key, entry] of this.store.entries()) {
36
+ if (now - entry.lastAccessed > maxIdle) {
37
+ this.store.delete(key);
38
+ }
39
+ }
40
+ }
41
+ check(ctx) {
42
+ if (!this.options.enabled || ctx.method === 'OPTIONS')
43
+ return true;
44
+ const key = ctx.ip ?? 'unknown';
45
+ const now = Date.now();
46
+ let entry = this.store.get(key);
47
+ if (entry) {
48
+ if (now > entry.resetTime) {
49
+ entry.count = 1;
50
+ entry.resetTime = now + this.options.windowMs;
51
+ entry.lastAccessed = now;
52
+ }
53
+ else {
54
+ entry.count += 1;
55
+ entry.lastAccessed = now;
56
+ }
57
+ }
58
+ else {
59
+ entry = {
60
+ count: 1,
61
+ resetTime: now + this.options.windowMs,
62
+ lastAccessed: now,
63
+ };
64
+ this.store.set(key, entry);
65
+ }
66
+ if (entry.count > this.options.maxRequests) {
67
+ const retryAfter = Math.max(1, Math.ceil((entry.resetTime - now) / 1000));
68
+ ctx.res.setHeader('Retry-After', String(retryAfter));
69
+ sendJson(ctx.res, 429, { error: 'Rate limit exceeded', retryAfter });
70
+ return false;
71
+ }
72
+ return true;
73
+ }
74
+ stop() {
75
+ this.cleanup.abort();
76
+ }
77
+ }
78
+ export function createRateLimitManagerImpl(options) {
79
+ return new RateLimiter(options);
80
+ }
81
+ //# sourceMappingURL=rate-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/http/rate-limit.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
+ //# sourceMappingURL=index.d.ts.map