@j0hanz/superfetch 2.0.0 → 2.1.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 (150) hide show
  1. package/README.md +139 -46
  2. package/dist/cache.d.ts +42 -0
  3. package/dist/cache.js +565 -0
  4. package/dist/config/env-parsers.d.ts +1 -0
  5. package/dist/config/env-parsers.js +12 -0
  6. package/dist/config/index.d.ts +7 -0
  7. package/dist/config/index.js +20 -8
  8. package/dist/config/types/content.d.ts +1 -0
  9. package/dist/config.d.ts +77 -0
  10. package/dist/config.js +261 -0
  11. package/dist/crypto.d.ts +2 -0
  12. package/dist/crypto.js +32 -0
  13. package/dist/errors.d.ts +10 -0
  14. package/dist/errors.js +28 -0
  15. package/dist/fetch.d.ts +40 -0
  16. package/dist/fetch.js +910 -0
  17. package/dist/http/auth.js +161 -2
  18. package/dist/http/base-middleware.d.ts +7 -0
  19. package/dist/http/base-middleware.js +143 -0
  20. package/dist/http/cors.d.ts +0 -5
  21. package/dist/http/cors.js +0 -6
  22. package/dist/http/download-routes.js +6 -2
  23. package/dist/http/error-handler.d.ts +2 -0
  24. package/dist/http/error-handler.js +55 -0
  25. package/dist/http/host-allowlist.d.ts +3 -0
  26. package/dist/http/host-allowlist.js +117 -0
  27. package/dist/http/mcp-routes.d.ts +8 -2
  28. package/dist/http/mcp-routes.js +101 -8
  29. package/dist/http/mcp-session-eviction.d.ts +3 -0
  30. package/dist/http/mcp-session-eviction.js +24 -0
  31. package/dist/http/mcp-session-init.d.ts +7 -0
  32. package/dist/http/mcp-session-init.js +94 -0
  33. package/dist/http/mcp-session-slots.d.ts +17 -0
  34. package/dist/http/mcp-session-slots.js +55 -0
  35. package/dist/http/mcp-session-transport-init.d.ts +7 -0
  36. package/dist/http/mcp-session-transport-init.js +41 -0
  37. package/dist/http/mcp-session-types.d.ts +5 -0
  38. package/dist/http/mcp-session-types.js +1 -0
  39. package/dist/http/mcp-session.d.ts +9 -9
  40. package/dist/http/mcp-session.js +5 -114
  41. package/dist/http/mcp-sessions.d.ts +41 -0
  42. package/dist/http/mcp-sessions.js +392 -0
  43. package/dist/http/rate-limit.js +2 -2
  44. package/dist/http/server-middleware.d.ts +6 -1
  45. package/dist/http/server-middleware.js +3 -117
  46. package/dist/http/server-shutdown.js +1 -1
  47. package/dist/http/server-tuning.d.ts +9 -0
  48. package/dist/http/server-tuning.js +45 -0
  49. package/dist/http/server.js +206 -9
  50. package/dist/http/session-cleanup.js +8 -5
  51. package/dist/http.d.ts +78 -0
  52. package/dist/http.js +1437 -0
  53. package/dist/index.js +3 -3
  54. package/dist/mcp.d.ts +3 -0
  55. package/dist/mcp.js +94 -0
  56. package/dist/middleware/error-handler.d.ts +1 -1
  57. package/dist/middleware/error-handler.js +31 -30
  58. package/dist/observability.d.ts +16 -0
  59. package/dist/observability.js +78 -0
  60. package/dist/resources/cached-content-params.d.ts +5 -0
  61. package/dist/resources/cached-content-params.js +36 -0
  62. package/dist/resources/cached-content.js +33 -33
  63. package/dist/server.js +21 -6
  64. package/dist/services/cache-events.d.ts +8 -0
  65. package/dist/services/cache-events.js +19 -0
  66. package/dist/services/cache.d.ts +5 -4
  67. package/dist/services/cache.js +49 -45
  68. package/dist/services/context.d.ts +2 -0
  69. package/dist/services/context.js +3 -0
  70. package/dist/services/extractor.d.ts +1 -0
  71. package/dist/services/extractor.js +77 -40
  72. package/dist/services/fetcher/agents.js +1 -1
  73. package/dist/services/fetcher/dns-selection.js +1 -1
  74. package/dist/services/fetcher/interceptors.js +29 -60
  75. package/dist/services/fetcher/redirects.js +12 -4
  76. package/dist/services/fetcher/response.js +18 -8
  77. package/dist/services/fetcher.d.ts +23 -0
  78. package/dist/services/fetcher.js +553 -13
  79. package/dist/services/logger.js +4 -1
  80. package/dist/services/telemetry.d.ts +19 -0
  81. package/dist/services/telemetry.js +43 -0
  82. package/dist/services/transform-worker-pool.d.ts +10 -3
  83. package/dist/services/transform-worker-pool.js +213 -184
  84. package/dist/tools/handlers/fetch-single.shared.d.ts +11 -3
  85. package/dist/tools/handlers/fetch-single.shared.js +131 -2
  86. package/dist/tools/handlers/fetch-url.tool.d.ts +6 -0
  87. package/dist/tools/handlers/fetch-url.tool.js +56 -12
  88. package/dist/tools/index.d.ts +1 -0
  89. package/dist/tools/index.js +13 -1
  90. package/dist/tools/schemas.d.ts +2 -0
  91. package/dist/tools/schemas.js +8 -0
  92. package/dist/tools/utils/content-shaping.js +19 -4
  93. package/dist/tools/utils/content-transform-core.d.ts +5 -0
  94. package/dist/tools/utils/content-transform-core.js +180 -0
  95. package/dist/tools/utils/content-transform-workers.d.ts +1 -0
  96. package/dist/tools/utils/content-transform-workers.js +1 -0
  97. package/dist/tools/utils/content-transform.d.ts +2 -1
  98. package/dist/tools/utils/content-transform.js +37 -136
  99. package/dist/tools/utils/fetch-pipeline.js +47 -56
  100. package/dist/tools/utils/frontmatter.d.ts +3 -0
  101. package/dist/tools/utils/frontmatter.js +73 -0
  102. package/dist/tools/utils/markdown-heuristics.d.ts +1 -0
  103. package/dist/tools/utils/markdown-heuristics.js +19 -0
  104. package/dist/tools/utils/markdown-signals.d.ts +1 -0
  105. package/dist/tools/utils/markdown-signals.js +19 -0
  106. package/dist/tools/utils/raw-markdown-frontmatter.d.ts +3 -0
  107. package/dist/tools/utils/raw-markdown-frontmatter.js +73 -0
  108. package/dist/tools/utils/raw-markdown.d.ts +6 -0
  109. package/dist/tools/utils/raw-markdown.js +149 -0
  110. package/dist/tools.d.ts +104 -0
  111. package/dist/tools.js +421 -0
  112. package/dist/transform.d.ts +69 -0
  113. package/dist/transform.js +1509 -0
  114. package/dist/transformers/markdown/fenced-code-rule.d.ts +2 -0
  115. package/dist/transformers/markdown/fenced-code-rule.js +38 -0
  116. package/dist/transformers/markdown/frontmatter.d.ts +2 -0
  117. package/dist/transformers/markdown/frontmatter.js +45 -0
  118. package/dist/transformers/markdown/noise-rule.d.ts +2 -0
  119. package/dist/transformers/markdown/noise-rule.js +80 -0
  120. package/dist/transformers/markdown/turndown-instance.d.ts +2 -0
  121. package/dist/transformers/markdown/turndown-instance.js +19 -0
  122. package/dist/transformers/markdown.d.ts +5 -0
  123. package/dist/transformers/markdown.js +314 -0
  124. package/dist/transformers/markdown.transformer.js +2 -189
  125. package/dist/utils/cancellation.d.ts +1 -0
  126. package/dist/utils/cancellation.js +18 -0
  127. package/dist/utils/code-language-bash.d.ts +1 -0
  128. package/dist/utils/code-language-bash.js +48 -0
  129. package/dist/utils/code-language-core.d.ts +2 -0
  130. package/dist/utils/code-language-core.js +13 -0
  131. package/dist/utils/code-language-detectors.d.ts +5 -0
  132. package/dist/utils/code-language-detectors.js +142 -0
  133. package/dist/utils/code-language-helpers.d.ts +5 -0
  134. package/dist/utils/code-language-helpers.js +62 -0
  135. package/dist/utils/code-language-parsing.d.ts +5 -0
  136. package/dist/utils/code-language-parsing.js +62 -0
  137. package/dist/utils/code-language.js +250 -46
  138. package/dist/utils/error-details.d.ts +3 -0
  139. package/dist/utils/error-details.js +12 -0
  140. package/dist/utils/filename-generator.js +14 -3
  141. package/dist/utils/host-normalizer.d.ts +1 -0
  142. package/dist/utils/host-normalizer.js +37 -0
  143. package/dist/utils/ip-address.d.ts +4 -0
  144. package/dist/utils/ip-address.js +6 -0
  145. package/dist/utils/tool-error-handler.js +12 -17
  146. package/dist/utils/url-redactor.d.ts +1 -0
  147. package/dist/utils/url-redactor.js +13 -0
  148. package/dist/utils/url-validator.js +35 -20
  149. package/dist/workers/transform-worker.js +82 -38
  150. package/package.json +13 -10
