@j0hanz/fetch-url-mcp 1.11.7 → 1.12.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.
- package/LICENSE +21 -0
- package/README.md +177 -99
- package/dist/http/health.d.ts.map +1 -1
- package/dist/http/health.js +0 -2
- package/dist/http/native.d.ts.map +1 -1
- package/dist/http/native.js +0 -25
- package/dist/lib/config.d.ts +0 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +0 -9
- package/dist/lib/core.d.ts +0 -3
- package/dist/lib/core.d.ts.map +1 -1
- package/dist/lib/core.js +0 -7
- package/dist/lib/fetch-pipeline.d.ts +1 -14
- package/dist/lib/fetch-pipeline.d.ts.map +1 -1
- package/dist/lib/fetch-pipeline.js +4 -147
- package/dist/lib/http.d.ts +0 -3
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +2 -105
- package/dist/lib/mcp-interop.js +2 -2
- package/dist/lib/utils.d.ts +0 -2
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +4 -39
- package/dist/resources/index.d.ts +1 -23
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/index.js +3 -294
- package/dist/schemas.d.ts +0 -14
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +1 -77
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -2
- package/dist/tools/fetch-url.d.ts +0 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +12 -43
- package/dist/transform/shared.js +4 -4
- package/dist/transform/transform.d.ts +1 -1
- package/dist/transform/transform.d.ts.map +1 -1
- package/dist/transform/transform.js +10 -10
- package/dist/transform/types.d.ts +2 -2
- package/dist/transform/types.d.ts.map +1 -1
- package/dist/transform/worker-pool.d.ts +3 -3
- package/dist/transform/worker-pool.d.ts.map +1 -1
- package/dist/transform/worker-pool.js +2 -2
- package/package.json +13 -4
- package/dist/lib/cache.d.ts +0 -48
- package/dist/lib/cache.d.ts.map +0 -1
- package/dist/lib/cache.js +0 -264
package/dist/lib/core.js
CHANGED
|
@@ -5,7 +5,6 @@ import {} from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
5
5
|
import { config } from './config.js';
|
|
6
6
|
import { getErrorMessage, isAbortError, startAbortableIntervalLoop, } from './utils.js';
|
|
7
7
|
export { config, enableHttpMode, serverVersion } from './config.js';
|
|
8
|
-
export { createCacheKey, get, getEntryMeta, isEnabled, keys, onCacheUpdate, parseCacheKey, set, } from './cache.js';
|
|
9
8
|
const requestContext = new AsyncLocalStorage({
|
|
10
9
|
name: 'requestContext',
|
|
11
10
|
});
|
|
@@ -314,12 +313,6 @@ export function logError(message, error) {
|
|
|
314
313
|
const errorMeta = error instanceof Error ? formatErrorMeta(error) : (error ?? {});
|
|
315
314
|
writeLog('error', message, errorMeta);
|
|
316
315
|
}
|
|
317
|
-
export function getMcpLogLevel(sessionId) {
|
|
318
|
-
if (sessionId) {
|
|
319
|
-
return (sessionMcpLogLevels.get(sessionId) ?? toMcpLogLevel(config.logging.level));
|
|
320
|
-
}
|
|
321
|
-
return stdioMcpLogLevel ?? toMcpLogLevel(config.logging.level);
|
|
322
|
-
}
|
|
323
316
|
export function setLogLevel(level, sessionId) {
|
|
324
317
|
const normalized = normalizeLogLevel(level);
|
|
325
318
|
if (!normalized)
|
|
@@ -16,41 +16,28 @@ export declare function finalizeInlineMarkdown(markdown: string | undefined, opt
|
|
|
16
16
|
}): string | undefined;
|
|
17
17
|
interface FetchPipelineOptions<T> {
|
|
18
18
|
url: string;
|
|
19
|
-
cacheNamespace: string;
|
|
20
19
|
signal?: AbortSignal;
|
|
21
|
-
cacheVary?: Record<string, unknown> | string;
|
|
22
|
-
forceRefresh?: boolean;
|
|
23
20
|
onStage?: (stage: SharedFetchStage) => void;
|
|
24
21
|
transform: (input: FetchTransformInput, url: string) => T | Promise<T>;
|
|
25
|
-
serialize?: (result: T) => string;
|
|
26
|
-
deserialize?: (cached: string) => T | undefined;
|
|
27
22
|
}
|
|
28
23
|
export interface PipelineResult<T> {
|
|
29
24
|
data: T;
|
|
30
|
-
fromCache: boolean;
|
|
31
25
|
url: string;
|
|
32
26
|
originalUrl?: string;
|
|
33
27
|
finalUrl?: string;
|
|
34
28
|
fetchedAt: string;
|
|
35
|
-
cacheKey?: string | null;
|
|
36
29
|
}
|
|
37
|
-
export type SharedFetchStage = 'resolve_url' | '
|
|
30
|
+
export type SharedFetchStage = 'resolve_url' | 'fetch_remote' | 'response_ready' | 'transform_start' | 'prepare_output' | 'finalize_output';
|
|
38
31
|
export declare function executeFetchPipeline<T>(options: FetchPipelineOptions<T>): Promise<PipelineResult<T>>;
|
|
39
32
|
export type MarkdownPipelineResult = MarkdownTransformResult & {
|
|
40
33
|
readonly content: string;
|
|
41
34
|
};
|
|
42
|
-
export declare function parseCachedMarkdownResult(cached: string): MarkdownPipelineResult | undefined;
|
|
43
35
|
export declare const markdownTransform: (input: FetchTransformInput, url: string, signal?: AbortSignal) => Promise<MarkdownPipelineResult>;
|
|
44
|
-
export declare function serializeMarkdownResult(result: MarkdownPipelineResult): string;
|
|
45
36
|
interface MarkdownFetchOptions {
|
|
46
37
|
readonly url: string;
|
|
47
38
|
readonly signal?: AbortSignal;
|
|
48
|
-
readonly cacheVary?: Record<string, unknown> | string;
|
|
49
|
-
readonly forceRefresh?: boolean;
|
|
50
39
|
readonly onStage?: (stage: SharedFetchStage) => void;
|
|
51
40
|
readonly transform: (input: FetchTransformInput, normalizedUrl: string) => MarkdownPipelineResult | Promise<MarkdownPipelineResult>;
|
|
52
|
-
readonly serialize?: (result: MarkdownPipelineResult) => string;
|
|
53
|
-
readonly deserialize?: (cached: string) => MarkdownPipelineResult | undefined;
|
|
54
41
|
}
|
|
55
42
|
interface SharedFetchDeps {
|
|
56
43
|
readonly executeFetchPipeline?: typeof executeFetchPipeline;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-pipeline.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetch-pipeline.d.ts","sourceRoot":"","sources":["../../src/lib/fetch-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAOrE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,CAAC;AAGtB,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AACD,UAAU,mBAAmB;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAmGD,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,MAAM,GAAG,SAAS,CAQpB;AAyBD,UAAU,oBAAoB,CAAC,CAAC;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,SAAS,EAAE,CAAC,KAAK,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACxE;AACD,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC;IACR,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,MAAM,MAAM,gBAAgB,GACxB,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,iBAAiB,CAAC;AAmBtB,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,OAAO,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAC/B,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAkC5B;AAED,MAAM,MAAM,sBAAsB,GAAG,uBAAuB,GAAG;IAC7D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAwBF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,mBAAmB,EAC1B,KAAK,MAAM,EACX,SAAS,WAAW,KACnB,OAAO,CAAC,sBAAsB,CAchC,CAAC;AAEF,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,mBAAmB,EAC1B,aAAa,EAAE,MAAM,KAClB,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC/D;AACD,UAAU,eAAe;IACvB,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,oBAAoB,CAAC;CAC7D;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,oBAAoB,EAC7B,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC;IACT,QAAQ,EAAE,cAAc,CAAC,sBAAsB,CAAC,CAAC;IACjD,YAAY,EAAE,mBAAmB,CAAC;CACnC,CAAC,CAaD"}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { cachedPayloadValueSchema, extractedMetadataSchema, normalizeExtractedMetadata, normalizePageTitle, parseCachedPayload, stringifyCachedPayload, } from '../schemas.js';
|
|
3
1
|
import { transformBufferToMarkdown } from '../transform/transform.js';
|
|
4
2
|
import {} from '../transform/types.js';
|
|
5
|
-
import {
|
|
6
|
-
import { toCacheScopeId } from './cache.js';
|
|
7
|
-
import { config, getSessionId, logDebug, logError, logWarn } from './core.js';
|
|
3
|
+
import { config, logDebug } from './core.js';
|
|
8
4
|
import { fetchNormalizedUrlBuffer, normalizeUrl, transformToRawUrl, } from './http.js';
|
|
9
|
-
import {
|
|
5
|
+
import { withSignal } from './utils.js';
|
|
10
6
|
export { withSignal };
|
|
11
7
|
const TRUNCATION_MARKER = '...[truncated]';
|
|
12
8
|
function getOpenCodeFence(content) {
|
|
@@ -114,99 +110,6 @@ function resolveNormalizedUrl(url) {
|
|
|
114
110
|
transformed: transformedResult.transformed,
|
|
115
111
|
};
|
|
116
112
|
}
|
|
117
|
-
function logCacheMiss(reason, cacheNamespace, normalizedUrl, error) {
|
|
118
|
-
// Deserialize exceptions indicate data corruption or schema drift —
|
|
119
|
-
// use logError so they surface in monitoring, not just debug logs.
|
|
120
|
-
const log = reason === 'deserialize exception'
|
|
121
|
-
? logError
|
|
122
|
-
: reason.startsWith('deserialize')
|
|
123
|
-
? logWarn
|
|
124
|
-
: logDebug;
|
|
125
|
-
log(`Cache miss due to ${reason}`, {
|
|
126
|
-
namespace: cacheNamespace,
|
|
127
|
-
url: normalizedUrl,
|
|
128
|
-
...(error ? { error: getErrorMessage(error) } : {}),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
function attemptCacheRetrieval(cacheKey, deserialize, cacheNamespace, normalizedUrl) {
|
|
132
|
-
if (!cacheKey)
|
|
133
|
-
return null;
|
|
134
|
-
const cached = get(cacheKey, { scopeId: toCacheScopeId(getSessionId()) });
|
|
135
|
-
if (!cached)
|
|
136
|
-
return null;
|
|
137
|
-
if (!deserialize) {
|
|
138
|
-
logCacheMiss('missing deserializer', cacheNamespace, normalizedUrl);
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
let data;
|
|
142
|
-
try {
|
|
143
|
-
data = deserialize(cached.content);
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
logCacheMiss('deserialize exception', cacheNamespace, normalizedUrl, error);
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
if (data === undefined) {
|
|
150
|
-
logCacheMiss('deserialize failure', cacheNamespace, normalizedUrl);
|
|
151
|
-
return null;
|
|
152
|
-
}
|
|
153
|
-
logDebug('Cache hit', { namespace: cacheNamespace, url: normalizedUrl });
|
|
154
|
-
const finalUrl = cached.url !== normalizedUrl ? cached.url : undefined;
|
|
155
|
-
return {
|
|
156
|
-
data,
|
|
157
|
-
fromCache: true,
|
|
158
|
-
url: normalizedUrl,
|
|
159
|
-
...(finalUrl ? { finalUrl } : {}),
|
|
160
|
-
fetchedAt: cached.fetchedAt,
|
|
161
|
-
cacheKey,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function restoreCachedPipelineResult(options, resolvedUrl, cacheKey) {
|
|
165
|
-
if (options.forceRefresh)
|
|
166
|
-
return null;
|
|
167
|
-
options.onStage?.('check_cache');
|
|
168
|
-
const cachedResult = attemptCacheRetrieval(cacheKey, options.deserialize, options.cacheNamespace, resolvedUrl.normalizedUrl);
|
|
169
|
-
if (!cachedResult)
|
|
170
|
-
return null;
|
|
171
|
-
options.onStage?.('cache_hit');
|
|
172
|
-
options.onStage?.('cache_restore');
|
|
173
|
-
return { ...cachedResult, originalUrl: resolvedUrl.originalUrl };
|
|
174
|
-
}
|
|
175
|
-
function persistCacheEntry(cacheKey, data, serialize, normalizedUrl, cacheNamespace) {
|
|
176
|
-
const serializer = serialize ?? JSON.stringify;
|
|
177
|
-
const dataRecord = isObject(data) ? data : undefined;
|
|
178
|
-
const title = typeof dataRecord?.['title'] === 'string' ? dataRecord['title'] : undefined;
|
|
179
|
-
const metadata = {
|
|
180
|
-
url: normalizedUrl,
|
|
181
|
-
scopeIds: [toCacheScopeId(getSessionId())],
|
|
182
|
-
...(title === undefined ? {} : { title }),
|
|
183
|
-
};
|
|
184
|
-
try {
|
|
185
|
-
set(cacheKey, serializer(data), metadata);
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
logWarn('Failed to persist cache entry', {
|
|
189
|
-
namespace: cacheNamespace,
|
|
190
|
-
url: normalizedUrl,
|
|
191
|
-
error: getErrorMessage(error),
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function persistCacheTargets(requestedUrl, finalUrl, cacheKey, data, options) {
|
|
196
|
-
if (!cacheKey)
|
|
197
|
-
return;
|
|
198
|
-
const targets = new Map();
|
|
199
|
-
targets.set(cacheKey, finalUrl ?? requestedUrl);
|
|
200
|
-
if (finalUrl && finalUrl !== requestedUrl) {
|
|
201
|
-
const finalCacheKey = createCacheKey(options.cacheNamespace, finalUrl, options.cacheVary);
|
|
202
|
-
if (finalCacheKey) {
|
|
203
|
-
targets.set(finalCacheKey, finalUrl);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
for (const [key, url] of targets) {
|
|
207
|
-
persistCacheEntry(key, data, options.serialize, url, options.cacheNamespace);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
113
|
export async function executeFetchPipeline(options) {
|
|
211
114
|
options.onStage?.('resolve_url');
|
|
212
115
|
const resolvedUrl = resolveNormalizedUrl(options.url);
|
|
@@ -215,10 +118,6 @@ export async function executeFetchPipeline(options) {
|
|
|
215
118
|
original: resolvedUrl.originalUrl,
|
|
216
119
|
});
|
|
217
120
|
}
|
|
218
|
-
const cacheKey = createCacheKey(options.cacheNamespace, resolvedUrl.normalizedUrl, options.cacheVary);
|
|
219
|
-
const cachedResult = restoreCachedPipelineResult(options, resolvedUrl, cacheKey);
|
|
220
|
-
if (cachedResult)
|
|
221
|
-
return cachedResult;
|
|
222
121
|
options.onStage?.('fetch_remote');
|
|
223
122
|
logDebug('Fetching URL', { url: resolvedUrl.normalizedUrl });
|
|
224
123
|
const { buffer, encoding, truncated, finalUrl } = await fetchNormalizedUrlBuffer(resolvedUrl.normalizedUrl, withSignal(options.signal));
|
|
@@ -226,26 +125,14 @@ export async function executeFetchPipeline(options) {
|
|
|
226
125
|
options.onStage?.('transform_start');
|
|
227
126
|
const resolvedFinalUrl = finalUrl || resolvedUrl.normalizedUrl;
|
|
228
127
|
const data = await options.transform({ buffer, encoding, ...(truncated ? { truncated: true } : {}) }, resolvedFinalUrl);
|
|
229
|
-
if (isEnabled()) {
|
|
230
|
-
persistCacheTargets(resolvedUrl.normalizedUrl, finalUrl, cacheKey, data, options);
|
|
231
|
-
}
|
|
232
128
|
return {
|
|
233
129
|
data,
|
|
234
|
-
fromCache: false,
|
|
235
130
|
url: resolvedUrl.normalizedUrl,
|
|
236
131
|
originalUrl: resolvedUrl.originalUrl,
|
|
237
132
|
...(finalUrl ? { finalUrl } : {}),
|
|
238
133
|
fetchedAt: new Date().toISOString(),
|
|
239
|
-
cacheKey,
|
|
240
134
|
};
|
|
241
135
|
}
|
|
242
|
-
const markdownPipelineResultSchema = z.strictObject({
|
|
243
|
-
markdown: z.string(),
|
|
244
|
-
content: z.string(),
|
|
245
|
-
title: z.union([z.string(), z.undefined()]),
|
|
246
|
-
metadata: extractedMetadataSchema.optional(),
|
|
247
|
-
truncated: z.boolean(),
|
|
248
|
-
});
|
|
249
136
|
function createMarkdownPipelineResult({ markdown: rawMarkdown, title, metadata, truncated, }) {
|
|
250
137
|
const markdown = normalizeMarkdownForTruncation(rawMarkdown, truncated);
|
|
251
138
|
return {
|
|
@@ -256,33 +143,9 @@ function createMarkdownPipelineResult({ markdown: rawMarkdown, title, metadata,
|
|
|
256
143
|
truncated,
|
|
257
144
|
};
|
|
258
145
|
}
|
|
259
|
-
const markdownPipelineCacheCodec = z.codec(cachedPayloadValueSchema, markdownPipelineResultSchema, {
|
|
260
|
-
decode: (payload) => createMarkdownPipelineResult({
|
|
261
|
-
markdown: payload.markdown,
|
|
262
|
-
title: payload.title,
|
|
263
|
-
metadata: payload.metadata,
|
|
264
|
-
truncated: payload.truncated ?? false,
|
|
265
|
-
}),
|
|
266
|
-
encode: (result) => {
|
|
267
|
-
const title = normalizePageTitle(result.title);
|
|
268
|
-
const metadata = normalizeExtractedMetadata(result.metadata);
|
|
269
|
-
return {
|
|
270
|
-
markdown: normalizeMarkdownForTruncation(result.markdown, result.truncated),
|
|
271
|
-
...(title !== undefined ? { title } : {}),
|
|
272
|
-
...(metadata ? { metadata } : {}),
|
|
273
|
-
truncated: result.truncated,
|
|
274
|
-
};
|
|
275
|
-
},
|
|
276
|
-
});
|
|
277
|
-
export function parseCachedMarkdownResult(cached) {
|
|
278
|
-
const payload = parseCachedPayload(cached);
|
|
279
|
-
if (!payload)
|
|
280
|
-
return undefined;
|
|
281
|
-
return z.decode(markdownPipelineCacheCodec, payload);
|
|
282
|
-
}
|
|
283
146
|
export const markdownTransform = async (input, url, signal) => {
|
|
284
147
|
const result = await transformBufferToMarkdown(input.buffer, url, {
|
|
285
|
-
|
|
148
|
+
includeMetadataFooter: true,
|
|
286
149
|
encoding: input.encoding,
|
|
287
150
|
...withSignal(signal),
|
|
288
151
|
...(input.truncated ? { inputTruncated: true } : {}),
|
|
@@ -294,14 +157,8 @@ export const markdownTransform = async (input, url, signal) => {
|
|
|
294
157
|
truncated: Boolean(result.truncated || input.truncated),
|
|
295
158
|
});
|
|
296
159
|
};
|
|
297
|
-
export function serializeMarkdownResult(result) {
|
|
298
|
-
return stringifyCachedPayload(z.encode(markdownPipelineCacheCodec, result));
|
|
299
|
-
}
|
|
300
160
|
function buildSharedFetchPipelineOptions(options) {
|
|
301
|
-
return {
|
|
302
|
-
...options,
|
|
303
|
-
cacheNamespace: 'markdown',
|
|
304
|
-
};
|
|
161
|
+
return { ...options };
|
|
305
162
|
}
|
|
306
163
|
export async function performSharedFetch(options, deps = {}) {
|
|
307
164
|
const executePipeline = deps.executeFetchPipeline ?? executeFetchPipeline;
|
package/dist/lib/http.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { type ServerResponse } from 'node:http';
|
|
2
1
|
import { Agent } from 'undici';
|
|
3
2
|
import { type TransformResult } from './url.js';
|
|
4
|
-
export declare function generateSafeFilename(url: string, title?: string, hashFallback?: string, extension?: string): string;
|
|
5
|
-
export declare function handleDownload(res: ServerResponse, namespace: string, hash: string): void;
|
|
6
3
|
interface FetchTelemetryContext {
|
|
7
4
|
requestId: string;
|
|
8
5
|
startTime: number;
|
package/dist/lib/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/lib/http.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,EAAmB,MAAM,QAAQ,CAAC;AAYhD,OAAO,EAOL,KAAK,eAAe,EAGrB,MAAM,UAAU,CAAC;AA2vClB,UAAU,qBAAqB;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAoKD,UAAU,YAAY;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AA6ND,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE/C;AACD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAEA;AACD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEjE;AACD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAE9D;AACD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAExD;AACD,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,qBAAqB,CAEvB;AACD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,qBAAqB,EAC9B,QAAQ,EAAE,QAAQ,EAClB,WAAW,CAAC,EAAE,MAAM,GACnB,IAAI,CAEN;AACD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,qBAAqB,EAC9B,KAAK,EAAE,OAAO,EACd,MAAM,CAAC,EAAE,MAAM,GACd,IAAI,CAEN;AACD,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC,CAE7D;AACD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CASzC;AACD,wBAAsB,kBAAkB,CACtC,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC,MAAM,CAAC,CAEjB;AACD,wBAAsB,wBAAwB,CAC5C,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC;IACT,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAED"}
|
package/dist/lib/http.js
CHANGED
|
@@ -1,119 +1,16 @@
|
|
|
1
1
|
import { isUtf8 } from 'node:buffer';
|
|
2
|
-
import {
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import diagnosticsChannel from 'node:diagnostics_channel';
|
|
4
|
-
import {} from 'node:http';
|
|
5
|
-
import { posix as pathPosix } from 'node:path';
|
|
6
4
|
import { PassThrough, Readable } from 'node:stream';
|
|
7
5
|
import { finished, pipeline } from 'node:stream/promises';
|
|
8
6
|
import {} from 'node:stream/web';
|
|
9
7
|
import tls from 'node:tls';
|
|
10
8
|
import { createBrotliDecompress, createGunzip, createInflate } from 'node:zlib';
|
|
11
9
|
import { Agent } from 'undici';
|
|
12
|
-
import {
|
|
13
|
-
import { parseCachedPayload, resolveCachedPayloadContent } from '../schemas.js';
|
|
14
|
-
import { get as cacheGet, config, getOperationId, getRequestId, logDebug, logError, logWarn, redactUrl, } from './core.js';
|
|
10
|
+
import { config, getOperationId, getRequestId, logDebug, logError, logWarn, redactUrl, } from './core.js';
|
|
15
11
|
import { isIP } from './url.js';
|
|
16
12
|
import { BLOCKED_HOST_SUFFIXES, createDnsPreflight, IpBlocker, RawUrlTransformer, SafeDnsResolver, UrlNormalizer, VALIDATION_ERROR_CODE, } from './url.js';
|
|
17
13
|
import { composeAbortSignal, createErrorWithCode, FetchError, isAbortError, isError, isObject, isSystemError, toError, } from './utils.js';
|
|
18
|
-
import { formatZodError } from './zod.js';
|
|
19
|
-
// ═══════════════════════════════════════════════════════════════════
|
|
20
|
-
// FILENAME GENERATION & DOWNLOAD
|
|
21
|
-
// ═══════════════════════════════════════════════════════════════════
|
|
22
|
-
const FILENAME_RULES = {
|
|
23
|
-
MAX_LEN: 200,
|
|
24
|
-
UNSAFE_CHARS: /[<>:"/\\|?*\p{C}]/gu,
|
|
25
|
-
WHITESPACE: /\s+/g,
|
|
26
|
-
EXTENSIONS: /\.(html?|php|aspx?|jsp)$/i,
|
|
27
|
-
};
|
|
28
|
-
function sanitizeString(input) {
|
|
29
|
-
return input
|
|
30
|
-
.toLowerCase()
|
|
31
|
-
.replace(FILENAME_RULES.UNSAFE_CHARS, '')
|
|
32
|
-
.replace(FILENAME_RULES.WHITESPACE, '-')
|
|
33
|
-
.replace(/-+/g, '-')
|
|
34
|
-
.replace(/(?:^-|-$)/g, '');
|
|
35
|
-
}
|
|
36
|
-
function resolveUrlFilenameCandidate(url) {
|
|
37
|
-
const parsed = new URL(url);
|
|
38
|
-
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')
|
|
39
|
-
return null;
|
|
40
|
-
const basename = pathPosix.basename(parsed.pathname);
|
|
41
|
-
if (!basename || basename === 'index')
|
|
42
|
-
return null;
|
|
43
|
-
const cleaned = basename.replace(FILENAME_RULES.EXTENSIONS, '');
|
|
44
|
-
const sanitized = sanitizeString(cleaned);
|
|
45
|
-
if (sanitized === 'index')
|
|
46
|
-
return null;
|
|
47
|
-
return sanitized || null;
|
|
48
|
-
}
|
|
49
|
-
function truncateFilenameBase(name, extension) {
|
|
50
|
-
const maxBase = FILENAME_RULES.MAX_LEN - extension.length;
|
|
51
|
-
return name.length > maxBase ? name.substring(0, maxBase) : name;
|
|
52
|
-
}
|
|
53
|
-
function resolveTitleFilenameCandidate(title) {
|
|
54
|
-
if (!title)
|
|
55
|
-
return null;
|
|
56
|
-
return sanitizeString(title) || null;
|
|
57
|
-
}
|
|
58
|
-
function resolveFilenameBase(url, title, hashFallback) {
|
|
59
|
-
try {
|
|
60
|
-
const fromUrl = resolveUrlFilenameCandidate(url);
|
|
61
|
-
if (fromUrl)
|
|
62
|
-
return fromUrl;
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// Ignore URL parsing errors and continue fallbacks.
|
|
66
|
-
}
|
|
67
|
-
const fromTitle = resolveTitleFilenameCandidate(title);
|
|
68
|
-
if (fromTitle)
|
|
69
|
-
return fromTitle;
|
|
70
|
-
if (hashFallback)
|
|
71
|
-
return hashFallback.substring(0, 16);
|
|
72
|
-
return `download-${hash('sha256', url, 'hex').substring(0, 16)}`;
|
|
73
|
-
}
|
|
74
|
-
export function generateSafeFilename(url, title, hashFallback, extension = '.md') {
|
|
75
|
-
const name = resolveFilenameBase(url, title, hashFallback);
|
|
76
|
-
return `${truncateFilenameBase(name, extension)}${extension}`;
|
|
77
|
-
}
|
|
78
|
-
const DownloadParamsSchema = z.strictObject({
|
|
79
|
-
namespace: z.literal('markdown'),
|
|
80
|
-
hash: z
|
|
81
|
-
.string()
|
|
82
|
-
.regex(/^[a-f0-9.]+$/i)
|
|
83
|
-
.min(8)
|
|
84
|
-
.max(64),
|
|
85
|
-
});
|
|
86
|
-
function writeJsonError(res, status, message, code) {
|
|
87
|
-
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
88
|
-
res.end(JSON.stringify({ error: message, code }));
|
|
89
|
-
}
|
|
90
|
-
export function handleDownload(res, namespace, hash) {
|
|
91
|
-
const parsed = DownloadParamsSchema.safeParse({ namespace, hash });
|
|
92
|
-
if (!parsed.success) {
|
|
93
|
-
writeJsonError(res, 400, `Invalid download parameters: ${formatZodError(parsed.error)}`, 'BAD_REQUEST');
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
const cacheKey = `${parsed.data.namespace}:${parsed.data.hash}`;
|
|
97
|
-
const entry = cacheGet(cacheKey, { force: true });
|
|
98
|
-
if (!entry) {
|
|
99
|
-
writeJsonError(res, 404, 'Not found or expired', 'NOT_FOUND');
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const payload = parseCachedPayload(entry.content);
|
|
103
|
-
const content = payload ? resolveCachedPayloadContent(payload) : null;
|
|
104
|
-
if (!content) {
|
|
105
|
-
writeJsonError(res, 404, 'Content missing', 'NOT_FOUND');
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const fileName = generateSafeFilename(entry.url, payload?.title, parsed.data.hash);
|
|
109
|
-
// Safe header generation — RFC 5987 encoding for non-ASCII filenames
|
|
110
|
-
const encoded = encodeURIComponent(fileName).replace(/'/g, '%27');
|
|
111
|
-
res.setHeader('Content-Type', 'text/markdown; charset=utf-8');
|
|
112
|
-
res.setHeader('Content-Disposition', `attachment; filename="${fileName}"; filename*=UTF-8''${encoded}`);
|
|
113
|
-
res.setHeader('Cache-Control', `private, max-age=${config.cache.ttl}`);
|
|
114
|
-
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
115
|
-
res.end(content);
|
|
116
|
-
}
|
|
117
14
|
// ═══════════════════════════════════════════════════════════════════
|
|
118
15
|
// ENCODING DETECTION
|
|
119
16
|
// ═══════════════════════════════════════════════════════════════════
|
package/dist/lib/mcp-interop.js
CHANGED
|
@@ -209,10 +209,10 @@ export function setTaskToolCallCapability(server, enabled) {
|
|
|
209
209
|
if (!requests)
|
|
210
210
|
return;
|
|
211
211
|
if (enabled) {
|
|
212
|
-
requests
|
|
212
|
+
requests['tools'] = { call: {} };
|
|
213
213
|
return;
|
|
214
214
|
}
|
|
215
|
-
delete requests
|
|
215
|
+
delete requests['tools'];
|
|
216
216
|
}
|
|
217
217
|
const DEFAULT_PROGRESS_TOTAL = 8;
|
|
218
218
|
const PROGRESS_NOTIFICATION_TIMEOUT_MS = 5000;
|
package/dist/lib/utils.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export declare function parseUrlOrNull(input: string, base?: string): URL | null
|
|
|
3
3
|
export declare function throwIfAborted(signal: AbortSignal | undefined, url: string, stage: string): void;
|
|
4
4
|
export declare function createAbortError(url: string, stage: string): FetchError;
|
|
5
5
|
export declare function timingSafeEqualUtf8(a: string, b: string): boolean;
|
|
6
|
-
export declare function sha256Hex(input: string | Uint8Array): string;
|
|
7
6
|
export declare function hmacSha256Hex(key: string | Uint8Array, input: string | Uint8Array): string;
|
|
8
7
|
export declare class FetchError extends Error {
|
|
9
8
|
readonly url: string;
|
|
@@ -17,7 +16,6 @@ export declare function toError(error: unknown): Error;
|
|
|
17
16
|
export declare function isAbortError(error: unknown): boolean;
|
|
18
17
|
export declare function createErrorWithCode(message: string, code: string, options?: ErrorOptions): NodeJS.ErrnoException;
|
|
19
18
|
export declare function isSystemError(error: unknown): error is NodeJS.ErrnoException;
|
|
20
|
-
export declare function stableStringify(obj: unknown): string;
|
|
21
19
|
interface TunableHttpServer {
|
|
22
20
|
headersTimeout?: number;
|
|
23
21
|
requestTimeout?: number;
|
package/dist/lib/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAaA,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,GAAG,SAAS,CAOzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAEvE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,IAAI,CAWN;AACD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAKvE;AACD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKjE;AACD,wBAAgB,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAaA,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,GAAG,SAAS,CAOzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAEvE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,IAAI,CAWN;AACD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,CAKvE;AACD,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKjE;AACD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,GAAG,UAAU,EACxB,KAAK,EAAE,MAAM,GAAG,UAAU,GACzB,MAAM,CAER;AAED,qBAAa,UAAW,SAAQ,KAAK;IAOjC,QAAQ,CAAC,GAAG,EAAE,MAAM;IANtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;gBAGlD,OAAO,EAAE,MAAM,EACN,GAAG,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACrC,OAAO,CAAC,EAAE,YAAY;CAezB;AACD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAsBtD;AACD,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAE7C;AACD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEpD;AACD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,YAAY,GACrB,MAAM,CAAC,cAAc,CAGvB;AACD,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAK5E;AACD,UAAU,iBAAiB;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;IACrE,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CA4CrE;AACD,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAK1E;AACD,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AACD,UAAU,mBAAmB,CAAC,CAAC;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AAgBD,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,CAAC,GACP,kBAAkB,CAAC,CAAC,CAAC,CAcvB;AACD,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,GAC9B,IAAI,CAiBN;AACD,wBAAgB,QAAQ,CACtB,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAEvC;AAMD,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAQtD;AACD,UAAU,QAAQ;IAChB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC5C;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAK5D;AAED,wBAAgB,UAAU,CACxB,MAAM,CAAC,EAAE,WAAW,GACnB;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAEjD;AAED,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;CAqBX,CAAC;AAEX,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQtD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AASD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,GACf,UAAU,CA4BZ;AAID,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA+B/D;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,SAAM,GAAG,OAAO,CAMhE;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK7E;AACD,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,CAAC,EAAE,QAAQ,GAClB;IAAE,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAU/C"}
|
package/dist/lib/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
|
-
import { createHmac,
|
|
2
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
3
3
|
import { setInterval as setIntervalPromise, setTimeout as setTimeoutPromise, } from 'node:timers/promises';
|
|
4
4
|
import { inspect } from 'node:util';
|
|
5
5
|
import { config, logDebug, logWarn } from './core.js';
|
|
@@ -39,9 +39,6 @@ export function timingSafeEqualUtf8(a, b) {
|
|
|
39
39
|
return false;
|
|
40
40
|
return timingSafeEqual(aBuf, bBuf);
|
|
41
41
|
}
|
|
42
|
-
export function sha256Hex(input) {
|
|
43
|
-
return oneShotHash('sha256', input, 'hex');
|
|
44
|
-
}
|
|
45
42
|
export function hmacSha256Hex(key, input) {
|
|
46
43
|
return createHmac('sha256', key).update(input).digest('hex');
|
|
47
44
|
}
|
|
@@ -75,9 +72,9 @@ export function getErrorMessage(error) {
|
|
|
75
72
|
if (typeof error === 'string' && error.length > 0)
|
|
76
73
|
return error;
|
|
77
74
|
if (isObject(error) &&
|
|
78
|
-
typeof error
|
|
79
|
-
error
|
|
80
|
-
return error
|
|
75
|
+
typeof error['message'] === 'string' &&
|
|
76
|
+
error['message'].length > 0) {
|
|
77
|
+
return error['message'];
|
|
81
78
|
}
|
|
82
79
|
if (error === null || error === undefined)
|
|
83
80
|
return UNKNOWN_ERROR_MESSAGE;
|
|
@@ -112,38 +109,6 @@ export function isSystemError(error) {
|
|
|
112
109
|
const { code } = error;
|
|
113
110
|
return typeof code === 'string';
|
|
114
111
|
}
|
|
115
|
-
const MAX_DEPTH = 20;
|
|
116
|
-
const CIRCULAR_ERROR = 'stableStringify: Circular reference detected';
|
|
117
|
-
export function stableStringify(obj) {
|
|
118
|
-
const seen = new WeakSet();
|
|
119
|
-
const process = (value, depth) => {
|
|
120
|
-
if (typeof value !== 'object' || value === null)
|
|
121
|
-
return value;
|
|
122
|
-
if (depth > MAX_DEPTH) {
|
|
123
|
-
throw new Error(`stableStringify: Max depth (${MAX_DEPTH}) exceeded`);
|
|
124
|
-
}
|
|
125
|
-
if (seen.has(value)) {
|
|
126
|
-
throw new Error(CIRCULAR_ERROR);
|
|
127
|
-
}
|
|
128
|
-
seen.add(value);
|
|
129
|
-
try {
|
|
130
|
-
if (Array.isArray(value)) {
|
|
131
|
-
return value.map((item) => process(item, depth + 1));
|
|
132
|
-
}
|
|
133
|
-
const sorted = {};
|
|
134
|
-
if (!isObject(value))
|
|
135
|
-
return value;
|
|
136
|
-
for (const key of Object.keys(value).sort()) {
|
|
137
|
-
sorted[key] = process(value[key], depth + 1);
|
|
138
|
-
}
|
|
139
|
-
return sorted;
|
|
140
|
-
}
|
|
141
|
-
finally {
|
|
142
|
-
seen.delete(value);
|
|
143
|
-
}
|
|
144
|
-
};
|
|
145
|
-
return JSON.stringify(process(obj, 0));
|
|
146
|
-
}
|
|
147
112
|
const DROP_LOG_INTERVAL_MS = 10_000;
|
|
148
113
|
export function applyHttpServerTuning(server) {
|
|
149
114
|
const { headersTimeoutMs, requestTimeoutMs, keepAliveTimeoutMs, keepAliveTimeoutBufferMs, maxHeadersCount, maxConnections, } = config.server.http;
|
|
@@ -1,28 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
2
|
import { type IconInfo } from '../lib/utils.js';
|
|
4
|
-
type TemplateVariableValue = string | string[] | undefined;
|
|
5
|
-
interface CacheEntryMetaView {
|
|
6
|
-
scopeIds: string[];
|
|
7
|
-
}
|
|
8
|
-
export declare function isCacheEntryVisibleToScope(scopeId: string, meta: CacheEntryMetaView): boolean;
|
|
9
|
-
export declare function listCacheResourcesForScope(scopeId: string): {
|
|
10
|
-
resources: {
|
|
11
|
-
uri: string;
|
|
12
|
-
name: string;
|
|
13
|
-
title: string;
|
|
14
|
-
description: string;
|
|
15
|
-
mimeType: string;
|
|
16
|
-
annotations: {
|
|
17
|
-
audience: ['assistant'];
|
|
18
|
-
priority: number;
|
|
19
|
-
};
|
|
20
|
-
}[];
|
|
21
|
-
};
|
|
22
|
-
export declare function readCacheResourceForScope(uri: URL, variables: Record<string, TemplateVariableValue>, scopeId: string): ReadResourceResult;
|
|
23
3
|
export declare function registerInstructionResource(server: McpServer, instructions: string, iconInfo?: IconInfo): void;
|
|
24
|
-
export declare function registerCacheResourceTemplate(server: McpServer, iconInfo?: IconInfo): void;
|
|
25
4
|
export declare function buildServerInstructions(): string;
|
|
26
5
|
export declare function registerGetHelpPrompt(server: McpServer, instructions: string, iconInfo?: IconInfo): void;
|
|
27
|
-
export {};
|
|
28
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAOzE,OAAO,EAAsB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIpE,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI,CAwBN;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CA8BhD;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI,CAwBN"}
|