@code-yeongyu/senpi 2026.10.25-2 → 2026.10.25-3

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 (199) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/bundle/chunks/{args-JXULI4EH.js → args-B444OQBK.js} +1 -1
  3. package/dist/bundle/chunks/{auth-4NUNUSTF.js → auth-C77UQA55.js} +1 -1
  4. package/dist/bundle/chunks/chunk-6O4SEW2W.js +5 -0
  5. package/dist/bundle/chunks/{chunk-Y5OTHMXO.js → chunk-7CNOCJCN.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-JRXKLIEQ.js → chunk-7W7OJDIY.js} +4 -4
  7. package/dist/bundle/chunks/chunk-AX72VNRS.js +27 -0
  8. package/dist/bundle/chunks/{chunk-LYGAV6KU.js → chunk-C5UFJ7B3.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-G2UETS2R.js → chunk-CNL6QSUB.js} +4 -4
  10. package/dist/bundle/chunks/{chunk-2EFVQWXZ.js → chunk-FFQOEC76.js} +3 -3
  11. package/dist/bundle/chunks/chunk-H3HNMY2W.js +13 -0
  12. package/dist/bundle/chunks/{chunk-W2BKZBYJ.js → chunk-HVJI5T75.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-YN7ELQ43.js → chunk-JA2R2ZSE.js} +1 -1
  14. package/dist/bundle/chunks/chunk-JPGT64RV.js +2 -0
  15. package/dist/bundle/chunks/chunk-KXB5WIS5.js +4 -0
  16. package/dist/bundle/chunks/chunk-L73UYAH5.js +3 -0
  17. package/dist/bundle/chunks/chunk-LTU6UFEX.js +2 -0
  18. package/dist/bundle/chunks/{chunk-KUE4AQN6.js → chunk-MJ5NNWX4.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-WFXUCVIR.js → chunk-O3Q2ET6W.js} +2 -5
  20. package/dist/bundle/chunks/{chunk-MXZPAUFB.js → chunk-ODTGC6YU.js} +1 -1
  21. package/dist/bundle/chunks/chunk-P3M2PF6K.js +27 -0
  22. package/dist/bundle/chunks/{chunk-VNN2V74Y.js → chunk-SWJXRC2I.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-RXKNOEQQ.js → chunk-UQNRW3VU.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-U67ML6CQ.js → chunk-WD6WBYC5.js} +1 -1
  25. package/dist/bundle/chunks/chunk-WJOT3DFL.js +2 -0
  26. package/dist/bundle/chunks/{chunk-XBUSVKWC.js → chunk-WLHNEUGD.js} +1 -1
  27. package/dist/bundle/chunks/chunk-YI7SPFDN.js +5 -0
  28. package/dist/bundle/chunks/{chunk-J2U5VDG7.js → chunk-YRF4I43T.js} +28 -28
  29. package/dist/bundle/chunks/chunk-Z3UYNSVR.js +3 -0
  30. package/dist/bundle/chunks/cli-main-HEKFFB5S.js +3 -0
  31. package/dist/bundle/chunks/{client-KWTLTKVV.js → client-WTYEICLH.js} +3 -3
  32. package/dist/bundle/chunks/dispatch-NYAULNVW.js +9 -0
  33. package/dist/bundle/chunks/{help-fast-path-ZHZGXAUG.js → help-fast-path-3Z26DQSV.js} +1 -1
  34. package/dist/bundle/chunks/host-command-Z3WPHJOW.js +2 -0
  35. package/dist/bundle/chunks/host-lifecycle-ONQIMWMX.js +3 -0
  36. package/dist/bundle/chunks/host-lifecycle.js +7 -5
  37. package/dist/bundle/chunks/host-session-command-J65ENSV5.js +20 -0
  38. package/dist/bundle/chunks/{host-socket-request-AS2OCRLP.js → host-socket-request-3CWE4265.js} +1 -1
  39. package/dist/bundle/chunks/interactive-mode-DEPQC6TX.js +2 -0
  40. package/dist/bundle/chunks/mcp-presenter-bootstrap-XUSCQVRC.js +2 -0
  41. package/dist/bundle/chunks/{multi-session-host-VTTY5MFT.js → multi-session-host-YI2WZOET.js} +12 -9
  42. package/dist/bundle/chunks/{package-manager-cli-DZFOC3MF.js → package-manager-cli-GHZPJMRF.js} +1 -1
  43. package/dist/bundle/chunks/{rotation-stream-U7YQMC7H.js → rotation-stream-ZPVCFOVD.js} +1 -1
  44. package/dist/bundle/chunks/rpc-mode-ORHBGBBV.js +2 -0
  45. package/dist/bundle/chunks/{rpc-monitor-source-B5NQ4ZVH.js → rpc-monitor-source-FFEQS744.js} +1 -1
  46. package/dist/bundle/chunks/{schedule-command-SLISTG4V.js → schedule-command-YWG6D6ZF.js} +1 -1
  47. package/dist/bundle/chunks/session-control-endpoint-36HAQSQO.js +3 -0
  48. package/dist/bundle/chunks/{session-picker-465FVXQG.js → session-picker-25H5KNYP.js} +1 -1
  49. package/dist/bundle/chunks/session-worker.js +278 -264
  50. package/dist/bundle/chunks/{stdio-IEC635SY.js → stdio-YXDKKKQZ.js} +1 -1
  51. package/dist/bundle/chunks/{streamableHttp-KJI5KE4K.js → streamableHttp-DKIBUWVY.js} +1 -1
  52. package/dist/bundle/chunks/{types-LLNV23LW.js → types-BJUEQ4II.js} +1 -1
  53. package/dist/bundle/chunks/zod-compat-RJDXCU7S.js +2 -0
  54. package/dist/bundle/cli.js +2 -2
  55. package/dist/bundle/host-supervisor.js +7 -5
  56. package/dist/bundle/index.js +1 -1
  57. package/dist/bundle/rpc-entry.js +1 -1
  58. package/dist/bundle/runtime-manifest.json +1 -1
  59. package/dist/cli/args.d.ts +2 -0
  60. package/dist/cli/args.js +9 -0
  61. package/dist/cli/host-command-args.d.ts +1 -0
  62. package/dist/cli/host-command-args.js +7 -1
  63. package/dist/cli/host-command.js +3 -1
  64. package/dist/core/agent-session.js +22 -7
  65. package/dist/core/extensions/builtin/goal/index.js +1 -0
  66. package/dist/core/extensions/builtin/goal/lifecycle-facts.d.ts +3 -0
  67. package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -1
  68. package/dist/core/extensions/builtin/mcp/catalog.js +2 -0
  69. package/dist/core/extensions/builtin/mcp/connection.d.ts +1 -0
  70. package/dist/core/extensions/builtin/mcp/connection.js +46 -1
  71. package/dist/core/extensions/builtin/mcp/elicitation.d.ts +6 -1
  72. package/dist/core/extensions/builtin/mcp/elicitation.js +56 -2
  73. package/dist/core/extensions/builtin/mcp/expose/call.js +6 -2
  74. package/dist/core/extensions/builtin/mcp/expose/session.d.ts +4 -1
  75. package/dist/core/extensions/builtin/mcp/expose/session.js +7 -0
  76. package/dist/core/extensions/builtin/mcp/health.js +5 -0
  77. package/dist/core/extensions/builtin/mcp/host-registry.js +7 -1
  78. package/dist/core/extensions/builtin/mcp/index.js +2 -0
  79. package/dist/core/extensions/builtin/mcp/modern/client.d.ts +5 -0
  80. package/dist/core/extensions/builtin/mcp/modern/client.js +15 -0
  81. package/dist/core/extensions/builtin/mcp/modern/consent-queue.d.ts +2 -0
  82. package/dist/core/extensions/builtin/mcp/modern/consent-queue.js +59 -0
  83. package/dist/core/extensions/builtin/mcp/modern/diagnostics.d.ts +4 -0
  84. package/dist/core/extensions/builtin/mcp/modern/diagnostics.js +39 -0
  85. package/dist/core/extensions/builtin/mcp/modern/dispatch.js +21 -11
  86. package/dist/core/extensions/builtin/mcp/modern/elicitation.d.ts +14 -0
  87. package/dist/core/extensions/builtin/mcp/modern/elicitation.js +145 -0
  88. package/dist/core/extensions/builtin/mcp/modern/errors.d.ts +21 -0
  89. package/dist/core/extensions/builtin/mcp/modern/errors.js +23 -0
  90. package/dist/core/extensions/builtin/mcp/modern/form-schema.d.ts +20 -0
  91. package/dist/core/extensions/builtin/mcp/modern/form-schema.js +153 -0
  92. package/dist/core/extensions/builtin/mcp/modern/http-fetch.d.ts +3 -1
  93. package/dist/core/extensions/builtin/mcp/modern/http-fetch.js +8 -2
  94. package/dist/core/extensions/builtin/mcp/modern/inputs.d.ts +11 -0
  95. package/dist/core/extensions/builtin/mcp/modern/inputs.js +65 -0
  96. package/dist/core/extensions/builtin/mcp/modern/parameter-headers.d.ts +11 -0
  97. package/dist/core/extensions/builtin/mcp/modern/parameter-headers.js +109 -0
  98. package/dist/core/extensions/builtin/mcp/modern/request.d.ts +20 -0
  99. package/dist/core/extensions/builtin/mcp/modern/request.js +292 -0
  100. package/dist/core/extensions/builtin/mcp/modern/stdio-probe.d.ts +1 -1
  101. package/dist/core/extensions/builtin/mcp/modern/stdio-probe.js +54 -6
  102. package/dist/core/extensions/builtin/mcp/modern/transport.js +80 -14
  103. package/dist/core/extensions/builtin/mcp/modern/wire.js +11 -7
  104. package/dist/core/extensions/builtin/mcp/prompts.d.ts +5 -1
  105. package/dist/core/extensions/builtin/mcp/prompts.js +6 -1
  106. package/dist/core/extensions/builtin/mcp/request-origin.d.ts +47 -0
  107. package/dist/core/extensions/builtin/mcp/request-origin.js +59 -0
  108. package/dist/core/extensions/builtin/mcp/resources.d.ts +4 -1
  109. package/dist/core/extensions/builtin/mcp/resources.js +19 -4
  110. package/dist/core/extensions/builtin/mcp/sdk.lazy.d.ts +3 -1
  111. package/dist/core/extensions/builtin/mcp/sdk.lazy.js +3 -1
  112. package/dist/core/extensions/builtin/mcp/service-register.d.ts +4 -1
  113. package/dist/core/extensions/builtin/mcp/service-register.js +3 -0
  114. package/dist/core/extensions/builtin/mcp/service-types.d.ts +2 -1
  115. package/dist/core/extensions/builtin/mcp/service.d.ts +1 -0
  116. package/dist/core/extensions/builtin/mcp/service.js +79 -4
  117. package/dist/core/extensions/builtin/mcp/shared-connection.js +36 -2
  118. package/dist/core/extensions/builtin/mcp/shared-lease.d.ts +1 -0
  119. package/dist/core/extensions/builtin/mcp/shared-lease.js +9 -0
  120. package/dist/core/extensions/builtin/mcp/transport-sdk.d.ts +3 -2
  121. package/dist/core/extensions/builtin/mcp/transport-sdk.js +56 -25
  122. package/dist/core/extensions/builtin/mcp/wrap.d.ts +7 -0
  123. package/dist/core/extensions/builtin/mcp/wrap.js +6 -0
  124. package/dist/core/extensions/runner.js +3 -2
  125. package/dist/core/extensions/types.d.ts +2 -0
  126. package/dist/core/lifecycle-ledger.d.ts +1 -0
  127. package/dist/core/lifecycle-ledger.js +7 -2
  128. package/dist/core/lifecycle-record.js +3 -0
  129. package/dist/core/lifecycle-session-binding.d.ts +11 -1
  130. package/dist/core/lifecycle-session-binding.js +29 -2
  131. package/dist/core/lifecycle-stop.d.ts +41 -0
  132. package/dist/core/lifecycle-stop.js +92 -0
  133. package/dist/core/mcp-form-types.d.ts +89 -0
  134. package/dist/core/mcp-form-types.js +23 -0
  135. package/dist/core/mcp-mrtr-presentations.d.ts +15 -0
  136. package/dist/core/mcp-mrtr-presentations.js +17 -0
  137. package/dist/core/session-lifecycle-types.d.ts +15 -0
  138. package/dist/core/session-lifecycle.d.ts +17 -1
  139. package/dist/core/session-lifecycle.js +40 -2
  140. package/dist/main.js +5 -1
  141. package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
  142. package/dist/modes/interactive/components/extension-selector.js +4 -0
  143. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  144. package/dist/modes/interactive/interactive-mode.js +34 -8
  145. package/dist/modes/interactive/mcp-local-presenter.d.ts +5 -0
  146. package/dist/modes/interactive/mcp-local-presenter.js +109 -0
  147. package/dist/modes/rpc/connection-handler.d.ts +1 -0
  148. package/dist/modes/rpc/connection-handler.js +7 -1
  149. package/dist/modes/rpc/host-capabilities.d.ts +1 -0
  150. package/dist/modes/rpc/host-capabilities.js +2 -1
  151. package/dist/modes/rpc/host-ensure-start.js +13 -2
  152. package/dist/modes/rpc/host-ensure-types.d.ts +2 -0
  153. package/dist/modes/rpc/host-ensure.js +1 -0
  154. package/dist/modes/rpc/host-handoff.d.ts +2 -0
  155. package/dist/modes/rpc/host-handover-wire.d.ts +2 -0
  156. package/dist/modes/rpc/host-handover-wire.js +1 -0
  157. package/dist/modes/rpc/host-lifecycle-launch.d.ts +1 -0
  158. package/dist/modes/rpc/host-lifecycle-launch.js +43 -2
  159. package/dist/modes/rpc/host-runner.d.ts +2 -0
  160. package/dist/modes/rpc/host-runner.js +8 -6
  161. package/dist/modes/rpc/host-successor.js +11 -1
  162. package/dist/modes/rpc/mcp-form-dialog.d.ts +45 -0
  163. package/dist/modes/rpc/mcp-form-dialog.js +159 -0
  164. package/dist/modes/rpc/mcp-form-worker.d.ts +14 -0
  165. package/dist/modes/rpc/mcp-form-worker.js +167 -0
  166. package/dist/modes/rpc/mcp-presenter-authority.d.ts +53 -0
  167. package/dist/modes/rpc/mcp-presenter-authority.js +309 -0
  168. package/dist/modes/rpc/mcp-presenter-bootstrap.d.ts +8 -0
  169. package/dist/modes/rpc/mcp-presenter-bootstrap.js +111 -0
  170. package/dist/modes/rpc/mcp-presenter-control.d.ts +24 -0
  171. package/dist/modes/rpc/mcp-presenter-control.js +330 -0
  172. package/dist/modes/rpc/multi-session-host.d.ts +3 -0
  173. package/dist/modes/rpc/multi-session-host.js +36 -1
  174. package/dist/modes/rpc/session-binding.js +6 -1
  175. package/dist/modes/rpc/session-event-writer.d.ts +14 -0
  176. package/dist/modes/rpc/session-event-writer.js +128 -1
  177. package/dist/modes/rpc/session-router-routing.js +1 -0
  178. package/dist/modes/rpc/session-worker-client.d.ts +3 -0
  179. package/dist/modes/rpc/session-worker-client.js +89 -0
  180. package/dist/modes/rpc/session-worker-protocol.d.ts +41 -0
  181. package/dist/modes/rpc/session-worker.js +9 -0
  182. package/docs/extensions.md +5 -0
  183. package/docs/mcp.md +20 -3
  184. package/docs/rpc.md +111 -0
  185. package/package.json +6 -6
  186. package/dist/bundle/chunks/chunk-B6TPQDBW.js +0 -5
  187. package/dist/bundle/chunks/chunk-CDRFFHLL.js +0 -4
  188. package/dist/bundle/chunks/chunk-HPCS4HM4.js +0 -27
  189. package/dist/bundle/chunks/chunk-KJZAY5YH.js +0 -27
  190. package/dist/bundle/chunks/chunk-OI4NMCKP.js +0 -3
  191. package/dist/bundle/chunks/chunk-SCVRKIFK.js +0 -2
  192. package/dist/bundle/chunks/cli-main-SWKFMTZQ.js +0 -3
  193. package/dist/bundle/chunks/dispatch-DEP4PEDZ.js +0 -10
  194. package/dist/bundle/chunks/host-command-BC6UWP33.js +0 -2
  195. package/dist/bundle/chunks/host-lifecycle-TN5NEGNF.js +0 -3
  196. package/dist/bundle/chunks/host-session-command-MGVBLBRV.js +0 -20
  197. package/dist/bundle/chunks/interactive-mode-SCSROHD5.js +0 -2
  198. package/dist/bundle/chunks/rpc-mode-TOXYD4XA.js +0 -2
  199. package/dist/bundle/chunks/session-control-endpoint-HFFMBALG.js +0 -3