@@ -1,16 +1,207 @@
1
+ import { setInterval as setIntervalPromise } from 'node:timers/promises';
1
2
  import { config, enableHttpMode } from '../config/index.js';
2
- import { logError, logInfo } from '../services/logger.js';
3
- import { errorHandler } from '../middleware/error-handler.js';
3
+ import { destroyAgents } from '../services/fetcher.js';
4
+ import { logError, logInfo, logWarn } from '../services/logger.js';
5
+ import { shutdownTransformWorkerPool } from '../services/transform-worker-pool.js';
6
+ import { getErrorMessage } from '../utils/error-details.js';
4
7
  import { createAuthMetadataRouter, createAuthMiddleware } from './auth.js';
8
+ import { attachBaseMiddleware } from './base-middleware.js';
5
9
  import { createCorsMiddleware } from './cors.js';
6
10
  import { registerDownloadRoutes } from './download-routes.js';
11
+ import { errorHandler } from './error-handler.js';
7
12
  import { registerMcpRoutes } from './mcp-routes.js';
8
- import { createRateLimitMiddleware } from './rate-limit.js';
9
- import { assertHttpConfiguration } from './server-config.js';
10
- import { attachBaseMiddleware } from './server-middleware.js';
11
- import { createShutdownHandler, registerSignalHandlers, } from './server-shutdown.js';
12
- import { startSessionCleanupLoop } from './session-cleanup.js';
13
- import { createSessionStore } from './sessions.js';
13
+ import { createSessionStore, startSessionCleanupLoop, } from './mcp-sessions.js';
14
+ import { applyHttpServerTuning, drainConnectionsOnShutdown, } from './server-tuning.js';
15
+ function getRateLimitKey(req) {
16
+ return req.ip ?? req.socket.remoteAddress ?? 'unknown';
17
+ }
18
+ function createCleanupInterval(store, options) {
19
+ const controller = new AbortController();
20
+ void startCleanupLoop(store, options, controller.signal).catch(handleCleanupError);
21
+ return controller;
22
+ }
23
+ function createRateLimitMiddleware(options) {
24
+ const store = new Map();
25
+ const cleanupController = createCleanupInterval(store, options);
26
+ const stop = () => {
27
+ cleanupController.abort();
28
+ };
29
+ const middleware = createRateLimitHandler(store, options);
30
+ return { middleware, stop, store };
31
+ }
32
+ function createRateLimitHandler(store, options) {
33
+ return (req, res, next) => {
34
+ if (shouldSkipRateLimit(req, options)) {
35
+ next();
36
+ return;
37
+ }
38
+ const now = Date.now();
39
+ const key = getRateLimitKey(req);
40
+ const resolution = resolveRateLimitEntry(store, key, now, options);
41
+ if (resolution.isNew) {
42
+ next();
43
+ return;
44
+ }
45
+ if (handleRateLimitExceeded(res, resolution.entry, now, options)) {
46
+ return;
47
+ }
48
+ next();
49
+ };
50
+ }
51
+ async function startCleanupLoop(store, options, signal) {
52
+ for await (const getNow of setIntervalPromise(options.cleanupIntervalMs, Date.now, { signal, ref: false })) {
53
+ evictStaleEntries(store, options, getNow());
54
+ }
55
+ }
56
+ function evictStaleEntries(store, options, now) {
57
+ for (const [key, entry] of store.entries()) {
58
+ if (now - entry.lastAccessed > options.windowMs * 2) {
59
+ store.delete(key);
60
+ }
61
+ }
62
+ }
63
+ function isAbortError(error) {
64
+ return error instanceof Error && error.name === 'AbortError';
65
+ }
66
+ function handleCleanupError(error) {
67
+ if (isAbortError(error)) {
68
+ return;
69
+ }
70
+ }
71
+ function shouldSkipRateLimit(req, options) {
72
+ return !options.enabled || req.method === 'OPTIONS';
73
+ }
74
+ function resolveRateLimitEntry(store, key, now, options) {
75
+ const existing = store.get(key);
76
+ if (!existing || now > existing.resetTime) {
77
+ const entry = createNewEntry(now, options);
78
+ store.set(key, entry);
79
+ return { entry, isNew: true };
80
+ }
81
+ updateEntry(existing, now);
82
+ return { entry: existing, isNew: false };
83
+ }
84
+ function createNewEntry(now, options) {
85
+ return {
86
+ count: 1,
87
+ resetTime: now + options.windowMs,
88
+ lastAccessed: now,
89
+ };
90
+ }
91
+ function updateEntry(entry, now) {
92
+ entry.count += 1;
93
+ entry.lastAccessed = now;
94
+ }
95
+ function handleRateLimitExceeded(res, entry, now, options) {
96
+ if (entry.count <= options.maxRequests) {
97
+ return false;
98
+ }
99
+ const retryAfter = Math.max(1, Math.ceil((entry.resetTime - now) / 1000));
100
+ res.set('Retry-After', String(retryAfter));
101
+ res.status(429).json({
102
+ error: 'Rate limit exceeded',
103
+ retryAfter,
104
+ });
105
+ return true;
106
+ }
107
+ function assertHttpConfiguration() {
108
+ ensureBindAllowed();
109
+ ensureStaticTokens();
110
+ if (config.auth.mode === 'oauth') {
111
+ ensureOauthConfiguration();
112
+ }
113
+ }
114
+ function ensureBindAllowed() {
115
+ const isLoopback = ['127.0.0.1', '::1', 'localhost'].includes(config.server.host);
116
+ if (!config.security.allowRemote && !isLoopback) {
117
+ logError('Refusing to bind to non-loopback host without ALLOW_REMOTE=true', { host: config.server.host });
118
+ process.exit(1);
119
+ }
120
+ if (!isLoopback &&
121
+ config.security.allowRemote &&
122
+ config.auth.mode !== 'oauth') {
123
+ logError('Remote HTTP mode requires OAuth configuration; refusing to start');
124
+ process.exit(1);
125
+ }
126
+ }
127
+ function ensureStaticTokens() {
128
+ if (config.auth.mode === 'static' && config.auth.staticTokens.length === 0) {
129
+ logError('At least one static access token is required for HTTP mode');
130
+ process.exit(1);
131
+ }
132
+ }
133
+ function ensureOauthConfiguration() {
134
+ if (!config.auth.issuerUrl || !config.auth.authorizationUrl) {
135
+ logError('OAUTH_ISSUER_URL and OAUTH_AUTHORIZATION_URL are required for OAuth mode');
136
+ process.exit(1);
137
+ }
138
+ if (!config.auth.tokenUrl) {
139
+ logError('OAUTH_TOKEN_URL is required for OAuth mode');
140
+ process.exit(1);
141
+ }
142
+ if (!config.auth.introspectionUrl) {
143
+ logError('OAUTH_INTROSPECTION_URL is required for OAuth mode');
144
+ process.exit(1);
145
+ }
146
+ }
147
+ function createShutdownHandler(server, sessionStore, sessionCleanupController, stopRateLimitCleanup) {
148
+ let inFlight = null;
149
+ let initialSignal = null;
150
+ return (signal) => {
151
+ if (inFlight) {
152
+ logWarn('Shutdown already in progress; ignoring signal', {
153
+ signal,
154
+ initialSignal,
155
+ });
156
+ return inFlight;
157
+ }
158
+ initialSignal = signal;
159
+ inFlight = shutdownServer(signal, server, sessionStore, sessionCleanupController, stopRateLimitCleanup).catch((error) => {
160
+ logError('Shutdown handler failed', error instanceof Error ? error : { error: getErrorMessage(error) });
161
+ throw error;
162
+ });
163
+ return inFlight;
164
+ };
165
+ }
166
+ async function shutdownServer(signal, server, sessionStore, sessionCleanupController, stopRateLimitCleanup) {
167
+ logInfo(`${signal} received, shutting down gracefully...`);
168
+ stopRateLimitCleanup();
169
+ sessionCleanupController.abort();
170
+ await closeSessions(sessionStore);
171
+ destroyAgents();
172
+ await shutdownTransformWorkerPool();
173
+ drainConnectionsOnShutdown(server);
174
+ closeServer(server);
175
+ scheduleForcedShutdown(10000);
176
+ }
177
+ async function closeSessions(sessionStore) {
178
+ const sessions = sessionStore.clear();
179
+ await Promise.allSettled(sessions.map((session) => session.transport.close().catch((error) => {
180
+ logWarn('Failed to close session during shutdown', {
181
+ error: getErrorMessage(error),
182
+ });
183
+ })));
184
+ }
185
+ function closeServer(server) {
186
+ server.close(() => {
187
+ logInfo('HTTP server closed');
188
+ process.exit(0);
189
+ });
190
+ }
191
+ function scheduleForcedShutdown(timeoutMs) {
192
+ setTimeout(() => {
193
+ logError('Forced shutdown after timeout');
194
+ process.exit(1);
195
+ }, timeoutMs).unref();
196
+ }
197
+ function registerSignalHandlers(shutdown) {
198
+ process.once('SIGINT', () => {
199
+ void shutdown('SIGINT');
200
+ });
201
+ process.once('SIGTERM', () => {
202
+ void shutdown('SIGTERM');
203
+ });
204
+ }
14
205
  function startListening(app) {
15
206
  return app
16
207
  .listen(config.server.port, config.server.host, () => {
@@ -68,7 +259,12 @@ async function buildServerContext() {
68
259
  async function createAppWithMiddleware() {
69
260
  const { app, jsonParser } = await createExpressApp();
70
261
  const { rateLimitMiddleware, stopRateLimitCleanup, authMiddleware, corsMiddleware, } = buildMiddleware();
71
- attachBaseMiddleware(app, jsonParser, rateLimitMiddleware, corsMiddleware);
262
+ attachBaseMiddleware({
263
+ app,
264
+ jsonParser,
265
+ rateLimitMiddleware,
266
+ corsMiddleware,
267
+ });
72
268
  attachAuthMetadata(app);
73
269
  assertHttpConfiguration();
74
270
  return { app, authMiddleware, stopRateLimitCleanup };
@@ -82,6 +278,7 @@ export async function startHttpServer() {
82
278
  enableHttpMode();
83
279
  const { app, sessionStore, sessionCleanupController, stopRateLimitCleanup } = await buildServerContext();
84
280
  const server = startListening(app);
281
+ applyHttpServerTuning(server);
85
282
  const shutdown = createShutdownHandler(server, sessionStore, sessionCleanupController, stopRateLimitCleanup);
86
283
  registerSignalHandlers(shutdown);
87
284
  return { shutdown };
@@ -1,6 +1,6 @@
1
1
  import { setInterval as setIntervalPromise } from 'node:timers/promises';
2
2
  import { logInfo, logWarn } from '../services/logger.js';
3
- import { evictExpiredSessions } from './mcp-session.js';
3
+ import { evictExpiredSessions } from './mcp-session-eviction.js';
4
4
  export function startSessionCleanupLoop(store, sessionTtlMs) {
5
5
  const controller = new AbortController();
6
6
  void runSessionCleanupLoop(store, sessionTtlMs, controller.signal).catch(handleSessionCleanupError);
@@ -8,11 +8,11 @@ export function startSessionCleanupLoop(store, sessionTtlMs) {
8
8
  }
9
9
  async function runSessionCleanupLoop(store, sessionTtlMs, signal) {
10
10
  const intervalMs = getCleanupIntervalMs(sessionTtlMs);
11
- for await (const _ of setIntervalPromise(intervalMs, undefined, {
11
+ for await (const getNow of setIntervalPromise(intervalMs, Date.now, {
12
12
  signal,
13
13
  ref: false,
14
14
  })) {
15
- handleSessionEvictions(store);
15
+ handleSessionEvictions(store, getNow());
16
16
  }
17
17
  }
18
18
  function getCleanupIntervalMs(sessionTtlMs) {
@@ -21,10 +21,13 @@ function getCleanupIntervalMs(sessionTtlMs) {
21
21
  function isAbortError(error) {
22
22
  return error instanceof Error && error.name === 'AbortError';
23
23
  }
24
- function handleSessionEvictions(store) {
24
+ function handleSessionEvictions(store, now) {
25
25
  const evicted = evictExpiredSessions(store);
26
26
  if (evicted > 0) {
27
- logInfo('Expired sessions evicted', { evicted });
27
+ logInfo('Expired sessions evicted', {
28
+ evicted,
29
+ timestamp: new Date(now).toISOString(),
30
+ });
28
31
  }
29
32
  }
30
33
  function handleSessionCleanupError(error) {
package/dist/http.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ import type { Express, NextFunction, Request, RequestHandler, Response } from 'express';
2
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
3
+ interface SessionEntry {
4
+ readonly transport: StreamableHTTPServerTransport;
5
+ createdAt: number;
6
+ lastSeen: number;
7
+ }
8
+ interface McpRequestParams {
9
+ _meta?: Record<string, unknown>;
10
+ [key: string]: unknown;
11
+ }
12
+ interface McpRequestBody {
13
+ jsonrpc: '2.0';
14
+ method: string;
15
+ id?: string | number;
16
+ params?: McpRequestParams;
17
+ }
18
+ export declare function startHttpServer(): Promise<{
19
+ shutdown: (signal: string) => Promise<void>;
20
+ }>;
21
+ export declare function errorHandler(err: Error, req: Request, res: Response, next: NextFunction): void;
22
+ export declare function normalizeHost(value: string): string | null;
23
+ export declare function attachBaseMiddleware(options: {
24
+ app: Express;
25
+ jsonParser: RequestHandler;
26
+ rateLimitMiddleware: RequestHandler;
27
+ corsMiddleware: RequestHandler;
28
+ }): void;
29
+ export declare function createCorsMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
30
+ export interface SessionStore {
31
+ get: (sessionId: string) => SessionEntry | undefined;
32
+ touch: (sessionId: string) => void;
33
+ set: (sessionId: string, entry: SessionEntry) => void;
34
+ remove: (sessionId: string) => SessionEntry | undefined;
35
+ size: () => number;
36
+ clear: () => SessionEntry[];
37
+ evictExpired: () => SessionEntry[];
38
+ evictOldest: () => SessionEntry | undefined;
39
+ }
40
+ interface McpSessionOptions {
41
+ readonly sessionStore: SessionStore;
42
+ readonly maxSessions: number;
43
+ }
44
+ export declare function createSessionStore(sessionTtlMs: number): SessionStore;
45
+ export declare function reserveSessionSlot(store: SessionStore, maxSessions: number): boolean;
46
+ interface SlotTracker {
47
+ readonly releaseSlot: () => void;
48
+ readonly markInitialized: () => void;
49
+ readonly isInitialized: () => boolean;
50
+ }
51
+ export declare function createSlotTracker(): SlotTracker;
52
+ export declare function ensureSessionCapacity({ store, maxSessions, res, evictOldest, }: {
53
+ store: SessionStore;
54
+ maxSessions: number;
55
+ res: Response;
56
+ evictOldest: (store: SessionStore) => boolean;
57
+ }): boolean;
58
+ export declare function resolveTransportForPost({ res, body, sessionId, options, }: {
59
+ res: Response;
60
+ body: Pick<McpRequestBody, 'method' | 'id'>;
61
+ sessionId: string | undefined;
62
+ options: McpSessionOptions;
63
+ }): Promise<StreamableHTTPServerTransport | null>;
64
+ export declare function isJsonRpcBatchRequest(body: unknown): boolean;
65
+ export declare function isMcpRequestBody(body: unknown): body is McpRequestBody;
66
+ export declare function ensureMcpProtocolVersionHeader(req: Request, res: Response): boolean;
67
+ export declare function ensurePostAcceptHeader(req: Request): void;
68
+ export declare function acceptsEventStream(req: Request): boolean;
69
+ interface HttpServerTuningTarget {
70
+ headersTimeout?: number;
71
+ requestTimeout?: number;
72
+ keepAliveTimeout?: number;
73
+ closeIdleConnections?: () => void;
74
+ closeAllConnections?: () => void;
75
+ }
76
+ export declare function applyHttpServerTuning(server: HttpServerTuningTarget): void;
77
+ export declare function drainConnectionsOnShutdown(server: HttpServerTuningTarget): void;
78
+ export {};