@novorb/mcp-core 2.1.1 → 3.0.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/README.md +82 -161
- package/bin/mcp-core-jest.mjs +112 -0
- package/dist/auth.d.ts +57 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +74 -0
- package/dist/auth.js.map +1 -0
- package/dist/bootstrap.d.ts +129 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +206 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/client-input.d.ts +72 -0
- package/dist/client-input.d.ts.map +1 -0
- package/dist/client-input.js +109 -0
- package/dist/client-input.js.map +1 -0
- package/dist/credential-checks.d.ts +80 -0
- package/dist/credential-checks.d.ts.map +1 -0
- package/dist/credential-checks.js +189 -0
- package/dist/credential-checks.js.map +1 -0
- package/dist/credential-health.d.ts +12 -0
- package/dist/credential-health.d.ts.map +1 -0
- package/dist/credential-health.js +12 -0
- package/dist/credential-health.js.map +1 -0
- package/dist/credential-report.d.ts +46 -0
- package/dist/credential-report.d.ts.map +1 -0
- package/dist/credential-report.js +135 -0
- package/dist/credential-report.js.map +1 -0
- package/dist/credential-status-tool.d.ts +20 -0
- package/dist/credential-status-tool.d.ts.map +1 -0
- package/dist/credential-status-tool.js +33 -0
- package/dist/credential-status-tool.js.map +1 -0
- package/dist/credentials.d.ts +288 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +652 -0
- package/dist/credentials.js.map +1 -0
- package/dist/express-peers.d.ts +29 -0
- package/dist/express-peers.d.ts.map +1 -0
- package/dist/express-peers.js +36 -0
- package/dist/express-peers.js.map +1 -0
- package/dist/express.d.ts +74 -0
- package/dist/express.d.ts.map +1 -0
- package/dist/express.js +164 -0
- package/dist/express.js.map +1 -0
- package/dist/http-client.d.ts +278 -43
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +620 -182
- package/dist/http-client.js.map +1 -1
- package/dist/index.d.ts +27 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -10
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +28 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +37 -0
- package/dist/limits.js.map +1 -0
- package/dist/list-pagination.d.ts +41 -0
- package/dist/list-pagination.d.ts.map +1 -0
- package/dist/list-pagination.js +104 -0
- package/dist/list-pagination.js.map +1 -0
- package/dist/net.d.ts +112 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +490 -0
- package/dist/net.js.map +1 -0
- package/dist/notifications.d.ts +78 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +173 -0
- package/dist/notifications.js.map +1 -0
- package/dist/pagination.d.ts +236 -5
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js +393 -6
- package/dist/pagination.js.map +1 -1
- package/dist/prompts.d.ts +70 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +109 -0
- package/dist/prompts.js.map +1 -0
- package/dist/protocol-errors.d.ts +15 -0
- package/dist/protocol-errors.d.ts.map +1 -0
- package/dist/protocol-errors.js +28 -0
- package/dist/protocol-errors.js.map +1 -0
- package/dist/protocol-logging.d.ts +37 -0
- package/dist/protocol-logging.d.ts.map +1 -0
- package/dist/protocol-logging.js +77 -0
- package/dist/protocol-logging.js.map +1 -0
- package/dist/rate-limiter.d.ts +36 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +79 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/request-state.d.ts +74 -0
- package/dist/request-state.d.ts.map +1 -0
- package/dist/request-state.js +190 -0
- package/dist/request-state.js.map +1 -0
- package/dist/resources.d.ts +181 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +302 -0
- package/dist/resources.js.map +1 -0
- package/dist/result-limits.d.ts +80 -0
- package/dist/result-limits.d.ts.map +1 -0
- package/dist/result-limits.js +248 -0
- package/dist/result-limits.js.map +1 -0
- package/dist/retry.d.ts +79 -23
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +170 -57
- package/dist/retry.js.map +1 -1
- package/dist/sdk/client-stdio.d.ts +6 -0
- package/dist/sdk/client-stdio.d.ts.map +1 -0
- package/dist/sdk/client-stdio.js +6 -0
- package/dist/sdk/client-stdio.js.map +1 -0
- package/dist/sdk/client.d.ts +6 -0
- package/dist/sdk/client.d.ts.map +1 -0
- package/dist/sdk/client.js +6 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/express.d.ts +3 -0
- package/dist/sdk/express.d.ts.map +1 -0
- package/dist/sdk/express.js +11 -0
- package/dist/sdk/express.js.map +1 -0
- package/dist/sdk/node.d.ts +6 -0
- package/dist/sdk/node.d.ts.map +1 -0
- package/dist/sdk/node.js +6 -0
- package/dist/sdk/node.js.map +1 -0
- package/dist/sdk/server-stdio.d.ts +6 -0
- package/dist/sdk/server-stdio.d.ts.map +1 -0
- package/dist/sdk/server-stdio.js +6 -0
- package/dist/sdk/server-stdio.js.map +1 -0
- package/dist/sdk/server.d.ts +6 -0
- package/dist/sdk/server.d.ts.map +1 -0
- package/dist/sdk/server.js +6 -0
- package/dist/sdk/server.js.map +1 -0
- package/dist/server.d.ts +88 -36
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +98 -44
- package/dist/server.js.map +1 -1
- package/dist/task-request.d.ts +20 -0
- package/dist/task-request.d.ts.map +1 -0
- package/dist/task-request.js +43 -0
- package/dist/task-request.js.map +1 -0
- package/dist/task-store.d.ts +230 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +459 -0
- package/dist/task-store.js.map +1 -0
- package/dist/task-tools.d.ts +115 -0
- package/dist/task-tools.d.ts.map +1 -0
- package/dist/task-tools.js +397 -0
- package/dist/task-tools.js.map +1 -0
- package/dist/testing/client.d.ts +25 -0
- package/dist/testing/client.d.ts.map +1 -0
- package/dist/testing/client.js +11 -0
- package/dist/testing/client.js.map +1 -0
- package/dist/testing/in-memory.d.ts +26 -0
- package/dist/testing/in-memory.d.ts.map +1 -0
- package/dist/testing/in-memory.js +41 -0
- package/dist/testing/in-memory.js.map +1 -0
- package/dist/testing/index.d.ts +20 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +20 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/isolated-dirs.d.ts +27 -0
- package/dist/testing/isolated-dirs.d.ts.map +1 -0
- package/dist/testing/isolated-dirs.js +67 -0
- package/dist/testing/isolated-dirs.js.map +1 -0
- package/dist/testing/logs.d.ts +61 -0
- package/dist/testing/logs.d.ts.map +1 -0
- package/dist/testing/logs.js +113 -0
- package/dist/testing/logs.js.map +1 -0
- package/dist/testing/raw-http.d.ts +25 -0
- package/dist/testing/raw-http.d.ts.map +1 -0
- package/dist/testing/raw-http.js +41 -0
- package/dist/testing/raw-http.js.map +1 -0
- package/dist/testing/raw-peer.d.ts +43 -0
- package/dist/testing/raw-peer.d.ts.map +1 -0
- package/dist/testing/raw-peer.js +101 -0
- package/dist/testing/raw-peer.js.map +1 -0
- package/dist/testing/recording-server.d.ts +38 -0
- package/dist/testing/recording-server.d.ts.map +1 -0
- package/dist/testing/recording-server.js +38 -0
- package/dist/testing/recording-server.js.map +1 -0
- package/dist/testing/server-process.d.ts +76 -0
- package/dist/testing/server-process.d.ts.map +1 -0
- package/dist/testing/server-process.js +241 -0
- package/dist/testing/server-process.js.map +1 -0
- package/dist/testing/tools.d.ts +53 -0
- package/dist/testing/tools.d.ts.map +1 -0
- package/dist/testing/tools.js +98 -0
- package/dist/testing/tools.js.map +1 -0
- package/dist/testing/unit.d.ts +52 -0
- package/dist/testing/unit.d.ts.map +1 -0
- package/dist/testing/unit.js +95 -0
- package/dist/testing/unit.js.map +1 -0
- package/dist/tools.d.ts +205 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +370 -0
- package/dist/tools.js.map +1 -0
- package/dist/transport.d.ts +144 -53
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +305 -122
- package/dist/transport.js.map +1 -1
- package/dist/url-path.d.ts +49 -0
- package/dist/url-path.d.ts.map +1 -0
- package/dist/url-path.js +165 -0
- package/dist/url-path.js.map +1 -0
- package/dist/utils/dataStore.d.ts +143 -0
- package/dist/utils/dataStore.d.ts.map +1 -0
- package/dist/utils/dataStore.js +429 -0
- package/dist/utils/dataStore.js.map +1 -0
- package/dist/utils/envLoader.d.ts +129 -0
- package/dist/utils/envLoader.d.ts.map +1 -0
- package/dist/utils/envLoader.js +399 -0
- package/dist/utils/envLoader.js.map +1 -0
- package/dist/utils/logger.d.ts +181 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +664 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/redact.d.ts +50 -0
- package/dist/utils/redact.d.ts.map +1 -0
- package/dist/utils/redact.js +318 -0
- package/dist/utils/redact.js.map +1 -0
- package/docs/api-reference.md +29 -0
- package/docs/building-a-server.md +63 -0
- package/docs/credentials.md +131 -0
- package/docs/data-store.md +37 -0
- package/docs/env.md +38 -0
- package/docs/features.md +28 -0
- package/docs/http-client.md +116 -0
- package/docs/logger.md +100 -0
- package/docs/migrating-to-v3.md +45 -0
- package/docs/outbound-urls.md +104 -0
- package/docs/pagination.md +45 -0
- package/docs/protocol-features.md +62 -0
- package/docs/resources-prompts-tasks.md +95 -0
- package/docs/sdk.md +33 -0
- package/docs/server.md +68 -0
- package/docs/testing-harness.md +139 -0
- package/docs/testing.md +151 -0
- package/docs/tools.md +88 -0
- package/docs/transport.md +85 -0
- package/examples/testing/tools.integration.test.example.ts +312 -0
- package/examples/testing/tools.unit.test.example.ts +149 -0
- package/package.json +140 -18
- package/dist/logger.d.ts +0 -80
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -236
- package/dist/logger.js.map +0 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @novorb/mcp-core - Tool result limits
|
|
3
|
+
*
|
|
4
|
+
* `registerTools` enforces two caps on every tool result, by default:
|
|
5
|
+
*
|
|
6
|
+
* - items: a list-shaped result (`structuredContent` of the `PagedResult` shape `{ items, nextCursor?,
|
|
7
|
+
* total? }`) carries at most `maxItems` items (MCP_MAX_RESULT_ITEMS, default 100; a smaller `limit`
|
|
8
|
+
* argument wins). The rest is reached through an opaque `nextCursor`.
|
|
9
|
+
* - bytes: the serialized result is at most `maxBytes` (MCP_MAX_RESULT_BYTES, default 256 KiB). A
|
|
10
|
+
* list-shaped result is first paged smaller; anything still too large becomes an actionable isError
|
|
11
|
+
* result (never a truncated, invalid or schema-breaking body).
|
|
12
|
+
*
|
|
13
|
+
* Cursors are stateless. mcp-core's cursor records the tool, a fingerprint of the other arguments, the
|
|
14
|
+
* offset inside the handler's page, and the handler's own cursor for that page; on the next call the
|
|
15
|
+
* handler is re-run with its own cursor (as `args.cursor` and `ctx.cursor`) and mcp-core serves the next
|
|
16
|
+
* slice, or wraps the handler's own `nextCursor` once its page is exhausted. A cursor for another tool or
|
|
17
|
+
* other arguments, or a malformed one, is refused (`Invalid cursor: ...`), so an edited cursor can only
|
|
18
|
+
* ever address the caller's own result set. The handler must be a deterministic read for a given cursor
|
|
19
|
+
* (list tools are).
|
|
20
|
+
*/
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import { decodeCursor, encodeCursor, InvalidCursorError } from './pagination.js';
|
|
23
|
+
import { getLogger } from './utils/logger.js';
|
|
24
|
+
function isPagedShape(value) {
|
|
25
|
+
return (typeof value === 'object' && value !== null && !Array.isArray(value) && Array.isArray(value.items));
|
|
26
|
+
}
|
|
27
|
+
function stable(value) {
|
|
28
|
+
if (Array.isArray(value))
|
|
29
|
+
return value.map(stable);
|
|
30
|
+
if (typeof value === 'object' && value !== null) {
|
|
31
|
+
const out = {};
|
|
32
|
+
for (const key of Object.keys(value).sort())
|
|
33
|
+
out[key] = stable(value[key]);
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
/** A short fingerprint of the arguments other than `cursor` / `limit` (binds a cursor to its query). */
|
|
39
|
+
export function argsFingerprint(args) {
|
|
40
|
+
const rest = typeof args === 'object' && args !== null ? { ...args } : {};
|
|
41
|
+
delete rest.cursor;
|
|
42
|
+
delete rest.limit;
|
|
43
|
+
return createHash('sha256')
|
|
44
|
+
.update(JSON.stringify(stable(rest)) ?? '')
|
|
45
|
+
.digest('hex')
|
|
46
|
+
.slice(0, 16);
|
|
47
|
+
}
|
|
48
|
+
function isToolCursorData(tool, fingerprint) {
|
|
49
|
+
return (data) => {
|
|
50
|
+
const r = typeof data === 'object' && data !== null && !Array.isArray(data) ? data : undefined;
|
|
51
|
+
if (!r || typeof r.t !== 'string')
|
|
52
|
+
return false;
|
|
53
|
+
if (r.t !== tool)
|
|
54
|
+
throw new InvalidCursorError('issued for another tool');
|
|
55
|
+
if (r.h !== fingerprint)
|
|
56
|
+
throw new InvalidCursorError('issued for other arguments');
|
|
57
|
+
return (typeof r.o === 'number' && Number.isInteger(r.o) && r.o >= 0 && (r.c === undefined || typeof r.c === 'string'));
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Decode `cursor` as an mcp-core tool cursor. Returns undefined when it is not one (a handler's own
|
|
62
|
+
* cursor; only allowed when `strict` is false). Throws `InvalidCursorError` for a mismatch.
|
|
63
|
+
*/
|
|
64
|
+
export function decodeToolCursor(tool, args, cursor, strict) {
|
|
65
|
+
try {
|
|
66
|
+
const data = decodeCursor(cursor, { validate: isToolCursorData(tool, argsFingerprint(args)) });
|
|
67
|
+
return data.c !== undefined ? { o: data.o, c: data.c } : { o: data.o };
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
if (e instanceof InvalidCursorError && /another tool|other arguments/.test(e.message))
|
|
71
|
+
throw e;
|
|
72
|
+
if (strict)
|
|
73
|
+
throw e instanceof InvalidCursorError ? e : new InvalidCursorError('unrecognised format');
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function encodeToolCursor(tool, args, position) {
|
|
78
|
+
const data = { t: tool, h: argsFingerprint(args), o: position.o };
|
|
79
|
+
if (position.c !== undefined)
|
|
80
|
+
data.c = position.c;
|
|
81
|
+
return encodeCursor(data);
|
|
82
|
+
}
|
|
83
|
+
/** The arguments handed to the handler: `cursor` = its own cursor (or none), `limit` capped. */
|
|
84
|
+
export function handlerArgs(args, decoded, maxItems) {
|
|
85
|
+
if (typeof args !== 'object' || args === null || Array.isArray(args))
|
|
86
|
+
return args;
|
|
87
|
+
const out = { ...args };
|
|
88
|
+
if (decoded) {
|
|
89
|
+
if (decoded.c !== undefined)
|
|
90
|
+
out.cursor = decoded.c;
|
|
91
|
+
else
|
|
92
|
+
delete out.cursor;
|
|
93
|
+
}
|
|
94
|
+
if (typeof out.limit === 'number')
|
|
95
|
+
out.limit = Math.max(1, Math.min(Math.floor(out.limit), maxItems));
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
function byteSize(value) {
|
|
99
|
+
return Buffer.byteLength(JSON.stringify(value) ?? '', 'utf8');
|
|
100
|
+
}
|
|
101
|
+
function pretty(value) {
|
|
102
|
+
return JSON.stringify(value, null, 2);
|
|
103
|
+
}
|
|
104
|
+
function refusal(text) {
|
|
105
|
+
return { content: [{ type: 'text', text }], isError: true };
|
|
106
|
+
}
|
|
107
|
+
/** The bytes of `result` with any text block that only repeats `payload` left out (it is counted once). */
|
|
108
|
+
function envelopeBytes(result, payload) {
|
|
109
|
+
const compact = JSON.stringify(payload);
|
|
110
|
+
const copies = new Set([compact, pretty(payload)]);
|
|
111
|
+
const content = result.content.filter((block) => !(block.type === 'text' && copies.has(block.text)));
|
|
112
|
+
return byteSize(content.length === result.content.length ? result : { ...result, content });
|
|
113
|
+
}
|
|
114
|
+
/** The caps for an envelope result: items of the payload member, bytes with the payload counted once. */
|
|
115
|
+
function enforceEnvelopeLimits(ctx, envelope, result) {
|
|
116
|
+
const sc = (result.isError === true ? undefined : result.structuredContent);
|
|
117
|
+
if (!sc || !(envelope.key in sc))
|
|
118
|
+
return enforceResultLimits({ ...ctx, envelope: undefined }, result);
|
|
119
|
+
const payload = sc[envelope.key];
|
|
120
|
+
const hint = envelope.hint ? `; ${envelope.hint}` : '';
|
|
121
|
+
const items = Array.isArray(payload) ? payload : isPagedShape(payload) ? payload.items : undefined;
|
|
122
|
+
if (items && items.length > ctx.maxItems) {
|
|
123
|
+
getLogger().warn(`Tool result over the item limit: ${ctx.tool}`, 'Tools', {
|
|
124
|
+
tool: ctx.tool,
|
|
125
|
+
items: items.length,
|
|
126
|
+
maxItems: ctx.maxItems,
|
|
127
|
+
});
|
|
128
|
+
return refusal(`${ctx.tool}: the result has ${items.length} items, over the ${ctx.maxItems} item limit per response${hint}`);
|
|
129
|
+
}
|
|
130
|
+
const bytes = envelopeBytes(result, payload);
|
|
131
|
+
if (bytes <= ctx.maxBytes)
|
|
132
|
+
return result;
|
|
133
|
+
getLogger().warn(`Tool result over the byte limit: ${ctx.tool}`, 'Tools', {
|
|
134
|
+
tool: ctx.tool,
|
|
135
|
+
bytes,
|
|
136
|
+
maxBytes: ctx.maxBytes,
|
|
137
|
+
isError: false,
|
|
138
|
+
});
|
|
139
|
+
const replacement = ctx.onOversize?.({
|
|
140
|
+
tool: ctx.tool,
|
|
141
|
+
bytes,
|
|
142
|
+
maxBytes: ctx.maxBytes,
|
|
143
|
+
result,
|
|
144
|
+
...(ctx.authInfo ? { authInfo: ctx.authInfo } : {}),
|
|
145
|
+
});
|
|
146
|
+
if (replacement && byteSize(replacement) <= ctx.maxBytes)
|
|
147
|
+
return replacement;
|
|
148
|
+
return refusal(`${ctx.tool}: the result is ${bytes} bytes, over the ${ctx.maxBytes} byte limit per response${hint}`);
|
|
149
|
+
}
|
|
150
|
+
function oversizeError(tool, bytes, maxBytes, paged) {
|
|
151
|
+
const hint = paged
|
|
152
|
+
? 'even one item is too large; request fewer fields or a narrower item'
|
|
153
|
+
: 'narrow the request (filters, fewer fields, a smaller range) or use a paginated variant with cursor/limit';
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: `${tool}: the result is ${bytes} bytes, over the ${maxBytes} byte limit per response; ${hint}`,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
isError: true,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function pageOf(ctx, result, sc, limit) {
|
|
165
|
+
const offset = ctx.decoded?.o ?? 0;
|
|
166
|
+
const end = offset + limit;
|
|
167
|
+
const page = { ...sc, items: sc.items.slice(offset, end) };
|
|
168
|
+
delete page.nextCursor;
|
|
169
|
+
const inner = ctx.decoded?.c;
|
|
170
|
+
let next;
|
|
171
|
+
if (end < sc.items.length)
|
|
172
|
+
next = inner !== undefined ? { o: end, c: inner } : { o: end };
|
|
173
|
+
else if (typeof sc.nextCursor === 'string' && sc.nextCursor !== '')
|
|
174
|
+
next = { o: 0, c: sc.nextCursor };
|
|
175
|
+
if (next)
|
|
176
|
+
page.nextCursor = encodeToolCursor(ctx.tool, ctx.args, next);
|
|
177
|
+
const first = result.content[0];
|
|
178
|
+
const textWasDump = result.content.length === 1 && first?.type === 'text' && first.text === pretty(sc);
|
|
179
|
+
const cut = page.items.length < sc.items.length;
|
|
180
|
+
const content = cut || textWasDump ? [{ type: 'text', text: pretty(page) }] : result.content;
|
|
181
|
+
return { ...result, content, structuredContent: page };
|
|
182
|
+
}
|
|
183
|
+
/** Apply the item and byte caps to one handler result. */
|
|
184
|
+
export function enforceResultLimits(ctx, result) {
|
|
185
|
+
if (ctx.envelope)
|
|
186
|
+
return enforceEnvelopeLimits(ctx, ctx.envelope, result);
|
|
187
|
+
const log = getLogger();
|
|
188
|
+
const sc = result.isError === true ? undefined : result.structuredContent;
|
|
189
|
+
let out = result;
|
|
190
|
+
if (isPagedShape(sc)) {
|
|
191
|
+
const requested = typeof ctx.args?.limit === 'number';
|
|
192
|
+
const limit = Math.max(1, Math.min(requested ? Number(ctx.args.limit) : ctx.maxItems, ctx.maxItems));
|
|
193
|
+
const needsPaging = (ctx.decoded?.o ?? 0) > 0 || sc.items.length > limit || typeof sc.nextCursor === 'string';
|
|
194
|
+
if (needsPaging) {
|
|
195
|
+
out = pageOf(ctx, result, sc, limit);
|
|
196
|
+
const served = out.structuredContent.items.length;
|
|
197
|
+
if (served < sc.items.length) {
|
|
198
|
+
log.info(`Tool result paged: ${ctx.tool}`, 'Tools', { tool: ctx.tool, items: sc.items.length, served, limit });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
let bytes = byteSize(out);
|
|
202
|
+
let size = out.structuredContent.items.length;
|
|
203
|
+
while (bytes > ctx.maxBytes && size > 1) {
|
|
204
|
+
size = Math.max(1, Math.floor(size / 2));
|
|
205
|
+
out = pageOf(ctx, result, sc, size);
|
|
206
|
+
bytes = byteSize(out);
|
|
207
|
+
}
|
|
208
|
+
if (size < limit && bytes <= ctx.maxBytes) {
|
|
209
|
+
log.warn(`Tool result paged to fit the byte limit: ${ctx.tool}`, 'Tools', {
|
|
210
|
+
tool: ctx.tool,
|
|
211
|
+
items: sc.items.length,
|
|
212
|
+
served: size,
|
|
213
|
+
bytes,
|
|
214
|
+
maxBytes: ctx.maxBytes,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const bytes = byteSize(out);
|
|
219
|
+
if (bytes <= ctx.maxBytes)
|
|
220
|
+
return out;
|
|
221
|
+
log.warn(`Tool result over the byte limit: ${ctx.tool}`, 'Tools', {
|
|
222
|
+
tool: ctx.tool,
|
|
223
|
+
bytes,
|
|
224
|
+
maxBytes: ctx.maxBytes,
|
|
225
|
+
isError: out.isError === true,
|
|
226
|
+
});
|
|
227
|
+
const replacement = ctx.onOversize?.({
|
|
228
|
+
tool: ctx.tool,
|
|
229
|
+
bytes,
|
|
230
|
+
maxBytes: ctx.maxBytes,
|
|
231
|
+
result: out,
|
|
232
|
+
...(ctx.authInfo ? { authInfo: ctx.authInfo } : {}),
|
|
233
|
+
});
|
|
234
|
+
if (replacement && byteSize(replacement) <= ctx.maxBytes)
|
|
235
|
+
return replacement;
|
|
236
|
+
return oversizeError(ctx.tool, bytes, ctx.maxBytes, isPagedShape(sc));
|
|
237
|
+
}
|
|
238
|
+
/** Whether an input schema declares `cursor` and `limit` properties (required for `paginated` tools). */
|
|
239
|
+
export function declaresPageArgs(schema) {
|
|
240
|
+
try {
|
|
241
|
+
const json = schema['~standard'].jsonSchema.input({ target: 'draft-2020-12' });
|
|
242
|
+
return json.properties?.cursor !== undefined && json.properties?.limit !== undefined;
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=result-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-limits.js","sourceRoot":"","sources":["../src/result-limits.ts"],"names":[],"mappings":"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"}
|
package/dist/retry.d.ts
CHANGED
|
@@ -1,51 +1,107 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @novorb/mcp-core
|
|
2
|
+
* @novorb/mcp-core - Retry utilities
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* One retry policy for the whole package, shared by `retryWithBackoff` and the HTTP client:
|
|
5
|
+
* - retryable statuses: 408, 425, 429, 500, 502, 503, 504 (never 501, never any other 4xx)
|
|
6
|
+
* - retryable network errors: ECONNRESET, ETIMEDOUT, EAI_AGAIN, and ECONNREFUSED on connect only
|
|
7
|
+
* - `Retry-After` (seconds or HTTP date) is honoured, capped by `maxRetryAfterMs`
|
|
8
|
+
* - otherwise exponential backoff with full jitter, capped by `maxDelayMs`
|
|
9
|
+
* - bounded attempts (a loop, never recursion) and abort-signal aware
|
|
10
|
+
*
|
|
11
|
+
* Idempotency (which methods may be replayed) is decided by the caller; the HTTP client only retries
|
|
12
|
+
* GET/HEAD/OPTIONS/PUT/DELETE unless the request carries an idempotency key or opts in explicitly.
|
|
5
13
|
*/
|
|
6
14
|
export interface RetryOptions {
|
|
7
|
-
/** Maximum number of retries (default: 3) */
|
|
15
|
+
/** Maximum number of retries after the first attempt (default: 3). */
|
|
8
16
|
maxRetries?: number;
|
|
9
|
-
/**
|
|
17
|
+
/** Base delay of the first retry in milliseconds (default: 1000). */
|
|
10
18
|
initialDelayMs?: number;
|
|
11
|
-
/**
|
|
19
|
+
/** Cap of one backoff delay in milliseconds (default: 10000). */
|
|
12
20
|
maxDelayMs?: number;
|
|
13
|
-
/** Backoff multiplier (default: 2) */
|
|
21
|
+
/** Backoff multiplier (default: 2). */
|
|
14
22
|
backoffMultiplier?: number;
|
|
15
|
-
/**
|
|
16
|
-
|
|
23
|
+
/** Cap applied to a server-sent Retry-After in milliseconds (default: 30000). */
|
|
24
|
+
maxRetryAfterMs?: number;
|
|
25
|
+
/** Stop retrying (and reject with the abort reason) once this signal aborts. */
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
/** Override the retry decision (default: `isRetryableError`). */
|
|
28
|
+
shouldRetry?: (error: unknown, context: RetryContext) => boolean;
|
|
29
|
+
/** Called before each wait with the delay about to be slept. */
|
|
30
|
+
onRetry?: (info: RetryInfo) => void;
|
|
31
|
+
/** Random source in [0, 1) for the jitter (default: Math.random). */
|
|
32
|
+
random?: () => number;
|
|
17
33
|
}
|
|
18
34
|
export interface RetryContext {
|
|
19
|
-
/** Current attempt number (0-based) */
|
|
35
|
+
/** Current attempt number (0-based). */
|
|
20
36
|
attempt: number;
|
|
21
|
-
/** Maximum retries configured */
|
|
37
|
+
/** Maximum retries configured. */
|
|
22
38
|
maxRetries: number;
|
|
23
|
-
/** Last error encountered */
|
|
39
|
+
/** Last error encountered. */
|
|
24
40
|
lastError?: Error;
|
|
25
41
|
}
|
|
42
|
+
export interface RetryInfo {
|
|
43
|
+
/** The attempt that failed (0-based). */
|
|
44
|
+
attempt: number;
|
|
45
|
+
/** Delay before the next attempt in milliseconds. */
|
|
46
|
+
delayMs: number;
|
|
47
|
+
/** True when the delay came from a Retry-After header. */
|
|
48
|
+
fromRetryAfter: boolean;
|
|
49
|
+
/** The error that triggered the retry. */
|
|
50
|
+
error: unknown;
|
|
51
|
+
}
|
|
52
|
+
/** HTTP statuses that are retried. 501 Not Implemented is permanent and deliberately absent. */
|
|
53
|
+
export declare const RETRYABLE_STATUS_CODES: ReadonlySet<number>;
|
|
54
|
+
/** Network error codes that are retried. ECONNREFUSED additionally requires the connect syscall. */
|
|
55
|
+
export declare const RETRYABLE_NETWORK_CODES: ReadonlySet<string>;
|
|
56
|
+
/** Methods that are safe to replay without an idempotency key. */
|
|
57
|
+
export declare const IDEMPOTENT_METHODS: ReadonlySet<string>;
|
|
58
|
+
/** True for a status in `RETRYABLE_STATUS_CODES`. */
|
|
59
|
+
export declare function isRetryableStatus(status: number): boolean;
|
|
60
|
+
/** True for GET/HEAD/OPTIONS/PUT/DELETE (case-insensitive). A missing method counts as GET. */
|
|
61
|
+
export declare function isIdempotentMethod(method: string | undefined): boolean;
|
|
62
|
+
/** Reads an HTTP status from an axios-style error (`response.status`) or a normalized one (`status`). */
|
|
63
|
+
export declare function errorStatus(error: unknown): number | undefined;
|
|
26
64
|
/**
|
|
27
|
-
*
|
|
65
|
+
* Determine if an error is retryable under the shared policy. A response status decides when one is
|
|
66
|
+
* present; otherwise the network error code (own or `cause`) decides.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isRetryableError(error: unknown): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Exponential backoff with full jitter: a uniform value in [0, min(maxDelayMs, initial * mult^attempt)].
|
|
28
71
|
*/
|
|
29
72
|
export declare function calculateRetryDelay(attempt: number, options?: RetryOptions): number;
|
|
30
73
|
/**
|
|
31
|
-
*
|
|
74
|
+
* Parse a Retry-After header value (delta seconds or an HTTP date) to milliseconds. Returns undefined
|
|
75
|
+
* for a missing or unparseable value; a date in the past gives 0.
|
|
32
76
|
*/
|
|
33
|
-
export declare function
|
|
77
|
+
export declare function parseRetryAfter(retryAfter: string | undefined, now?: number): number | undefined;
|
|
34
78
|
/**
|
|
35
|
-
*
|
|
79
|
+
* The Retry-After delay carried by an error, in milliseconds: a normalized error's `retryAfterMs`, or
|
|
80
|
+
* the `retry-after` header of an axios-style `response`.
|
|
36
81
|
*/
|
|
37
|
-
export declare function
|
|
82
|
+
export declare function retryAfterFromError(error: unknown, now?: number): number | undefined;
|
|
38
83
|
/**
|
|
39
|
-
* Retry
|
|
84
|
+
* The delay before the next attempt: the error's Retry-After capped by `maxRetryAfterMs`, else the
|
|
85
|
+
* full-jitter backoff for `attempt`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function retryDelayFor(error: unknown, attempt: number, options?: RetryOptions): {
|
|
88
|
+
delayMs: number;
|
|
89
|
+
fromRetryAfter: boolean;
|
|
90
|
+
};
|
|
91
|
+
/** Throws the signal's abort reason when it has aborted. */
|
|
92
|
+
export declare function throwIfAborted(signal: AbortSignal | undefined): void;
|
|
93
|
+
/**
|
|
94
|
+
* Sleep for `ms` milliseconds. With a signal, rejects with its abort reason as soon as it aborts.
|
|
95
|
+
*/
|
|
96
|
+
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
97
|
+
/**
|
|
98
|
+
* Retry a function under the shared policy.
|
|
40
99
|
*
|
|
41
100
|
* @param fn - Async function to retry (receives RetryContext)
|
|
42
101
|
* @param options - Retry options
|
|
43
|
-
* @returns Result of successful
|
|
44
|
-
* @throws
|
|
102
|
+
* @returns Result of the first successful call
|
|
103
|
+
* @throws The last error when retries are exhausted or the error is not retryable; the abort reason
|
|
104
|
+
* when the signal aborts
|
|
45
105
|
*/
|
|
46
106
|
export declare function retryWithBackoff<T>(fn: (context: RetryContext) => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
47
|
-
/**
|
|
48
|
-
* Parse Retry-After header value to milliseconds.
|
|
49
|
-
*/
|
|
50
|
-
export declare function parseRetryAfter(retryAfter: string | undefined): number | undefined;
|
|
51
107
|
//# sourceMappingURL=retry.d.ts.map
|
package/dist/retry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"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"}
|