@@ -0,0 +1,2 @@
1
+ export declare function queuedForm<T>(binding: object, signal: AbortSignal, run: () => Promise<T>): Promise<T>;
2
+ //# sourceMappingURL=consent-queue.d.ts.map
@@ -0,0 +1,59 @@
1
+ import { McpMrtrError } from "./errors.js";
2
+ const queues = new WeakMap();
3
+ export function queuedForm(binding, signal, run) {
4
+ let queue = queues.get(binding);
5
+ if (!queue) {
6
+ queue = { busy: false, jobs: [] };
7
+ queues.set(binding, queue);
8
+ }
9
+ const current = queue;
10
+ const pump = () => {
11
+ if (current.busy)
12
+ return;
13
+ const next = current.jobs.shift();
14
+ if (!next) {
15
+ queues.delete(binding);
16
+ return;
17
+ }
18
+ next.signal.removeEventListener("abort", next.abort);
19
+ if (next.signal.aborted) {
20
+ next.reject(new McpMrtrError("MCP_MRTR_PROCESSING_UNAVAILABLE"));
21
+ pump();
22
+ return;
23
+ }
24
+ current.busy = true;
25
+ void next.run().finally(() => {
26
+ current.busy = false;
27
+ pump();
28
+ });
29
+ };
30
+ return new Promise((resolve, reject) => {
31
+ const job = {
32
+ signal,
33
+ run: async () => {
34
+ try {
35
+ resolve(await run());
36
+ }
37
+ catch (error) {
38
+ reject(error);
39
+ }
40
+ },
41
+ reject,
42
+ abort: () => { },
43
+ };
44
+ job.abort = () => {
45
+ const index = current.jobs.indexOf(job);
46
+ if (index >= 0) {
47
+ current.jobs.splice(index, 1);
48
+ signal.removeEventListener("abort", job.abort);
49
+ reject(new McpMrtrError("MCP_MRTR_PROCESSING_UNAVAILABLE"));
50
+ }
51
+ };
52
+ current.jobs.push(job);
53
+ signal.addEventListener("abort", job.abort, { once: true });
54
+ if (signal.aborted)
55
+ job.abort();
56
+ pump();
57
+ });
58
+ }
59
+ //# sourceMappingURL=consent-queue.js.map
@@ -0,0 +1,4 @@
1
+ import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
2
+ /** Control/diagnostic payloads are private from admission, not merely after consent starts. */
3
+ export declare function sanitizeModernMessage(message: JSONRPCMessage): JSONRPCMessage | undefined;
4
+ //# sourceMappingURL=diagnostics.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { McpMrtrError } from "./errors.js";
2
+ /** Control/diagnostic payloads are private from admission, not merely after consent starts. */
3
+ export function sanitizeModernMessage(message) {
4
+ if ("error" in message)
5
+ return {
6
+ jsonrpc: "2.0",
7
+ id: message.id,
8
+ error: { code: message.error.code, message: "MCP server request failed." },
9
+ };
10
+ if (!("method" in message))
11
+ return message;
12
+ if ("id" in message)
13
+ throw new McpMrtrError("MCP_MRTR_INVALID_RESULT");
14
+ if (message.method === "notifications/progress") {
15
+ const params = message.params;
16
+ if (!params ||
17
+ typeof params.progress !== "number" ||
18
+ !Number.isFinite(params.progress) ||
19
+ (params.total !== undefined && (typeof params.total !== "number" || !Number.isFinite(params.total))))
20
+ return undefined;
21
+ return {
22
+ jsonrpc: "2.0",
23
+ method: message.method,
24
+ params: {
25
+ progressToken: params.progressToken,
26
+ progress: params.progress,
27
+ ...(params.total === undefined ? {} : { total: params.total }),
28
+ },
29
+ };
30
+ }
31
+ if (message.method === "notifications/message")
32
+ return {
33
+ jsonrpc: "2.0",
34
+ method: message.method,
35
+ params: { level: "info", data: "MCP server diagnostic suppressed." },
36
+ };
37
+ return message;
38
+ }
39
+ //# sourceMappingURL=diagnostics.js.map
@@ -1,19 +1,22 @@
1
- import { configureMcpElicitation, mcpClientCapabilities } from "../elicitation.js";
2
1
  import { ConnectError } from "../errors.js";
