@orkestrel/mcp 0.0.24 → 0.0.26

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.
@@ -318,9 +318,11 @@ export declare function buildSubscriptionAcknowledgement(notifications: MCPSubsc
318
318
  *
319
319
  * @param requested - The notification families requested by the client
320
320
  * @param supported - The notification families the server can actually produce
321
+ * @param enabled - If `true`, carries the requested task identifiers into the filter; if `false`,
322
+ * omits them. Default: `false`
321
323
  * @returns The exact subset the server will honour
322
324
  */
323
- export declare function buildSubscriptionFilter(requested: MCPSubscriptionFilter, supported: MCPSubscriptionFilter): MCPSubscriptionFilter;
325
+ export declare function buildSubscriptionFilter(requested: MCPSubscriptionFilter, supported: MCPSubscriptionFilter, enabled?: boolean): MCPSubscriptionFilter;
324
326
 
325
327
  /**
326
328
  * Builds the terminating response for a subscription source that closes gracefully.
@@ -395,13 +397,14 @@ export declare function createDuplexClientTransport(transport: MCPTransportInter
395
397
  /**
396
398
  * Creates a transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE
397
399
  * MCP server over an injected {@link import('./types.js').MCPClientTransportInterface},
398
- * runs the `initialize` handshake, and exposes the server's tools as local
400
+ * negotiates the modern revision through `server/discover`, and exposes the server's tools as local
399
401
  * {@link import('@orkestrel/tool').ToolInterface}s an agent can run.
400
402
  *
401
403
  * @remarks
402
404
  * The egress mirror of {@link createMCPServer}: where the server exposes a local tool
403
- * registry over MCP, the client USES a remote server's tools. `connect()` handshakes,
404
- * validates and exposes the negotiated protocol, `tools()` lists + wraps the remote
405
+ * registry over MCP, the client USES a remote server's tools. `connect()` discovers,
406
+ * validates, and exposes the negotiated modern protocol; a legacy peer requires
407
+ * {@link createMCPLegacyClientTransport}. `tools()` lists + wraps the remote
405
408
  * tools (each `execute` calls back over the wire),
406
409
  * and `call(name, args)` runs a remote `tools/call` (a remote tool failure throws
407
410
  * locally, so an agent's {@link import('@orkestrel/tool').ToolManagerInterface}
@@ -437,6 +440,23 @@ export declare function createMCPClient(options: MCPClientOptions): MCPClientInt
437
440
  */
438
441
  export declare function createMCPLegacy(server: MCPServerInterface): MCPDispatcherInterface;
439
442
 
443
+ /**
444
+ * Decorates one client transport with explicit legacy handshake and era translation.
445
+ *
446
+ * @param transport - The transport connected to a legacy MCP peer
447
+ * @param options - Optional legacy handshake identity, capabilities, revision, and deadline
448
+ * @returns A modern-facing client transport over the legacy peer
449
+ *
450
+ * @example
451
+ * ```ts
452
+ * const transport = createMCPLegacyClientTransport(legacyTransport)
453
+ * const client = createMCPClient({ transport })
454
+ * await client.connect()
455
+ * client.version // '2026-07-28'
456
+ * ```
457
+ */
458
+ export declare function createMCPLegacyClientTransport(transport: MCPClientTransportInterface, options?: MCPLegacyClientTransportOptions): MCPClientTransportInterface;
459
+
440
460
  /**
441
461
  * Creates a transport-agnostic Model Context Protocol server — exposes a live
442
462
  * {@link import('@orkestrel/tool').ToolManagerInterface} and an optional
@@ -548,6 +568,9 @@ export declare const DEFAULT_MCP_LIMITS: Readonly<{
548
568
  */
549
569
  export declare const DEFAULT_MCP_REQUEST_TIMEOUT = 30000;
550
570
 
571
+ /** The default number of subscription frames retained while no client read is parked. */
572
+ export declare const DEFAULT_MCP_SUBSCRIPTION_CAPACITY = 64;
573
+
551
574
  /**
552
575
  * Computes a lowercase host-neutral SHA-256 digest of one bounded canonical JSON value.
553
576
  *
@@ -596,9 +619,14 @@ export declare function extractContentText(result: unknown): string;
596
619
  /**
597
620
  * Infers the wire era for an MCP protocol revision.
598
621
  *
622
+ * @remarks
623
+ * The era is READ from the two era guards rather than restated here, so a revision added
624
+ * to {@link SUPPORTED_MODERN_PROTOCOL_VERSIONS} or {@link SUPPORTED_LEGACY_PROTOCOL_VERSIONS}
625
+ * carries its era with it and no third list can disagree with those two.
626
+ *
599
627
  * @param version - The protocol revision to classify
600
- * @returns `'modern'` for `2026-07-28`, `'legacy'` for either supported legacy
601
- * revision, or `undefined` when the revision is unsupported
628
+ * @returns `'modern'` for a revision a bare server accepts, `'legacy'` for a revision the
629
+ * optional decorator accepts, or `undefined` when the revision is unsupported
602
630
  */
603
631
  export declare function inferEra(version: string): MCPEra | undefined;
604
632
 
@@ -634,12 +662,12 @@ export declare function inferEra(version: string): MCPEra | undefined;
634
662
  export declare function inferRequestVersion(message: JSONRPCMessage): string | undefined;
635
663
 
636
664
  /**
637
- * Infers the newest supported protocol revision present in a peer's offer.
665
+ * Infers the newest supported modern protocol revision present in a peer's offer.
638
666
  *
639
667
  * @param offered - The protocol revisions offered by the peer
640
- * @returns The newest locally supported offered revision, or `undefined`
668
+ * @returns The newest locally supported modern revision, or `undefined`
641
669
  */
642
- export declare function inferVersion(offered: readonly string[]): MCPVersion | undefined;
670
+ export declare function inferVersion(offered: readonly string[]): MCPModernVersion | undefined;
643
671
 
644
672
  /**
645
673
  * Determines whether a value is one absolute URI under RFC 3986 syntax.
@@ -1190,6 +1218,14 @@ export declare function isMCPInputResult(value: unknown): value is MCPInputResul
1190
1218
  */
1191
1219
  export declare function isMCPLegacyResult(value: unknown): value is MCPLegacyResult;
1192
1220
 
1221
+ /**
1222
+ * Determines whether a value is a revision accepted by the optional legacy decorator.
1223
+ *
1224
+ * @param value - The unknown value to inspect
1225
+ * @returns `true` when the value is one of {@link SUPPORTED_LEGACY_PROTOCOL_VERSIONS}
1226
+ */
1227
+ export declare function isMCPLegacyVersion(value: unknown): value is MCPLegacyVersion;
1228
+
1193
1229
  /** Determines whether a value is one dated MCP logging level. */
1194
1230
  export declare function isMCPLoggingLevel(value: unknown): value is MCPLoggingLevel;
1195
1231
 
@@ -1199,6 +1235,35 @@ export declare function isMCPMetaKey(value: unknown): value is string;
1199
1235
  /** Determines whether a value is exact finite MCP metadata with valid keys. */
1200
1236
  export declare function isMCPMetaObject(value: unknown): value is MCPMetaObject;
1201
1237
 
1238
+ /**
1239
+ * Determines whether a value is a modern protocol revision accepted by a bare server.
1240
+ *
1241
+ * @param value - The unknown value to inspect
1242
+ * @returns `true` when the value is one of {@link SUPPORTED_MODERN_PROTOCOL_VERSIONS}
1243
+ */
1244
+ export declare function isMCPModernVersion(value: unknown): value is MCPModernVersion;
1245
+
1246
+ /**
1247
+ * Determines whether a value is exact notification metadata with a valid reserved
1248
+ * subscription id.
1249
+ *
1250
+ * @remarks
1251
+ * The reserved key is OPTIONAL, so a frame delivered outside a `subscriptions/listen`
1252
+ * stream passes with no stamp at all. When the key IS present its value must be a valid
1253
+ * {@link JSONRPCId}, because a stamp naming nothing addressable is worse than no stamp.
1254
+ *
1255
+ * @param value - The unknown value to inspect
1256
+ * @returns `true` when the value is exact metadata whose subscription stamp, if present, is valid
1257
+ *
1258
+ * @example
1259
+ * ```ts
1260
+ * isMCPNotificationMetaObject({}) // true — an unstamped frame carries no subscription
1261
+ * isMCPNotificationMetaObject({ 'io.modelcontextprotocol/subscriptionId': 7 }) // true
1262
+ * isMCPNotificationMetaObject({ 'io.modelcontextprotocol/subscriptionId': null }) // false
1263
+ * ```
1264
+ */
1265
+ export declare function isMCPNotificationMetaObject(value: unknown): value is MCPNotificationMetaObject;
1266
+
1202
1267
  /**
1203
1268
  * Determines whether a value carries the shared optional pagination cursor.
1204
1269
  *
@@ -1341,16 +1406,28 @@ export declare function isMCPStringArguments(value: unknown): value is Readonly<
1341
1406
  * Determines whether a value is an MCP {@link MCPSubscriptionFilter}.
1342
1407
  *
1343
1408
  * @remarks
1344
- * Every filter field is optional. Boolean notification families accept only booleans, and
1345
- * `resourceSubscriptions` accepts only an array of string URIs. Unknown fields remain open
1346
- * for protocol extensions and are ignored by the built-in subscription matcher. Total over
1347
- * hostile input.
1409
+ * Every filter field is optional. Boolean notification families accept only booleans,
1410
+ * `resourceSubscriptions` accepts only an array of string URIs, and `taskIds` accepts only
1411
+ * an array of string task identifiers. Unknown fields remain open for protocol extensions
1412
+ * and are ignored by the built-in subscription matcher. Total over hostile input.
1413
+ *
1414
+ * A malformed `taskIds` is refused here rather than dropped, so the listen request that
1415
+ * carried it fails outright instead of quietly agreeing to a narrower subscription than
1416
+ * the caller asked for.
1348
1417
  *
1349
1418
  * @param value - The unknown value to inspect
1350
1419
  * @returns `true` when every recognized filter field has its protocol shape
1351
1420
  */
1352
1421
  export declare function isMCPSubscriptionFilter(value: unknown): value is MCPSubscriptionFilter;
1353
1422
 
1423
+ /**
1424
+ * Determines whether a value is a graceful `subscriptions/listen` result.
1425
+ *
1426
+ * @param value - The unknown value to inspect
1427
+ * @returns `true` when the result is complete and carries a valid subscription id
1428
+ */
1429
+ export declare function isMCPSubscriptionResult(value: unknown): value is MCPSubscriptionResult;
1430
+
1354
1431
  /**
1355
1432
  * Determines whether a value is one durable task's full snapshot.
1356
1433
  *
@@ -1361,9 +1438,14 @@ export declare function isMCPSubscriptionFilter(value: unknown): value is MCPSub
1361
1438
  * the requests to answer, `completed` owns the deferred call's result, `failed` owns the
1362
1439
  * JSON-RPC error that ended it, and `working` / `cancelled` own nothing further.
1363
1440
  *
1364
- * Unrecognized members stay valid, because the extension is DRAFT and a manager tracking a
1365
- * later revision must not be refused by this one. What is checked is what this package
1366
- * publishes as the contract.
1441
+ * A `completed` task's `result` is checked as an OBJECT and no further. The schema declares
1442
+ * it an open record, so its contents belong to whichever method was deferred; a guard that
1443
+ * demanded a protocol result here would refuse payloads the extension permits.
1444
+ * `ttlMs` and `pollIntervalMs` are integer milliseconds, per the schema's `int` formats.
1445
+ *
1446
+ * Unrecognized members stay valid, because this guard reads a value a consumer's manager
1447
+ * produced, and a guard over a foreign contract enforces the published contract and no more.
1448
+ * What is checked is what this package publishes as the contract.
1367
1449
  *
1368
1450
  * @param value - The unknown value to inspect
1369
1451
  * @returns Whether the value is a well-formed {@link MCPTaskDetail}
@@ -1378,6 +1460,64 @@ export declare function isMCPSubscriptionFilter(value: unknown): value is MCPSub
1378
1460
  */
1379
1461
  export declare function isMCPTaskDetail(value: unknown): value is MCPTaskDetail;
1380
1462
 
1463
+ /**
1464
+ * Determines whether a value is the wire answer to `tasks/get`.
1465
+ *
1466
+ * @remarks
1467
+ * {@link isMCPTaskDetail} plus the stamp the METHOD owes. The schema types a `tasks/get`
1468
+ * reply as the detail intersected with the standard result, so `resultType: 'complete'` is
1469
+ * part of the answer rather than decoration on it — and an unstamped payload, or one
1470
+ * carrying the creation answer's `resultType: 'task'`, is a peer answering some other
1471
+ * shape. Use this guard wherever a `tasks/get` REPLY is read; use
1472
+ * {@link isMCPTaskDetail} wherever a consumer's manager answers directly.
1473
+ *
1474
+ * `_meta` is checked only when present, and only as result metadata: the server identity a
1475
+ * peer stamps there is the peer's to write.
1476
+ *
1477
+ * @param value - The unknown value to inspect
1478
+ * @returns Whether the value is a well-formed {@link MCPTaskDetailResult}
1479
+ *
1480
+ * @example
1481
+ * ```ts
1482
+ * isMCPTaskDetailResult({ resultType: 'complete', taskId: 'a', status: 'working',
1483
+ * createdAt: '', lastUpdatedAt: '', ttlMs: null }) // true
1484
+ * isMCPTaskDetailResult({ taskId: 'a', status: 'working', createdAt: '',
1485
+ * lastUpdatedAt: '', ttlMs: null }) // false — the reply owes its `resultType`
1486
+ * ```
1487
+ */
1488
+ export declare function isMCPTaskDetailResult(value: unknown): value is MCPTaskDetailResult;
1489
+
1490
+ /**
1491
+ * Determines whether a value is a `notifications/tasks` frame carrying a task snapshot.
1492
+ *
1493
+ * @remarks
1494
+ * The ADMISSION guard for a task transition: a subscription producer is consumer-written,
1495
+ * so the frame it hands over is foreign input, and this is what stands between a mutated
1496
+ * or half-built snapshot and a subscribed client. Both halves are checked — the method
1497
+ * literal the extension fixes, and params that hold together as an
1498
+ * {@link MCPTaskDetail} — because either alone admits a frame the other rejects.
1499
+ *
1500
+ * `_meta` is checked for SHAPE WHEN PRESENT and nothing more. The reserved subscription
1501
+ * stamp is the SERVER'S to write, after this guard admits the frame and the matcher agrees
1502
+ * to it, so a guard that demanded the stamp would refuse every frame a producer emits.
1503
+ *
1504
+ * @param value - The unknown value to inspect
1505
+ * @returns Whether the value is a well-formed `notifications/tasks` notification
1506
+ *
1507
+ * @example
1508
+ * ```ts
1509
+ * isMCPTaskNotification({ jsonrpc: '2.0', method: 'notifications/tasks',
1510
+ * params: { taskId: 'a', status: 'working', createdAt: '', lastUpdatedAt: '',
1511
+ * ttlMs: null } }) // true
1512
+ * isMCPTaskNotification({ jsonrpc: '2.0', method: 'notifications/tasks',
1513
+ * params: { taskId: 'a' } }) // false — the params owe a whole snapshot
1514
+ * ```
1515
+ */
1516
+ export declare function isMCPTaskNotification(value: unknown): value is JSONRPCNotification & {
1517
+ readonly method: 'notifications/tasks';
1518
+ readonly params: MCPTaskNotificationParams;
1519
+ };
1520
+
1381
1521
  /**
1382
1522
  * Determines whether a value is a modern MCP task-creation result.
1383
1523
  *
@@ -1386,7 +1526,8 @@ export declare function isMCPTaskDetail(value: unknown): value is MCPTaskDetail;
1386
1526
  * shape. The manager is consumer-supplied, so its types are a promise rather than a
1387
1527
  * proof: this is what stands between a manager that answers a numeric `taskId` and a
1388
1528
  * client that would receive one. `ttlMs` accepts `null` because the schema uses it to
1389
- * mean "no expiry", which is distinct from an absent field.
1529
+ * mean "no expiry", which is distinct from an absent field, and both durations must be
1530
+ * INTEGER milliseconds because the schema formats them `int`.
1390
1531
  *
1391
1532
  * @param value - The unknown value to inspect
1392
1533
  * @returns Whether the value is a well-formed `resultType: 'task'` result
@@ -1425,7 +1566,7 @@ export declare function isMCPTextResource(value: unknown): value is MCPTextResou
1425
1566
  * Determines whether a value is a supported {@link MCPVersion}.
1426
1567
  *
1427
1568
  * @param value - The unknown value to inspect
1428
- * @returns `true` when the value is one of {@link SUPPORTED_PROTOCOL_VERSIONS}
1569
+ * @returns `true` when the value is one of {@link SUPPORTED_MCP_VERSIONS}
1429
1570
  */
1430
1571
  export declare function isMCPVersion(value: unknown): value is MCPVersion;
1431
1572
 
@@ -1503,26 +1644,29 @@ export declare function isRFC3339DateTime(value: unknown): value is string;
1503
1644
  export declare function isStandardBase64(value: unknown): value is string;
1504
1645
 
1505
1646
  /**
1506
- * Determines whether a client capability record declares the draft Tasks extension.
1647
+ * Determines whether a client capability record declares the stable Tasks extension.
1507
1648
  *
1508
1649
  * @remarks
1509
- * The declaration lives at `extensions['io.modelcontextprotocol/tasks']` and its value is
1510
- * an empty object, so this is a PRESENCE check: the extension defines no options, and a
1511
- * server that read one would be reading a field no client can meaningfully set. The value
1512
- * must still be a record, because that is the shape the capability record declares a
1513
- * `true` or a string there is a client speaking a different protocol, not a shorthand.
1650
+ * The declaration lives at `extensions['io.modelcontextprotocol/tasks']` and the schema
1651
+ * types its value EXACTLY EMPTY `Record<string, never>`, an object with no additional
1652
+ * properties. So the key's presence is the whole declaration, and the value carries the
1653
+ * whole of the check: a `true` or a string there is a client speaking a different protocol
1654
+ * rather than a shorthand, and a member inside the object is a client declaring an option
1655
+ * this extension does not define. Both are refused, because a server that accepted either
1656
+ * would be reading a shape no peer can produce from the snapshot's own schema.
1514
1657
  *
1515
1658
  * A client declares this PER REQUEST. Nothing here consults a session, because the modern
1516
1659
  * revision is stateless and a capability declared once at connect time says nothing about
1517
1660
  * the request in hand. Total over hostile input.
1518
1661
  *
1519
1662
  * @param value - The client capability record to inspect
1520
- * @returns `true` when the tasks extension is declared
1663
+ * @returns `true` when the tasks extension is declared as the schema's empty object
1521
1664
  *
1522
1665
  * @example
1523
1666
  * ```ts
1524
1667
  * isTaskSupported({ extensions: { 'io.modelcontextprotocol/tasks': {} } }) // true
1525
1668
  * isTaskSupported({ extensions: {} }) // false — the key is the declaration
1669
+ * isTaskSupported({ extensions: { 'io.modelcontextprotocol/tasks': { on: true } } }) // false
1526
1670
  * ```
1527
1671
  */
1528
1672
  export declare function isTaskSupported(value: unknown): boolean;
@@ -1677,6 +1821,28 @@ export declare interface JSONRPCResultResponse {
1677
1821
  readonly error?: never;
1678
1822
  }
1679
1823
 
1824
+ /**
1825
+ * Stamps one legacy request for the modern dispatcher.
1826
+ *
1827
+ * @param request - The legacy request to translate
1828
+ * @returns A modern request carrying the package revision and an empty capability set
1829
+ */
1830
+ export declare function legacyInvocationToModern(request: JSONRPCRequest): JSONRPCRequest;
1831
+
1832
+ /**
1833
+ * Restores one legacy result to the modern complete-result shape.
1834
+ *
1835
+ * @remarks
1836
+ * Legacy `tools/list` results receive the required modern cache fields. Other legacy results are
1837
+ * non-cacheable. Every restored result receives the server identity learned during `initialize`.
1838
+ *
1839
+ * @param result - The unstamped legacy result
1840
+ * @param method - The request method whose result is being restored
1841
+ * @param identity - The server identity learned during the legacy handshake
1842
+ * @returns The modern complete result
1843
+ */
1844
+ export declare function legacyResultToModern(result: MCPLegacyResult, method: string, identity: MCPIdentity): MCPResult;
1845
+
1680
1846
  /**
1681
1847
  * Determines whether one method may answer with a given modern `resultType`.
1682
1848
  *
@@ -1713,22 +1879,33 @@ export declare function matchesResultType(method: string, resultType: unknown):
1713
1879
  export declare function matchesSubscriptionNotification(notification: JSONRPCNotification, filter: MCPSubscriptionFilter): boolean;
1714
1880
 
1715
1881
  /**
1716
- * The reserved extension key identifying the draft Tasks extension.
1882
+ * The reserved extension key identifying the stable Tasks extension.
1717
1883
  *
1718
1884
  * @remarks
1719
- * The ONE spelling of it in this package. A client declares it per REQUEST, under
1885
+ * The ONE spelling of it in this package, and the identity of the immutable snapshot dated
1886
+ * 2026-07-28 this package implements. A client declares it per REQUEST, under
1720
1887
  * `_meta['io.modelcontextprotocol/clientCapabilities'].extensions`; a server advertises it
1721
1888
  * under `server/discover`'s `capabilities.extensions`. Both sides carry an empty object —
1722
1889
  * the extension defines no options, so presence is the entire declaration.
1723
1890
  */
1724
1891
  export declare const MCP_EXTENSION_TASKS = "io.modelcontextprotocol/tasks";
1725
1892
 
1893
+ /** The older legacy revision the optional legacy decorator accepts and an adapter can pin. */
1894
+ export declare const MCP_FALLBACK_VERSION: MCPLegacyVersion;
1895
+
1896
+ /**
1897
+ * The revision offered and defaulted to in the legacy `initialize` handshake.
1898
+ *
1899
+ * @remarks
1900
+ * This is deliberately a legacy revision, and the newest one supported. 2026-07-28 is stateless
1901
+ * and defines no `initialize`, so it can never be the handshake's version — a client that offers
1902
+ * it is asking to negotiate a revision with no negotiation.
1903
+ */
1904
+ export declare const MCP_HANDSHAKE_VERSION: MCPLegacyVersion;
1905
+
1726
1906
  /** MCP reserved error: required HTTP metadata does not match the request body. */
1727
1907
  export declare const MCP_HEADER_MISMATCH = -32020;
1728
1908
 
1729
- /** The legacy fallback anchor used when an initialize request cannot be accepted as modern. */
1730
- export declare const MCP_LEGACY_VERSION: MCPVersion;
1731
-
1732
1909
  /** Reserved modern `_meta` key carrying the client's open capability record. */
1733
1910
  export declare const MCP_META_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
1734
1911
 
@@ -1754,23 +1931,13 @@ export declare const MCP_META_VERSION = "io.modelcontextprotocol/protocolVersion
1754
1931
  * `error.data.requiredCapabilities` alone (`{ elicitation: {} }` against
1755
1932
  * `{ extensions: { 'io.modelcontextprotocol/tasks': {} } }`). They are instances of the same
1756
1933
  * condition, so a separate numeral would describe the same fact twice. The Tasks extension's
1757
- * own draft prose still shows `-32003` in examples; the dated core schema fixes this code,
1758
- * and the dated schema is what a peer implements against.
1934
+ * own prose examples show `-32003`; the dated core schema fixes this code, and the dated
1935
+ * schema is what a peer implements against.
1759
1936
  */
1760
1937
  export declare const MCP_MISSING_CAPABILITY = -32021;
1761
1938
 
1762
1939
  /** The modern revision offered by an unpinned client during discovery. */
1763
- export declare const MCP_MODERN_VERSION: MCPVersion;
1764
-
1765
- /**
1766
- * The revision offered and defaulted to in the legacy `initialize` handshake.
1767
- *
1768
- * @remarks
1769
- * This is deliberately a legacy revision, and the newest one supported. 2026-07-28 is stateless
1770
- * and defines no `initialize`, so it can never be the handshake's version — a client that offers
1771
- * it is asking to negotiate a revision with no negotiation.
1772
- */
1773
- export declare const MCP_PROTOCOL_VERSION: MCPVersion;
1940
+ export declare const MCP_MODERN_VERSION: MCPModernVersion;
1774
1941
 
1775
1942
  /** MCP reserved error: a request names an unsupported protocol revision. */
1776
1943
  export declare const MCP_UNSUPPORTED_VERSION = -32022;
@@ -1800,11 +1967,10 @@ export declare interface MCPBlobResource {
1800
1967
  }
1801
1968
 
1802
1969
  /**
1803
- * Per-call policy for one remote `tools/call` — the caller's cancellation and its
1804
- * progress consumer.
1970
+ * Configures per-call policy and continuation data for one remote `tools/call`.
1805
1971
  *
1806
1972
  * @remarks
1807
- * Both leaves are the CALLER's, and both live for exactly one request:
1973
+ * Each option lives for exactly one request:
1808
1974
  *
1809
1975
  * - `signal` cancels THAT request and nothing else. It never closes the connection, never
1810
1976
  * reaches a durable task the call may have become, and never asks the peer to undo work
@@ -1814,16 +1980,25 @@ export declare interface MCPBlobResource {
1814
1980
  * - `progress` receives each `notifications/progress` frame the peer publishes for this
1815
1981
  * request. Supplying it is what stamps the request's progress token, so a peer only
1816
1982
  * 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.
1817
1987
  *
1818
- * Neither leaf survives the call: when the request settles answered, refused, timed out,
1819
- * aborted, or drained by a `disconnect` — the signal listener is removed and the progress
1820
- * handler is dropped in the same step.
1988
+ * No option survives the call: the continuation data is placed only on that request, and when
1989
+ * the request settles — answered, refused, timed out, aborted, or drained by a `disconnect` —
1990
+ * the signal listener is removed and the progress handler is dropped in the same step.
1821
1991
  */
1822
1992
  export declare interface MCPCallOptions {
1823
1993
  /** Cancels this one in-flight request; an already-aborted signal refuses it unsent. */
1824
1994
  readonly signal?: AbortSignal;
1825
1995
  /** Receives this request's progress frames; supplying it stamps the progress token. */
1826
1996
  readonly progress?: MCPProgressHandler;
1997
+ /** Carries the protected state and responses for one input-required retry. */
1998
+ readonly input?: {
1999
+ readonly state: string;
2000
+ readonly responses: Readonly<Record<string, unknown>>;
2001
+ };
1827
2002
  }
1828
2003
 
1829
2004
  /**
@@ -1857,14 +2032,14 @@ export declare type MCPCallResult = MCPUnstampedCallResult & {
1857
2032
 
1858
2033
  /**
1859
2034
  * A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP server
1860
- * over an injected {@link MCPClientTransportInterface}, negotiates the modern or legacy
1861
- * wire era, and exposes the server's tools as local {@link ToolInterface}s an agent can run.
2035
+ * over an injected {@link MCPClientTransportInterface}, negotiates the modern revision, and
2036
+ * exposes the server's tools as local {@link ToolInterface}s an agent can run.
1862
2037
  *
1863
2038
  * @remarks
1864
2039
  * - **The mirror of `MCPServer`.** The server DISPATCHES requests over a tool registry;
1865
- * this client ISSUES them over a transport. `connect` probes `server/discover` unless
1866
- * pinned legacy, falls back to `initialize` only for a legacy peer, and exposes the
1867
- * negotiated `version`; `tools()` lists the remote tools and wraps each as a
2040
+ * this client ISSUES them over a transport. `connect` probes `server/discover` and exposes
2041
+ * the negotiated `version`; a legacy peer requires an explicit transport adapter.
2042
+ * `tools()` lists the remote tools and wraps each as a
1868
2043
  * local {@link ToolInterface} whose `execute` calls back through `call`; `call` runs a
1869
2044
  * remote `tools/call` and reports the arm the peer answered with — a value, a durable
1870
2045
  * task, or a request for more input (a remote `isError: true` throws locally, so an
@@ -1921,13 +2096,14 @@ export declare class MCPClient implements MCPClientInterface {
1921
2096
  constructor(options: MCPClientOptions);
1922
2097
  get emitter(): EmitterInterface<MCPClientEventMap>;
1923
2098
  get connected(): boolean;
1924
- get version(): MCPVersion | undefined;
2099
+ get version(): MCPModernVersion | undefined;
1925
2100
  get transport(): MCPClientTransportInterface;
1926
2101
  get tasks(): MCPTaskClientInterface;
1927
2102
  connect(): Promise<void>;
1928
2103
  discover(): Promise<MCPDiscoverResult>;
1929
2104
  disconnect(): Promise<void>;
1930
2105
  tools(): Promise<readonly ToolInterface[]>;
2106
+ listen(notifications: MCPSubscriptionFilter | undefined, options: MCPListenOptions): MCPSubscriptionStream;
1931
2107
  call(name: string, args: Readonly<Record<string, unknown>>, options?: MCPCallOptions): Promise<MCPCallOutcome>;
1932
2108
  }
1933
2109
 
@@ -1951,8 +2127,9 @@ export declare type MCPClientCapabilities = Readonly<Record<string, MCPMetaObjec
1951
2127
  * fire-and-forget observer (logging, tracing) subscribes to through `client.emitter.on`.
1952
2128
  *
1953
2129
  * @remarks
1954
- * - `connect` — era negotiation completed and the client is connected: modern after
1955
- * `server/discover`, legacy after `initialize` and its notification.
2130
+ * - `connect` — modern revision negotiation completed through `server/discover`, and the client
2131
+ * is connected. A legacy transport adapter presents this same modern boundary after completing
2132
+ * its own handshake.
1956
2133
  * - `disconnect` — the connection this client had announced ended (every pending request
1957
2134
  * rejected, and the connection it owned on the transport closed — or that close faulted or
1958
2135
  * timed out, which rejects the `disconnect` caller rather than withholding this event).
@@ -1980,14 +2157,15 @@ export declare type MCPClientEventMap = {
1980
2157
  /**
1981
2158
  * A transport-agnostic Model Context Protocol CLIENT — connects to a REMOTE MCP
1982
2159
  * server over an injected {@link MCPClientTransportInterface}, negotiates the
1983
- * modern or legacy wire era, and exposes the server's tools as local
2160
+ * modern wire revision, and exposes the server's tools as local
1984
2161
  * {@link ToolInterface}s an agent can run.
1985
2162
  *
1986
2163
  * @remarks
1987
2164
  * - **The mirror of {@link MCPServerInterface}.** Where the server DISPATCHES requests
1988
- * over a tool registry, the client ISSUES them over a transport: `connect` probes
1989
- * `server/discover` first unless pinned to a legacy revision, falling back to the
1990
- * legacy `initialize` handshake only when the peer does not speak the modern era.
2165
+ * over a tool registry, the client ISSUES them over a transport: `connect` negotiates through
2166
+ * `server/discover`. A legacy peer requires an explicit
2167
+ * {@link MCPLegacyClientTransportOptions legacy transport adapter}; the bare client refuses a
2168
+ * peer that does not speak the modern era and names that adapter.
1991
2169
  * The negotiated revision is exposed through `version`; `tools()` lists
1992
2170
  * the remote tools and wraps each as a local {@link ToolInterface} whose `execute`
1993
2171
  * calls back through `call`; `call(name, args)` runs a remote `tools/call` and reports
@@ -2031,14 +2209,14 @@ export declare type MCPClientEventMap = {
2031
2209
  */
2032
2210
  export declare interface MCPClientInterface {
2033
2211
  readonly emitter: EmitterInterface<MCPClientEventMap>;
2034
- /** Whether era negotiation has completed and the client is connected. */
2212
+ /** Whether modern revision negotiation has completed and the client is connected. */
2035
2213
  readonly connected: boolean;
2036
2214
  /** The negotiated protocol revision, or `undefined` while disconnected. */
2037
- readonly version: MCPVersion | undefined;
2215
+ readonly version: MCPModernVersion | undefined;
2038
2216
  /** The injected transport the client drives the remote server over. */
2039
2217
  readonly transport: MCPClientTransportInterface;
2040
2218
  /**
2041
- * The draft Tasks extension's client half — reading, answering, and stopping a durable task.
2219
+ * The stable Tasks extension's client half — reading, answering, and stopping a durable task.
2042
2220
  *
2043
2221
  * @remarks
2044
2222
  * Always present, because the `tasks/*` methods are ordinary requests a client may
@@ -2049,7 +2227,7 @@ export declare interface MCPClientInterface {
2049
2227
  readonly tasks: MCPTaskClientInterface;
2050
2228
  /**
2051
2229
  * Connects to the remote server — opens a connection on the transport and negotiates the
2052
- * modern or legacy wire era without exposing that choice to the caller.
2230
+ * modern wire revision.
2053
2231
  *
2054
2232
  * @remarks
2055
2233
  * Idempotent — a second `connect` while already connected is a no-op, and one issued
@@ -2062,8 +2240,8 @@ export declare interface MCPClientInterface {
2062
2240
  * or having outrun its deadline without ever confirming that the connection ended — closes that
2063
2241
  * connection FIRST, joining a close still running rather than issuing a second one, and rejects
2064
2242
  * with the fault if that close fails or goes unanswered again; so the transport is never opened
2065
- * beside a connection no path has closed. An unpinned client probes `server/discover`; a pinned legacy
2066
- * client and a legacy fallback run `initialize` and send `notifications/initialized`.
2243
+ * beside a connection no path has closed. The client probes `server/discover`; an explicit legacy
2244
+ * transport adapter owns any `initialize` handshake and presents a modern discovery result.
2067
2245
  * On success {@link version} contains a supported revision and the `connect` event
2068
2246
  * fires. Whichever side owns the open connection closes it when the attempt rejects — the
2069
2247
  * attempt itself, or the {@link disconnect} that superseded it — and a `close` that fails, or
@@ -2135,6 +2313,14 @@ export declare interface MCPClientInterface {
2135
2313
  * @returns The remote tools as local {@link ToolInterface}s, in server order
2136
2314
  */
2137
2315
  tools(): Promise<readonly ToolInterface[]>;
2316
+ /**
2317
+ * Listens for the remote server's matching subscription notifications.
2318
+ *
2319
+ * @param notifications - The requested filter, or `undefined` for an empty filter
2320
+ * @param options - Required cancellation and optional queue-capacity policy
2321
+ * @returns The acknowledgement and matching notifications, with the graceful result on closure
2322
+ */
2323
+ listen(notifications: MCPSubscriptionFilter | undefined, options: MCPListenOptions): MCPSubscriptionStream;
2138
2324
  /**
2139
2325
  * Calls a remote tool by name — runs `tools/call` and reports which permitted arm
2140
2326
  * the peer answered with.
@@ -2171,15 +2357,17 @@ export declare interface MCPClientInterface {
2171
2357
  *
2172
2358
  * @remarks
2173
2359
  * - `transport` — the carrier the client drives a remote MCP server over (REQUIRED;
2174
- * a concrete one from `src/server/mcp`, or an in-process loopback).
2175
- * - `identity` identifies the client in the `initialize` handshake (`clientInfo`);
2176
- * defaults to {@link import('./constants.js').DEFAULT_MCP_CLIENT_NAME} /
2360
+ * a concrete one from `src/server/mcp`, or an in-process loopback). The bare client negotiates
2361
+ * the modern revision through `server/discover`; wrap the carrier with
2362
+ * {@link import('./factories.js').createMCPLegacyClientTransport} for a legacy peer.
2363
+ * - `identity` — identifies the client in modern request metadata; defaults to
2364
+ * {@link import('./constants.js').DEFAULT_MCP_CLIENT_NAME} /
2177
2365
  * {@link import('./constants.js').DEFAULT_MCP_CLIENT_VERSION}.
2178
2366
  * - `capabilities` — the open client-capability record carried by every modern
2179
- * request; defaults to an empty record when the modern client implementation lands.
2180
- * - `version` — an optional protocol pin; absence lets the modern client negotiate.
2181
- * - `timeout` — the per-request deadline in milliseconds: a `tools/list` / `tools/call`
2182
- * / `initialize` that the server does not answer within it REJECTS (the pending
2367
+ * request; defaults to an empty record.
2368
+ * - `version` — an optional modern protocol pin; absence lets `server/discover` negotiate.
2369
+ * - `timeout` — the per-request deadline in milliseconds: a `server/discover` / `tools/list` /
2370
+ * `tools/call` that the server does not answer within it REJECTS (the pending
2183
2371
  * request is settled by an `AbortSignal.timeout(timeout)` deadline — never a raw
2184
2372
  * `setTimeout`). The same deadline bounds the client's WAIT on the transport's `close`, so a
2185
2373
  * shutdown the transport accepts and never answers rejects its caller instead of wedging the
@@ -2197,11 +2385,11 @@ export declare interface MCPClientOptions {
2197
2385
  /** The open client-capability record carried by modern requests. */
2198
2386
  readonly capabilities?: MCPClientCapabilities;
2199
2387
  /**
2200
- * An optional exact protocol revision pin; absence permits negotiation. A defined pin must
2201
- * match the peer's negotiated revision. An unsupported runtime value throws an
2388
+ * An optional exact modern protocol revision pin; absence permits modern negotiation. A defined
2389
+ * pin must match the peer's discovery advertisement. An unsupported runtime value throws an
2202
2390
  * {@link MCPError} synchronously during construction.
2203
2391
  */
2204
- readonly version?: MCPVersion;
2392
+ readonly version?: MCPModernVersion;
2205
2393
  /** The per-request deadline in milliseconds (default {@link import('./constants.js').DEFAULT_MCP_REQUEST_TIMEOUT}). */
2206
2394
  readonly timeout?: number;
2207
2395
  }
@@ -2400,7 +2588,7 @@ export declare interface MCPContinuationInterface {
2400
2588
 
2401
2589
  /** The mandatory modern `server/discover` result. */
2402
2590
  export declare type MCPDiscoverResult = {
2403
- readonly supportedVersions: readonly MCPVersion[];
2591
+ readonly supportedVersions: readonly MCPModernVersion[];
2404
2592
  readonly capabilities: MCPServerCapabilities;
2405
2593
  readonly resultType: 'complete';
2406
2594
  readonly ttlMs: number;
@@ -2784,9 +2972,12 @@ export declare interface MCPJSONLimitOptions {
2784
2972
  * Translates the fixed legacy method set onto one modern dispatcher.
2785
2973
  *
2786
2974
  * @remarks
2787
- * This decorator owns no execution engine or result normalizer. Modern invocations
2788
- * pass through untouched. Legacy tool methods acquire modern request metadata, run
2789
- * through the configured dispatcher, and lose only fields their dated result shape
2975
+ * This decorator answers `initialize` and `ping` itself, under the limits the configured
2976
+ * dispatcher advertises through {@link MCPLegacy.limit}: an invocation outside the message
2977
+ * bound earns the same id-less `-32600` refusal the dispatcher produces, whether this
2978
+ * decorator would have answered it or forwarded it. It owns no result normalizer. Modern
2979
+ * invocations pass through untouched. Legacy tool methods acquire modern request metadata,
2980
+ * run through the configured dispatcher, and lose only fields their dated result shape
2790
2981
  * cannot represent.
2791
2982
  */
2792
2983
  export declare class MCPLegacy implements MCPDispatcherInterface {
@@ -2805,6 +2996,70 @@ export declare class MCPLegacy implements MCPDispatcherInterface {
2805
2996
  handle(message: string, options?: MCPDispatchOptions): Promise<string | MCPTextStreamControllerInterface | undefined>;
2806
2997
  }
2807
2998
 
2999
+ /**
3000
+ * Adapts a legacy MCP peer to the modern client transport boundary.
3001
+ *
3002
+ * @remarks
3003
+ * `start` performs the legacy `initialize` handshake. The adapter answers
3004
+ * `server/discover` locally from that handshake, removes modern request metadata before writes,
3005
+ * restores legacy results to modern complete-result shapes before delivery, and bounds retained
3006
+ * request correlations with the configured deadline.
3007
+ */
3008
+ export declare class MCPLegacyClientTransport implements MCPClientTransportInterface {
3009
+ #private;
3010
+ /**
3011
+ * Creates a legacy client transport adapter.
3012
+ *
3013
+ * @param transport - The legacy peer transport
3014
+ * @param options - The legacy handshake identity, capabilities, revision, and deadline
3015
+ */
3016
+ constructor(transport: MCPClientTransportInterface, options?: MCPLegacyClientTransportOptions);
3017
+ get emitter(): EmitterInterface<MCPClientTransportEventMap>;
3018
+ get session(): string | undefined;
3019
+ get duplex(): boolean;
3020
+ start(): Promise<void>;
3021
+ send(message: JSONRPCMessage): Promise<void>;
3022
+ /**
3023
+ * Closes the wrapped transport and clears retained adapter state.
3024
+ *
3025
+ * @remarks
3026
+ * The cleared handshake state — the server identity, the supported reading, and the retained
3027
+ * `instructions` value — is unobservable between `close()` and the next accepted handshake.
3028
+ * Discovery answers the pre-handshake refusal in that window, and the accepted handshake
3029
+ * reassigns the state unconditionally.
3030
+ *
3031
+ * @returns Resolves after the wrapped transport closes
3032
+ */
3033
+ close(): Promise<void>;
3034
+ }
3035
+
3036
+ /**
3037
+ * Options for the explicit legacy client transport adapter.
3038
+ *
3039
+ * @remarks
3040
+ * - `identity` — the client identity sent through the legacy `clientInfo` field. Defaults to the
3041
+ * package client identity.
3042
+ * - `capabilities` — the legacy handshake capability record. Defaults to an empty record.
3043
+ * - `version` — an optional exact legacy handshake revision. Absence offers the newest supported
3044
+ * legacy revision and accepts the supported revision the peer selects.
3045
+ * - `timeout` — the legacy handshake, handshake-write, and forwarded-request deadline in
3046
+ * milliseconds. Default:
3047
+ * {@link import('./constants.js').DEFAULT_MCP_REQUEST_TIMEOUT}.
3048
+ *
3049
+ * The adapter reserves JSON-RPC wire id `0` for its handshake while `start()` is waiting for
3050
+ * the peer. Do not send unrelated id-`0` traffic through the wrapped transport in that window.
3051
+ */
3052
+ export declare interface MCPLegacyClientTransportOptions {
3053
+ /** The client identity sent during the legacy handshake. */
3054
+ readonly identity?: MCPIdentity;
3055
+ /** The client capabilities sent during the legacy handshake. */
3056
+ readonly capabilities?: MCPClientCapabilities;
3057
+ /** The exact legacy revision to request and require. */
3058
+ readonly version?: MCPLegacyVersion;
3059
+ /** The legacy handshake and forwarded-request deadline in milliseconds. */
3060
+ readonly timeout?: number;
3061
+ }
3062
+
2808
3063
  /** Construction options for the removable legacy protocol decorator. */
2809
3064
  export declare interface MCPLegacyOptions {
2810
3065
  /** The sole dispatcher and execution engine. */
@@ -2825,8 +3080,7 @@ export declare interface MCPLegacyOptions {
2825
3080
  * `result.resultType === undefined` narrows a {@link JSONRPCResultResponse}'s
2826
3081
  * `result` to the legacy arm.
2827
3082
  *
2828
- * This arm exists only while `MCPServer` still carries the legacy branch, and is
2829
- * removed with it.
3083
+ * This arm exists only for the optional legacy server decorator and client transport adapter.
2830
3084
  */
2831
3085
  export declare interface MCPLegacyResult {
2832
3086
  /** Forbidden — the legacy revision has no result discriminator. */
@@ -2834,6 +3088,9 @@ export declare interface MCPLegacyResult {
2834
3088
  readonly [key: string]: unknown;
2835
3089
  }
2836
3090
 
3091
+ /** A legacy protocol revision supported by the optional legacy decorators. */
3092
+ export declare type MCPLegacyVersion = '2025-11-25' | '2025-06-18';
3093
+
2837
3094
  /** Configurable hostile-input and live-resource bounds for an MCP server. */
2838
3095
  export declare interface MCPLimitOptions {
2839
3096
  /** Maximum UTF-8 bytes accepted by the raw string boundary. */
@@ -2852,6 +3109,14 @@ export declare interface MCPLimitOptions {
2852
3109
  readonly depth?: number;
2853
3110
  }
2854
3111
 
3112
+ /** Per-subscription cancellation and bounded buffering policy. */
3113
+ export declare interface MCPListenOptions {
3114
+ /** Aborts the subscription and rejects its pending read with the signal reason. */
3115
+ readonly signal: AbortSignal;
3116
+ /** The maximum number of delivered frames retained while no read is parked. */
3117
+ readonly capacity?: number;
3118
+ }
3119
+
2855
3120
  /**
2856
3121
  * The MCP `tools/list` result — tool descriptors plus optional modern result
2857
3122
  * stamps.
@@ -3006,6 +3271,27 @@ export declare interface MCPMethodOptions {
3006
3271
  readonly caller?: unknown;
3007
3272
  }
3008
3273
 
3274
+ /** A modern protocol revision supported by the bare MCP server. */
3275
+ export declare type MCPModernVersion = '2026-07-28';
3276
+
3277
+ /**
3278
+ * Open notification metadata with the dated reserved subscription field.
3279
+ *
3280
+ * @remarks
3281
+ * The subscription id is OPTIONAL here, and that is the schema's own split rather than
3282
+ * this package hedging. A frame delivered down a `subscriptions/listen` stream carries the
3283
+ * stamp naming the listen request that agreed to it; the same notification delivered any
3284
+ * other way carries no stamp, because there is no subscription to name. A required key
3285
+ * would refuse a frame the protocol permits.
3286
+ *
3287
+ * Compare {@link MCPSubscriptionResultMetaObject}, where the same key is REQUIRED: that one
3288
+ * sits on the terminating result of a stream, so a subscription always exists to name.
3289
+ */
3290
+ export declare type MCPNotificationMetaObject = MCPMetaObject & {
3291
+ /** The JSON-RPC id of the `subscriptions/listen` request whose stream delivered the frame. */
3292
+ readonly 'io.modelcontextprotocol/subscriptionId'?: JSONRPCId;
3293
+ };
3294
+
3009
3295
  /** Shared cursor parameters for every paginated modern list method. */
3010
3296
  export declare interface MCPPaginationParams {
3011
3297
  /** Opaque cursor returned by the preceding page. */
@@ -3430,7 +3716,7 @@ export declare type MCPRole = 'user' | 'assistant';
3430
3716
  * - **One modern seam.** `server/discover`, `tools/list`, `tools/call`, and
3431
3717
  * `subscriptions/listen` are always registered; `resources/*`, `prompts/*`, and
3432
3718
  * `completion/complete` register independently when their respective host ports are
3433
- * configured — plus `tasks/get`, `tasks/update`, and `tasks/cancel` when the draft Tasks
3719
+ * configured — plus `tasks/get`, `tasks/update`, and `tasks/cancel` when the stable Tasks
3434
3720
  * extension is configured — and every method is resolved from the registry on
3435
3721
  * every dispatch: the same path a later method or a consumer's own takes, with an
3436
3722
  * unregistered method still answering `-32601`.
@@ -3445,8 +3731,8 @@ export declare type MCPRole = 'user' | 'assistant';
3445
3731
  * const tools = createToolManager()
3446
3732
  * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))
3447
3733
  * const server = new MCPServer({ identity: { name: 'demo', version: '1.0.0' }, tools })
3448
- * await server.handle('{"jsonrpc":"2.0","method":"ping","id":1,"params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}')
3449
- * // '{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","_meta":{"io.modelcontextprotocol/serverInfo":{"name":"demo","version":"1.0.0"}}}}'
3734
+ * await server.handle('{"jsonrpc":"2.0","method":"server/discover","id":1,"params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}')
3735
+ * // The result advertises only `2026-07-28`; wrap with `createMCPLegacy` to serve initialize or ping.
3450
3736
  * ```
3451
3737
  */
3452
3738
  export declare class MCPServer implements MCPServerInterface {
@@ -3530,7 +3816,7 @@ export declare type MCPServerEventMap = {
3530
3816
 
3531
3817
  /**
3532
3818
  * A transport-agnostic Model Context Protocol server — dispatches JSON-RPC 2.0
3533
- * requests (the fixed legacy methods plus the modern subscription method) over a live
3819
+ * modern requests over a live
3534
3820
  * {@link ToolManagerInterface}, with NO transport coupling (a transport layer
3535
3821
  * pumps strings through `handle`).
3536
3822
  *
@@ -3657,7 +3943,7 @@ export declare interface MCPServerInterface extends MCPDispatcherInterface {
3657
3943
  * {@link MCPServerEventMap}, wired at construction. `input` enables modern
3658
3944
  * `tools/call` multi-round trips: the consumer decides when input is needed and
3659
3945
  * supplies principal/continuation/TTL policy, while MCP assigns the request key and
3660
- * owns the protected wire round trip. `task` enables the draft Tasks extension: the
3946
+ * owns the protected wire round trip. `task` enables the stable Tasks extension: the
3661
3947
  * consumer supplies the durable store and the deferral decision, while MCP owns the
3662
3948
  * capability gate and the `resultType: 'task'` answer. `limit` configures the server's
3663
3949
  * hostile-input and live-subscription bounds; every omitted leaf uses
@@ -3700,12 +3986,12 @@ export declare interface MCPServerOptions {
3700
3986
  /** Optional event-driven producer for the modern `subscriptions/listen` method. */
3701
3987
  readonly subscription?: MCPSubscriptionOptions;
3702
3988
  /**
3703
- * Optional draft Tasks extension; the durable store and the deferral decision are consumer-supplied.
3989
+ * Optional Tasks extension; the durable store and the deferral decision are consumer-supplied.
3704
3990
  *
3705
3991
  * @remarks
3706
3992
  * Omitting it leaves every existing path untouched — nothing is advertised, no call is
3707
- * deferred, and `tasks/*` stays unregistered. The extension is DRAFT and carries no
3708
- * stability guarantee.
3993
+ * deferred, and `tasks/*` stays unregistered. The extension is the STABLE, immutable
3994
+ * snapshot dated 2026-07-28, so the shape this option admits is fixed.
3709
3995
  */
3710
3996
  readonly task?: MCPTaskOptions;
3711
3997
  /** Hostile-input and live-resource bounds; omitted leaves use secure defaults. */
@@ -3946,6 +4232,25 @@ export declare interface MCPSubscriptionFilter {
3946
4232
  readonly resourcesListChanged?: boolean;
3947
4233
  /** Receives `notifications/resources/updated` for these resource URIs. */
3948
4234
  readonly resourceSubscriptions?: readonly string[];
4235
+ /**
4236
+ * Receives `notifications/tasks` for these task identifiers.
4237
+ *
4238
+ * @remarks
4239
+ * The wire placement is `params.notifications.taskIds`, beside `resourceSubscriptions`,
4240
+ * and that placement is THIS PACKAGE'S READING rather than a settled fact: the Tasks
4241
+ * extension declares the fragment carrying this member without composing it into the
4242
+ * `subscriptions/listen` request, so no source states where the fragment lands. The
4243
+ * spelling itself is the schema's and is carried verbatim under the same wire-key
4244
+ * exemption as its siblings.
4245
+ *
4246
+ * The server honours the member only when a consumer configured BOTH a task manager and
4247
+ * a subscription producer: the manager resolves each requested identifier before the
4248
+ * acknowledgement agrees to it, and the producer is what a transition frame arrives
4249
+ * through. Either one missing leaves nothing to deliver, so the acknowledgement omits
4250
+ * the member. That fact is DERIVED from the two configured options at the moment the
4251
+ * listen request is answered; no third flag records it, so it cannot drift from them.
4252
+ */
4253
+ readonly taskIds?: readonly string[];
3949
4254
  }
3950
4255
 
3951
4256
  /**
@@ -3982,6 +4287,9 @@ export declare type MCPSubscriptionResultMetaObject = MCPResultMetaObject & {
3982
4287
  readonly 'io.modelcontextprotocol/subscriptionId': JSONRPCId;
3983
4288
  };
3984
4289
 
4290
+ /** A client subscription's owned notifications and graceful terminal result. */
4291
+ export declare type MCPSubscriptionStream = AsyncGenerator<JSONRPCNotification, MCPSubscriptionResult, unknown>;
4292
+
3985
4293
  /**
3986
4294
  * One durable task's wire snapshot — the payload a deferred `tools/call` answers with.
3987
4295
  *
@@ -4010,7 +4318,7 @@ export declare type MCPTask = {
4010
4318
  };
4011
4319
 
4012
4320
  /**
4013
- * The CLIENT half of the draft Tasks extension — the `tasks/*` methods over one
4321
+ * The CLIENT half of the stable Tasks extension — the `tasks/*` methods over one
4014
4322
  * correlated-request door, exposed as an {@link import('./types.js').MCPClientInterface}'s
4015
4323
  * `tasks`.
4016
4324
  *
@@ -4054,7 +4362,7 @@ export declare class MCPTaskClient implements MCPTaskClientInterface {
4054
4362
  }
4055
4363
 
4056
4364
  /**
4057
- * The CLIENT half of the draft Tasks extension — reading, answering, and stopping a durable
4365
+ * The CLIENT half of the stable Tasks extension — reading, answering, and stopping a durable
4058
4366
  * task the peer created.
4059
4367
  *
4060
4368
  * @remarks
@@ -4073,8 +4381,11 @@ export declare class MCPTaskClient implements MCPTaskClientInterface {
4073
4381
  * beside it. It supplies no timer, no scheduler, no terminal-await helper, and no cache,
4074
4382
  * because it has no durable place to keep a task, no way to know when the application still
4075
4383
  * cares, and no lifetime to hang a timer on that outlives the request. Schedule the reads
4076
- * yourself, or wait for the peer to push: an inbound task notification arrives on the client's
4077
- * existing `notification` event at zero new mechanism.
4384
+ * yourself, or wait for the peer to push. A task notification the server stamped for a
4385
+ * subscription is claimed by the `listen` stream that asked for it and does not re-emit
4386
+ * through the `MCPClientEventMap` `notification` event, so a subscribed consumer reads its
4387
+ * transitions from the stream it opened; an unstamped notification arrives on that event at
4388
+ * no added mechanism.
4078
4389
  *
4079
4390
  * Every method authorizes on the peer's side, so a task belonging to another principal is
4080
4391
  * indistinguishable from one that never existed and one whose TTL purged it — each is
@@ -4093,7 +4404,7 @@ export declare interface MCPTaskClientInterface {
4093
4404
  *
4094
4405
  * The peer's payload is carried VERBATIM once it proves well-formed. A modern result's own
4095
4406
  * `resultType: 'complete'` and `_meta` stamps therefore ride along on the snapshot, because
4096
- * rebuilding the object to drop them would also drop the unrecognized draft members this
4407
+ * rebuilding the object to drop them would also drop the unrecognized members this
4097
4408
  * package deliberately preserves.
4098
4409
  *
4099
4410
  * @param id - The `taskId` to read
@@ -4202,9 +4513,12 @@ export declare interface MCPTaskContext {
4202
4513
  * `completed` carries the deferred call's result, `failed` carries the JSON-RPC error
4203
4514
  * that ended it, and `working` / `cancelled` carry nothing extra. Narrow on `status`.
4204
4515
  *
4205
- * `result` is an open {@link MCPResult} rather than an {@link MCPCallResult}: only
4206
- * `tools/call` can be deferred, but the payload is the deferred method's
4207
- * own result and the extension says nothing that fixes it to one method forever.
4516
+ * `result` is an OPEN RECORD rather than an {@link MCPResult} or an
4517
+ * {@link MCPCallResult}, because the schema declares it one: a completed task's payload
4518
+ * is whatever the deferred method answered, and the extension constrains nothing inside
4519
+ * it — not even a `resultType`. Only `tools/call` can be deferred today, and the
4520
+ * extension says nothing that fixes the payload to one method forever, so a reader that
4521
+ * knows which call it deferred narrows this record with that method's own guard.
4208
4522
  */
4209
4523
  export declare type MCPTaskDetail = (MCPTask & {
4210
4524
  readonly status: 'working';
@@ -4213,7 +4527,7 @@ export declare type MCPTaskDetail = (MCPTask & {
4213
4527
  readonly inputRequests: MCPInputRequestMap;
4214
4528
  }) | (MCPTask & {
4215
4529
  readonly status: 'completed';
4216
- readonly result: MCPResult;
4530
+ readonly result: Readonly<Record<string, unknown>>;
4217
4531
  }) | (MCPTask & {
4218
4532
  readonly status: 'failed';
4219
4533
  readonly error: JSONRPCError;
@@ -4221,6 +4535,27 @@ export declare type MCPTaskDetail = (MCPTask & {
4221
4535
  readonly status: 'cancelled';
4222
4536
  });
4223
4537
 
4538
+ /**
4539
+ * The wire answer to `tasks/get` — one snapshot under the completed-result stamp.
4540
+ *
4541
+ * @remarks
4542
+ * DISTINCT from {@link MCPTaskDetail}, and the distinction is the whole point. A detail is
4543
+ * what the consumer's {@link MCPTaskManagerInterface} answers, unstamped, because a durable
4544
+ * store knows nothing about the request that read it. This is what a `tasks/get` REPLY
4545
+ * carries: the schema types that reply as the detail intersected with the standard result,
4546
+ * so `resultType: 'complete'` is required rather than incidental and a peer that omits it
4547
+ * has answered something other than the method's declared result.
4548
+ *
4549
+ * `complete`, not `task`. Only the creation answer ({@link MCPTaskResult}) carries
4550
+ * `resultType: 'task'`; reading a task is an ordinary completed call whose payload happens
4551
+ * to be a task.
4552
+ */
4553
+ export declare type MCPTaskDetailResult = MCPTaskDetail & {
4554
+ readonly resultType: 'complete';
4555
+ /** Open modern protocol metadata, including reserved namespaced keys. */
4556
+ readonly _meta?: MCPResultMetaObject;
4557
+ };
4558
+
4224
4559
  /**
4225
4560
  * Decides whether the `tools/call` in hand becomes a durable task.
4226
4561
  *
@@ -4347,7 +4682,28 @@ export declare interface MCPTaskManagerInterface {
4347
4682
  }
4348
4683
 
4349
4684
  /**
4350
- * Consumer policy for the server's draft Tasks extension.
4685
+ * The parameters of a `notifications/tasks` frame one snapshot, flat, optionally stamped
4686
+ * with the subscription that delivered it.
4687
+ *
4688
+ * @remarks
4689
+ * FLAT, and that is the schema's shape rather than a choice: the extension types these
4690
+ * parameters as the notification envelope intersected with the detail, so every task field
4691
+ * sits directly under `params` and no `task` wrapper member exists. Narrow on `status`
4692
+ * exactly as with {@link MCPTaskDetail}.
4693
+ *
4694
+ * The index signature is the envelope's own openness, carried through. `_meta` is optional
4695
+ * because the reserved subscription stamp is present only on a frame delivered down a
4696
+ * `subscriptions/listen` stream and absent on one delivered any other way — see
4697
+ * {@link MCPNotificationMetaObject}.
4698
+ */
4699
+ export declare type MCPTaskNotificationParams = MCPTaskDetail & {
4700
+ /** Open notification metadata, including the reserved subscription stamp. */
4701
+ readonly _meta?: MCPNotificationMetaObject;
4702
+ readonly [key: string]: unknown;
4703
+ };
4704
+
4705
+ /**
4706
+ * Consumer policy for the server's stable Tasks extension.
4351
4707
  *
4352
4708
  * @remarks
4353
4709
  * Supplying this is what turns the extension on: an unconfigured server advertises
@@ -4645,8 +5001,8 @@ export declare interface MCPTransportInterface {
4645
5001
  * `resultType`, which is the only shape the legacy revision has for one.
4646
5002
  * {@link MCPCallResult} is this payload plus the modern `'complete'` stamp, so
4647
5003
  * stamping is the one difference between the modern and legacy answers to `tools/call`.
4648
- * Its sole producer is `MCPServer`'s legacy branch, and it is removed with that
4649
- * branch.
5004
+ * `MCPServer` produces it before modern stamping, and `MCPLegacy` projects the
5005
+ * stamped answer back to this shape.
4650
5006
  *
4651
5007
  * A success carries the tool's value unchanged as `structuredContent` alongside
4652
5008
  * its serialized form in one `text` content block. A value-less success omits
@@ -4665,8 +5021,32 @@ export declare type MCPUnstampedCallResult = {
4665
5021
  readonly _meta?: MCPResultMetaObject;
4666
5022
  };
4667
5023
 
4668
- /** A protocol revision supported by this MCP package. */
4669
- export declare type MCPVersion = '2026-07-28' | '2025-11-25' | '2025-06-18';
5024
+ /** A protocol revision supported by an MCP package surface. */
5025
+ export declare type MCPVersion = MCPModernVersion | MCPLegacyVersion;
5026
+
5027
+ /**
5028
+ * Removes modern request metadata before an invocation reaches a legacy peer.
5029
+ *
5030
+ * @remarks
5031
+ * Non-reserved metadata such as `progressToken` remains on the legacy wire. When no metadata
5032
+ * remains, the translated parameters omit `_meta`.
5033
+ *
5034
+ * @param invocation - The modern invocation to translate
5035
+ * @returns The legacy invocation with reserved modern metadata removed
5036
+ */
5037
+ export declare function modernInvocationToLegacy(invocation: JSONRPCInvocation): JSONRPCInvocation;
5038
+
5039
+ /**
5040
+ * Projects one complete modern result onto the legacy wire shape.
5041
+ *
5042
+ * @remarks
5043
+ * The projection removes the modern discriminator, cache fields, and reserved server identity.
5044
+ * A non-complete result has no legacy representation and returns `undefined`.
5045
+ *
5046
+ * @param result - The modern result to project
5047
+ * @returns The legacy result, or `undefined` when the modern arm cannot be represented
5048
+ */
5049
+ export declare function modernResultToLegacy(result: MCPResult | MCPLegacyResult): MCPLegacyResult | undefined;
4670
5050
 
4671
5051
  /**
4672
5052
  * Narrows an already-parsed value to a {@link JSONRPCMessage}, or `undefined` when
@@ -4884,15 +5264,20 @@ export declare function snapshotToolResult(value: unknown, limits: MCPJSONLimitO
4884
5264
  */
4885
5265
  export declare function stampSubscriptionNotification(notification: JSONRPCNotification, id: JSONRPCId): JSONRPCNotification;
4886
5266
 
5267
+ /** The protocol revisions accepted by the optional legacy decorator. */
5268
+ export declare const SUPPORTED_LEGACY_PROTOCOL_VERSIONS: readonly MCPLegacyVersion[];
5269
+
5270
+ /** The protocol revisions the `isMCPVersion` guard admits, spanning the modern and legacy eras. */
5271
+ export declare const SUPPORTED_MCP_VERSIONS: readonly MCPVersion[];
5272
+
4887
5273
  /**
4888
- * The MCP protocol revisions this server can negotiate.
5274
+ * The modern MCP protocol revisions a bare server accepts and advertises.
4889
5275
  *
4890
5276
  * @remarks
4891
- * `initialize` echoes the client's requested `protocolVersion` when it appears in
4892
- * this list. Frozen in client-preference and discovery-advertisement order. The
4893
- * package does not advertise `2025-03-26` because that revision mandates JSON-RPC
4894
- * batching, while this package accepts only individual JSON-RPC messages.
5277
+ * Frozen in discovery-advertisement order. Legacy revisions are absent because
5278
+ * only {@link SUPPORTED_LEGACY_PROTOCOL_VERSIONS} and the optional legacy
5279
+ * decorator own them.
4895
5280
  */
4896
- export declare const SUPPORTED_PROTOCOL_VERSIONS: readonly MCPVersion[];
5281
+ export declare const SUPPORTED_MODERN_PROTOCOL_VERSIONS: readonly MCPModernVersion[];
4897
5282
 
4898
5283
  export { }