@orkestrel/mcp 0.0.26 → 0.0.27

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.
@@ -189,6 +189,60 @@ export declare function buildCancelledNotification(id: JSONRPCId, reason?: strin
189
189
  */
190
190
  export declare function buildDiscoverResult(options: MCPServerOptions): MCPDiscoverResult;
191
191
 
192
+ /**
193
+ * Builds the `x-mcp-header` projections one tool's `inputSchema` declares.
194
+ *
195
+ * @remarks
196
+ * The single decision both sides of the protocol make about an annotated tool: an HTTP
197
+ * CLIENT excludes a definition this refuses from the `tools/list` result it delivers, and a
198
+ * SERVER recognizes exactly the `Mcp-Param-*` names this returns for its own definitions.
199
+ *
200
+ * `undefined` means the definition is invalid, and every rule the protocol states produces
201
+ * it: a value that is not an RFC 9110 token, a non-primitive or untyped annotated leaf, a
202
+ * name repeated case-insensitively within the schema, an annotation the `properties` chain
203
+ * does not reach, and a schema that is not a record at all. An empty list is the valid answer
204
+ * for a schema carrying no annotation.
205
+ *
206
+ * Total — never throws, and a cyclic or stack-hostile schema is refused rather than followed.
207
+ *
208
+ * @param schema - The tool's advertised `inputSchema`
209
+ * @returns The declared projections, or `undefined` when the definition is invalid
210
+ *
211
+ * @example
212
+ * ```ts
213
+ * buildHeaderParameters({
214
+ * type: 'object',
215
+ * properties: { region: { type: 'string', 'x-mcp-header': 'Region' } },
216
+ * }) // → [{ name: 'Region', path: ['region'], primitive: 'string' }]
217
+ * ```
218
+ */
219
+ export declare function buildHeaderParameters(schema: unknown): readonly MCPHeaderParameter[] | undefined;
220
+
221
+ /**
222
+ * Builds the `Mcp-Param-*` request headers one `tools/call` carries.
223
+ *
224
+ * @remarks
225
+ * The projection SEP-2243 requires of an HTTP client, and the same derivation a server runs
226
+ * to know what the request should have carried. Each parameter's value is read at its exact
227
+ * property path in the call's own `arguments`; an absent or `null` value omits its header
228
+ * entirely, which is the protocol's distinction between "not supplied" and "supplied empty".
229
+ * The rendered text then travels through {@link encodeSentinel}, so a value carrying
230
+ * non-ASCII, control, or edge whitespace characters reaches the peer intact.
231
+ *
232
+ * @param parameters - The projections the tool's `inputSchema` declares
233
+ * @param values - The call's `arguments` record
234
+ * @returns The header field names and values, empty when nothing projects
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * buildHeaderProjection(
239
+ * [{ name: 'Region', path: ['region'], primitive: 'string' }],
240
+ * { region: 'us-west1' },
241
+ * ) // → { 'Mcp-Param-Region': 'us-west1' }
242
+ * ```
243
+ */
244
+ export declare function buildHeaderProjection(parameters: readonly MCPHeaderParameter[], values: unknown): Readonly<Record<string, string>>;
245
+
192
246
  /**
193
247
  * Builds the MCP `initialize` result — the negotiated protocol version, the
194
248
  * advertised capabilities, and the server identity.
@@ -358,6 +412,65 @@ export declare function buildToolCall(request: JSONRPCRequest, caller?: unknown,
358
412
  */
359
413
  export declare function buildToolDescriptors(manager: ToolManagerInterface): readonly MCPToolDescriptor[];
360
414
 
415
+ /**
416
+ * Computes the capabilities one round of input requests needs and the client did not declare.
417
+ *
418
+ * @remarks
419
+ * The protocol's rule is about SENDING: a server never issues a request kind the client's
420
+ * declared capabilities exclude. So this reads the round rather than the method, and it
421
+ * answers with the refusal's own payload — the `requiredCapabilities` record a
422
+ * `MissingRequiredClientCapability` error carries, keyed by each missing capability, in the
423
+ * `ClientCapabilities` shape the schema defines rather than as a list of names.
424
+ *
425
+ * Each kind maps to one declaration: `sampling/createMessage` to `sampling`, `roots/list` to
426
+ * `roots`, a form elicitation to what {@link isFormElicitationSupported} accepts, and a
427
+ * URL-mode elicitation to a record-valued `elicitation.url`. A request this package cannot
428
+ * recognize needs nothing, because {@link import('./validators.js').isMCPInputRequestMap}
429
+ * has already refused the round it would have travelled in. Total over hostile input.
430
+ *
431
+ * The `elicitation` value names the ARM the round needs, so a client can act on the refusal
432
+ * by declaring exactly what the payload asks for. A missing URL arm answers `{ url: {} }`, a
433
+ * missing form arm answers the empty record this package reads as form-only, and a round
434
+ * needing both answers `{ form: {}, url: {} }`. An empty record for a URL round would name
435
+ * the declaration a URL-capable client already sent, and refuse the identical round again.
436
+ *
437
+ * @param requests - The round the server is about to issue
438
+ * @param capabilities - The client capability record the request declared
439
+ * @returns The missing capabilities, or `undefined` when the client declared every one
440
+ *
441
+ * @example
442
+ * ```ts
443
+ * computeMissingCapabilities({ answer: { method: 'roots/list' } }, {}) // { roots: {} }
444
+ * computeMissingCapabilities({ answer: { method: 'roots/list' } }, { roots: {} }) // undefined
445
+ * ```
446
+ */
447
+ export declare function computeMissingCapabilities(requests: MCPInputRequestMap, capabilities: unknown): MCPClientCapabilities | undefined;
448
+
449
+ /**
450
+ * Counts every {@link MCP_HEADER_ANNOTATION} key one JSON value carries, at any position.
451
+ *
452
+ * @remarks
453
+ * The companion of {@link extractHeaderAnnotations}, which reads only the annotations a
454
+ * `properties` chain reaches. Comparing the two answers is how
455
+ * {@link buildHeaderParameters} decides reachability without a second walk that would have
456
+ * to re-state which JSON Schema keywords are traversable: an annotation the reachable walk
457
+ * did not read is one sitting under `items`, a composition or conditional keyword, a `$ref`
458
+ * target, or any other position, and the protocol makes the whole tool definition invalid for
459
+ * it.
460
+ *
461
+ * Iterative and ancestor-tracked, so a deeply nested or self-referential value terminates
462
+ * rather than exhausting the stack. Total — never throws, whatever the input.
463
+ *
464
+ * @param value - The value to scan, normally a tool's `inputSchema`
465
+ * @returns How many annotation keys the value carries
466
+ *
467
+ * @example
468
+ * ```ts
469
+ * countHeaderAnnotations({ properties: { region: { 'x-mcp-header': 'Region' } } }) // 1
470
+ * ```
471
+ */
472
+ export declare function countHeaderAnnotations(value: unknown): number;
473
+
361
474
  /**
362
475
  * Adapts an {@link MCPTransportInterface} (the environment-agnostic duplex message
363
476
  * channel) into a {@link MCPClientTransportInterface} — the additive bridge that lets
@@ -525,6 +638,55 @@ export declare function createMCPServer(options: MCPServerOptions): MCPServerInt
525
638
  */
526
639
  export declare function decodeBoundedMessage(message: string, limits: MCPJSONLimitOptions): JSONRPCMessage | undefined;
527
640
 
641
+ /**
642
+ * Reads the value one standard MCP request header carries, decoding the Base64 sentinel.
643
+ *
644
+ * @remarks
645
+ * The sentinel format is `=?base64?{Base64OfUTF8}?=`, spelled once as
646
+ * {@link MCP_SENTINEL_PREFIX} and {@link MCP_SENTINEL_SUFFIX} and read from there by both
647
+ * directions of the codec.
648
+ * The markers alone decide whether a value is a sentinel: a value carrying the prefix and the
649
+ * suffix is one, and its payload is then held to `decodeBase64` from `@orkestrel/codec` — the
650
+ * canonical RFC 4648 § 4 grammar, which admits exactly one spelling per byte sequence — and to
651
+ * well-formed UTF-8. A payload leaving a non-zero bit in the sextet its padding discards is a
652
+ * second spelling of a byte, so it is refused: `=?base64?QR==?=` reaches for the byte
653
+ * `=?base64?QQ==?=` spells canonically, and only the canonical spelling decodes. A malformed
654
+ * payload answers `undefined` rather than falling back to the literal, because the protocol
655
+ * requires a server to REJECT invalid characters, and a fallback would admit the very value
656
+ * the rule exists to refuse. A value missing either marker is a literal and comes back
657
+ * unchanged.
658
+ *
659
+ * `decodeUTF8` from `@orkestrel/codec` reads the bytes back as text: strict RFC 3629, where an
660
+ * overlong, an encoded surrogate, a code point past U+10FFFF, and a truncated sequence each
661
+ * answer `undefined` rather than a replacement character, and total, so the refusal arrives as
662
+ * that value instead of as a throw. It also keeps a leading U+FEFF as a character of the
663
+ * value, where the platform decoder consumes it as a byte order mark — which is what lets a
664
+ * value leading with U+FEFF survive {@link encodeSentinel} and come back whole.
665
+ *
666
+ * {@link import('./validators.js').isStandardBase64} is a wider and separate rule: it names
667
+ * JSON Schema `byte` membership for the blob, image, and audio content a peer sends, where
668
+ * this package receives liberally. It does not govern this payload.
669
+ *
670
+ * Optional whitespace is excluded first, per RFC 9110 § 5.5: a recipient parses a field value
671
+ * with its surrounding spaces and horizontal tabs removed, so a peer that padded a plain value
672
+ * still matches the body. A value whose own leading or trailing whitespace is significant
673
+ * cannot survive that, which is what {@link encodeSentinel} encodes it for.
674
+ *
675
+ * Total — never throws, whatever the input.
676
+ *
677
+ * @param value - The raw header field value the peer sent
678
+ * @returns The carried value, or `undefined` when the sentinel's payload is invalid
679
+ *
680
+ * @example
681
+ * ```ts
682
+ * decodeSentinel('=?base64?Y2Fmw6k=?=') // 'café'
683
+ * decodeSentinel(' search ') // 'search' — optional whitespace excluded
684
+ * decodeSentinel('=?base64?SGVsbG8?=') // undefined — invalid padding
685
+ * decodeSentinel('=?base64?QR==?=') // undefined — a non-canonical spelling
686
+ * ```
687
+ */
688
+ export declare function decodeSentinel(value: string): string | undefined;
689
+
528
690
  /**
529
691
  * Default modern result freshness lifetime in milliseconds.
530
692
  *
@@ -547,10 +709,11 @@ export declare const DEFAULT_MCP_CLIENT_VERSION = "1.0.0";
547
709
  * One MiB admits ordinary JSON-RPC requests and substantial tool arguments; 16 KiB admits
548
710
  * extension-rich modern metadata and signed multi-round state; four MiB admits substantial
549
711
  * JSON tool output without allowing an unconfigured service to serialize arbitrary process
550
- * memory; 64 metadata keys admits the reserved keys plus many extensions; 128 concurrent
551
- * streams admits a busy service while bounding retained producers; depth 32 admits ordinary
552
- * JSON documents while rejecting stack-hostile nesting. Frozen so callers cannot alter the
553
- * defaults observed by later servers.
712
+ * memory; 64 keys admits `_meta`'s reserved keys plus many extensions, and bounds a produced
713
+ * result's breadth by the same leaf; 128 concurrent streams admits a busy service while
714
+ * bounding retained producers; depth 32 admits ordinary JSON documents while rejecting
715
+ * stack-hostile nesting. Frozen so callers cannot alter the defaults observed by later
716
+ * servers.
554
717
  */
555
718
  export declare const DEFAULT_MCP_LIMITS: Readonly<{
556
719
  message: 1048576;
@@ -596,6 +759,44 @@ export declare function digestJSON(value: unknown, limits: MCPJSONLimitOptions):
596
759
  */
597
760
  export declare const EMPTY_MCP_ARGUMENTS: Readonly<Record<string, unknown>>;
598
761
 
762
+ /**
763
+ * Builds the wire form one standard MCP request header value must travel as.
764
+ *
765
+ * @remarks
766
+ * The exact inverse of {@link decodeSentinel}, and its membership rule is stated as that
767
+ * inverse rather than as a second list that could drift: a value travels LITERALLY when it is
768
+ * plain printable ASCII — every code point in `U+0020`–`U+007E`, the RFC 9110 field-value
769
+ * range this package admits — and {@link decodeSentinel} gives it back unchanged. Every other
770
+ * value travels wrapped in {@link MCP_SENTINEL_PREFIX} and {@link MCP_SENTINEL_SUFFIX}, the
771
+ * same markers the decode recognizes a sentinel by. `encodeBase64` from `@orkestrel/codec`
772
+ * spells the payload, so the wire form carries the canonical spelling {@link decodeSentinel}
773
+ * accepts.
774
+ *
775
+ * That one rule covers each row of the protocol's encoding table. A non-ASCII value and a
776
+ * value carrying a control character fail the ASCII test. A value with leading or trailing
777
+ * whitespace comes back trimmed, so it fails the round trip. A value already wearing the
778
+ * sentinel markers decodes to something else, or to nothing, so it fails the round trip too
779
+ * and is encoded rather than read back as a sentinel it never was.
780
+ *
781
+ * The bytes come from the platform `TextEncoder`, not from codec's `encodeUTF8`, and that is a
782
+ * ruling rather than an oversight. `TextEncoder` is total: it spells ill-formed text — a lone
783
+ * surrogate, which has no UTF-8 spelling — with the replacement character, so this function
784
+ * answers a `string` for every input. `encodeUTF8` refuses that text with `undefined`, which
785
+ * would widen this return to `string | undefined` and oblige every header projection to handle
786
+ * a value it cannot send. The decode side carries no such tension, so it reads back through
787
+ * codec's strict `decodeUTF8`.
788
+ *
789
+ * @param value - The value the header must carry
790
+ * @returns The literal value, or its Base64 sentinel form
791
+ *
792
+ * @example
793
+ * ```ts
794
+ * encodeSentinel('search') // 'search'
795
+ * encodeSentinel('café') // '=?base64?Y2Fmw6k=?='
796
+ * ```
797
+ */
798
+ export declare function encodeSentinel(value: string): string;
799
+
599
800
  /**
600
801
  * Concatenates an MCP tool-call result's text content blocks into one string.
601
802
  *
@@ -616,6 +817,56 @@ export declare const EMPTY_MCP_ARGUMENTS: Readonly<Record<string, unknown>>;
616
817
  */
617
818
  export declare function extractContentText(result: unknown): string;
618
819
 
820
+ /**
821
+ * Reads every `x-mcp-header` annotation reachable from a schema node through `properties`.
822
+ *
823
+ * @remarks
824
+ * Reachability is the protocol's own rule: an annotation counts only where a chain of
825
+ * `properties` keys leads to it from the `inputSchema` root, so `path` is both the schema
826
+ * position and the position the call's `arguments` carry the value at. A property named
827
+ * `items` is reachable like any other, because the chain is read by key POSITION rather than
828
+ * by key name.
829
+ *
830
+ * `undefined` means the definition is invalid rather than empty: a reachable annotation whose
831
+ * value is not an {@link import('./validators.js').isFieldToken} token, one sitting on the
832
+ * schema ROOT (which is no property), one on a leaf whose declared type is not an
833
+ * {@link import('./validators.js').isMCPHeaderPrimitive} primitive, or a chain deeper than
834
+ * `DEFAULT_MCP_LIMITS.depth` — which is also what makes a self-referential schema terminate.
835
+ * A node that is not a record carries nothing and answers an empty list, because a leaf the
836
+ * walk cannot read is not a violation.
837
+ *
838
+ * @param schema - The schema node to read
839
+ * @param path - The `properties` keys already traversed; the root is called with `[]`
840
+ * @returns The annotations reachable from this node, or `undefined` when one is invalid
841
+ *
842
+ * @example
843
+ * ```ts
844
+ * extractHeaderAnnotations({ properties: { region: { type: 'string', 'x-mcp-header': 'Region' } } }, [])
845
+ * // → [{ name: 'Region', path: ['region'], primitive: 'string' }]
846
+ * ```
847
+ */
848
+ export declare function extractHeaderAnnotations(schema: unknown, path: readonly string[]): readonly MCPHeaderParameter[] | undefined;
849
+
850
+ /**
851
+ * Reads one named tool's advertised `inputSchema` out of a `tools/list` answer.
852
+ *
853
+ * @remarks
854
+ * The answer is read as foreign data end to end — a dispatched response, an error envelope,
855
+ * and a result whose `tools` member is absent or is not an array all read as "no schema"
856
+ * rather than as a fault. That is what lets the HTTP POST handler ask its own dispatcher
857
+ * which `Mcp-Param-*` names a `tools/call` may carry without narrowing anything first.
858
+ *
859
+ * @param response - The `tools/list` answer, normally a {@link JSONRPCResponse}
860
+ * @param name - The tool whose schema to read
861
+ * @returns The advertised `inputSchema`, or `undefined` when the answer carries none
862
+ *
863
+ * @example
864
+ * ```ts
865
+ * extractToolSchema(answer, 'search')?.['properties']
866
+ * ```
867
+ */
868
+ export declare function extractToolSchema(response: unknown, name: string): Readonly<Record<string, unknown>> | undefined;
869
+
619
870
  /**
620
871
  * Infers the wire era for an MCP protocol revision.
621
872
  *
@@ -758,6 +1009,27 @@ export declare function isBoundedString(value: unknown, bytes: number): value is
758
1009
  */
759
1010
  export declare function isElicitContent(value: unknown, schema: unknown): value is Readonly<Record<string, MCPElicitValue>>;
760
1011
 
1012
+ /**
1013
+ * Determines whether a value is one RFC 9110 field token.
1014
+ *
1015
+ * @remarks
1016
+ * A token is one or more `tchar`: the ASCII letters, the digits, and
1017
+ * ``!#$%&'*+-.^_`|~``. That set already excludes the empty string, whitespace, a colon, a
1018
+ * control character, and every non-ASCII code point, so it is the whole constraint an
1019
+ * `x-mcp-header` annotation's value must satisfy — the value is appended verbatim to
1020
+ * {@link MCP_PARAM_PREFIX} and must survive as an HTTP field name.
1021
+ *
1022
+ * @param value - The unknown value to inspect
1023
+ * @returns Whether the value is a non-empty RFC 9110 token
1024
+ *
1025
+ * @example
1026
+ * ```ts
1027
+ * isFieldToken('Region') // true
1028
+ * isFieldToken('My Region') // false
1029
+ * ```
1030
+ */
1031
+ export declare function isFieldToken(value: unknown): value is string;
1032
+
761
1033
  /**
762
1034
  * Determines whether a client capability record declares form-mode elicitation.
763
1035
  *
@@ -1144,6 +1416,25 @@ export declare function isMCPElicitURL(value: unknown): value is MCPElicitURL;
1144
1416
  */
1145
1417
  export declare function isMCPError(value: unknown): value is MCPError;
1146
1418
 
1419
+ /**
1420
+ * Determines whether a value is a JSON Schema type an `x-mcp-header` annotation may sit on.
1421
+ *
1422
+ * @remarks
1423
+ * `number` is refused deliberately: a JSON number has no interoperable decimal text form, so
1424
+ * a header carrying one could not be compared with the body byte for byte. `integer` renders
1425
+ * exactly, and the server compares it numerically.
1426
+ *
1427
+ * @param value - The unknown value to inspect
1428
+ * @returns Whether the value is one of `'string'`, `'integer'`, or `'boolean'`
1429
+ *
1430
+ * @example
1431
+ * ```ts
1432
+ * isMCPHeaderPrimitive('integer') // true
1433
+ * isMCPHeaderPrimitive('number') // false
1434
+ * ```
1435
+ */
1436
+ export declare function isMCPHeaderPrimitive(value: unknown): value is MCPHeaderPrimitive;
1437
+
1147
1438
  /**
1148
1439
  * Determines whether a value is one exact dated-schema MCP icon.
1149
1440
  *
@@ -1159,7 +1450,7 @@ export declare function isMCPIdentity(value: unknown): value is MCPIdentity;
1159
1450
  * Determines whether a value is one legal embedded multi-round-trip request.
1160
1451
  *
1161
1452
  * @param value - The unknown value to inspect
1162
- * @returns `true` for elicitation, deprecated sampling, or deprecated roots requests
1453
+ * @returns `true` for an embedded elicitation, sampling, or roots request
1163
1454
  *
1164
1455
  * @example
1165
1456
  * ```ts
@@ -1169,7 +1460,7 @@ export declare function isMCPIdentity(value: unknown): value is MCPIdentity;
1169
1460
  export declare function isMCPInputRequest(value: unknown): value is MCPInputRequest;
1170
1461
 
1171
1462
  /**
1172
- * Determines whether a value is a server-keyed map of embedded input requests.
1463
+ * Determines whether a value is a consumer-keyed map of embedded input requests.
1173
1464
  *
1174
1465
  * @param value - The unknown value to inspect
1175
1466
  * @returns `true` when every own value is a legal {@link MCPInputRequest}
@@ -1181,6 +1472,30 @@ export declare function isMCPInputRequest(value: unknown): value is MCPInputRequ
1181
1472
  */
1182
1473
  export declare function isMCPInputRequestMap(value: unknown): value is MCPInputRequestMap;
1183
1474
 
1475
+ /**
1476
+ * Determines whether a response answers the exact embedded request that was issued.
1477
+ *
1478
+ * @remarks
1479
+ * A response carries no `method` of its own, so the ISSUED request selects which arm applies
1480
+ * — the same way {@link isElicitContent} takes the issued schema rather than trusting the
1481
+ * content to describe itself. A form elicitation is checked twice: once for the response
1482
+ * shape and once, on `accept`, for the content against the schema that round issued. A
1483
+ * URL-mode elicitation issues no schema, so only the shape is checked. A request this
1484
+ * package cannot recognize admits NOTHING, because an unrecognized question has no correct
1485
+ * answer. Total over hostile responses and hostile requests alike.
1486
+ *
1487
+ * @param value - The client's answer to check
1488
+ * @param request - The exact {@link MCPInputRequest} that was issued under the same key
1489
+ * @returns `true` when the answer is legal for that request
1490
+ *
1491
+ * @example
1492
+ * ```ts
1493
+ * isMCPInputResponse({ roots: [] }, { method: 'roots/list' }) // true
1494
+ * isMCPInputResponse({ roots: [] }, { method: 'sampling/createMessage', params: {} }) // false
1495
+ * ```
1496
+ */
1497
+ export declare function isMCPInputResponse(value: unknown, request: unknown): value is MCPInputResponse;
1498
+
1184
1499
  /**
1185
1500
  * Determines whether a value is an MCP input-required result.
1186
1501
  *
@@ -1391,6 +1706,95 @@ export declare function isMCPResult(value: unknown): value is MCPResult;
1391
1706
  /** Determines whether a value is exact result metadata with a valid reserved server identity. */
1392
1707
  export declare function isMCPResultMetaObject(value: unknown): value is MCPResultMetaObject;
1393
1708
 
1709
+ /**
1710
+ * Determines whether a value is one filesystem root a client exposes.
1711
+ *
1712
+ * @remarks
1713
+ * The dated schema declares `uri` with `format: uri`, so this applies the same RFC 3986
1714
+ * check {@link isAbsoluteURI} gives every other `format: uri` field the package validates,
1715
+ * including a URL-mode elicitation's `url`. Total over hostile input.
1716
+ *
1717
+ * @param value - The unknown value to inspect
1718
+ * @returns `true` when `value` carries an absolute `uri` and an optional string `name`
1719
+ *
1720
+ * @example
1721
+ * ```ts
1722
+ * isMCPRoot({ uri: 'file:///workspace', name: 'workspace' }) // true
1723
+ * isMCPRoot({ uri: 'workspace' }) // false — the schema declares `format: uri`
1724
+ * ```
1725
+ */
1726
+ export declare function isMCPRoot(value: unknown): value is MCPRoot;
1727
+
1728
+ /**
1729
+ * Determines whether a value is one client answer to an embedded `roots/list` request.
1730
+ *
1731
+ * @remarks
1732
+ * The dated schema requires the `roots` array, and each root is checked by
1733
+ * {@link isMCPRoot}. Total over hostile input.
1734
+ *
1735
+ * @param value - The unknown value to inspect
1736
+ * @returns `true` when `value` carries an array of valid roots
1737
+ *
1738
+ * @example
1739
+ * ```ts
1740
+ * isMCPRootResult({ roots: [{ uri: 'file:///workspace' }] }) // true
1741
+ * isMCPRootResult({ roots: {} }) // false — the schema requires an array
1742
+ * ```
1743
+ */
1744
+ export declare function isMCPRootResult(value: unknown): value is MCPRootResult;
1745
+
1746
+ /**
1747
+ * Determines whether a value is one block a sampling completion may carry.
1748
+ *
1749
+ * @remarks
1750
+ * The schema's `SamplingMessageContentBlock`: the text, image, and audio blocks
1751
+ * {@link isMCPContent} also admits, plus `tool_use` and `tool_result`. The resource arms of
1752
+ * {@link isMCPContent} are refused, because the schema leaves them out of a sampling
1753
+ * completion. A `tool_result` carries ordinary {@link isMCPContent} blocks and an open
1754
+ * `structuredContent`, which the schema constrains to no shape at all. Total over hostile
1755
+ * input.
1756
+ *
1757
+ * @param value - The unknown value to inspect
1758
+ * @returns `true` when `value` is one legal sampling content block
1759
+ *
1760
+ * @example
1761
+ * ```ts
1762
+ * isMCPSampleContent({ type: 'text', text: 'Paris' }) // true
1763
+ * isMCPSampleContent({ type: 'tool_use', id: 'c1', name: 'lookup', input: {} }) // true
1764
+ * isMCPSampleContent({ type: 'resource_link', name: 'doc', uri: 'file:///doc' }) // false
1765
+ * ```
1766
+ */
1767
+ export declare function isMCPSampleContent(value: unknown): value is MCPSampleContent;
1768
+
1769
+ /**
1770
+ * Determines whether a value is one client answer to an embedded sampling request.
1771
+ *
1772
+ * @remarks
1773
+ * The schema's `CreateMessageResult` types `content` as an `anyOf` over one
1774
+ * {@link isMCPSampleContent} block or an ARRAY of them, so both are admitted here: a
1775
+ * tool-using model answers with `tool_use` and `tool_result` blocks, and a model answering in
1776
+ * several parts answers with the array. `stopReason` stays an open string because the schema
1777
+ * names four values and permits any other a provider reports. Total over hostile input.
1778
+ *
1779
+ * @param value - The unknown value to inspect
1780
+ * @returns `true` when `value` has the sampling-completion shape
1781
+ *
1782
+ * @example
1783
+ * ```ts
1784
+ * isMCPSampleResult({
1785
+ * role: 'assistant',
1786
+ * content: { type: 'text', text: 'Paris' },
1787
+ * model: 'test-model',
1788
+ * }) // true
1789
+ * isMCPSampleResult({
1790
+ * role: 'assistant',
1791
+ * content: [{ type: 'text', text: 'Paris' }],
1792
+ * model: 'test-model',
1793
+ * }) // true
1794
+ * ```
1795
+ */
1796
+ export declare function isMCPSampleResult(value: unknown): value is MCPSampleResult;
1797
+
1394
1798
  /** Determines whether a value is one exact open dated server-capability declaration. */
1395
1799
  export declare function isMCPServerCapabilities(value: unknown): value is MCPServerCapabilities;
1396
1800
 
@@ -1903,9 +2307,36 @@ export declare const MCP_FALLBACK_VERSION: MCPLegacyVersion;
1903
2307
  */
1904
2308
  export declare const MCP_HANDSHAKE_VERSION: MCPLegacyVersion;
1905
2309
 
2310
+ /**
2311
+ * The tool-schema annotation key naming the header one parameter projects into.
2312
+ *
2313
+ * @remarks
2314
+ * It is valid ONLY on a primitive property schema statically reachable from the `inputSchema`
2315
+ * root through `properties` keys alone. An occurrence anywhere else — under `items`, a
2316
+ * composition or conditional keyword, or a `$ref` target — makes the whole tool definition
2317
+ * invalid, which is what {@link import('@orkestrel/mcp').buildHeaderParameters} decides.
2318
+ */
2319
+ export declare const MCP_HEADER_ANNOTATION = "x-mcp-header";
2320
+
1906
2321
  /** MCP reserved error: required HTTP metadata does not match the request body. */
1907
2322
  export declare const MCP_HEADER_MISMATCH = -32020;
1908
2323
 
2324
+ /**
2325
+ * The `tools/list` pages one modern `tools/call` walks to reach its own annotations.
2326
+ *
2327
+ * @remarks
2328
+ * The HTTP POST handler reads a called tool's {@link MCP_HEADER_ANNOTATION} annotations by
2329
+ * dispatching `tools/list` fresh on every `tools/call`, following `nextCursor` until the
2330
+ * named tool is found or the answer carries no cursor. The walk is bounded because its cost
2331
+ * is paid per call: at a page size of 100 this bound reaches 800 definitions, and a consumer
2332
+ * whose replacement `tools/list` pages more finely than that pays the extra dispatches on
2333
+ * every call it serves. The built-in listing answers the whole registry on one page and
2334
+ * never reaches the second. A definition further in than the walk reaches reads as no
2335
+ * definition, so its {@link MCP_PARAM_PREFIX} headers are forwarded untouched — the same
2336
+ * answer a name no served definition annotates receives.
2337
+ */
2338
+ export declare const MCP_LOOKUP_PAGES = 8;
2339
+
1909
2340
  /** Reserved modern `_meta` key carrying the client's open capability record. */
1910
2341
  export declare const MCP_META_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
1911
2342
 
@@ -1939,6 +2370,31 @@ export declare const MCP_MISSING_CAPABILITY = -32021;
1939
2370
  /** The modern revision offered by an unpinned client during discovery. */
1940
2371
  export declare const MCP_MODERN_VERSION: MCPModernVersion;
1941
2372
 
2373
+ /**
2374
+ * The request-header prefix an `x-mcp-header` annotation projects a tool argument onto.
2375
+ *
2376
+ * @remarks
2377
+ * The full field name is this prefix followed by the annotation's own value verbatim, so
2378
+ * `x-mcp-header: 'Region'` becomes `Mcp-Param-Region`. HTTP field names are case-insensitive,
2379
+ * which is why {@link MCP_HEADER_ANNOTATION} values are unique case-insensitively within one
2380
+ * `inputSchema`.
2381
+ */
2382
+ export declare const MCP_PARAM_PREFIX = "Mcp-Param-";
2383
+
2384
+ /**
2385
+ * The opening marker of the Base64 sentinel a standard MCP header value travels in.
2386
+ *
2387
+ * @remarks
2388
+ * The markers are LOWERCASE and exact, and this constant with {@link MCP_SENTINEL_SUFFIX} is
2389
+ * their ONE spelling in this package: {@link import('@orkestrel/mcp').encodeSentinel} builds a
2390
+ * sentinel from them and {@link import('@orkestrel/mcp').decodeSentinel} recognizes one by
2391
+ * them, so the two directions cannot drift apart.
2392
+ */
2393
+ export declare const MCP_SENTINEL_PREFIX = "=?base64?";
2394
+
2395
+ /** The closing marker of the Base64 sentinel a standard MCP header value travels in. */
2396
+ export declare const MCP_SENTINEL_SUFFIX = "?=";
2397
+
1942
2398
  /** MCP reserved error: a request names an unsupported protocol revision. */
1943
2399
  export declare const MCP_UNSUPPORTED_VERSION = -32022;
1944
2400
 
@@ -1980,10 +2436,11 @@ export declare interface MCPBlobResource {
1980
2436
  * - `progress` receives each `notifications/progress` frame the peer publishes for this
1981
2437
  * request. Supplying it is what stamps the request's progress token, so a peer only
1982
2438
  * reports where a caller is listening.
1983
- * - `input` carries one input-required retry. Its `state` and `responses` leaves are
1984
- * required together. The retry must repeat the original `name` and byte-identical
1985
- * `arguments`; the client maps the leaves to the top-level `requestState` and
1986
- * `inputResponses` parameters.
2439
+ * - `input` carries one input-required retry. `responses` is required; `state` is optional
2440
+ * because a peer may issue a round with no `requestState` to return, and the client sends
2441
+ * the `requestState` parameter exactly when a state is supplied. The retry must repeat the
2442
+ * original `name` and byte-identical `arguments`; the client maps the leaves to the
2443
+ * top-level `requestState` and `inputResponses` parameters.
1987
2444
  *
1988
2445
  * No option survives the call: the continuation data is placed only on that request, and when
1989
2446
  * the request settles — answered, refused, timed out, aborted, or drained by a `disconnect` —
@@ -1994,9 +2451,9 @@ export declare interface MCPCallOptions {
1994
2451
  readonly signal?: AbortSignal;
1995
2452
  /** Receives this request's progress frames; supplying it stamps the progress token. */
1996
2453
  readonly progress?: MCPProgressHandler;
1997
- /** Carries the protected state and responses for one input-required retry. */
2454
+ /** Carries the responses, and any protected state, for one input-required retry. */
1998
2455
  readonly input?: {
1999
- readonly state: string;
2456
+ readonly state?: string;
2000
2457
  readonly responses: Readonly<Record<string, unknown>>;
2001
2458
  };
2002
2459
  }
@@ -2660,12 +3117,6 @@ export declare interface MCPDispatchOptions {
2660
3117
  readonly caller?: unknown;
2661
3118
  }
2662
3119
 
2663
- /** One consumer-requested form elicitation, before MCP assigns its map key and signs state. */
2664
- export declare interface MCPElicitation {
2665
- readonly request: MCPElicitForm;
2666
- readonly state?: JSONValue;
2667
- }
2668
-
2669
3120
  /** One titled value in a form elicitation's single- or multi-select schema. */
2670
3121
  export declare interface MCPElicitChoice {
2671
3122
  readonly const: string;
@@ -2837,6 +3288,34 @@ export declare interface MCPExecutionContext {
2837
3288
  /** Executes one canonical tool call or return a fully formed complete MCP result. */
2838
3289
  export declare type MCPExecutionHandler = (context: MCPExecutionContext) => ToolResult | MCPCallResult | Promise<ToolResult | MCPCallResult>;
2839
3290
 
3291
+ /**
3292
+ * One `x-mcp-header` projection a tool's `inputSchema` declares.
3293
+ *
3294
+ * @remarks
3295
+ * - `name` — the annotation's own value, appended verbatim to {@link MCP_PARAM_PREFIX} to
3296
+ * form the request field name.
3297
+ * - `path` — the `properties` keys leading from the `inputSchema` root to the annotated
3298
+ * leaf, which is also the path the call's `arguments` carry the value at.
3299
+ * - `primitive` — the leaf's declared type, which fixes the value's text rendering and, for
3300
+ * `integer`, makes the server's comparison numeric rather than textual.
3301
+ */
3302
+ export declare interface MCPHeaderParameter {
3303
+ readonly name: string;
3304
+ readonly path: readonly string[];
3305
+ readonly primitive: MCPHeaderPrimitive;
3306
+ }
3307
+
3308
+ /**
3309
+ * The JSON Schema types an `x-mcp-header` annotation may sit on.
3310
+ *
3311
+ * @remarks
3312
+ * The protocol admits primitives alone, and it splits the JSON Schema number tower: `integer`
3313
+ * carries a decimal rendering an HTTP field can hold exactly, while `number` has no
3314
+ * interoperable text form and is refused. `object`, `array`, and `null` are refused for the
3315
+ * same reason — a header field carries text, not structure.
3316
+ */
3317
+ export declare type MCPHeaderPrimitive = 'boolean' | 'integer' | 'string';
3318
+
2840
3319
  /** One sized, themed icon associated with an MCP resource link. */
2841
3320
  export declare type MCPIcon = MCPMetaObject & {
2842
3321
  readonly src: string;
@@ -2869,18 +3348,19 @@ export declare interface MCPInputContext {
2869
3348
  readonly request: JSONRPCRequest;
2870
3349
  readonly name: string;
2871
3350
  readonly arguments: Readonly<Record<string, unknown>>;
2872
- readonly response?: MCPElicitResult;
3351
+ /** Every verified answer to the previous round, under the keys that round assigned. */
3352
+ readonly responses?: MCPInputResponseMap;
2873
3353
  readonly state?: JSONValue;
2874
3354
  }
2875
3355
 
2876
3356
  /**
2877
- * Decides whether the current `tools/call` needs operator input.
3357
+ * Decides whether the current `tools/call` still needs input from the client.
2878
3358
  *
2879
- * @param context - The original call plus a verified response/state on a retry
3359
+ * @param context - The original call plus every verified answer and state on a retry
2880
3360
  * @param options - The resolved per-request method options
2881
- * @returns A form elicitation to send, or `undefined` to continue into the tool registry
3361
+ * @returns The next round to send, or `undefined` to continue into the tool registry
2882
3362
  */
2883
- export declare type MCPInputHandler = (context: MCPInputContext, options: MCPMethodOptions) => MCPElicitation | undefined | Promise<MCPElicitation | undefined>;
3363
+ export declare type MCPInputHandler = (context: MCPInputContext, options: MCPMethodOptions) => MCPInputRound | undefined | Promise<MCPInputRound | undefined>;
2884
3364
 
2885
3365
  /** Consumer policy for the server's multi-round-trip input mechanism. */
2886
3366
  export declare interface MCPInputOptions {
@@ -2890,17 +3370,19 @@ export declare interface MCPInputOptions {
2890
3370
  readonly ttl: number;
2891
3371
  /** Resolves the authenticated principal for the call in hand. */
2892
3372
  readonly principal: MCPPrincipalHandler;
2893
- /** Decides whether the call needs a form elicitation, including on verified retries. */
2894
- readonly elicit: MCPInputHandler;
3373
+ /** Composes the next round of input requests, including on verified retries. */
3374
+ readonly selector: MCPInputHandler;
2895
3375
  }
2896
3376
 
2897
3377
  /**
2898
3378
  * One embedded multi-round-trip request.
2899
3379
  *
2900
3380
  * @remarks
2901
- * This package produces only {@link MCPElicitRequest}. The deprecated sampling and roots
2902
- * requests remain legal protocol union members and therefore retain their open parameter
2903
- * records here without gaining package-owned producers.
3381
+ * A consumer composes any of the three arms into an {@link MCPInputRound}, and this server
3382
+ * issues whichever arms that round carries. The elicitation arm is fully typed because this
3383
+ * package issues its schema and enforces the answer against it. The sampling and roots arms
3384
+ * keep OPEN parameter records: the dated schema leaves their request bodies to the caller, and
3385
+ * narrowing them here would refuse parameters the protocol permits.
2904
3386
  */
2905
3387
  export declare type MCPInputRequest = MCPElicitRequest | {
2906
3388
  readonly method: 'sampling/createMessage';
@@ -2910,9 +3392,24 @@ export declare type MCPInputRequest = MCPElicitRequest | {
2910
3392
  readonly params?: Readonly<Record<string, unknown>>;
2911
3393
  };
2912
3394
 
2913
- /** A server-keyed map of embedded requests the client must fulfil. */
3395
+ /** A consumer-keyed map of embedded requests the client must fulfil. */
2914
3396
  export declare type MCPInputRequestMap = Readonly<Record<string, MCPInputRequest>>;
2915
3397
 
3398
+ /**
3399
+ * One client answer to one embedded input request.
3400
+ *
3401
+ * @remarks
3402
+ * The arms are discriminated by their own required members — `action` for an elicitation,
3403
+ * `roots` for a roots listing, and `model` beside `role` for a sampling completion — because
3404
+ * the protocol gives a response no `method` of its own. The server knows which arm applies
3405
+ * from the request it ISSUED under that key, so {@link MCPInputHandler} receives every answer
3406
+ * already checked against the question it answers.
3407
+ */
3408
+ export declare type MCPInputResponse = MCPElicitResult | MCPSampleResult | MCPRootResult;
3409
+
3410
+ /** A consumer-keyed map of the client's answers to one issued round. */
3411
+ export declare type MCPInputResponseMap = Readonly<Record<string, MCPInputResponse>>;
3412
+
2916
3413
  /**
2917
3414
  * An incomplete modern result carrying input requests, protected request state, or both.
2918
3415
  *
@@ -2932,16 +3429,30 @@ export declare type MCPInputResult = {
2932
3429
  readonly _meta?: MCPResultMetaObject;
2933
3430
  };
2934
3431
 
3432
+ /**
3433
+ * One consumer-composed round of embedded requests, before MCP seals its continuation state.
3434
+ *
3435
+ * @remarks
3436
+ * The consumer owns the keys and the request kinds, because the keys are how it correlates
3437
+ * each answer and the kinds are what its own policy needs. MCP owns everything protective
3438
+ * around the round: the capability gate, the seal, the expiry, and the per-answer check on
3439
+ * the retry.
3440
+ */
3441
+ export declare interface MCPInputRound {
3442
+ readonly requests: MCPInputRequestMap;
3443
+ readonly state?: JSONValue;
3444
+ }
3445
+
2935
3446
  /**
2936
3447
  * The integrity-protected payload carried inside an opaque `requestState` token.
2937
3448
  *
2938
3449
  * @remarks
2939
3450
  * `id` is the FIRST round's request id and stays bound across every later round, so a
2940
3451
  * multi-round exchange remains one correlated call rather than a chain whose origin is lost
2941
- * after the second hop. `schema` is the EXACT schema that was issued with the round it
2942
- * protects: a schema that is bound but never enforced buys nothing, so an accepted response
2943
- * is checked against this member by {@link isElicitContent} before the tool runs. `key`,
2944
- * `expiry`, and `schema` are re-minted every round; `principal`, `id`, `version`, `method`,
3452
+ * after the second hop. `requests` is the EXACT round that was issued: it carries the keys the
3453
+ * retry must answer and, for a form elicitation, the schema {@link isElicitContent} enforces
3454
+ * an accepted answer against a round that is bound but never enforced buys nothing.
3455
+ * `requests` and `expiry` are re-minted every round; `principal`, `id`, `version`, `method`,
2945
3456
  * `name`, and `digest` are the bindings that must not move.
2946
3457
  */
2947
3458
  export declare interface MCPInputState {
@@ -2950,11 +3461,10 @@ export declare interface MCPInputState {
2950
3461
  readonly id: JSONRPCId;
2951
3462
  readonly version: string;
2952
3463
  readonly method: string;
2953
- readonly key: string;
3464
+ /** The exact round issued under this state, enforced answer by answer on the retry. */
3465
+ readonly requests: MCPInputRequestMap;
2954
3466
  readonly name: string;
2955
3467
  readonly digest: string;
2956
- /** The exact schema issued with this round, enforced on the accepted response. */
2957
- readonly schema: MCPElicitSchema;
2958
3468
  readonly state?: JSONValue;
2959
3469
  }
2960
3470
 
@@ -3097,7 +3607,10 @@ export declare interface MCPLimitOptions {
3097
3607
  readonly message?: number;
3098
3608
  /** Maximum serialized UTF-8 bytes accepted in one `_meta` value. */
3099
3609
  readonly metadata?: number;
3100
- /** Maximum total enumerable keys accepted across one `_meta` value. */
3610
+ /**
3611
+ * Maximum total enumerable keys accepted in one bounded value: one `_meta` value under
3612
+ * `metadata`, and one produced tool-call result under `content`.
3613
+ */
3101
3614
  readonly keys?: number;
3102
3615
  /** Maximum UTF-8 bytes accepted in one protected `requestState`. */
3103
3616
  readonly state?: number;
@@ -3247,7 +3760,7 @@ export declare interface MCPMethodManagerInterface {
3247
3760
  * The mirror of {@link MCPDispatchOptions} on the far side of dispatch: a CALLER may
3248
3761
  * have no signal to offer, but a dispatched method always has one to observe, so
3249
3762
  * `signal` is REQUIRED here. Dispatch resolves it once, at the single ingress, and
3250
- * supplies the same value to every handler, elicitation, principal, and subscription
3763
+ * supplies the same value to every handler, input, principal, and subscription
3251
3764
  * producer the request reaches — none of them may reinvent a cancellation source or
3252
3765
  * treat absence as a case.
3253
3766
  *
@@ -3700,6 +4213,49 @@ export declare type MCPResultMetaObject = MCPMetaObject & {
3700
4213
  /** The intended recipient of annotated MCP content. */
3701
4214
  export declare type MCPRole = 'user' | 'assistant';
3702
4215
 
4216
+ /** One filesystem root a client exposes to a server. */
4217
+ export declare interface MCPRoot {
4218
+ readonly uri: string;
4219
+ readonly name?: string;
4220
+ readonly _meta?: MCPMetaObject;
4221
+ }
4222
+
4223
+ /** The client's answer to one embedded `roots/list` request. */
4224
+ export declare interface MCPRootResult {
4225
+ readonly roots: readonly MCPRoot[];
4226
+ readonly _meta?: MCPMetaObject;
4227
+ }
4228
+
4229
+ /**
4230
+ * One block a sampling completion may carry.
4231
+ *
4232
+ * @remarks
4233
+ * The dated schema's `SamplingMessageContentBlock`: the text, image, and audio blocks
4234
+ * {@link MCPContent} also admits, plus the two tool blocks a tool-using model produces. The
4235
+ * resource arms of {@link MCPContent} are deliberately absent — the schema leaves them out of
4236
+ * a sampling completion.
4237
+ */
4238
+ export declare type MCPSampleContent = MCPTextContent | MCPImageContent | MCPAudioContent | MCPToolUseContent | MCPToolResultContent;
4239
+
4240
+ /**
4241
+ * The client's answer to one embedded `sampling/createMessage` request.
4242
+ *
4243
+ * @remarks
4244
+ * `content` is the dated schema's own `anyOf`: one {@link MCPSampleContent} block, or an array
4245
+ * of them. A tool-using model answers with `tool_use` and `tool_result` blocks, and a model
4246
+ * answering in several parts answers with the array, so narrowing this to a single text, image,
4247
+ * or audio block would refuse completions the schema permits. `stopReason` is an open string
4248
+ * because the schema names `endTurn`, `stopSequence`, `maxTokens`, and `toolUse` while
4249
+ * permitting any other value a provider reports.
4250
+ */
4251
+ export declare interface MCPSampleResult {
4252
+ readonly role: 'user' | 'assistant';
4253
+ readonly content: MCPSampleContent | readonly MCPSampleContent[];
4254
+ readonly model: string;
4255
+ readonly stopReason?: string;
4256
+ readonly _meta?: MCPMetaObject;
4257
+ }
4258
+
3703
4259
  /**
3704
4260
  * A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0
3705
4261
  * requests over a live {@link ToolManagerInterface}, with NO transport coupling.
@@ -3791,6 +4347,15 @@ export declare type MCPServerEventMap = {
3791
4347
  * inbound traffic. Only SCALARS are reported: nothing read out of the request graph
3792
4348
  * escapes here, so a listener can never observe a value the ownership seam has not yet
3793
4349
  * bounded.
4350
+ *
4351
+ * Not every reported invocation arrived from a peer. A modern `tools/call` reaching the
4352
+ * HTTP POST handler (`createMCPPostHandler`) reports the SYNTHETIC `tools/list` that
4353
+ * handler dispatches to read the called tool's `x-mcp-header` annotations, ahead of the
4354
+ * call itself. Each carries the RESERVED id `0`, and one fires per page the handler
4355
+ * walks, up to {@link MCP_LOOKUP_PAGES}. So an observer accounting for inbound traffic
4356
+ * subtracts a `('tools/list', 0, 'modern')` that precedes a `tools/call`, and one
4357
+ * tracing the server's own work keeps it. The id is reserved by convention rather than
4358
+ * enforced: a peer sending its own `tools/list` under id `0` is not told apart here.
3794
4359
  */
3795
4360
  readonly request: readonly [method: string, id: JSONRPCId | undefined, era: MCPEra];
3796
4361
  /**
@@ -3972,6 +4537,11 @@ export declare interface MCPServerOptions {
3972
4537
  * completion even after the request that asked for it has ended, and abandons the result.
3973
4538
  * An {@link MCPExecutionHandler} receives `signal` on its {@link MCPExecutionContext} and
3974
4539
  * can stop the work itself.
4540
+ *
4541
+ * A handler returning a complete {@link MCPCallResult} is taken at its word: the server
4542
+ * bounds it and re-proves its shape, then sends what the handler composed. Nothing stamps
4543
+ * the `_meta` server identity `buildModernResult` puts on a normalized result, so a handler
4544
+ * whose peer reads that key composes it through `buildModernResult` itself.
3975
4545
  */
3976
4546
  readonly execution?: MCPExecutionHandler;
3977
4547
  /** Optional human guidance exposed by `server/discover`. */
@@ -4656,7 +5226,7 @@ export declare interface MCPTaskManagerInterface {
4656
5226
  * VERBATIM — it holds none of the task's keys, so the ignoring is this method's to do.
4657
5227
  *
4658
5228
  * This is the SECOND multi-round-trip mechanism in the package, and it is the weaker one.
4659
- * The elicitation path binds each round with a sealed `requestState`, an argument digest,
5229
+ * The built-in input path binds each round with a sealed `requestState`, an argument digest,
4660
5230
  * an absolute expiry, and the resolved principal; this path has none of them, because MCP
4661
5231
  * neither issued the question nor owns the channel it is answered on. Anything equivalent
4662
5232
  * has to live here: bind each published key to the principal that may answer it, expire
@@ -4958,6 +5528,25 @@ export declare interface MCPToolDescriptor {
4958
5528
  readonly inputSchema: Readonly<Record<string, unknown>>;
4959
5529
  }
4960
5530
 
5531
+ /** One tool's outcome returned to the model, carried inside a sampling completion. */
5532
+ export declare interface MCPToolResultContent {
5533
+ readonly type: 'tool_result';
5534
+ readonly toolUseId: string;
5535
+ readonly content: readonly MCPContent[];
5536
+ readonly isError?: boolean;
5537
+ readonly structuredContent?: JSONValue;
5538
+ readonly _meta?: MCPMetaObject;
5539
+ }
5540
+
5541
+ /** A model's request to call one tool, carried inside a sampling completion. */
5542
+ export declare interface MCPToolUseContent {
5543
+ readonly type: 'tool_use';
5544
+ readonly id: string;
5545
+ readonly name: string;
5546
+ readonly input: Readonly<Record<string, unknown>>;
5547
+ readonly _meta?: MCPMetaObject;
5548
+ }
5549
+
4961
5550
  /**
4962
5551
  * A duplex message channel an environment face provides to the pure engine — the
4963
5552
  * one port `bindServer` and `bindClient` (`./helpers.js`) pipe an
@@ -5104,17 +5693,18 @@ export declare function parseJSONRPCMessage(value: unknown, limits?: MCPJSONLimi
5104
5693
  * This parser does not open the opaque continuation carrier; the configured
5105
5694
  * continuation port performs that boundary first. The protected
5106
5695
  * payload binds the authenticated principal, absolute expiry, ORIGINAL request id, version,
5107
- * method, server-assigned key, tool name, argument digest, the exact issued elicitation
5108
- * schema, and optional application state. Every member is required except application state:
5109
- * a payload missing its schema cannot have its accepted response enforced, so it is refused
5110
- * rather than admitted unenforced. Total over malformed or hostile input.
5696
+ * method, the exact round that was issued, tool name, argument digest, and optional
5697
+ * application state. Every member is required except application state: a payload missing its
5698
+ * round cannot have the client's answers enforced, so it is refused rather than admitted
5699
+ * unenforced. An EMPTY round is refused for the same reason — a retry against it would answer
5700
+ * no question at all. Total over malformed or hostile input.
5111
5701
  *
5112
5702
  * @param value - The opened canonical continuation value to parse
5113
5703
  * @returns The protected input state, or `undefined` when malformed
5114
5704
  *
5115
5705
  * @example
5116
5706
  * ```ts
5117
- * parseMCPInputState('{"principal":"user-1","expiry":2000,"id":1,"version":"2026-07-28","method":"tools/call","key":"k","name":"reply","digest":"abc","schema":{"type":"object","properties":{}}}')
5707
+ * parseMCPInputState('{"principal":"user-1","expiry":2000,"id":1,"version":"2026-07-28","method":"tools/call","requests":{"k":{"method":"roots/list"}},"name":"reply","digest":"abc"}')
5118
5708
  * ```
5119
5709
  */
5120
5710
  export declare function parseMCPInputState(value: unknown): MCPInputState | undefined;
@@ -5161,6 +5751,29 @@ export declare function parseRequestContext(value: unknown, limits?: MCPJSONLimi
5161
5751
  */
5162
5752
  export declare function readCancelledId(message: JSONRPCMessage): JSONRPCId | undefined;
5163
5753
 
5754
+ /**
5755
+ * Renders one projected argument as the text its `Mcp-Param-*` header carries.
5756
+ *
5757
+ * @remarks
5758
+ * The protocol's conversion table, and the ONE place it is stated: a string travels as
5759
+ * itself, an integer in decimal, and a boolean as lowercase `true` or `false`. The value's
5760
+ * runtime shape must match the leaf's declared type, so a schema that declares `integer` and
5761
+ * an argument that supplies a string, a fraction, or a magnitude outside the IEEE 754 safe
5762
+ * range carries NOTHING — a header that cannot round-trip the body value is worse than an
5763
+ * absent one, and the tool's own argument validation owns the disagreement.
5764
+ *
5765
+ * @param value - The argument value read at the parameter's path
5766
+ * @param primitive - The leaf's declared type
5767
+ * @returns The header text, or `undefined` when the value cannot travel as that type
5768
+ *
5769
+ * @example
5770
+ * ```ts
5771
+ * renderHeaderValue(42, 'integer') // '42'
5772
+ * renderHeaderValue(false, 'boolean') // 'false'
5773
+ * ```
5774
+ */
5775
+ export declare function renderHeaderValue(value: unknown, primitive: MCPHeaderPrimitive): string | undefined;
5776
+
5164
5777
  /**
5165
5778
  * Pumps a controlled serialized exchange onto a transport — every notification in order, then
5166
5779
  * the terminating response — and END the exchange however the pump leaves.