3
- import { loadMcpSdkClient } from "../sdk.lazy.js";
4
2
  import { materializeMcpTransport, } from "../transport-sdk.js";
5
3
  import { probeHttpEra } from "./era.js";
6
- import { modernHttpFetch } from "./http-fetch.js";
4
+ import { modernCredentialSnapshot, modernHttpFetch } from "./http-fetch.js";
5
+ import { createMcpRequestClient } from "./client.js";
7
6
  import { ModernSdkBridge } from "./sdk-bridge.js";
8
7
  import { probeStdioTransport } from "./stdio-probe.js";
9
8
  import { ModernHttpTransport } from "./transport.js";
10
9
  import { MODERN_PROTOCOL_VERSION } from "./wire.js";
11
10
  const clientInfo = { name: "senpi-mcp-client", version: "0.0.0" };
11
+ const probeOptions = {
12
+ clientInfo,
13
+ clientCapabilities: {},
14
+ supportedVersions: [MODERN_PROTOCOL_VERSION],
15
+ };
12
16
  export async function materializeNegotiatedTransport(options, serverName, timeoutMs, signal) {
13
17
  signal.throwIfAborted();
14
- const clientCapabilities = mcpClientCapabilities(options.elicitationEnabled);
15
- const probeOptions = { clientInfo, clientCapabilities, supportedVersions: [MODERN_PROTOCOL_VERSION] };
16
18
  const { spec, logger } = options;
19
+ const protocol = {};
17
20
  let outcome = { kind: "legacy-fallback" };
18
21
  if (spec.kind === "http") {
19
22
  const fetch = modernHttpFetch(spec, signal);
@@ -28,14 +31,13 @@ export async function materializeNegotiatedTransport(options, serverName, timeou
28
31
  serverName,
29
32
  });
30
33
  }
