@code-yeongyu/senpi 2026.10.25-1 → 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.
- package/CHANGELOG.md +36 -0
- package/dist/bundle/chunks/{args-JXULI4EH.js → args-B444OQBK.js} +1 -1
- package/dist/bundle/chunks/{auth-4NUNUSTF.js → auth-C77UQA55.js} +1 -1
- package/dist/bundle/chunks/{chunk-RHHBXIRN.js → chunk-4WZRVZNX.js} +1 -1
- package/dist/bundle/chunks/chunk-6O4SEW2W.js +5 -0
- package/dist/bundle/chunks/{chunk-Y5OTHMXO.js → chunk-7CNOCJCN.js} +1 -1
- package/dist/bundle/chunks/{chunk-YDCRA5ES.js → chunk-7W7OJDIY.js} +4 -4
- package/dist/bundle/chunks/chunk-AX72VNRS.js +27 -0
- package/dist/bundle/chunks/{chunk-FWXMMMCV.js → chunk-C5UFJ7B3.js} +1 -1
- package/dist/bundle/chunks/{chunk-7IRLFYNM.js → chunk-CNL6QSUB.js} +4 -4
- package/dist/bundle/chunks/{chunk-BTNYLNWZ.js → chunk-FFQOEC76.js} +5 -5
- package/dist/bundle/chunks/{chunk-VOBD6FQG.js → chunk-FHXR4ZAC.js} +1 -1
- package/dist/bundle/chunks/chunk-H3HNMY2W.js +13 -0
- package/dist/bundle/chunks/{chunk-BMYNMUVZ.js → chunk-HVJI5T75.js} +1 -1
- package/dist/bundle/chunks/{chunk-EWOEVVQT.js → chunk-JA2R2ZSE.js} +1 -1
- package/dist/bundle/chunks/chunk-JPGT64RV.js +2 -0
- package/dist/bundle/chunks/chunk-KXB5WIS5.js +4 -0
- package/dist/bundle/chunks/chunk-L73UYAH5.js +3 -0
- package/dist/bundle/chunks/chunk-LTU6UFEX.js +2 -0
- package/dist/bundle/chunks/{chunk-EYBDBR7V.js → chunk-MJ5NNWX4.js} +1 -1
- package/dist/bundle/chunks/{chunk-RVYSJBZ7.js → chunk-O3Q2ET6W.js} +2 -5
- package/dist/bundle/chunks/chunk-O5RYI3IW.js +2 -0
- package/dist/bundle/chunks/{chunk-SGDOZT6B.js → chunk-ODTGC6YU.js} +1 -1
- package/dist/bundle/chunks/chunk-P3M2PF6K.js +27 -0
- package/dist/bundle/chunks/chunk-SWJXRC2I.js +5 -0
- package/dist/bundle/chunks/{chunk-QH2HSCMX.js → chunk-TTU2RNVX.js} +3 -3
- package/dist/bundle/chunks/{chunk-PXKF2RHD.js → chunk-UFJ2K7Q7.js} +1 -1
- package/dist/bundle/chunks/{chunk-7UUOGZKR.js → chunk-UQNRW3VU.js} +1 -1
- package/dist/bundle/chunks/{chunk-U67ML6CQ.js → chunk-WD6WBYC5.js} +1 -1
- package/dist/bundle/chunks/chunk-WJOT3DFL.js +2 -0
- package/dist/bundle/chunks/{chunk-7WAJCESX.js → chunk-WLHNEUGD.js} +1 -1
- package/dist/bundle/chunks/chunk-YI7SPFDN.js +5 -0
- package/dist/bundle/chunks/{chunk-URBJS24R.js → chunk-YRF4I43T.js} +35 -35
- package/dist/bundle/chunks/chunk-Z3UYNSVR.js +3 -0
- package/dist/bundle/chunks/cli-main-HEKFFB5S.js +3 -0
- package/dist/bundle/chunks/{client-KWTLTKVV.js → client-WTYEICLH.js} +3 -3
- package/dist/bundle/chunks/dispatch-NYAULNVW.js +9 -0
- package/dist/bundle/chunks/{help-fast-path-ZHZGXAUG.js → help-fast-path-3Z26DQSV.js} +1 -1
- package/dist/bundle/chunks/host-command-Z3WPHJOW.js +2 -0
- package/dist/bundle/chunks/host-lifecycle-ONQIMWMX.js +3 -0
- package/dist/bundle/chunks/host-lifecycle.js +9 -7
- package/dist/bundle/chunks/host-session-command-J65ENSV5.js +20 -0
- package/dist/bundle/chunks/{host-socket-request-ZDJGSSZO.js → host-socket-request-3CWE4265.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-DEPQC6TX.js +2 -0
- package/dist/bundle/chunks/mcp-presenter-bootstrap-XUSCQVRC.js +2 -0
- package/dist/bundle/chunks/{multi-session-host-M7HVUMRH.js → multi-session-host-YI2WZOET.js} +12 -9
- package/dist/bundle/chunks/{package-manager-cli-FSR5P6YL.js → package-manager-cli-GHZPJMRF.js} +1 -1
- package/dist/bundle/chunks/{role-M2MTVACJ.js → role-JVSBNKGE.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-U7YQMC7H.js → rotation-stream-ZPVCFOVD.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-ORHBGBBV.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-OL5KU6NO.js → rpc-monitor-source-FFEQS744.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-CLNODAYE.js → runtime-session-V5OO7ZRM.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-XBW4EOG5.js → schedule-command-YWG6D6ZF.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-36HAQSQO.js +3 -0
- package/dist/bundle/chunks/{session-picker-KQUFWDQC.js → session-picker-25H5KNYP.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +285 -271
- package/dist/bundle/chunks/{stdio-IEC635SY.js → stdio-YXDKKKQZ.js} +1 -1
- package/dist/bundle/chunks/{streamableHttp-KJI5KE4K.js → streamableHttp-DKIBUWVY.js} +1 -1
- package/dist/bundle/chunks/{types-LLNV23LW.js → types-BJUEQ4II.js} +1 -1
- package/dist/bundle/chunks/zod-compat-RJDXCU7S.js +2 -0
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +9 -7
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.js +9 -0
- package/dist/cli/host-command-args.d.ts +1 -0
- package/dist/cli/host-command-args.js +7 -1
- package/dist/cli/host-command.js +3 -1
- package/dist/core/agent-session.d.ts +1 -0
- package/dist/core/agent-session.js +50 -16
- package/dist/core/engine-turn-limit.d.ts +2 -0
- package/dist/core/engine-turn-limit.js +7 -1
- package/dist/core/extensions/builtin/anthropic-subscription/auth-attempt.js +5 -0
- package/dist/core/extensions/builtin/goal/index.js +1 -0
- package/dist/core/extensions/builtin/goal/lifecycle-facts.d.ts +3 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +2 -1
- package/dist/core/extensions/builtin/loop/session-hold.js +2 -1
- package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/catalog.js +2 -0
- package/dist/core/extensions/builtin/mcp/connection.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/connection.js +46 -1
- package/dist/core/extensions/builtin/mcp/elicitation.d.ts +6 -1
- package/dist/core/extensions/builtin/mcp/elicitation.js +56 -2
- package/dist/core/extensions/builtin/mcp/expose/call.js +6 -2
- package/dist/core/extensions/builtin/mcp/expose/session.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/expose/session.js +7 -0
- package/dist/core/extensions/builtin/mcp/health.js +5 -0
- package/dist/core/extensions/builtin/mcp/host-registry.js +7 -1
- package/dist/core/extensions/builtin/mcp/index.js +2 -0
- package/dist/core/extensions/builtin/mcp/modern/client.d.ts +5 -0
- package/dist/core/extensions/builtin/mcp/modern/client.js +15 -0
- package/dist/core/extensions/builtin/mcp/modern/consent-queue.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/modern/consent-queue.js +59 -0
- package/dist/core/extensions/builtin/mcp/modern/diagnostics.d.ts +4 -0
- package/dist/core/extensions/builtin/mcp/modern/diagnostics.js +39 -0
- package/dist/core/extensions/builtin/mcp/modern/dispatch.js +21 -11
- package/dist/core/extensions/builtin/mcp/modern/elicitation.d.ts +14 -0
- package/dist/core/extensions/builtin/mcp/modern/elicitation.js +145 -0
- package/dist/core/extensions/builtin/mcp/modern/errors.d.ts +21 -0
- package/dist/core/extensions/builtin/mcp/modern/errors.js +23 -0
- package/dist/core/extensions/builtin/mcp/modern/form-schema.d.ts +20 -0
- package/dist/core/extensions/builtin/mcp/modern/form-schema.js +153 -0
- package/dist/core/extensions/builtin/mcp/modern/http-fetch.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/modern/http-fetch.js +8 -2
- package/dist/core/extensions/builtin/mcp/modern/inputs.d.ts +11 -0
- package/dist/core/extensions/builtin/mcp/modern/inputs.js +65 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.d.ts +11 -0
- package/dist/core/extensions/builtin/mcp/modern/parameter-headers.js +109 -0
- package/dist/core/extensions/builtin/mcp/modern/request.d.ts +20 -0
- package/dist/core/extensions/builtin/mcp/modern/request.js +292 -0
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.js +54 -6
- package/dist/core/extensions/builtin/mcp/modern/transport.js +80 -14
- package/dist/core/extensions/builtin/mcp/modern/wire.js +11 -7
- package/dist/core/extensions/builtin/mcp/prompts.d.ts +5 -1
- package/dist/core/extensions/builtin/mcp/prompts.js +6 -1
- package/dist/core/extensions/builtin/mcp/request-origin.d.ts +47 -0
- package/dist/core/extensions/builtin/mcp/request-origin.js +59 -0
- package/dist/core/extensions/builtin/mcp/resources.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/resources.js +19 -4
- package/dist/core/extensions/builtin/mcp/sdk.lazy.d.ts +3 -1
- package/dist/core/extensions/builtin/mcp/sdk.lazy.js +3 -1
- package/dist/core/extensions/builtin/mcp/service-register.d.ts +4 -1
- package/dist/core/extensions/builtin/mcp/service-register.js +3 -0
- package/dist/core/extensions/builtin/mcp/service-types.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/service.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/service.js +79 -4
- package/dist/core/extensions/builtin/mcp/shared-connection.js +36 -2
- package/dist/core/extensions/builtin/mcp/shared-lease.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/shared-lease.js +9 -0
- package/dist/core/extensions/builtin/mcp/transport-sdk.d.ts +3 -2
- package/dist/core/extensions/builtin/mcp/transport-sdk.js +56 -25
- package/dist/core/extensions/builtin/mcp/wrap.d.ts +7 -0
- package/dist/core/extensions/builtin/mcp/wrap.js +6 -0
- package/dist/core/extensions/runner.js +3 -2
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/lifecycle-ledger.d.ts +1 -0
- package/dist/core/lifecycle-ledger.js +7 -2
- package/dist/core/lifecycle-record.js +3 -0
- package/dist/core/lifecycle-runtime-facts.js +3 -0
- package/dist/core/lifecycle-session-binding.d.ts +11 -1
- package/dist/core/lifecycle-session-binding.js +35 -4
- package/dist/core/lifecycle-stop.d.ts +41 -0
- package/dist/core/lifecycle-stop.js +92 -0
- package/dist/core/mcp-form-types.d.ts +89 -0
- package/dist/core/mcp-form-types.js +23 -0
- package/dist/core/mcp-mrtr-presentations.d.ts +15 -0
- package/dist/core/mcp-mrtr-presentations.js +17 -0
- package/dist/core/run-resume-turn.d.ts +1 -0
- package/dist/core/run-resume-turn.js +4 -3
- package/dist/core/session-lifecycle-types.d.ts +15 -0
- package/dist/core/session-lifecycle.d.ts +17 -1
- package/dist/core/session-lifecycle.js +40 -2
- package/dist/core/stop-resume-directive.d.ts +1 -1
- package/dist/core/stop-resume-directive.js +10 -1
- package/dist/main.js +5 -1
- package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
- package/dist/modes/interactive/components/extension-selector.js +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.js +35 -8
- package/dist/modes/interactive/mcp-local-presenter.d.ts +5 -0
- package/dist/modes/interactive/mcp-local-presenter.js +109 -0
- package/dist/modes/interactive/pause-footer.d.ts +5 -0
- package/dist/modes/interactive/pause-footer.js +2 -0
- package/dist/modes/rpc/connection-handler.d.ts +1 -0
- package/dist/modes/rpc/connection-handler.js +7 -1
- package/dist/modes/rpc/host-capabilities.d.ts +1 -0
- package/dist/modes/rpc/host-capabilities.js +2 -1
- package/dist/modes/rpc/host-ensure-start.js +13 -2
- package/dist/modes/rpc/host-ensure-types.d.ts +2 -0
- package/dist/modes/rpc/host-ensure.js +1 -0
- package/dist/modes/rpc/host-handoff.d.ts +2 -0
- package/dist/modes/rpc/host-handover-wire.d.ts +2 -0
- package/dist/modes/rpc/host-handover-wire.js +1 -0
- package/dist/modes/rpc/host-lifecycle-launch.d.ts +1 -0
- package/dist/modes/rpc/host-lifecycle-launch.js +43 -2
- package/dist/modes/rpc/host-reservations.js +3 -2
- package/dist/modes/rpc/host-runner.d.ts +2 -0
- package/dist/modes/rpc/host-runner.js +8 -6
- package/dist/modes/rpc/host-stalled-evidence.js +2 -1
- package/dist/modes/rpc/host-successor.js +11 -1
- package/dist/modes/rpc/mcp-form-dialog.d.ts +45 -0
- package/dist/modes/rpc/mcp-form-dialog.js +159 -0
- package/dist/modes/rpc/mcp-form-worker.d.ts +14 -0
- package/dist/modes/rpc/mcp-form-worker.js +167 -0
- package/dist/modes/rpc/mcp-presenter-authority.d.ts +53 -0
- package/dist/modes/rpc/mcp-presenter-authority.js +309 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.d.ts +8 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.js +111 -0
- package/dist/modes/rpc/mcp-presenter-control.d.ts +24 -0
- package/dist/modes/rpc/mcp-presenter-control.js +330 -0
- package/dist/modes/rpc/multi-session-host.d.ts +3 -0
- package/dist/modes/rpc/multi-session-host.js +36 -1
- package/dist/modes/rpc/session-binding.js +6 -1
- package/dist/modes/rpc/session-event-writer.d.ts +14 -0
- package/dist/modes/rpc/session-event-writer.js +128 -1
- package/dist/modes/rpc/session-router-routing.js +1 -0
- package/dist/modes/rpc/session-worker-client.d.ts +3 -0
- package/dist/modes/rpc/session-worker-client.js +89 -0
- package/dist/modes/rpc/session-worker-protocol.d.ts +41 -0
- package/dist/modes/rpc/session-worker.js +9 -0
- package/dist/modes/rpc/tool-child/group-ownership.js +4 -2
- package/dist/utils/process-identity.d.ts +7 -0
- package/dist/utils/process-identity.js +32 -5
- package/docs/extensions.md +5 -0
- package/docs/mcp.md +20 -3
- package/docs/rpc.md +111 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-3VOG6WFU.js +0 -27
- package/dist/bundle/chunks/chunk-7ASLQ243.js +0 -2
- package/dist/bundle/chunks/chunk-CDRFFHLL.js +0 -4
- package/dist/bundle/chunks/chunk-HPCS4HM4.js +0 -27
- package/dist/bundle/chunks/chunk-II22E3CV.js +0 -3
- package/dist/bundle/chunks/chunk-J5P2VL3Y.js +0 -5
- package/dist/bundle/chunks/chunk-SCVRKIFK.js +0 -2
- package/dist/bundle/chunks/chunk-XUFUKDKJ.js +0 -5
- package/dist/bundle/chunks/cli-main-TABBP55A.js +0 -3
- package/dist/bundle/chunks/dispatch-DEP4PEDZ.js +0 -10
- package/dist/bundle/chunks/host-command-OQR4RDTM.js +0 -2
- package/dist/bundle/chunks/host-lifecycle-U36U7JTE.js +0 -3
- package/dist/bundle/chunks/host-session-command-IGB27ZPJ.js +0 -20
- package/dist/bundle/chunks/interactive-mode-DGQNSXUA.js +0 -2
- package/dist/bundle/chunks/rpc-mode-SZAJNKKL.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-WEF3XTJR.js +0 -3
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
3
|
+
import type { McpMrtrPresentation } from "../../../mcp-mrtr-presentations.ts";
|
|
4
|
+
import type { McpFormPresentation } from "../../../mcp-form-types.ts";
|
|
5
|
+
import type { ServerConnection } from "./connection.ts";
|
|
6
|
+
declare const originOption: unique symbol;
|
|
7
|
+
export declare const physicalMcpClient: (client: Client) => Client;
|
|
8
|
+
export declare function registerMcpClientAlias(alias: Client, physical: Client): void;
|
|
9
|
+
export interface McpRequestOrigin {
|
|
10
|
+
readonly binding: object;
|
|
11
|
+
readonly connection: ServerConnection;
|
|
12
|
+
readonly signal: AbortSignal;
|
|
13
|
+
readonly presentation?: McpMrtrPresentation;
|
|
14
|
+
readonly privateForm?: McpFormPresentation;
|
|
15
|
+
readonly privateFormsEnforced?: boolean;
|
|
16
|
+
readonly serverLabel: string;
|
|
17
|
+
readonly serverSource?: "user" | "project" | "plugin";
|
|
18
|
+
readonly isCurrent: () => boolean;
|
|
19
|
+
readonly resolveAuthority: (signal: AbortSignal) => Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export declare function beginLegacyMcpOperation(client: Client, origin: McpRequestOrigin, caller?: AbortSignal): () => void;
|
|
22
|
+
export declare function legacyMcpOperation(client: Client): "ambiguous" | {
|
|
23
|
+
readonly origin: McpRequestOrigin;
|
|
24
|
+
readonly signal: AbortSignal;
|
|
25
|
+
} | undefined;
|
|
26
|
+
/** Issued by the binding-specific registration boundary, never from JSON/model arguments. */
|
|
27
|
+
export declare function createMcpRequestOrigin(origin: McpRequestOrigin): McpRequestOrigin;
|
|
28
|
+
export declare function mcpRequestOptions(origin: McpRequestOrigin | undefined, options?: RequestOptions): RequestOptions & {
|
|
29
|
+
[originOption]?: McpRequestOrigin;
|
|
30
|
+
};
|
|
31
|
+
export declare function takeMcpRequestOrigin(options: RequestOptions | undefined, client: Client): {
|
|
32
|
+
origin: McpRequestOrigin | undefined;
|
|
33
|
+
sdkOptions: {
|
|
34
|
+
relatedRequestId?: import("@modelcontextprotocol/sdk/types").RequestId;
|
|
35
|
+
resumptionToken?: string;
|
|
36
|
+
onresumptiontoken?: (token: string) => void;
|
|
37
|
+
onprogress?: import("@modelcontextprotocol/sdk/shared/protocol.js").ProgressCallback;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
timeout?: number;
|
|
40
|
+
resetTimeoutOnProgress?: boolean;
|
|
41
|
+
maxTotalTimeout?: number;
|
|
42
|
+
task?: import("@modelcontextprotocol/sdk/types").TaskCreationParams;
|
|
43
|
+
relatedTask?: import("@modelcontextprotocol/sdk/types").RelatedTaskMetadata;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=request-origin.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { McpMrtrError } from "./modern/errors.js";
|
|
2
|
+
const originOption = Symbol("mcp-request-origin");
|
|
3
|
+
const origins = new WeakSet();
|
|
4
|
+
const aliases = new WeakMap();
|
|
5
|
+
export const physicalMcpClient = (client) => aliases.get(client) ?? client;
|
|
6
|
+
export function registerMcpClientAlias(alias, physical) {
|
|
7
|
+
aliases.set(alias, physical);
|
|
8
|
+
}
|
|
9
|
+
const legacyOperations = new WeakMap();
|
|
10
|
+
export function beginLegacyMcpOperation(client, origin, caller) {
|
|
11
|
+
const lifetime = new AbortController();
|
|
12
|
+
const operation = {
|
|
13
|
+
origin,
|
|
14
|
+
signal: AbortSignal.any([origin.signal, lifetime.signal, ...(caller ? [caller] : [])]),
|
|
15
|
+
};
|
|
16
|
+
let operations = legacyOperations.get(client);
|
|
17
|
+
if (!operations) {
|
|
18
|
+
operations = new Set();
|
|
19
|
+
legacyOperations.set(client, operations);
|
|
20
|
+
}
|
|
21
|
+
operations.add(operation);
|
|
22
|
+
return () => {
|
|
23
|
+
operations.delete(operation);
|
|
24
|
+
lifetime.abort();
|
|
25
|
+
if (operations.size === 0)
|
|
26
|
+
legacyOperations.delete(client);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function legacyMcpOperation(client) {
|
|
30
|
+
const operations = legacyOperations.get(client);
|
|
31
|
+
if (operations && operations.size > 1)
|
|
32
|
+
return "ambiguous";
|
|
33
|
+
if (operations?.size !== 1)
|
|
34
|
+
return undefined;
|
|
35
|
+
const operation = operations.values().next().value;
|
|
36
|
+
return operation && !operation.signal.aborted && operation.origin.isCurrent() ? operation : undefined;
|
|
37
|
+
}
|
|
38
|
+
/** Issued by the binding-specific registration boundary, never from JSON/model arguments. */
|
|
39
|
+
export function createMcpRequestOrigin(origin) {
|
|
40
|
+
origins.add(origin);
|
|
41
|
+
return origin;
|
|
42
|
+
}
|
|
43
|
+
export function mcpRequestOptions(origin, options = {}) {
|
|
44
|
+
return origin === undefined ? options : { ...options, [originOption]: origin };
|
|
45
|
+
}
|
|
46
|
+
export function takeMcpRequestOrigin(options, client) {
|
|
47
|
+
const supplied = options;
|
|
48
|
+
const origin = supplied?.[originOption];
|
|
49
|
+
const { [originOption]: _origin, ...sdkOptions } = supplied ?? {};
|
|
50
|
+
if (origin !== undefined) {
|
|
51
|
+
if (!origins.has(origin) || !origin.isCurrent())
|
|
52
|
+
throw new McpMrtrError("MCP_MRTR_CONTEXT_CHANGED");
|
|
53
|
+
const candidate = origin.connection.client;
|
|
54
|
+
if (physicalMcpClient(candidate) !== client)
|
|
55
|
+
throw new McpMrtrError("MCP_MRTR_CONTEXT_CHANGED");
|
|
56
|
+
}
|
|
57
|
+
return { origin, sdkOptions };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=request-origin.js.map
|
|
@@ -6,7 +6,10 @@ import type { ServerConnection } from "./connection.ts";
|
|
|
6
6
|
import type { McpToolDetails } from "./expose/register.ts";
|
|
7
7
|
import type { McpOutputArtifacts } from "./guard/output-guard.ts";
|
|
8
8
|
import { applyMcpOutputGuard } from "./guard/output-guard.ts";
|
|
9
|
+
import { type McpRequestOrigin } from "./request-origin.ts";
|
|
9
10
|
export interface McpResourceServer {
|
|
11
|
+
readonly ensureFresh?: () => Promise<void>;
|
|
12
|
+
readonly requestOrigin?: () => McpRequestOrigin | undefined;
|
|
10
13
|
readonly server: string;
|
|
11
14
|
readonly connection: ServerConnection;
|
|
12
15
|
readonly agentDir?: string;
|
|
@@ -22,7 +25,7 @@ export declare function ensureMcpResourceSubscriptions(client: Client, resources
|
|
|
22
25
|
uri: string;
|
|
23
26
|
}>): Promise<void>;
|
|
24
27
|
/** Read one resource and flatten its contents to guarded text. */
|
|
25
|
-
export declare function readMcpResourceAsText(server: McpResourceServer, uri: string): Promise<string>;
|
|
28
|
+
export declare function readMcpResourceAsText(server: McpResourceServer, uri: string, signal?: AbortSignal): Promise<string>;
|
|
26
29
|
declare const ListParams: Type.TObject<{
|
|
27
30
|
server: Type.TOptional<Type.TString>;
|
|
28
31
|
}>;
|
|
@@ -16,6 +16,9 @@ import { redactResolvedReferenceData, redactResolvedReferenceValues } from "../.
|
|
|
16
16
|
import { ToolExecError } from "./errors.js";
|
|
17
17
|
import { applyMcpOutputGuard } from "./guard/output-guard.js";
|
|
18
18
|
import { ResourceUpdatedNotificationSchema, registerMcpNotificationHandler } from "./notification-schemas.js";
|
|
19
|
+
import { mcpRequestOptions } from "./request-origin.js";
|
|
20
|
+
import { McpMrtrError } from "./modern/errors.js";
|
|
21
|
+
import { ensureMcpToolCallConnection } from "./health.js";
|
|
19
22
|
/** Route resource updated notifications into the shared refresh path. */
|
|
20
23
|
export function subscribeMcpResourceUpdated(client, onChange) {
|
|
21
24
|
registerMcpNotificationHandler(client, ResourceUpdatedNotificationSchema, () => {
|
|
@@ -29,13 +32,20 @@ export async function ensureMcpResourceSubscriptions(client, resources) {
|
|
|
29
32
|
await Promise.all(resources.map((resource) => client.subscribeResource({ uri: resource.uri }).catch(() => undefined)));
|
|
30
33
|
}
|
|
31
34
|
/** Read one resource and flatten its contents to guarded text. */
|
|
32
|
-
export async function readMcpResourceAsText(server, uri) {
|
|
35
|
+
export async function readMcpResourceAsText(server, uri, signal) {
|
|
33
36
|
let contents;
|
|
34
37
|
try {
|
|
35
|
-
|
|
38
|
+
if (server.requestOrigin)
|
|
39
|
+
await ensureMcpToolCallConnection(server.connection, server.ensureFresh);
|
|
40
|
+
const result = await server.connection.client.readResource({ uri }, mcpRequestOptions(server.requestOrigin?.(), {
|
|
41
|
+
timeout: server.requestTimeoutMs,
|
|
42
|
+
...(signal === undefined ? {} : { signal }),
|
|
43
|
+
}));
|
|
36
44
|
contents = result.contents;
|
|
37
45
|
}
|
|
38
46
|
catch (error) {
|
|
47
|
+
if (error instanceof McpMrtrError)
|
|
48
|
+
throw error;
|
|
39
49
|
throw new ToolExecError(redactResolvedReferenceValues(`Failed to read MCP resource ${uri}: ${error instanceof Error ? error.message : String(error)}`), {
|
|
40
50
|
phase: "call",
|
|
41
51
|
serverName: server.server,
|
|
@@ -93,7 +103,7 @@ export function createMcpResourceTools(servers) {
|
|
|
93
103
|
description: "Read one MCP resource by server name and URI; returns its (guarded) content.",
|
|
94
104
|
parameters: ReadParams,
|
|
95
105
|
executionMode: "parallel",
|
|
96
|
-
async execute(_id, params) {
|
|
106
|
+
async execute(_id, params, signal) {
|
|
97
107
|
const entry = servers().find((candidate) => candidate.server === params.server);
|
|
98
108
|
if (entry === undefined) {
|
|
99
109
|
throw new ToolExecError(redactResolvedReferenceValues(`Unknown MCP server '${params.server}' for resource ${params.uri}.`), {
|
|
@@ -101,7 +111,7 @@ export function createMcpResourceTools(servers) {
|
|
|
101
111
|
serverName: params.server,
|
|
102
112
|
});
|
|
103
113
|
}
|
|
104
|
-
const text = await readMcpResourceAsText(entry, params.uri);
|
|
114
|
+
const text = await readMcpResourceAsText(entry, params.uri, signal);
|
|
105
115
|
return {
|
|
106
116
|
content: [{ type: "text", text }],
|
|
107
117
|
details: redactResolvedReferenceData({
|
|
@@ -137,6 +147,11 @@ export async function expandMcpResourceMentions(text, servers) {
|
|
|
137
147
|
expanded = expanded.replace(mention, `<mcp-resource server="${serverName}" uri="${uri}">\n${body}\n</mcp-resource>`);
|
|
138
148
|
}
|
|
139
149
|
catch (error) {
|
|
150
|
+
if (error instanceof McpMrtrError &&
|
|
151
|
+
["MCP_MRTR_CANCELLED", "MCP_MRTR_CONTEXT_CHANGED", "MCP_MRTR_TIMEOUT"].includes(error.code)) {
|
|
152
|
+
notices.push("MCP resource request canceled; mention left unchanged.");
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
140
155
|
notices.push(`@mcp mention left as-is: ${error instanceof Error ? error.message : String(error)}`);
|
|
141
156
|
}
|
|
142
157
|
}
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
/** `Client` — the MCP client class, built once per transport connection. */
|
|
17
17
|
export declare const loadMcpSdkClient: () => Promise<typeof import("@modelcontextprotocol/sdk/client/index.js")>;
|
|
18
|
+
/** Compatibility parser for final caller schemas at the modern request boundary. */
|
|
19
|
+
export declare const loadMcpSdkZodCompat: () => Promise<typeof import("@modelcontextprotocol/sdk/server/zod-compat.js")>;
|
|
18
20
|
/** `StdioClientTransport` + `getDefaultEnvironment` — stdio servers and the stdio diagnostic rerun. */
|
|
19
21
|
export declare const loadMcpSdkStdioTransport: () => Promise<typeof import("@modelcontextprotocol/sdk/client/stdio.js")>;
|
|
20
|
-
/**
|
|
22
|
+
/** SDK-owned protocol schemas for elicitation and modern request results. */
|
|
21
23
|
export declare const loadMcpSdkTypes: () => Promise<typeof import("@modelcontextprotocol/sdk/types.js")>;
|
|
22
24
|
/** OAuth 2.1 discovery, authorization, token exchange and refresh. */
|
|
23
25
|
export declare const loadMcpSdkAuth: () => Promise<typeof import("@modelcontextprotocol/sdk/client/auth.js")>;
|
|
@@ -36,9 +36,11 @@ function memoizeLoader(load) {
|
|
|
36
36
|
}
|
|
37
37
|
/** `Client` — the MCP client class, built once per transport connection. */
|
|
38
38
|
export const loadMcpSdkClient = memoizeLoader(() => import("@modelcontextprotocol/sdk/client/index.js"));
|
|
39
|
+
/** Compatibility parser for final caller schemas at the modern request boundary. */
|
|
40
|
+
export const loadMcpSdkZodCompat = memoizeLoader(() => import("@modelcontextprotocol/sdk/server/zod-compat.js"));
|
|
39
41
|
/** `StdioClientTransport` + `getDefaultEnvironment` — stdio servers and the stdio diagnostic rerun. */
|
|
40
42
|
export const loadMcpSdkStdioTransport = memoizeLoader(() => import("@modelcontextprotocol/sdk/client/stdio.js"));
|
|
41
|
-
/**
|
|
43
|
+
/** SDK-owned protocol schemas for elicitation and modern request results. */
|
|
42
44
|
export const loadMcpSdkTypes = memoizeLoader(() => import("@modelcontextprotocol/sdk/types.js"));
|
|
43
45
|
let authModule;
|
|
44
46
|
/** OAuth 2.1 discovery, authorization, token exchange and refresh. */
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "../../types.ts";
|
|
1
|
+
import type { ExtensionAPI, ExtensionUIContext } from "../../types.ts";
|
|
2
2
|
import type { ToolSearchService } from "../tool-search/service.ts";
|
|
3
3
|
import type { ResolvedMcpConfig } from "./config-schema.ts";
|
|
4
4
|
import type { McpSessionRegistration } from "./expose/session.ts";
|
|
5
5
|
import type { McpConnectionEntry } from "./service-types.ts";
|
|
6
|
+
import type { McpRequestOrigin } from "./request-origin.ts";
|
|
6
7
|
type McpToolRegistrar = Pick<ExtensionAPI, "getActiveTools" | "setActiveTools" | "registerTool">;
|
|
7
8
|
export interface McpServiceDirectToolRegistrationOptions {
|
|
9
|
+
readonly requestOrigin?: (entry: McpConnectionEntry) => McpRequestOrigin;
|
|
10
|
+
readonly bindPresentation?: (ui: ExtensionUIContext) => void;
|
|
8
11
|
readonly refreshActiveSetWhenEmpty?: boolean;
|
|
9
12
|
readonly onRegistered?: (entry: McpConnectionEntry, identity: string) => void;
|
|
10
13
|
readonly isCurrent?: (entry: McpConnectionEntry) => boolean;
|
|
@@ -39,6 +39,7 @@ export async function registerMcpServiceDirectTools(pi, config, entries, toolSea
|
|
|
39
39
|
ensureFresh: () => entry.authPlan?.refresh?.ensureFresh().then(() => undefined) ?? Promise.resolve(),
|
|
40
40
|
outputGuard: config.settings.outputGuard,
|
|
41
41
|
invocation,
|
|
42
|
+
requestOrigin: () => options.requestOrigin?.(entry),
|
|
42
43
|
});
|
|
43
44
|
return computeMcpExposurePolicy(current, serverConfig, config.settings).filteredEntries.find((candidate) => candidate.tool === tool);
|
|
44
45
|
},
|
|
@@ -54,6 +55,8 @@ export async function registerMcpServiceDirectTools(pi, config, entries, toolSea
|
|
|
54
55
|
startupCatalogPending,
|
|
55
56
|
localCatalogOnly: true,
|
|
56
57
|
invocation,
|
|
58
|
+
requestOrigin: () => options.requestOrigin?.(entry),
|
|
59
|
+
bindPresentation: options.bindPresentation,
|
|
57
60
|
onRegistered: (identity) => options.onRegistered?.(entry, identity),
|
|
58
61
|
connection: entry.connection,
|
|
59
62
|
ensureFresh: () => entry.authPlan?.refresh?.ensureFresh().then(() => undefined) ?? Promise.resolve(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtensionContext, SessionShutdownEvent, SessionStartEvent } from "../../types.ts";
|
|
1
|
+
import type { ExtensionContext, ExtensionUIContext, SessionShutdownEvent, SessionStartEvent } from "../../types.ts";
|
|
2
2
|
import type { ServerAuthPlan } from "./auth/context.ts";
|
|
3
3
|
import type { McpCachedServerCatalog } from "./catalog-cache.ts";
|
|
4
4
|
import type { ResolvedMcpServer } from "./config-schema.ts";
|
|
@@ -65,6 +65,7 @@ export type McpWireStatusSnapshot = {
|
|
|
65
65
|
readonly servers: readonly McpWireStatusServer[];
|
|
66
66
|
};
|
|
67
67
|
export type McpSessionContext = Pick<ExtensionContext, "cwd" | "isProjectTrusted"> & {
|
|
68
|
+
ui?: ExtensionUIContext;
|
|
68
69
|
mode?: ExtensionContext["mode"];
|
|
69
70
|
/**
|
|
70
71
|
* Session history access, present on the real ExtensionContext. Only
|
|
@@ -89,6 +89,7 @@ export declare class McpService {
|
|
|
89
89
|
setMcpInstructions(instructions: string): void;
|
|
90
90
|
getMcpInstructions(): string;
|
|
91
91
|
setMcpElicitationUiProvider(provider: (() => McpElicitationUi | undefined) | undefined): void;
|
|
92
|
+
bindMcpMrtrPresentation(pi: object, ui: ExtensionUIContext): void;
|
|
92
93
|
getMcpElicitationUi(): McpElicitationUi | undefined;
|
|
93
94
|
isMcpPromptCommandRegistered(name: string): boolean;
|
|
94
95
|
markMcpPromptCommandRegistered(name: string): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ConfigReferenceError } from "@earendil-works/pi-ai/utils/config-reference";
|
|
2
2
|
import { getAgentDir } from "../../../../config.js";
|
|
3
3
|
import { redactResolvedReferenceData } from "../../../config-reference-redaction.js";
|
|
4
|
+
import { getMcpMrtrPresentation } from "../../../mcp-mrtr-presentations.js";
|
|
4
5
|
import { getToolSearchService, getToolSearchServiceForExtension, resetToolSearchServiceForTests, ToolSearchService, } from "../tool-search/service.js";
|
|
5
6
|
import { mcpCredentialIdentity } from "./auth/catalog-identity.js";
|
|
6
7
|
import { resolveAuthMode } from "./auth/context.js";
|
|
@@ -13,6 +14,8 @@ import { HostMcpRegistry } from "./host-registry.js";
|
|
|
13
14
|
import { refreshMcpInstructionsForSession } from "./instructions.js";
|
|
14
15
|
import { createMcpLogger } from "./log.js";
|
|
15
16
|
import { prepareProjectSkillServer } from "./project-skill-policy.js";
|
|
17
|
+
import { createMcpRequestOrigin } from "./request-origin.js";
|
|
18
|
+
import { McpMrtrError } from "./modern/errors.js";
|
|
16
19
|
import { reconnectMcpNow } from "./reconnect.js";
|
|
17
20
|
import { createMcpSessionConnection, disposeEntryConnection } from "./service-connection.js";
|
|
18
21
|
import { getMcpServiceExposureStatus } from "./service-exposure.js";
|
|
@@ -181,8 +184,12 @@ export class McpService {
|
|
|
181
184
|
};
|
|
182
185
|
const previous = this.#bindings.get(pi);
|
|
183
186
|
// A session-owned service serves exactly one session: a new attach takes over its binding.
|
|
184
|
-
|
|
187
|
+
previous?.lifetime.abort();
|
|
188
|
+
if (!this.#servesManySessions) {
|
|
189
|
+
for (const binding of this.#bindings.values())
|
|
190
|
+
binding.lifetime.abort();
|
|
185
191
|
this.#bindings.clear();
|
|
192
|
+
}
|
|
186
193
|
let fallbackToolSearch;
|
|
187
194
|
let holdsProcessFallback = false;
|
|
188
195
|
const sessionToolSearch = getToolSearchServiceForExtension(pi);
|
|
@@ -205,6 +212,8 @@ export class McpService {
|
|
|
205
212
|
}
|
|
206
213
|
}
|
|
207
214
|
const binding = {
|
|
215
|
+
lifetime: new AbortController(),
|
|
216
|
+
presentation: owner.context.ui === undefined ? undefined : getMcpMrtrPresentation(owner.context.ui),
|
|
208
217
|
pi,
|
|
209
218
|
fallbackToolSearch,
|
|
210
219
|
holdsProcessFallback,
|
|
@@ -224,8 +233,10 @@ export class McpService {
|
|
|
224
233
|
#liveBindings() {
|
|
225
234
|
for (const [pi, binding] of this.#bindings) {
|
|
226
235
|
// A disposed session retires its own tool-search service; its binding goes with it.
|
|
227
|
-
if (getToolSearchServiceForExtension(binding.pi)?.isDisposed === true)
|
|
236
|
+
if (getToolSearchServiceForExtension(binding.pi)?.isDisposed === true) {
|
|
237
|
+
binding.lifetime.abort();
|
|
228
238
|
this.#bindings.delete(pi);
|
|
239
|
+
}
|
|
229
240
|
}
|
|
230
241
|
return [...this.#bindings.values()];
|
|
231
242
|
}
|
|
@@ -240,6 +251,7 @@ export class McpService {
|
|
|
240
251
|
*/
|
|
241
252
|
async releaseSession(pi, disposeReason) {
|
|
242
253
|
const released = this.#bindings.get(pi);
|
|
254
|
+
released?.lifetime.abort();
|
|
243
255
|
this.#bindings.delete(pi);
|
|
244
256
|
if (disposeReason !== undefined)
|
|
245
257
|
this.#releasedSessions.add(pi);
|
|
@@ -386,7 +398,7 @@ export class McpService {
|
|
|
386
398
|
? await prepareProjectSkillServer(name, decl, {
|
|
387
399
|
context: binding.context,
|
|
388
400
|
options: binding.options,
|
|
389
|
-
ui:
|
|
401
|
+
ui: this.#elicitationProviderFor(binding),
|
|
390
402
|
notice: (identity, names) => {
|
|
391
403
|
// An untrusted project keeps the skill's references literal (senpi#2345); keep that fix in
|
|
392
404
|
// the one notice instead of a generic withheld line (senpi#3796).
|
|
@@ -527,6 +539,8 @@ export class McpService {
|
|
|
527
539
|
this.#disposed = true;
|
|
528
540
|
this.#disposeCount += 1;
|
|
529
541
|
this.#lastDisposeReason = reason;
|
|
542
|
+
for (const binding of this.#bindings.values())
|
|
543
|
+
binding.lifetime.abort();
|
|
530
544
|
this.#bindings.clear();
|
|
531
545
|
this.#sessionContext = null;
|
|
532
546
|
this.#config = null;
|
|
@@ -711,7 +725,7 @@ export class McpService {
|
|
|
711
725
|
session: options,
|
|
712
726
|
elicitationEnabled: declarer.context.mode !== "print" && declarer.context.mode !== "json",
|
|
713
727
|
cwd: declarer.context.cwd,
|
|
714
|
-
ui:
|
|
728
|
+
ui: this.#elicitationProviderFor(declarer),
|
|
715
729
|
artifacts: this.#outputArtifacts,
|
|
716
730
|
shouldReconnect: (current) => !this.#disposed &&
|
|
717
731
|
this.#entryForName(name) === current &&
|
|
@@ -813,6 +827,8 @@ export class McpService {
|
|
|
813
827
|
onRegistered: (entry, identity) => binding.registeredIdentities.set(entry.key, identity),
|
|
814
828
|
contextRequired: binding.context.mode !== undefined,
|
|
815
829
|
sessionManager: binding.context.sessionManager,
|
|
830
|
+
requestOrigin: (entry) => this.#requestOrigin(binding, entry),
|
|
831
|
+
bindPresentation: (ui) => this.bindMcpMrtrPresentation(binding.pi, ui),
|
|
816
832
|
// A new attach of this session replaces its binding (and with it its config); a peer's attach does not.
|
|
817
833
|
isCurrent: (entry) => !this.#disposed &&
|
|
818
834
|
this.#bindings.get(binding.pi) === binding &&
|
|
@@ -955,9 +971,68 @@ export class McpService {
|
|
|
955
971
|
setMcpElicitationUiProvider(provider) {
|
|
956
972
|
this.#elicitationUiProvider = provider;
|
|
957
973
|
}
|
|
974
|
+
bindMcpMrtrPresentation(pi, ui) {
|
|
975
|
+
const binding = this.#bindings.get(pi);
|
|
976
|
+
const presentation = getMcpMrtrPresentation(ui);
|
|
977
|
+
if (binding && presentation)
|
|
978
|
+
binding.presentation = presentation;
|
|
979
|
+
}
|
|
980
|
+
#requestOrigin(binding, entry) {
|
|
981
|
+
const source = binding.config.servers[entry.name]?.source;
|
|
982
|
+
return createMcpRequestOrigin({
|
|
983
|
+
binding,
|
|
984
|
+
connection: entry.connection,
|
|
985
|
+
signal: AbortSignal.any([binding.lifetime.signal, entry.connection.requestLifetimeSignal]),
|
|
986
|
+
presentation: binding.presentation,
|
|
987
|
+
privateFormsEnforced: binding.presentation?.privateForms !== undefined,
|
|
988
|
+
privateForm: binding.presentation?.privateForms?.capture(),
|
|
989
|
+
serverLabel: entry.name,
|
|
990
|
+
serverSource: source === "project" || source === "claude"
|
|
991
|
+
? "project"
|
|
992
|
+
: source === "skill" || source === "extension"
|
|
993
|
+
? "plugin"
|
|
994
|
+
: "user",
|
|
995
|
+
isCurrent: () => !this.#disposed &&
|
|
996
|
+
!binding.lifetime.signal.aborted &&
|
|
997
|
+
this.#bindings.get(binding.pi) === binding &&
|
|
998
|
+
[...this.#connections.values()].includes(entry) &&
|
|
999
|
+
declares(binding.config, entry.name, entry.configHash) &&
|
|
1000
|
+
entry.isCurrent?.() !== false &&
|
|
1001
|
+
entry.credentialsCurrent?.() !== false,
|
|
1002
|
+
resolveAuthority: async (signal) => {
|
|
1003
|
+
if (await entry.generationChanged?.())
|
|
1004
|
+
throw new McpMrtrError("MCP_MRTR_CONTEXT_CHANGED");
|
|
1005
|
+
// Same observed-revocation boundary as ordinary MCP requests. Never prompts for a new grant.
|
|
1006
|
+
return await entry.connection.projectPolicy?.resolve(signal, false);
|
|
1007
|
+
},
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
958
1010
|
getMcpElicitationUi() {
|
|
959
1011
|
return this.#elicitationUiProvider?.();
|
|
960
1012
|
}
|
|
1013
|
+
#elicitationProviderFor(owner) {
|
|
1014
|
+
// Connections outlive their first declarer's extension context. Capture its host-owned
|
|
1015
|
+
// references while it is live; readiness must never read a released session's ctx.ui.
|
|
1016
|
+
const binding = [...this.#bindings.values()].find((candidate) => candidate === owner);
|
|
1017
|
+
const ui = owner.context.ui;
|
|
1018
|
+
const privateBinding = () => {
|
|
1019
|
+
// Keep observing presentation replacements on the binding, not just its initial grant.
|
|
1020
|
+
const presentation = binding
|
|
1021
|
+
? binding.presentation
|
|
1022
|
+
: ui === undefined
|
|
1023
|
+
? undefined
|
|
1024
|
+
: getMcpMrtrPresentation(ui);
|
|
1025
|
+
return presentation?.privateForms;
|
|
1026
|
+
};
|
|
1027
|
+
return Object.assign(() => this.getMcpElicitationUi(), {
|
|
1028
|
+
enforced: () => privateBinding() !== undefined,
|
|
1029
|
+
subscribe: (listener) => privateBinding()?.subscribe?.(listener) ?? (() => { }),
|
|
1030
|
+
eligible: () => {
|
|
1031
|
+
const binding = privateBinding();
|
|
1032
|
+
return binding === undefined || binding.capture()?.ready() === true;
|
|
1033
|
+
},
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
961
1036
|
isMcpPromptCommandRegistered(name) {
|
|
962
1037
|
return this.#promptCommandNames.has(name);
|
|
963
1038
|
}
|
|
@@ -9,6 +9,8 @@ import { safeInterval, safeTimer } from "./wrap.js";
|
|
|
9
9
|
/** Owns one SDK handler set, reconnect loop, cache writer and aggregate lifetime. */
|
|
10
10
|
export class SharedMcpConnection {
|
|
11
11
|
#calls;
|
|
12
|
+
#readinessListeners;
|
|
13
|
+
#readinessSubscriptions;
|
|
12
14
|
#options;
|
|
13
15
|
#onDispose;
|
|
14
16
|
#idleTimeoutMin;
|
|
@@ -22,6 +24,8 @@ export class SharedMcpConnection {
|
|
|
22
24
|
constructor(options, onDispose) {
|
|
23
25
|
this.leases = new Set();
|
|
24
26
|
this.#calls = new Map();
|
|
27
|
+
this.#readinessListeners = new Set();
|
|
28
|
+
this.#readinessSubscriptions = new Map();
|
|
25
29
|
this.#cacheGeneration = -1;
|
|
26
30
|
this.#disposed = false;
|
|
27
31
|
this.#inFlight = 0;
|
|
@@ -64,13 +68,30 @@ export class SharedMcpConnection {
|
|
|
64
68
|
},
|
|
65
69
|
},
|
|
66
70
|
logger,
|
|
67
|
-
elicitationUiProvider: () => {
|
|
71
|
+
elicitationUiProvider: Object.assign(() => {
|
|
68
72
|
// SDK server requests carry no originating tool-call id.
|
|
69
73
|
const owners = [...this.#calls.keys()];
|
|
70
74
|
return owners.length === 1 && this.leases.has(owners[0])
|
|
71
75
|
? owners[0].options.elicitationUiProvider?.()
|
|
72
76
|
: undefined;
|
|
73
|
-
},
|
|
77
|
+
}, {
|
|
78
|
+
enforced: () => [...this.leases].some((lease) => lease.options.elicitationUiProvider?.enforced?.()),
|
|
79
|
+
subscribe: (listener) => {
|
|
80
|
+
this.#readinessListeners.add(listener);
|
|
81
|
+
return () => {
|
|
82
|
+
this.#readinessListeners.delete(listener);
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
eligible: () => {
|
|
86
|
+
const leases = [...this.leases];
|
|
87
|
+
const eligible = (lease) => lease.options.elicitationEnabled !== false &&
|
|
88
|
+
lease.options.elicitationUiProvider?.eligible?.() !== false;
|
|
89
|
+
// Any ready owner permits negotiation; per-operation authority still selects the holder.
|
|
90
|
+
if (leases.some((lease) => lease.options.elicitationUiProvider?.enforced?.()))
|
|
91
|
+
return leases.some(eligible);
|
|
92
|
+
return leases.length > 0 && leases.every(eligible);
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
74
95
|
});
|
|
75
96
|
this.connection.onToolsChanged(() => {
|
|
76
97
|
this.#catalog = undefined;
|
|
@@ -112,6 +133,14 @@ export class SharedMcpConnection {
|
|
|
112
133
|
this.#clearIdle();
|
|
113
134
|
const lease = new SharedMcpLease(this, options, owner, key);
|
|
114
135
|
this.leases.add(lease);
|
|
136
|
+
const unsubscribe = options.elicitationUiProvider?.subscribe?.(() => {
|
|
137
|
+
for (const listener of this.#readinessListeners)
|
|
138
|
+
listener();
|
|
139
|
+
});
|
|
140
|
+
if (unsubscribe)
|
|
141
|
+
this.#readinessSubscriptions.set(lease, unsubscribe);
|
|
142
|
+
for (const listener of this.#readinessListeners)
|
|
143
|
+
listener();
|
|
115
144
|
this.#idleTimeoutMin = Math.max(...[...this.leases].map((item) => item.options.config.idleTimeoutMin));
|
|
116
145
|
this.#refreshKeepAlive();
|
|
117
146
|
return lease;
|
|
@@ -154,6 +183,11 @@ export class SharedMcpConnection {
|
|
|
154
183
|
// Capture the last attached policy before removing the final owner.
|
|
155
184
|
this.#idleTimeoutMin = Math.max(...[...this.leases].map((item) => item.options.config.idleTimeoutMin));
|
|
156
185
|
this.leases.delete(lease);
|
|
186
|
+
this.#readinessSubscriptions.get(lease)?.();
|
|
187
|
+
this.#readinessSubscriptions.delete(lease);
|
|
188
|
+
if (this.leases.size > 0)
|
|
189
|
+
for (const listener of this.#readinessListeners)
|
|
190
|
+
listener();
|
|
157
191
|
this.#refreshKeepAlive();
|
|
158
192
|
this.#armIdle();
|
|
159
193
|
}
|
|
@@ -9,6 +9,7 @@ export declare class SharedMcpLease extends ServerConnection {
|
|
|
9
9
|
readonly key: string;
|
|
10
10
|
readonly options: ServerConnectionOptions;
|
|
11
11
|
readonly shared: SharedMcpConnection;
|
|
12
|
+
get requestLifetimeSignal(): AbortSignal;
|
|
12
13
|
constructor(shared: SharedMcpConnection, options: ServerConnectionOptions, owner: object, key: string);
|
|
13
14
|
get state(): import("./connection-types.ts").ServerConnectionState;
|
|
14
15
|
get generation(): number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ServerConnection } from "./connection.js";
|
|
2
2
|
import { ConnectError } from "./errors.js";
|
|
3
|
+
import { registerMcpClientAlias } from "./request-origin.js";
|
|
3
4
|
const requestMethods = new Set([
|
|
4
5
|
"request",
|
|
5
6
|
"listTools",
|
|
@@ -19,6 +20,10 @@ export class SharedMcpLease extends ServerConnection {
|
|
|
19
20
|
#unsubscribeTools;
|
|
20
21
|
#stateSubscriptions = new Set();
|
|
21
22
|
#released = false;
|
|
23
|
+
#requestLifetime = new AbortController();
|
|
24
|
+
get requestLifetimeSignal() {
|
|
25
|
+
return this.#requestLifetime.signal;
|
|
26
|
+
}
|
|
22
27
|
#localGeneration = 0;
|
|
23
28
|
#client;
|
|
24
29
|
#physicalClient;
|
|
@@ -63,6 +68,7 @@ export class SharedMcpLease extends ServerConnection {
|
|
|
63
68
|
return typeof value === "function" ? value.bind(target) : value;
|
|
64
69
|
},
|
|
65
70
|
});
|
|
71
|
+
registerMcpClientAlias(this.#client, physical);
|
|
66
72
|
}
|
|
67
73
|
if (this.#client === undefined)
|
|
68
74
|
throw new ConnectError("MCP client unavailable", { phase: "client" });
|
|
@@ -79,6 +85,8 @@ export class SharedMcpLease extends ServerConnection {
|
|
|
79
85
|
}
|
|
80
86
|
async bumpGeneration() {
|
|
81
87
|
this.#assertAttached();
|
|
88
|
+
this.#requestLifetime.abort();
|
|
89
|
+
this.#requestLifetime = new AbortController();
|
|
82
90
|
this.#localGeneration++;
|
|
83
91
|
this.#refreshCatalog = true;
|
|
84
92
|
// Re-list only this owner's catalog; never interrupt another owner's call.
|
|
@@ -128,6 +136,7 @@ export class SharedMcpLease extends ServerConnection {
|
|
|
128
136
|
if (this.#released)
|
|
129
137
|
return;
|
|
130
138
|
this.#released = true;
|
|
139
|
+
this.#requestLifetime.abort();
|
|
131
140
|
this.#unsubscribeTools();
|
|
132
141
|
for (const off of this.#stateSubscriptions)
|
|
133
142
|
off();
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
12
12
|
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
13
13
|
import type { McpOAuthProvider } from "./auth/oauth-provider.ts";
|
|
14
|
-
import {
|
|
14
|
+
import type { McpElicitationUiProvider } from "./elicitation.ts";
|
|
15
15
|
import type { McpLogger } from "./log.ts";
|
|
16
|
+
import type { ModernProtocolState } from "./modern/request.ts";
|
|
16
17
|
import { type McpAsyncErrorSink } from "./wrap.ts";
|
|
17
18
|
export type McpStdioTransportSpec = {
|
|
18
19
|
readonly projectPolicy?: boolean;
|
|
@@ -48,5 +49,5 @@ export interface MaterializeMcpTransportOptions {
|
|
|
48
49
|
/** Invoked once the stdio child has started, so the caller can capture its pid. */
|
|
49
50
|
readonly onStart: () => void;
|
|
50
51
|
}
|
|
51
|
-
export declare function materializeMcpTransport(options: MaterializeMcpTransportOptions): Promise<McpMaterializedTransport>;
|
|
52
|
+
export declare function materializeMcpTransport(options: MaterializeMcpTransportOptions, protocol?: ModernProtocolState): Promise<McpMaterializedTransport>;
|
|
52
53
|
//# sourceMappingURL=transport-sdk.d.ts.map
|