@openrouter/agent 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +267 -2
  2. package/THIRD_PARTY_NOTICES.md +25 -0
  3. package/esm/index.d.ts +4 -3
  4. package/esm/index.d.ts.map +1 -1
  5. package/esm/index.js +1 -1
  6. package/esm/index.js.map +1 -1
  7. package/esm/inner-loop/call-model.d.ts.map +1 -1
  8. package/esm/inner-loop/call-model.js +26 -7
  9. package/esm/inner-loop/call-model.js.map +1 -1
  10. package/esm/lib/agent-tool.d.ts +1 -1
  11. package/esm/lib/agent-tool.d.ts.map +1 -1
  12. package/esm/lib/agent-tool.js.map +1 -1
  13. package/esm/lib/async-params.d.ts +23 -1
  14. package/esm/lib/async-params.d.ts.map +1 -1
  15. package/esm/lib/async-params.js +26 -1
  16. package/esm/lib/async-params.js.map +1 -1
  17. package/esm/lib/conversation-state.d.ts +1 -1
  18. package/esm/lib/conversation-state.d.ts.map +1 -1
  19. package/esm/lib/conversation-state.js +48 -13
  20. package/esm/lib/conversation-state.js.map +1 -1
  21. package/esm/lib/hooks-schemas.d.ts +3 -7
  22. package/esm/lib/hooks-schemas.d.ts.map +1 -1
  23. package/esm/lib/hooks-schemas.js.map +1 -1
  24. package/esm/lib/model-result.d.ts +32 -4
  25. package/esm/lib/model-result.d.ts.map +1 -1
  26. package/esm/lib/model-result.js +444 -128
  27. package/esm/lib/model-result.js.map +1 -1
  28. package/esm/lib/next-turn-params.d.ts.map +1 -1
  29. package/esm/lib/next-turn-params.js +3 -1
  30. package/esm/lib/next-turn-params.js.map +1 -1
  31. package/esm/lib/next-turn-params.test.js +72 -0
  32. package/esm/lib/next-turn-params.test.js.map +1 -1
  33. package/esm/lib/reusable-stream.d.ts +30 -3
  34. package/esm/lib/reusable-stream.d.ts.map +1 -1
  35. package/esm/lib/reusable-stream.js +127 -32
  36. package/esm/lib/reusable-stream.js.map +1 -1
  37. package/esm/lib/stream-transformers.d.ts +1 -1
  38. package/esm/lib/stream-transformers.d.ts.map +1 -1
  39. package/esm/lib/stream-transformers.js.map +1 -1
  40. package/esm/lib/tool-event-broadcaster.d.ts +18 -5
  41. package/esm/lib/tool-event-broadcaster.d.ts.map +1 -1
  42. package/esm/lib/tool-event-broadcaster.js +90 -19
  43. package/esm/lib/tool-event-broadcaster.js.map +1 -1
  44. package/esm/lib/tool-set-types.d.ts +298 -0
  45. package/esm/lib/tool-set-types.d.ts.map +1 -0
  46. package/esm/lib/tool-set-types.js +2 -0
  47. package/esm/lib/tool-set-types.js.map +1 -0
  48. package/esm/lib/tool-set.d.ts +157 -0
  49. package/esm/lib/tool-set.d.ts.map +1 -0
  50. package/esm/lib/tool-set.js +473 -0
  51. package/esm/lib/tool-set.js.map +1 -0
  52. package/esm/lib/tool-types.d.ts +203 -29
  53. package/esm/lib/tool-types.d.ts.map +1 -1
  54. package/esm/lib/tool-types.js.map +1 -1
  55. package/esm/lib/tool.d.ts +47 -21
  56. package/esm/lib/tool.d.ts.map +1 -1
  57. package/esm/lib/tool.js +13 -3
  58. package/esm/lib/tool.js.map +1 -1
  59. package/esm/lib/turn-context.d.ts +1 -1
  60. package/esm/lib/turn-context.d.ts.map +1 -1
  61. package/esm/lib/turn-context.js +1 -2
  62. package/esm/lib/turn-context.js.map +1 -1
  63. package/esm/mcp/auth/auth-resolver.d.ts +14 -0
  64. package/esm/mcp/auth/auth-resolver.d.ts.map +1 -0
  65. package/esm/mcp/auth/auth-resolver.js +27 -0
  66. package/esm/mcp/auth/auth-resolver.js.map +1 -0
  67. package/esm/mcp/auth/auth-types.d.ts +33 -0
  68. package/esm/mcp/auth/auth-types.d.ts.map +1 -0
  69. package/esm/mcp/auth/auth-types.js +4 -0
  70. package/esm/mcp/auth/auth-types.js.map +1 -0
  71. package/esm/mcp/build-tools.d.ts +29 -0
  72. package/esm/mcp/build-tools.d.ts.map +1 -0
  73. package/esm/mcp/build-tools.js +80 -0
  74. package/esm/mcp/build-tools.js.map +1 -0
  75. package/esm/mcp/cache/cache-store.d.ts +24 -0
  76. package/esm/mcp/cache/cache-store.d.ts.map +1 -0
  77. package/esm/mcp/cache/cache-store.js +20 -0
  78. package/esm/mcp/cache/cache-store.js.map +1 -0
  79. package/esm/mcp/cache/cache-types.d.ts +71 -0
  80. package/esm/mcp/cache/cache-types.d.ts.map +1 -0
  81. package/esm/mcp/cache/cache-types.js +49 -0
  82. package/esm/mcp/cache/cache-types.js.map +1 -0
  83. package/esm/mcp/cache/serialize.d.ts +25 -0
  84. package/esm/mcp/cache/serialize.d.ts.map +1 -0
  85. package/esm/mcp/cache/serialize.js +96 -0
  86. package/esm/mcp/cache/serialize.js.map +1 -0
  87. package/esm/mcp/close-quietly.d.ts +24 -0
  88. package/esm/mcp/close-quietly.d.ts.map +1 -0
  89. package/esm/mcp/close-quietly.js +30 -0
  90. package/esm/mcp/close-quietly.js.map +1 -0
  91. package/esm/mcp/create-mcp-tools.d.ts +13 -0
  92. package/esm/mcp/create-mcp-tools.d.ts.map +1 -0
  93. package/esm/mcp/create-mcp-tools.js +87 -0
  94. package/esm/mcp/create-mcp-tools.js.map +1 -0
  95. package/esm/mcp/elicitation.d.ts +11 -0
  96. package/esm/mcp/elicitation.d.ts.map +1 -0
  97. package/esm/mcp/elicitation.js +51 -0
  98. package/esm/mcp/elicitation.js.map +1 -0
  99. package/esm/mcp/errors.d.ts +91 -0
  100. package/esm/mcp/errors.d.ts.map +1 -0
  101. package/esm/mcp/errors.js +91 -0
  102. package/esm/mcp/errors.js.map +1 -0
  103. package/esm/mcp/handle.d.ts +66 -0
  104. package/esm/mcp/handle.d.ts.map +1 -0
  105. package/esm/mcp/handle.js +323 -0
  106. package/esm/mcp/handle.js.map +1 -0
  107. package/esm/mcp/index.d.ts +13 -0
  108. package/esm/mcp/index.d.ts.map +1 -0
  109. package/esm/mcp/index.js +11 -0
  110. package/esm/mcp/index.js.map +1 -0
  111. package/esm/mcp/mcp-connection.d.ts +150 -0
  112. package/esm/mcp/mcp-connection.d.ts.map +1 -0
  113. package/esm/mcp/mcp-connection.js +478 -0
  114. package/esm/mcp/mcp-connection.js.map +1 -0
  115. package/esm/mcp/mcp-sdk.d.ts +10 -0
  116. package/esm/mcp/mcp-sdk.d.ts.map +1 -0
  117. package/esm/mcp/mcp-sdk.js +37 -0
  118. package/esm/mcp/mcp-sdk.js.map +1 -0
  119. package/esm/mcp/rehydrate.d.ts +76 -0
  120. package/esm/mcp/rehydrate.d.ts.map +1 -0
  121. package/esm/mcp/rehydrate.js +505 -0
  122. package/esm/mcp/rehydrate.js.map +1 -0
  123. package/esm/mcp/resource-tools.d.ts +17 -0
  124. package/esm/mcp/resource-tools.d.ts.map +1 -0
  125. package/esm/mcp/resource-tools.js +155 -0
  126. package/esm/mcp/resource-tools.js.map +1 -0
  127. package/esm/mcp/result-mapper.d.ts +19 -0
  128. package/esm/mcp/result-mapper.d.ts.map +1 -0
  129. package/esm/mcp/result-mapper.js +40 -0
  130. package/esm/mcp/result-mapper.js.map +1 -0
  131. package/esm/mcp/schema/json-schema-guards.d.ts +14 -0
  132. package/esm/mcp/schema/json-schema-guards.d.ts.map +1 -0
  133. package/esm/mcp/schema/json-schema-guards.js +19 -0
  134. package/esm/mcp/schema/json-schema-guards.js.map +1 -0
  135. package/esm/mcp/schema/json-schema-to-zod.d.ts +20 -0
  136. package/esm/mcp/schema/json-schema-to-zod.d.ts.map +1 -0
  137. package/esm/mcp/schema/json-schema-to-zod.js +72 -0
  138. package/esm/mcp/schema/json-schema-to-zod.js.map +1 -0
  139. package/esm/mcp/tool-wrapper.d.ts +41 -0
  140. package/esm/mcp/tool-wrapper.d.ts.map +1 -0
  141. package/esm/mcp/tool-wrapper.js +131 -0
  142. package/esm/mcp/tool-wrapper.js.map +1 -0
  143. package/esm/mcp/transport-types.d.ts +45 -0
  144. package/esm/mcp/transport-types.d.ts.map +1 -0
  145. package/esm/mcp/transport-types.js +2 -0
  146. package/esm/mcp/transport-types.js.map +1 -0
  147. package/esm/mcp/types.d.ts +119 -0
  148. package/esm/mcp/types.d.ts.map +1 -0
  149. package/esm/mcp/types.js +2 -0
  150. package/esm/mcp/types.js.map +1 -0
  151. package/esm/mcp/version.d.ts +3 -0
  152. package/esm/mcp/version.d.ts.map +1 -0
  153. package/esm/mcp/version.js +5 -0
  154. package/esm/mcp/version.js.map +1 -0
  155. package/package.json +48 -7