31
- const { Client } = await loadMcpSdkClient();
32
- const client = new Client(clientInfo, { capabilities: clientCapabilities });
33
- await configureMcpElicitation(client, options.elicitationUiProvider, undefined, options.elicitationEnabled);
34
+ protocol.version = outcome.version;
35
+ const client = await createMcpRequestClient(protocol, options.elicitationUiProvider, () => modernCredentialSnapshot(spec.authProvider?.tokens()), options.elicitationEnabled);
34
36
  const transport = new ModernSdkBridge(new ModernHttpTransport({
35
37
  url: spec.url,
36
- fetch,
38
+ fetch: modernHttpFetch(spec, signal, false),
37
39
  clientInfo,
38
- clientCapabilities,
40
+ clientCapabilities: {},
39
41
  protocolVersion: outcome.version,
40
42
  }), outcome.discovery, outcome.version);
41
43
  const version = outcome.version;
@@ -59,12 +61,20 @@ export async function materializeNegotiatedTransport(options, serverName, timeou
59
61
  }
60
62
  }
61
63
  // Unknown endpoints (including legacy session-required 404s and auth challenges) retain SDK diagnostics.
62
- const legacy = await materializeMcpTransport(options);
64
+ if (spec.kind === "http")
65
+ protocol.legacy = true;
66
+ const legacy = await materializeMcpTransport(options, protocol);
63
67
  // A modern stdio child is detected when the SDK starts it, before its local initialize answer sets the version.
64
68
  let stdioModernVersion;
65
69
  if (spec.kind === "stdio") {
66
70
  probeStdioTransport(legacy.transport, probeOptions, logger, timeoutMs, serverName, (version) => {
67
71
  stdioModernVersion = version;
72
+ protocol.version = version;
73
+ protocol.activateRequests?.();
74
+ protocol.resolveStdioDiagnostics?.(true);
75
+ }, undefined, () => {
76
+ protocol.legacy = true;
77
+ protocol.resolveStdioDiagnostics?.(false);
68
78
  });
69
79
  }
70
80
  logVersion(legacy.transport, () => stdioModernVersion);
@@ -0,0 +1,14 @@
1
+ import type { McpMrtrPresentation } from "../../../../mcp-mrtr-presentations.ts";
2
+ import { type Value } from "./form-schema.ts";
3
+ export type MrtrInputResponse = {
4
+ action: "accept";
5
+ content: Record<string, Value>;
6
+ } | {
7
+ action: "decline" | "cancel";
8
+ };
9
+ /** No model-facing questions, RPC requests, timers, persistence, or network operations. */
10
+ export declare function collectMrtrForm(presentation: McpMrtrPresentation, serverLabel: string, params: {
11
+ message: string;
12
+ requestedSchema: unknown;
13
+ }, signal: AbortSignal): Promise<MrtrInputResponse>;
14
+ //# sourceMappingURL=elicitation.d.ts.map
@@ -0,0 +1,145 @@
1
+ import { stripVTControlCharacters } from "node:util";
2
+ import { bindMcpFormPresented } from "../../../../mcp-form-types.js";
3
+ import { McpMrtrError } from "./errors.js";
4
+ import { enums, isRecord, validValue, validateMrtrForm } from "./form-schema.js";
5
+ const own = (value, key) => Object.hasOwn(value, key);
6
+ const inert = (value) => stripVTControlCharacters(value).replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, "");
7
+ /** No model-facing questions, RPC requests, timers, persistence, or network operations. */
8
+ export async function collectMrtrForm(presentation, serverLabel, params, signal) {
9
+ if (!validateMrtrForm(params.requestedSchema))
10
+ throw new McpMrtrError("MCP_MRTR_INVALID_INPUT");
11
+ const schema = params.requestedSchema;
12
+ const abort = new AbortController();
13
+ const combined = AbortSignal.any([signal, presentation.signal, abort.signal]);
14
+ const opts = { signal: combined, ephemeral: true };
15
+ bindMcpFormPresented(opts, presentation.presented);
16
+ const heading = `MCP server: ${inert(serverLabel)}\n${inert(params.message)}`;
17
+ const select = async (title, choices) => {
18
+ if (combined.aborted)
19
+ return undefined;
20
+ const answer = presentation.ui.select(title, choices, opts);
21
+ const result = await answer;
22
+ return combined.aborted ? undefined : result;
23
+ };
24
+ const content = Object.create(null);
25
+ const finish = (result) => {
26
+ if (!combined.aborted)
27
+ presentation.admit?.();
28
+ return result;
29
+ };
30
+ const required = new Set(schema.required ?? []);
31
+ const entries = Object.entries(schema.properties);
32
+ const field = async (name, property) => {
33
+ const title = `${heading}\n${inert(String(property.title ?? name))}${typeof property.description === "string" ? `\n${inert(property.description)}` : ""}`;
34
+ for (;;) {
35
+ const actions = ["Enter value"];
36
+ if (!required.has(name))
37
+ actions.push("Leave unset");
38
+ if (own(property, "default"))
39
+ actions.push("Use default");
40
+ // Primitive selectors already require an explicit choice; do not conflate false with dismissal.
41
+ let action = "Enter value";
42
+ if (actions.length > 1) {
43
+ const chosen = await select(title, actions);
44
+ if (chosen === undefined)
45
+ return false;
46
+ action = chosen;
47
+ }
48
+ if (action === "Leave unset") {
49
+ delete content[name];
50
+ return true;
51
+ }
52
+ if (action === "Use default") {
53
+ content[name] = structuredClone(property.default);
54
+ return true;
55
+ }
56
+ let value;
57
+ if (property.type === "boolean") {
58
+ const chosen = await select(title, ["true", "false"]);
59
+ if (chosen === undefined)
60
+ return false;
61
+ value = chosen === "true";
62
+ }
63
+ else if (property.type === "array" || enums(property)) {
64
+ const choices = property.type === "array" && isRecord(property.items) ? enums(property.items) : enums(property);
65
+ if (choices === undefined)
66
+ return false;
67
+ const values = [];
68
+ for (;;) {
69
+ const labels = choices.map((choice, index) => `${index + 1}. ${inert(choice.label)}${values.includes(choice.value) ? " [selected]" : ""}`);
70
+ if (property.type === "array")
71
+ labels.push("Done");
72
+ const chosen = await select(title, labels);
73
+ if (chosen === undefined)
74
+ return false;
75
+ if (chosen === "Done") {
76
+ value = values;
77
+ break;
78
+ }
79
+ const index = labels.indexOf(chosen);
80
+ const choice = choices[index];
81
+ if (!choice)
82
+ continue;
83
+ if (property.type !== "array") {
84
+ value = choice.value;
85
+ break;
86
+ }
87
+ const existing = values.indexOf(choice.value);
88
+ if (existing >= 0)
89
+ values.splice(existing, 1);
90
+ else
91
+ values.push(choice.value);
92
+ }
93
+ }
94
+ else {
95
+ if (combined.aborted)
96
+ return false;
97
+ const text = await presentation.ui.input(title, undefined, opts);
98
+ if (text === undefined || combined.aborted)
99
+ return false;
100
+ value =
101
+ property.type === "number" || property.type === "integer"
102
+ ? text.trim() === ""
103
+ ? NaN
104
+ : Number(text)
105
+ : text;
106
+ }
107
+ if (validValue(property, value)) {
108
+ content[name] = value;
109
+ return true;
110
+ }
111
+ if ((await select(`${title}\nValue does not satisfy this field.`, ["Try again", "Cancel"])) !== "Try again")
112
+ return false;
113
+ }
114
+ };
115
+ try {
116
+ const begin = await select(heading, ["Continue", "Decline", "Cancel"]);
117
+ if (begin !== "Continue")
118
+ return finish({ action: begin === "Decline" ? "decline" : "cancel" });
119
+ for (const [name, property] of entries)
120
+ if (!(await field(name, property)))
121
+ return finish({ action: "cancel" });
122
+ for (;;) {
123
+ const review = entries
124
+ .map(([name]) => `${inert(name)}: ${own(content, name) ? inert(JSON.stringify(content[name])) : "(unset)"}`)
125
+ .join("\n");
126
+ const action = await select(`${heading}\nReview\n${review}`, ["Submit", "Edit field", "Decline", "Cancel"]);
127
+ if (action === "Submit" && !combined.aborted)
128
+ return finish({ action: "accept", content: structuredClone(content) });
129
+ if (action !== "Edit field")
130
+ return finish({ action: action === "Decline" ? "decline" : "cancel" });
131
+ const labels = entries.map(([name], index) => `${index + 1}. ${inert(name)}`);
132
+ const chosen = await select(`${heading}\nEdit field`, labels);
133
+ const entry = chosen === undefined ? undefined : entries[labels.indexOf(chosen)];
134
+ if (!entry || !(await field(...entry)))
135
+ return finish({ action: "cancel" });
136
+ }
137
+ }
138
+ finally {
139
+ bindMcpFormPresented(opts, undefined);
140
+ abort.abort();
141
+ for (const key of Object.keys(content))
142
+ delete content[key];
143
+ }
144
+ }
145
+ //# sourceMappingURL=elicitation.js.map
@@ -0,0 +1,21 @@
1
+ declare const messages: {
2
+ readonly MCP_MRTR_ROUND_LIMIT: "Request stopped after 8 input rounds; start a new request to continue.";
3
+ readonly MCP_MRTR_INPUT_LIMIT: "Server input exceeds the client's supported limits.";
4
+ readonly MCP_MRTR_INVALID_INPUT: "Server returned an invalid input request or form schema.";
5
+ readonly MCP_MRTR_UNSUPPORTED_INPUT: "Server requested an undeclared client feature.";
6
+ readonly MCP_MRTR_PROCESSING_UNAVAILABLE: "Elicitation processing unavailable.";
7
+ readonly MCP_MRTR_INVALID_RESULT: "Server returned an unsupported or invalid result type/shape.";
8
+ readonly MCP_MRTR_CONTEXT_CHANGED: "Request stopped because its session or server authorization changed.";
9
+ readonly MCP_MRTR_CANCELLED: "Request was canceled before completion.";
10
+ readonly MCP_MRTR_TIMEOUT: "Request exceeded its operation deadline.";
11
+ readonly MCP_MRTR_TRANSPORT_FAILED: "Request could not complete; it was not automatically replayed.";
12
+ };
13
+ export declare class McpMrtrError extends Error {
14
+ readonly source = "local";
15
+ readonly retriable = false;
16
+ readonly code: keyof typeof messages;
17
+ readonly remoteCode?: number;
18
+ constructor(code: keyof typeof messages, remoteCode?: number);
19
+ }
20
+ export {};
21
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1,23 @@
1
+ const messages = {
2
+ MCP_MRTR_ROUND_LIMIT: "Request stopped after 8 input rounds; start a new request to continue.",
3
+ MCP_MRTR_INPUT_LIMIT: "Server input exceeds the client's supported limits.",
4
+ MCP_MRTR_INVALID_INPUT: "Server returned an invalid input request or form schema.",
5
+ MCP_MRTR_UNSUPPORTED_INPUT: "Server requested an undeclared client feature.",
6
+ MCP_MRTR_PROCESSING_UNAVAILABLE: "Elicitation processing unavailable.",
7
+ MCP_MRTR_INVALID_RESULT: "Server returned an unsupported or invalid result type/shape.",
8
+ MCP_MRTR_CONTEXT_CHANGED: "Request stopped because its session or server authorization changed.",
9
+ MCP_MRTR_CANCELLED: "Request was canceled before completion.",
10
+ MCP_MRTR_TIMEOUT: "Request exceeded its operation deadline.",
11
+ MCP_MRTR_TRANSPORT_FAILED: "Request could not complete; it was not automatically replayed.",
12
+ };
13
+ export class McpMrtrError extends Error {
14
+ constructor(code, remoteCode) {
15
+ super(remoteCode === undefined ? messages[code] : `${messages[code]} (remote code ${remoteCode})`);
16
+ this.source = "local";
17
+ this.retriable = false;
18
+ this.code = code;
19
+ this.remoteCode = remoteCode;
20
+ this.name = "McpMrtrError";
21
+ }
22
+ }
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1,20 @@
1
+ export type Value = string | number | boolean | string[];
2
+ export type Property = Record<string, unknown>;
3
+ export type ValidatedMcpFormSchema = Form;
4
+ type Form = {
5
+ type: "object";
6
+ properties: Record<string, Property>;
7
+ required?: string[];
8
+ };
9
+ export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
10
+ export declare function enums(property: Property): Array<{
11
+ value: string;
12
+ label: string;
13
+ }> | undefined;
14
+ export declare function validValue(property: Property, value: unknown): value is Value;
15
+ /** Validate a complete submitted form, including unknown keys and omitted required fields. */
16
+ export declare function validMcpFormContent(schema: Form, content: unknown): content is Record<string, Value>;
17
+ /** Reject unsupported constraints rather than presenting a weaker schema. */
18
+ export declare function validateMrtrForm(schema: unknown): schema is Form;
19
+ export {};
20
+ //# sourceMappingURL=form-schema.d.ts.map
@@ -0,0 +1,153 @@
1
+ export const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2
+ const own = (value, key) => Object.hasOwn(value, key);
3
+ export function enums(property) {
4
+ if (Array.isArray(property.enum) &&
5
+ property.enum.length > 0 &&
6
+ property.enum.every((entry) => typeof entry === "string")) {
7
+ return property.enum.map((value) => ({ value, label: value }));
8
+ }
9
+ const choices = property.oneOf ?? property.anyOf;
10
+ if (Array.isArray(choices) &&
11
+ choices.length > 0 &&
12
+ choices.every((entry) => isRecord(entry) &&
13
+ typeof entry.const === "string" &&
14
+ typeof entry.title === "string" &&
15
+ Object.keys(entry).every((key) => key === "const" || key === "title"))) {
16
+ return choices.map((entry) => ({ value: entry.const, label: entry.title }));
17
+ }
18
+ return undefined;
19
+ }
20
+ export function validValue(property, value) {
21
+ if (property.type === "boolean")
22
+ return typeof value === "boolean";
23
+ if (property.type === "integer" || property.type === "number") {
24
+ return (typeof value === "number" &&
25
+ Number.isFinite(value) &&
26
+ (property.type !== "integer" || Number.isInteger(value)) &&
27
+ (typeof property.minimum !== "number" || value >= property.minimum) &&
28
+ (typeof property.maximum !== "number" || value <= property.maximum));
29
+ }
30
+ if (property.type === "array") {
31
+ const choices = isRecord(property.items) ? enums(property.items) : undefined;
32
+ return (Array.isArray(value) &&
33
+ value.every((entry) => typeof entry === "string" && choices?.some((choice) => choice.value === entry)) &&
34
+ new Set(value).size === value.length &&
35
+ (typeof property.minItems !== "number" || value.length >= property.minItems) &&
36
+ (typeof property.maxItems !== "number" || value.length <= property.maxItems));
37
+ }
38
+ if (typeof value !== "string")
39
+ return false;
40
+ const choices = enums(property);
41
+ if (choices && !choices.some((choice) => choice.value === value))
42
+ return false;
43
+ if (typeof property.minLength === "number" && [...value].length < property.minLength)
44
+ return false;
45
+ if (typeof property.maxLength === "number" && [...value].length > property.maxLength)
46
+ return false;
47
+ switch (property.format) {
48
+ case "email":
49
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
50
+ case "uri": {
51
+ try {
52
+ return new URL(value).protocol.length > 1;
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ case "date":
59
+ return (/^\d{4}-\d{2}-\d{2}$/.test(value) &&
60
+ Number.isFinite(Date.parse(value)) &&
61
+ new Date(value).toISOString().slice(0, 10) === value);
62
+ case "date-time": {
63
+ const date = value.slice(0, 10);
64
+ return (/^\d{4}-\d{2}-\d{2}T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-](?:[01]\d|2[0-3]):[0-5]\d)$/.test(value) &&
65
+ Number.isFinite(Date.parse(value)) &&
66
+ new Date(date).toISOString().slice(0, 10) === date);
67
+ }
68
+ default:
69
+ return true;
70
+ }
71
+ }
72
+ /** Validate a complete submitted form, including unknown keys and omitted required fields. */
73
+ export function validMcpFormContent(schema, content) {
74
+ return (isRecord(content) &&
75
+ (schema.required ?? []).every((key) => own(content, key)) &&
76
+ Object.entries(content).every(([key, value]) => own(schema.properties, key) && validValue(schema.properties[key], value)));
77
+ }
78
+ /** Reject unsupported constraints rather than presenting a weaker schema. */
79
+ export function validateMrtrForm(schema) {
80
+ if (!isRecord(schema) || schema.type !== "object" || !isRecord(schema.properties))
81
+ return false;
82
+ for (const key of ["title", "description"])
83
+ if (own(schema, key) && typeof schema[key] !== "string")
84
+ return false;
85
+ if (Object.keys(schema).some((key) => !["type", "properties", "required", "title", "description", "$schema"].includes(key)))
86
+ return false;
87
+ if (schema.required !== undefined &&
88
+ (!Array.isArray(schema.required) ||
89
+ !schema.required.every((key) => typeof key === "string" && own(schema.properties, key))))
90
+ return false;
91
+ for (const property of Object.values(schema.properties)) {
92
+ if (!isRecord(property))
93
+ return false;
94
+ const allowed = ["type", "title", "description", "default"];
95
+ switch (property.type) {
96
+ case "string":
97
+ allowed.push("minLength", "maxLength", "format", "enum", "oneOf");
98
+ if (property.format !== undefined &&
99
+ !["email", "uri", "date", "date-time"].includes(String(property.format)))
100
+ return false;
101
+ if ((own(property, "enum") || own(property, "oneOf")) && !enums(property))
102
+ return false;
103
+ if (own(property, "enum") && own(property, "oneOf"))
104
+ return false;
105
+ break;
106
+ case "number":
107
+ case "integer":
108
+ allowed.push("minimum", "maximum");
109
+ break;
110
+ case "boolean":
111
+ break;
112
+ case "array":
113
+ allowed.push("items", "minItems", "maxItems");
114
+ if (!isRecord(property.items) ||
115
+ !enums(property.items) ||
116
+ Object.keys(property.items).some((key) => !["type", "enum", "anyOf"].includes(key)) ||
117
+ (property.items.type !== undefined && property.items.type !== "string"))
118
+ return false;
119
+ break;
120
+ default:
121
+ return false;
122
+ }
123
+ if (Object.keys(property).some((key) => !allowed.includes(key)))
124
+ return false;
125
+ for (const key of ["title", "description"])
126
+ if (own(property, key) && typeof property[key] !== "string")
127
+ return false;
128
+ for (const key of ["minimum", "maximum", "minLength", "maxLength", "minItems", "maxItems"]) {
129
+ const value = property[key];
130
+ if (value !== undefined &&
131
+ (typeof value !== "number" ||
132
+ !Number.isFinite(value) ||
133
+ (!["minimum", "maximum"].includes(key) && (!Number.isInteger(value) || value < 0))))
134
+ return false;
135
+ }
136
+ for (const [min, max] of [
137
+ ["minimum", "maximum"],
138
+ ["minLength", "maxLength"],
139
+ ["minItems", "maxItems"],
140
+ ]) {
141
+ if (min &&
142
+ max &&
143
+ typeof property[min] === "number" &&
144
+ typeof property[max] === "number" &&
145
+ property[min] > property[max])
146
+ return false;
147
+ }
148
+ if (own(property, "default") && !validValue(property, property.default))
149
+ return false;
150
+ }
151
+ return true;
152
+ }
153
+ //# sourceMappingURL=form-schema.js.map
@@ -1,5 +1,7 @@
1
1
  import type { FetchLike } from "@modelcontextprotocol/sdk/shared/transport.js";