@@ -0,0 +1,37 @@
1
+ import { MCPMissingPeerDependencyError } from './errors.js';
2
+ let sdkPromise;
3
+ function isMissingSdk(error) {
4
+ let current = error;
5
+ while (current instanceof Error) {
6
+ const code = 'code' in current ? current.code : undefined;
7
+ const specifier = /Cannot find (?:package|module) '([^']+)'/.exec(current.message)?.[1];
8
+ if ((code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') &&
9
+ (specifier === '@modelcontextprotocol/client' ||
10
+ specifier?.startsWith('@modelcontextprotocol/client/') === true)) {
11
+ return true;
12
+ }
13
+ current = current.cause;
14
+ }
15
+ return false;
16
+ }
17
+ /** Load the optional MCP client only when a connection is actually requested. */
18
+ export function loadMcpSdk() {
19
+ sdkPromise ?? (sdkPromise = import('@modelcontextprotocol/client')
20
+ .then((client) => ({
21
+ Client: client.Client,
22
+ SSEClientTransport: client.SSEClientTransport,
23
+ StreamableHTTPClientTransport: client.StreamableHTTPClientTransport,
24
+ UnauthorizedError: client.UnauthorizedError,
25
+ }))
26
+ .catch((cause) => {
27
+ sdkPromise = undefined;
28
+ if (isMissingSdk(cause)) {
29
+ throw new MCPMissingPeerDependencyError({
30
+ cause,
31
+ });
32
+ }
33
+ throw cause;
34
+ }));
35
+ return sdkPromise;
36
+ }
37
+ //# sourceMappingURL=mcp-sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-sdk.js","sourceRoot":"","sources":["../../src/mcp/mcp-sdk.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,6BAA6B,EAAE,MAAM,aAAa,CAAC;AAS5D,IAAI,UAAuC,CAAC;AAE5C,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,OAAO,OAAO,YAAY,KAAK,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1D,MAAM,SAAS,GAAG,0CAA0C,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxF,IACE,CAAC,IAAI,KAAK,sBAAsB,IAAI,IAAI,KAAK,kBAAkB,CAAC;YAChE,CAAC,SAAS,KAAK,8BAA8B;gBAC3C,SAAS,EAAE,UAAU,CAAC,+BAA+B,CAAC,KAAK,IAAI,CAAC,EAClE,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU;IACxB,UAAU,KAAV,UAAU,GAAK,MAAM,CAAC,8BAA8B,CAAC;SAClD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,kBAAkB,EAAE,MAAM,CAAC,kBAAkB;QAC7C,6BAA6B,EAAE,MAAM,CAAC,6BAA6B;QACnE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;KAC5C,CAAC,CAAC;SACF,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QACxB,UAAU,GAAG,SAAS,CAAC;QACvB,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,6BAA6B,CAAC;gBACtC,KAAK;aACN,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,EAAC;IACL,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,76 @@
1
+ import type { MCPAuth } from './auth/auth-types.js';
2
+ import type { MCPCacheStore } from './cache/cache-store.js';
3
+ import type { SerializedMCPServer } from './cache/cache-types.js';
4
+ import type { UnconvertibleSchemaMode } from './schema/json-schema-to-zod.js';
5
+ import type { CreateMCPToolsOptions, ElicitationHandler, MCPProtocolNegotiation, MCPToolsHandle, ResourcesOption } from './types.js';
6
+ export interface RehydrateMCPToolsOptions {
7
+ snapshot: SerializedMCPServer;
8
+ /** Required when the snapshot carries no cached credentials. */
9
+ auth?: MCPAuth;
10
+ fetch?: typeof fetch;
11
+ onUnconvertibleSchema?: UnconvertibleSchemaMode;
12
+ onElicitation?: ElicitationHandler;
13
+ signal?: AbortSignal;
14
+ /** Protocol-revision negotiation policy; defaults to `'auto'`. */
15
+ protocolNegotiation?: MCPProtocolNegotiation;
16
+ /** Ceiling on the `server/discover` probe, in ms; defaults to 30000. */
17
+ probeTimeoutMs?: number;
18
+ /** Re-list tools instead of replaying a snapshot older than this. */
19
+ staleness?: {
20
+ maxAgeMs?: number;
21
+ };
22
+ /**
23
+ * Cache to refresh on reconnect/fallback.
24
+ *
25
+ * A successful replay does **not** write here — the snapshot it would write is
26
+ * the one you passed in, so the write is skipped as a no-op. The store is
27
+ * written when something genuinely new exists: a `refresh()`, a
28
+ * `tools/list_changed` auto-refresh, or the fresh-connect fallback. To seed a
29
+ * store from a snapshot obtained elsewhere, write it yourself
30
+ * (`store.set(key, snapshot)`) or call `handle.refresh()` after rehydrating.
31
+ */
32
+ cache?: {
33
+ store: MCPCacheStore;
34
+ key?: string;
35
+ };
36
+ /**
37
+ * On expired cached tokens, missing credentials, an over-age snapshot
38
+ * (`staleness.maxAgeMs`), or a replay connection failure, transparently fall
39
+ * back to a full fresh connect. Default true.
40
+ *
41
+ * The fallback is skipped when the replay's connect ended in a credential
42
+ * rejection (the SDK's `UnauthorizedError`, or a 401 status when an OAuth
43
+ * provider is configured): the fallback reuses the same auth, so retrying
44
+ * cannot succeed and would re-drive an OAuth authorization flow. Those
45
+ * failures reject with `MCPCacheError` instead. A 403 does not skip it — the
46
+ * SDK's OAuth side effects only occur on 401, and gateways commonly answer
47
+ * unknown methods with 403.
48
+ */
49
+ reconnectOnExpiry?: boolean;
50
+ toolNamePrefix?: string;
51
+ includeTools?: readonly string[];
52
+ excludeTools?: readonly string[];
53
+ resources?: ResourcesOption;
54
+ emitProgress?: boolean;
55
+ /** Doom-loop identities for wrapped tools, keyed by unprefixed MCP name. */
56
+ loopKeys?: CreateMCPToolsOptions['loopKeys'];
57
+ autoRefreshOnListChanged?: boolean;
58
+ cacheCredentials?: boolean;
59
+ clientInfo?: {
60
+ name: string;
61
+ version: string;
62
+ };
63
+ }
64
+ /**
65
+ * Rebuild an {@link MCPToolsHandle} from a cached snapshot. On the happy path we
66
+ * reconnect the transport and rebuild tools directly from the snapshot —
67
+ * skipping `listTools()`. If cached tokens are expired, credentials are missing,
68
+ * the snapshot is older than `staleness.maxAgeMs`, or the replay connection
69
+ * fails, we transparently fall back to a fresh connect (unless
70
+ * `reconnectOnExpiry` is false) — with one exception: a credential rejection is
71
+ * not retried, because the fallback reuses the same auth and re-attempting
72
+ * would re-drive an OAuth authorization flow. See {@link
73
+ * RehydrateMCPToolsOptions.reconnectOnExpiry}.
74
+ */
75
+ export declare function rehydrateMCPTools(options: RehydrateMCPToolsOptions): Promise<MCPToolsHandle>;
76
+ //# sourceMappingURL=rehydrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehydrate.d.ts","sourceRoot":"","sources":["../../src/mcp/rehydrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAQlE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE9E,OAAO,KAAK,EACV,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,gEAAgE;IAChE,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,qBAAqB,CAAC,EAAE,uBAAuB,CAAC;IAChD,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kEAAkE;IAClE,mBAAmB,CAAC,EAAE,sBAAsB,CAAC;IAC7C,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,aAAa,CAAC;QACrB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAG5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC7C,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAoaD;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,cAAc,CAAC,CAqHzB"}
@@ -0,0 +1,505 @@
1
+ import { resolveAuth } from './auth/auth-resolver.js';
2
+ import { isOAuthAuth } from './auth/auth-types.js';
3
+ import { defaultCacheKey } from './cache/cache-store.js';
4
+ import { isSerializedMCPServer } from './cache/cache-types.js';
5
+ import { closeQuietly } from './close-quietly.js';
6
+ import { MCPCacheError, MCPCacheWriteError, MCPStaleSnapshotError } from './errors.js';
7
+ import { freshConnect, makeHandle } from './handle.js';
8
+ import { connect, isAuthFailure } from './mcp-connection.js';
9
+ import { loadMcpSdk } from './mcp-sdk.js';
10
+ /** Clock skew (ms) treated as "already expired" when checking cached tokens. */
11
+ const EXPIRY_SKEW_MS = 30000;
12
+ function snapshotToToolDefs(snapshot) {
13
+ return snapshot.tools.map((t) => ({
14
+ name: t.name,
15
+ ...(t.description !== undefined && {
16
+ description: t.description,
17
+ }),
18
+ inputSchema: {
19
+ ...t.inputSchema,
20
+ },
21
+ ...(t.outputSchema !== undefined && {
22
+ outputSchema: {
23
+ ...t.outputSchema,
24
+ },
25
+ }),
26
+ ...(t.loopKey !== undefined && {
27
+ loopKey: t.loopKey,
28
+ }),
29
+ }));
30
+ }
31
+ /** A snapshot older than `maxAgeMs` should be re-listed rather than replayed. */
32
+ function snapshotIsStale(snapshot, maxAgeMs) {
33
+ if (maxAgeMs === undefined) {
34
+ return false;
35
+ }
36
+ return Date.now() - snapshot.cachedAt > maxAgeMs;
37
+ }
38
+ /** Cached tokens are unusable if they have a known expiry within the skew window. */
39
+ function tokensExpired(snapshot) {
40
+ const expiresAt = snapshot.auth?.tokens?.expiresAt;
41
+ if (expiresAt === undefined) {
42
+ return false;
43
+ }
44
+ return expiresAt - Date.now() <= EXPIRY_SKEW_MS;
45
+ }
46
+ /**
47
+ * Reconstruct an {@link MCPAuth} from credentials persisted in a snapshot (only
48
+ * present when it was serialized with `cacheCredentials: true`). Prefer static
49
+ * headers when present; otherwise fall back to the OAuth/bearer access token.
50
+ * Returns undefined when the snapshot carries no usable credentials.
51
+ */
52
+ function authFromSnapshot(snapshot) {
53
+ const auth = snapshot.auth;
54
+ if (auth === undefined) {
55
+ return undefined;
56
+ }
57
+ if (auth.headers !== undefined && Object.keys(auth.headers).length > 0) {
58
+ return {
59
+ kind: 'headers',
60
+ headers: auth.headers,
61
+ };
62
+ }
63
+ if (auth.tokens?.accessToken !== undefined) {
64
+ return {
65
+ kind: 'bearer',
66
+ token: auth.tokens.accessToken,
67
+ };
68
+ }
69
+ return undefined;
70
+ }
71
+ /**
72
+ * Options copied straight from a rehydrate call onto the `createMCPTools`
73
+ * options used for the fresh-connect fallback. `satisfies` keeps this honest:
74
+ * a key that isn't on both types fails to compile rather than silently
75
+ * dropping.
76
+ *
77
+ * `staleness` is deliberately absent — it compares a snapshot's age, and the
78
+ * fallback path has no snapshot to compare.
79
+ */
80
+ const PASS_THROUGH_CREATE_KEYS = [
81
+ 'fetch',
82
+ 'onUnconvertibleSchema',
83
+ 'onElicitation',
84
+ 'protocolNegotiation',
85
+ 'probeTimeoutMs',
86
+ 'signal',
87
+ 'clientInfo',
88
+ 'toolNamePrefix',
89
+ 'includeTools',
90
+ 'excludeTools',
91
+ 'resources',
92
+ 'emitProgress',
93
+ 'loopKeys',
94
+ 'autoRefreshOnListChanged',
95
+ 'cacheCredentials',
96
+ 'cache',
97
+ ];
98
+ function toCreateOptions(options, snapshot, effectiveAuth) {
99
+ const out = {
100
+ url: snapshot.url,
101
+ transport: snapshot.transport,
102
+ ...(effectiveAuth !== undefined && {
103
+ auth: effectiveAuth,
104
+ }),
105
+ };
106
+ // Copy every defined pass-through key in one pass. Written as a loop rather
107
+ // than a spread per key so adding an option doesn't push this function's
108
+ // cyclomatic complexity past the structural gate's ceiling; it also mirrors
109
+ // `forwardedRehydrateOptions` in create-mcp-tools.ts, which forwards the same
110
+ // set in the opposite direction.
111
+ for (const key of PASS_THROUGH_CREATE_KEYS) {
112
+ const value = options[key];
113
+ if (value !== undefined) {
114
+ Object.assign(out, {
115
+ [key]: value,
116
+ });
117
+ }
118
+ }
119
+ return out;
120
+ }
121
+ /**
122
+ * Connect options for the snapshot-replay path.
123
+ *
124
+ * Distinct from {@link toCreateOptions}, which builds the *fallback*
125
+ * `createMCPTools` options: this one carries the snapshot's own `transport` and
126
+ * `sessionId` because the point is to re-establish the connection the snapshot
127
+ * describes, and it deliberately omits the tool-shaping keys, which are applied
128
+ * by `makeHandle` rather than at connect time.
129
+ */
130
+ function toReplayConnectOptions(args) {
131
+ const { options, snapshot, url, effectiveAuth } = args;
132
+ return {
133
+ url,
134
+ transport: snapshot.transport,
135
+ ...(effectiveAuth !== undefined && {
136
+ auth: effectiveAuth,
137
+ }),
138
+ ...(options.fetch !== undefined && {
139
+ fetch: options.fetch,
140
+ }),
141
+ ...(options.clientInfo !== undefined && {
142
+ clientInfo: options.clientInfo,
143
+ }),
144
+ // `sessionId` is deliberately NOT forwarded. When a transport reports one,
145
+ // SDK v2 skips negotiation entirely — no `server/discover` probe and no
146
+ // `initialize` — and returns with `getProtocolEra()`,
147
+ // `getServerCapabilities()` and `getServerVersion()` all left undefined. It
148
+ // does not error, which is what makes it dangerous: `serverHasResources()`
149
+ // reads those capabilities, so a snapshot carrying a `sessionId` would
150
+ // silently replay with resource tools missing and no server info. Sessions
151
+ // are also removed outright in 2026-07-28 (SEP-2567), so a fresh handshake
152
+ // is both correct and cheap — one round trip on a path that already opens a
153
+ // connection.
154
+ ...(options.onElicitation !== undefined && {
155
+ onElicitation: options.onElicitation,
156
+ }),
157
+ ...(options.protocolNegotiation !== undefined && {
158
+ protocolNegotiation: options.protocolNegotiation,
159
+ }),
160
+ ...(options.probeTimeoutMs !== undefined && {
161
+ probeTimeoutMs: options.probeTimeoutMs,
162
+ }),
163
+ ...(options.signal !== undefined && {
164
+ signal: options.signal,
165
+ }),
166
+ };
167
+ }
168
+ /**
169
+ * Re-list tools on a handle built from a snapshot older than the caller's
170
+ * `staleness.maxAgeMs`.
171
+ *
172
+ * Reached only when `reconnectOnExpiry` is false — otherwise a stale snapshot
173
+ * has already gone to `freshConnect`. Re-listing over the connection just opened
174
+ * honours `maxAgeMs` without the reconnect the caller declined: "stale" means the
175
+ * tool set needs re-reading, not that the transport needs rebuilding.
176
+ * `refresh()` also clears the carried `cachedAt`, so the write-back records the
177
+ * new age rather than carrying the snapshot's forward.
178
+ */
179
+ async function refreshStaleReplay(handle) {
180
+ // `refresh()` swaps `handle.tools` to a fresh array exactly when the re-list
181
+ // succeeded, before it persists — so the reference tells re-list failure
182
+ // apart from persistence failure. Keying on that rather than on
183
+ // `MCPCacheWriteError` matters because persistence can fail OUTSIDE the
184
+ // store op too (the caller's OAuth provider rejecting inside `snapshot()`),
185
+ // and that failure must not masquerade as "re-listing tools failed".
186
+ const before = handle.tools;
187
+ try {
188
+ await handle.refresh();
189
+ }
190
+ catch (refreshErr) {
191
+ // Tools adopted: the re-list succeeded and only the persistence after it
192
+ // broke. Survivable, and must not fail the call — the tools ARE current;
193
+ // only the cache entry is stale, and the next rehydrate re-reads it.
194
+ // (A transient store outage here used to discard a connection whose tools
195
+ // had just been read successfully.)
196
+ if (handle.tools !== before || refreshErr instanceof MCPCacheWriteError) {
197
+ return;
198
+ }
199
+ // A failed re-list is not. The connection is live and the snapshot's tools
200
+ // would work, but they are older than the caller's own `maxAgeMs` — serving
201
+ // them anyway is exactly the unbounded-age bug that check exists to prevent.
202
+ await closeQuietly(handle);
203
+ throw new MCPStaleSnapshotError('Snapshot is older than staleness.maxAgeMs and re-listing tools failed', {
204
+ cause: refreshErr,
205
+ });
206
+ }
207
+ }
208
+ /**
209
+ * The cases where a successful replay still writes to the cache store.
210
+ *
211
+ * The replay write-back is normally skipped as a no-op — the snapshot it would
212
+ * persist is the one just read. Three exceptions where the write genuinely does
213
+ * something, all best-effort:
214
+ *
215
+ * 1. **OAuth token rotation.** With `cacheCredentials: true` and an OAuth
216
+ * provider, the old per-hit write re-serialized the provider's *current*
217
+ * tokens; without it the stored entry keeps cold-connect-time tokens, and
218
+ * once those pass `expiresAt` every rehydrate takes the fresh-connect
219
+ * detour even though the provider holds a valid refreshed token.
220
+ * 2. **Static credential rotation.** Same story for `bearer`/`headers` auth:
221
+ * the old per-hit write kept the stored `auth.headers` in sync with the
222
+ * caller's live `auth`, so a rotated API key propagated on the next warm
223
+ * hit. When the caller passes static auth under `cacheCredentials: true`
224
+ * and the resolved headers differ from the stored ones, the stored entry's
225
+ * header block is updated — otherwise a later credential-bearing rehydrate
226
+ * (`authFromSnapshot`) would dial with the superseded secret.
227
+ * 3. **Legacy `sessionId` scrub.** Entries written by earlier versions can
228
+ * carry a bearer-equivalent `Mcp-Session-Id` under `cacheCredentials`; with
229
+ * the warm path never rewriting, that credential-grade value would sit in
230
+ * the external store indefinitely. One write — the entry copied without the
231
+ * field — removes it.
232
+ *
233
+ * All three share one invariant: they only ever REWRITE an entry the store
234
+ * already holds, read back first. The credential grafts move only their block
235
+ * onto the stored entry rather than re-serializing this call's live state — a
236
+ * direct `rehydrateMCPTools` may have loaded its snapshot from a file or
237
+ * another key, and writing that snapshot's (older) tool set and `cachedAt`
238
+ * over the store's entry would roll back a newer entry written by a concurrent
239
+ * `refresh()`. Copying the stored entry also cannot strip or introduce
240
+ * credentials the way a re-serialize under this call's options could (the
241
+ * DEV-766 hazard): each block is only updated where the stored entry already
242
+ * carries that block.
243
+ */
244
+ /**
245
+ * Graft the provider's current tokens onto the STORED entry — never the other
246
+ * way round.
247
+ *
248
+ * Only the token block moves; the stored entry's tool set and `cachedAt` stay
249
+ * untouched, so a direct rehydrate whose input snapshot is older than the
250
+ * store's entry (a concurrent `refresh()` having written since) cannot roll the
251
+ * entry back. Returns undefined — no write — when the stored entry carries no
252
+ * tokens (grafting would introduce credentials into an entry that never held
253
+ * them) or the fresh serialize produced none.
254
+ *
255
+ * An UNROTATED token — same access token as stored — grafts nothing at all,
256
+ * for three reasons that all point the same way. No per-replay write (the
257
+ * documented warm-path economy, and no re-touching TTL-extending stores). No
258
+ * expiry ratchet: `serializeServer` stamps `expiresAt` as `Date.now() +
259
+ * expires_in * 1000`, but `expires_in` is relative to *issuance* (RFC 6749
260
+ * §5.1), so re-persisting the same token would push the recorded expiry
261
+ * forward each replay and `tokensExpired()` would never trip. And no field
262
+ * loss: a wholesale replace would drop stored fields the provider's `tokens()`
263
+ * no longer reports (a `refreshToken` held elsewhere, say) without any actual
264
+ * rotation. A rotated token replaces the block, fresh restamp included — the
265
+ * SDK just obtained it, so its relative `expires_in` genuinely is from ~now.
266
+ */
267
+ function graftRotatedTokens(stored, serialized) {
268
+ const prev = stored.auth?.tokens;
269
+ const next = serialized.auth?.tokens;
270
+ if (prev === undefined || next === undefined) {
271
+ return undefined;
272
+ }
273
+ if (next.accessToken === prev.accessToken) {
274
+ return undefined;
275
+ }
276
+ return {
277
+ ...stored,
278
+ auth: {
279
+ ...stored.auth,
280
+ tokens: {
281
+ ...next,
282
+ },
283
+ },
284
+ };
285
+ }
286
+ function headersEqual(a, b) {
287
+ const aKeys = Object.keys(a);
288
+ return aKeys.length === Object.keys(b).length && aKeys.every((k) => a[k] === b[k]);
289
+ }
290
+ /**
291
+ * Graft the caller's current static headers onto the STORED entry — the
292
+ * `bearer`/`headers` counterpart of {@link graftRotatedTokens}, under the same
293
+ * invariants: only the header block moves, and only where the stored entry
294
+ * already carries headers (never introducing credentials into an entry that
295
+ * had none). Returns undefined — no write — when there is nothing to update.
296
+ */
297
+ function graftStaticHeaders(stored, headers) {
298
+ const prev = stored.auth?.headers;
299
+ if (prev === undefined || Object.keys(prev).length === 0 || Object.keys(headers).length === 0) {
300
+ return undefined;
301
+ }
302
+ if (headersEqual(prev, headers)) {
303
+ return undefined;
304
+ }
305
+ return {
306
+ ...stored,
307
+ auth: {
308
+ ...stored.auth,
309
+ headers,
310
+ },
311
+ };
312
+ }
313
+ /**
314
+ * Compute the maintenance rewrite for a stored entry, if any: an OAuth token
315
+ * graft, a static-header graft, or nothing. Split from
316
+ * {@link maintainReplayedEntry} to keep each piece readable.
317
+ */
318
+ async function graftForReplay(args) {
319
+ const { options, handle, stored, effectiveAuth } = args;
320
+ if (options.cacheCredentials !== true) {
321
+ return undefined;
322
+ }
323
+ if (isOAuthAuth(effectiveAuth)) {
324
+ return graftRotatedTokens(stored, await handle.serialize());
325
+ }
326
+ // Static graft keys on the CALLER's auth, not `effectiveAuth`: auth derived
327
+ // from the input snapshot is by definition not a rotation.
328
+ if (options.auth !== undefined) {
329
+ return graftStaticHeaders(stored, resolveAuth(options.auth).headers);
330
+ }
331
+ return undefined;
332
+ }
333
+ async function maintainReplayedEntry(args) {
334
+ const { options, handle, cacheKey, effectiveAuth } = args;
335
+ const store = options.cache?.store;
336
+ if (store === undefined) {
337
+ return;
338
+ }
339
+ try {
340
+ // Cheap gates first, so a warm hit with nothing to maintain performs ZERO
341
+ // store operations. Credential grafts can only apply under
342
+ // `cacheCredentials: true`; the scrub can only be needed when the *input*
343
+ // snapshot carries a legacy `sessionId` (on the warm `createMCPTools` path
344
+ // the input IS the store's entry, so a sessionId-free input — every entry
345
+ // this version writes — means a sessionId-free store).
346
+ const mayGraft = options.cacheCredentials === true &&
347
+ (isOAuthAuth(effectiveAuth) || options.auth !== undefined);
348
+ if (!mayGraft && args.snapshot.sessionId === undefined) {
349
+ return;
350
+ }
351
+ // Read back before writing: every maintenance write is a rewrite of what
352
+ // THIS store currently holds, never a serialize of this call's state — a
353
+ // direct rehydrate's input snapshot may be older than the store's entry (a
354
+ // concurrent refresh() having written since), and its auth may belong to a
355
+ // store that never held credentials. One read per maintained replay is the
356
+ // price.
357
+ const stored = await store.get(cacheKey);
358
+ if (stored === null || stored === undefined || !isSerializedMCPServer(stored)) {
359
+ return;
360
+ }
361
+ const grafted = mayGraft
362
+ ? await graftForReplay({
363
+ options,
364
+ handle,
365
+ stored,
366
+ effectiveAuth,
367
+ })
368
+ : undefined;
369
+ // Nothing to graft and nothing to scrub — no write. A legacy sessionId in
370
+ // the stored entry composes with either graft into one write.
371
+ if (grafted === undefined && stored.sessionId === undefined) {
372
+ return;
373
+ }
374
+ const next = {
375
+ ...(grafted ?? stored),
376
+ };
377
+ delete next.sessionId;
378
+ await store.set(cacheKey, next);
379
+ }
380
+ catch {
381
+ // Best-effort, like every other store write: a cache outage never fails a
382
+ // working replay.
383
+ }
384
+ }
385
+ /**
386
+ * Rebuild an {@link MCPToolsHandle} from a cached snapshot. On the happy path we
387
+ * reconnect the transport and rebuild tools directly from the snapshot —
388
+ * skipping `listTools()`. If cached tokens are expired, credentials are missing,
389
+ * the snapshot is older than `staleness.maxAgeMs`, or the replay connection
390
+ * fails, we transparently fall back to a fresh connect (unless
391
+ * `reconnectOnExpiry` is false) — with one exception: a credential rejection is
392
+ * not retried, because the fallback reuses the same auth and re-attempting
393
+ * would re-drive an OAuth authorization flow. See {@link
394
+ * RehydrateMCPToolsOptions.reconnectOnExpiry}.
395
+ */
396
+ export async function rehydrateMCPTools(options) {
397
+ const { snapshot } = options;
398
+ if (!isSerializedMCPServer(snapshot)) {
399
+ throw new MCPCacheError('Invalid MCP snapshot: failed structural validation');
400
+ }
401
+ const reconnectOnExpiry = options.reconnectOnExpiry ?? true;
402
+ const url = new URL(snapshot.url);
403
+ const cacheKey = options.cache?.key ?? defaultCacheKey(url.href);
404
+ // Fall back to credentials cached in the snapshot when the caller didn't pass
405
+ // any — otherwise a credential-bearing snapshot would reconnect unauthenticated.
406
+ const effectiveAuth = options.auth ?? authFromSnapshot(snapshot);
407
+ const hasCredentials = effectiveAuth !== undefined;
408
+ // Route the fallback through `freshConnect`, NOT `createMCPTools`: the latter
409
+ // would re-read this same snapshot and re-enter rehydrate, recursing without
410
+ // bound on any no-credential / expired-token snapshot. `freshConnect` still
411
+ // writes the refreshed result back to the cache via `makeHandle`.
412
+ const createOptions = toCreateOptions(options, snapshot, effectiveAuth);
413
+ // Staleness is checked here as well as in `createMCPTools`'s cache-hit path,
414
+ // so a direct `rehydrateMCPTools()` call honours `staleness.maxAgeMs` too.
415
+ // Previously only the `createMCPTools` route checked it, meaning callers who
416
+ // held their own snapshot silently got unbounded-age tools.
417
+ const staleSnapshot = snapshotIsStale(snapshot, options.staleness?.maxAgeMs);
418
+ if ((tokensExpired(snapshot) || !hasCredentials || staleSnapshot) && reconnectOnExpiry) {
419
+ return freshConnect(createOptions, url, cacheKey);
420
+ }
421
+ // Held outside the `try` so the `catch` can tear it down. `connect()` releases
422
+ // its own client when it fails, so this stays undefined on that path and only
423
+ // a post-connect failure has something to close.
424
+ let connection;
425
+ try {
426
+ connection = await connect(toReplayConnectOptions({
427
+ options,
428
+ snapshot,
429
+ url,
430
+ effectiveAuth,
431
+ }));
432
+ // Rebuild tools from the snapshot — no listTools() round-trip.
433
+ const handle = await makeHandle({
434
+ connection,
435
+ options: createOptions,
436
+ context: {
437
+ url,
438
+ transport: connection.transport,
439
+ cacheKey,
440
+ },
441
+ initialToolDefs: snapshotToToolDefs(snapshot),
442
+ // Replay, not a listTools() — keep the snapshot's original age so
443
+ // staleness.maxAgeMs stays measurable across repeated rehydrates.
444
+ replayedCachedAt: snapshot.cachedAt,
445
+ });
446
+ if (staleSnapshot) {
447
+ // `refresh()` re-listed and wrote the entry through `serialize` — which
448
+ // carries the provider's current tokens and omits `sessionId` — so every
449
+ // maintenance concern below is already satisfied. Running the scrub here
450
+ // would clobber the just-refreshed entry with the caller's older input
451
+ // snapshot.
452
+ await refreshStaleReplay(handle);
453
+ }
454
+ else {
455
+ await maintainReplayedEntry({
456
+ options,
457
+ snapshot,
458
+ handle,
459
+ cacheKey,
460
+ effectiveAuth,
461
+ });
462
+ }
463
+ return handle;
464
+ }
465
+ catch (err) {
466
+ // The stale re-list above already closed and reported; let its verdict stand
467
+ // rather than re-wrapping it as a generic rehydrate failure (and
468
+ // double-closing). It is a deliberate refusal, not a rehydrate that broke.
469
+ if (err instanceof MCPStaleSnapshotError) {
470
+ throw err;
471
+ }
472
+ // Tear down the replay connection before leaving this path, mirroring
473
+ // `freshConnect`'s guarantee in handle.ts. Whether we fall back (which opens
474
+ // its own connection) or rethrow, nothing else holds a reference to this
475
+ // one, so without the close its transport leaks. Reachable via `buildTools`
476
+ // rejecting on a duplicate tool name, or a caller's `cache.store.set`
477
+ // throwing during the initial write.
478
+ if (connection !== undefined) {
479
+ await closeQuietly(connection);
480
+ }
481
+ // The fallback is a third reconnect layer, and it reuses the same auth. If
482
+ // the replay's connect ended in a credential rejection, `freshConnect` would
483
+ // re-drive the OAuth flow — a third `redirectToAuthorization` behind the two
484
+ // layers below that already guard against exactly this. Rejected credentials
485
+ // are not something a fresh connection fixes.
486
+ // An aborted caller gets no fallback either — the third reconnect layer,
487
+ // matching the guards on the SSE fallback and the legacy retry. Dialling a
488
+ // fresh connection after the caller cancelled would both waste the dial and
489
+ // bury the cancellation under a "failed to connect" it didn't cause.
490
+ const { UnauthorizedError } = await loadMcpSdk();
491
+ if (reconnectOnExpiry &&
492
+ options.signal?.aborted !== true &&
493
+ !isAuthFailure({
494
+ err,
495
+ auth: effectiveAuth,
496
+ UnauthorizedErrorType: UnauthorizedError,
497
+ })) {
498
+ return freshConnect(createOptions, url, cacheKey);
499
+ }
500
+ throw new MCPCacheError('Failed to rehydrate MCP connection from snapshot', {
501
+ cause: err,
502
+ });
503
+ }
504
+ }
505
+ //# sourceMappingURL=rehydrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehydrate.js","sourceRoot":"","sources":["../../src/mcp/rehydrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Client } from '@modelcontextprotocol/client';
2
+ import type { McpBranded } from '../lib/tool-types.js';
3
+ export interface ResourceToolsOptions {
4
+ client: Client;
5
+ namePrefix?: string;
6
+ signal?: AbortSignal;
7
+ }
8
+ /**
9
+ * Build synthetic tools that let the model browse and read MCP resources
10
+ * through the normal tool loop:
11
+ * - `list_resources`: concrete resources plus resource templates.
12
+ * - `read_resource`: fetch a resource's contents by URI.
13
+ *
14
+ * Only call this when the server advertises the `resources` capability.
15
+ */
16
+ export declare function buildResourceTools(options: ResourceToolsOptions): McpBranded[];
17
+ //# sourceMappingURL=resource-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/resource-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAG3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAgFD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,UAAU,EAAE,CAwH9E"}