2
+ import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
2
3
  import type { McpHttpTransportSpec } from "../transport-sdk.ts";
4
+ export declare const modernCredentialSnapshot: (tokens: OAuthTokens | undefined) => string | undefined;
3
5
  /** The existing OAuth provider owns credentials; the SDK owns authorization and origin-safe redirects. */
4
- export declare function modernHttpFetch(spec: McpHttpTransportSpec, signal: AbortSignal): FetchLike;
6
+ export declare function modernHttpFetch(spec: McpHttpTransportSpec, signal: AbortSignal, authorizeResend?: boolean): FetchLike;
5
7
  //# sourceMappingURL=http-fetch.d.ts.map
@@ -1,13 +1,18 @@
1
1
  import { fetchWithinOrigin } from "@modelcontextprotocol/sdk/shared/transport.js";
2
2
  import { loadMcpSdkAuth } from "../sdk.lazy.js";
3
+ import { modernDispatchGuard } from "./request.js";
4
+ import { clearMcpParameterHeaders } from "./parameter-headers.js";
5
+ export const modernCredentialSnapshot = (tokens) => tokens === undefined ? undefined : JSON.stringify([tokens.access_token, tokens.refresh_token]);
3
6
  /** The existing OAuth provider owns credentials; the SDK owns authorization and origin-safe redirects. */
4
- export function modernHttpFetch(spec, signal) {
7
+ export function modernHttpFetch(spec, signal, authorizeResend = true) {
5
8
  const fetch = fetchWithinOrigin();
6
9
  return async (url, init) => {
7
10
  const requestSignal = init?.signal ? AbortSignal.any([signal, init.signal]) : signal;
8
11
  const send = () => {
9
12
  const headers = new Headers();
10
13
  const tokens = spec.authProvider?.tokens();
14
+ const guard = init?.[modernDispatchGuard];
15
+ guard?.(modernCredentialSnapshot(tokens));
11
16
  if (tokens)
12
17
  headers.set("Authorization", `Bearer ${tokens.access_token}`);
13
18
  new Headers(spec.requestInit?.headers).forEach((value, key) => {
@@ -15,6 +20,7 @@ export function modernHttpFetch(spec, signal) {
15
20
  });
16
21
  for (const key of ["Mcp-Session-Id", "Mcp-Name", "Mcp-Method", "MCP-Protocol-Version"])
17
22
  headers.delete(key);
23
+ clearMcpParameterHeaders(headers);
18
24
  new Headers(init?.headers).forEach((value, key) => {
19
25
  headers.set(key, value);
20
26
  });
@@ -27,7 +33,7 @@ export function modernHttpFetch(spec, signal) {
27
33
  });
28
34
  };
29
35
  let response = await send();
30
- if (spec.authProvider && (response.status === 401 || response.status === 403)) {
36
+ if (authorizeResend && spec.authProvider && (response.status === 401 || response.status === 403)) {
31
37
  const { auth, extractWWWAuthenticateParams, UnauthorizedError } = await loadMcpSdkAuth();
32
38
  const { resourceMetadataUrl, scope, error } = extractWWWAuthenticateParams(response);
33
39
  if (response.status === 401 || error === "insufficient_scope") {
@@ -0,0 +1,11 @@
1
+ type Input = {
2
+ method: "elicitation/create";
3
+ params: {
4
+ mode?: "form" | "url";
5
+ message: string;
6
+ requestedSchema?: unknown;
7
+ };
8
+ };
9
+ export declare function parseInputs(result: Record<string, unknown>): Map<string, Input> | undefined;
10
+ export {};
11
+ //# sourceMappingURL=inputs.d.ts.map