@code-yeongyu/senpi 2026.10.25-3 → 2026.10.26-1
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 +40 -0
- package/dist/bundle/chunks/{anthropic-messages-WBASBTIW.js → anthropic-messages-M235FJQV.js} +3 -3
- package/dist/bundle/chunks/{args-B444OQBK.js → args-FBNJOJSR.js} +1 -1
- package/dist/bundle/chunks/azure-openai-responses-YQRTQ7H6.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +3 -3
- package/dist/bundle/chunks/{chunk-FFQOEC76.js → chunk-3A3XCLNH.js} +3 -3
- package/dist/bundle/chunks/{chunk-EHQXLHRB.js → chunk-3LPWILUZ.js} +2 -2
- package/dist/bundle/chunks/{chunk-3BTN337S.js → chunk-3WP5RFQR.js} +1 -1
- package/dist/bundle/chunks/{chunk-WLHNEUGD.js → chunk-5FQMNHXV.js} +1 -1
- package/dist/bundle/chunks/{chunk-HVJI5T75.js → chunk-5KZH6EYQ.js} +2 -2
- package/dist/bundle/chunks/{chunk-4P7WARQZ.js → chunk-5LWUUXMH.js} +1 -1
- package/dist/bundle/chunks/{chunk-ODTGC6YU.js → chunk-6U3TBFBA.js} +1 -1
- package/dist/bundle/chunks/chunk-6VWIMHMH.js +2 -0
- package/dist/bundle/chunks/{chunk-BWA4FVFW.js → chunk-7KOUQSBX.js} +2 -2
- package/dist/bundle/chunks/{chunk-7CNOCJCN.js → chunk-ADQAPDPV.js} +1 -1
- package/dist/bundle/chunks/{chunk-ITGYN22E.js → chunk-CDQPA4FP.js} +1 -1
- package/dist/bundle/chunks/{chunk-WDPQ6CZJ.js → chunk-DMFAVE5N.js} +1 -1
- package/dist/bundle/chunks/{chunk-XF3LJC3O.js → chunk-DYWIFF2Q.js} +1 -1
- package/dist/bundle/chunks/{chunk-YRF4I43T.js → chunk-EZP6AYW2.js} +37 -31
- package/dist/bundle/chunks/chunk-GQJYNFMO.js +2 -0
- package/dist/bundle/chunks/{chunk-O3Q2ET6W.js → chunk-GWGNVYPB.js} +1 -1
- package/dist/bundle/chunks/{chunk-Z3UYNSVR.js → chunk-H4WJ4LY3.js} +1 -1
- package/dist/bundle/chunks/{chunk-UQNRW3VU.js → chunk-HWTD4QF3.js} +1 -1
- package/dist/bundle/chunks/{chunk-WD6WBYC5.js → chunk-I7QWTWVZ.js} +1 -1
- package/dist/bundle/chunks/{chunk-SWJXRC2I.js → chunk-J2YAYTB2.js} +1 -1
- package/dist/bundle/chunks/{chunk-TTU2RNVX.js → chunk-J5FCH7TI.js} +1 -1
- package/dist/bundle/chunks/chunk-JFQUWEN7.js +13 -0
- package/dist/bundle/chunks/{chunk-JA2R2ZSE.js → chunk-L2O6K3SJ.js} +1 -1
- package/dist/bundle/chunks/{chunk-4AOMNOGY.js → chunk-LO5MYLGF.js} +1 -1
- package/dist/bundle/chunks/{chunk-P3M2PF6K.js → chunk-MSHRIZGT.js} +8 -6
- package/dist/bundle/chunks/{chunk-T36LJ6MW.js → chunk-MY4ZD3EW.js} +1 -1
- package/dist/bundle/chunks/{chunk-UFJ2K7Q7.js → chunk-OQ3WDMB3.js} +1 -1
- package/dist/bundle/chunks/{chunk-7GZUFOM3.js → chunk-PH3JDRB2.js} +1 -1
- package/dist/bundle/chunks/{chunk-E6WYH3ZL.js → chunk-QREKAXKX.js} +7 -5
- package/dist/bundle/chunks/{chunk-MJ5NNWX4.js → chunk-QYFOHFPS.js} +1 -1
- package/dist/bundle/chunks/chunk-SOXQ42VS.js +2 -0
- package/dist/bundle/chunks/{chunk-FHXR4ZAC.js → chunk-UDM7VO6O.js} +1 -1
- package/dist/bundle/chunks/{chunk-OLCDIITS.js → chunk-UW6M3EXY.js} +1 -1
- package/dist/bundle/chunks/chunk-VICDRG3J.js +410 -0
- package/dist/bundle/chunks/chunk-VL7O5PO4.js +5 -0
- package/dist/bundle/chunks/chunk-XMJKZK5H.js +2 -0
- package/dist/bundle/chunks/{chunk-C5UFJ7B3.js → chunk-XMNPK472.js} +1 -1
- package/dist/bundle/chunks/{chunk-GSSD3R5X.js → chunk-XQ45JMGN.js} +1 -1
- package/dist/bundle/chunks/{client-WTYEICLH.js → chunk-Y3TMJV3J.js} +3 -3
- package/dist/bundle/chunks/{chunk-KXB5WIS5.js → chunk-Z6SAQ5O3.js} +1 -1
- package/dist/bundle/chunks/{chunk-CNL6QSUB.js → chunk-ZAUVY6ZC.js} +3 -3
- package/dist/bundle/chunks/{chunk-E4LBKOZG.js → chunk-ZLIVZQDY.js} +4 -4
- package/dist/bundle/chunks/{chunk-6AOVUTUR.js → chunk-ZXHLH4MW.js} +2 -2
- package/dist/bundle/chunks/cli-main-55EQA5PS.js +3 -0
- package/dist/bundle/chunks/client-LOS6GSEW.js +2 -0
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-K5H6BJP3.js → cloudflare-workers-ai-system-one-ZJQGIIRC.js} +1 -1
- package/dist/bundle/chunks/cursor-agent.js +3 -3
- package/dist/bundle/chunks/devin-agent.js +3 -3
- package/dist/bundle/chunks/dispatch-C2IBP5VV.js +9 -0
- package/dist/bundle/chunks/google-generative-ai-5G4RIQA6.js +2 -0
- package/dist/bundle/chunks/google-vertex-ALD4P27O.js +2 -0
- package/dist/bundle/chunks/{help-fast-path-3Z26DQSV.js → help-fast-path-PEIKGCKZ.js} +1 -1
- package/dist/bundle/chunks/host-command-657VCQ34.js +2 -0
- package/dist/bundle/chunks/{host-lifecycle-ONQIMWMX.js → host-lifecycle-HX3EGRRW.js} +1 -1
- package/dist/bundle/chunks/host-lifecycle.js +2 -2
- package/dist/bundle/chunks/{host-session-command-J65ENSV5.js → host-session-command-OV5XDOJK.js} +1 -1
- package/dist/bundle/chunks/{host-socket-request-3CWE4265.js → host-socket-request-K4LCUOUD.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-MLXSYK2H.js +2 -0
- package/dist/bundle/chunks/{mcp-presenter-bootstrap-XUSCQVRC.js → mcp-presenter-bootstrap-FOMKF4TU.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-DH44NOYV.js → mistral-conversations-RAE4K2XY.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-YI2WZOET.js → multi-session-host-774MACJU.js} +5 -6
- package/dist/bundle/chunks/{openai-codex-responses-SERAFKAS.js → openai-codex-responses-3CW4R7TG.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-BZB5O45A.js → openai-completions-5UIJXQUF.js} +1 -1
- package/dist/bundle/chunks/openai-responses-2BO44MRW.js +3 -0
- package/dist/bundle/chunks/{package-manager-cli-GHZPJMRF.js → package-manager-cli-MZHVCX2S.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-VXATX45B.js → pi-messages-RF6GER4R.js} +2 -2
- package/dist/bundle/chunks/{role-JVSBNKGE.js → role-ETSFSDTS.js} +1 -1
- package/dist/bundle/chunks/rotation-stream-ZMQB4GPO.js +2 -0
- package/dist/bundle/chunks/rpc-mode-UJXOIZCW.js +2 -0
- package/dist/bundle/chunks/{rpc-monitor-source-FFEQS744.js → rpc-monitor-source-DRZXJHTL.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-YWG6D6ZF.js → schedule-command-KA7LFFNK.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-MFWXUR7Z.js +3 -0
- package/dist/bundle/chunks/session-picker-BP33NRSL.js +2 -0
- package/dist/bundle/chunks/session-worker.js +212 -203
- package/dist/bundle/chunks/{typesafe-system-one-P75WJ767.js → typesafe-system-one-GNNZ5O5U.js} +1 -1
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +2 -2
- 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/host-command-args.d.ts +1 -0
- package/dist/cli/host-command-args.js +5 -0
- package/dist/cli/host-command.js +7 -1
- package/dist/cli.js +21 -3
- package/dist/core/extensions/builtin/mcp/catalog-cache.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/catalog-cache.js +19 -6
- package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -2
- package/dist/core/extensions/builtin/mcp/catalog.js +20 -3
- package/dist/core/extensions/builtin/mcp/elicitation.js +2 -4
- package/dist/core/extensions/builtin/mcp/expose/call.d.ts +2 -1
- package/dist/core/extensions/builtin/mcp/expose/call.js +2 -1
- package/dist/core/extensions/builtin/mcp/expose/register.js +1 -1
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts +2 -2
- package/dist/core/extensions/builtin/mcp/expose/schema-compat.js +11 -1
- package/dist/core/extensions/builtin/mcp/invocation.js +16 -2
- package/dist/core/extensions/builtin/mcp/modern/request.d.ts +1 -1
- package/dist/core/extensions/builtin/mcp/modern/request.js +1 -1
- package/dist/core/extensions/builtin/mcp/modern/sdk-bridge.js +18 -3
- package/dist/core/extensions/builtin/mcp/modern/stdio-probe.js +23 -0
- package/dist/core/extensions/builtin/mcp/modern/subscriptions.d.ts +14 -0
- package/dist/core/extensions/builtin/mcp/modern/subscriptions.js +226 -0
- package/dist/core/extensions/builtin/mcp/modern/tool-schema.d.ts +13 -0
- package/dist/core/extensions/builtin/mcp/modern/tool-schema.js +75 -0
- package/dist/core/extensions/builtin/mcp/modern/tools.d.ts +107 -0
- package/dist/core/extensions/builtin/mcp/modern/tools.js +53 -0
- package/dist/core/extensions/builtin/mcp/resources.js +4 -0
- package/dist/core/extensions/builtin/mcp/tool-client.d.ts +13 -0
- package/dist/core/extensions/builtin/mcp/tool-client.js +17 -0
- package/dist/core/extensions/builtin/mcp/tool-contracts.d.ts +19 -0
- package/dist/core/extensions/builtin/mcp/tool-contracts.js +2 -0
- package/dist/core/extensions/builtin/mcp/wrap.js +2 -2
- package/dist/core/extensions/builtin/permission-system/bash-command-segments.d.ts +37 -0
- package/dist/core/extensions/builtin/permission-system/bash-command-segments.js +899 -0
- package/dist/core/extensions/builtin/permission-system/parsers.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/parsers.js +44 -10
- package/dist/core/session-control-actions.js +0 -2
- package/dist/modes/interactive/session-control-attach.d.ts +20 -0
- package/dist/modes/interactive/session-control-attach.js +13 -0
- package/dist/modes/interactive/session-control-commands.js +37 -10
- package/dist/modes/interactive/session-control-registry.d.ts +2 -1
- package/dist/modes/interactive/session-control-registry.js +3 -2
- package/dist/modes/interactive/session-control-rpc-commands.d.ts +4 -2
- package/dist/modes/interactive/session-control-rpc-commands.js +133 -4
- package/dist/modes/interactive/session-control-server.js +9 -3
- package/dist/modes/rpc/compact-content-store.d.ts +96 -0
- package/dist/modes/rpc/compact-content-store.js +269 -0
- package/dist/modes/rpc/compact-session-state.d.ts +111 -0
- package/dist/modes/rpc/compact-session-state.js +206 -0
- package/dist/modes/rpc/compact-spool-dir.d.ts +5 -0
- package/dist/modes/rpc/compact-spool-dir.js +61 -0
- package/dist/modes/rpc/compact-storage-io.d.ts +27 -0
- package/dist/modes/rpc/compact-storage-io.js +19 -0
- package/dist/modes/rpc/connection-handler.d.ts +2 -0
- package/dist/modes/rpc/connection-handler.js +45 -47
- package/dist/modes/rpc/connection-question-bridge.d.ts +2 -1
- package/dist/modes/rpc/connection-question-bridge.js +6 -2
- package/dist/modes/rpc/custom-capability.d.ts +6 -0
- package/dist/modes/rpc/custom-capability.js +6 -0
- package/dist/modes/rpc/extension-ui-response.d.ts +7 -2
- package/dist/modes/rpc/extension-ui-response.js +27 -7
- package/dist/modes/rpc/get-entries-command.d.ts +13 -0
- package/dist/modes/rpc/get-entries-command.js +61 -0
- package/dist/modes/rpc/get-entries-page.d.ts +22 -0
- package/dist/modes/rpc/get-entries-page.js +41 -2
- package/dist/modes/rpc/get-snapshot.d.ts +18 -0
- package/dist/modes/rpc/get-snapshot.js +43 -0
- package/dist/modes/rpc/host-capabilities.js +7 -1
- package/dist/modes/rpc/host-ensure-start.js +1 -0
- 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-request.d.ts +1 -1
- package/dist/modes/rpc/host-handover-request.js +4 -3
- package/dist/modes/rpc/host-handover-wire.js +6 -0
- package/dist/modes/rpc/host-idle-handover.d.ts +2 -0
- package/dist/modes/rpc/host-idle-handover.js +3 -1
- package/dist/modes/rpc/host-observe-request.d.ts +2 -1
- package/dist/modes/rpc/host-observe-request.js +5 -1
- package/dist/modes/rpc/host-runner.d.ts +1 -0
- package/dist/modes/rpc/host-runner.js +9 -7
- package/dist/modes/rpc/host-successor.js +4 -0
- package/dist/modes/rpc/json-normal-value.d.ts +6 -0
- package/dist/modes/rpc/json-normal-value.js +100 -0
- package/dist/modes/rpc/mcp-presenter-bootstrap.js +5 -0
- package/dist/modes/rpc/media-placeholders.d.ts +9 -3
- package/dist/modes/rpc/media-placeholders.js +12 -4
- package/dist/modes/rpc/rpc-host-command-types.d.ts +2 -0
- package/dist/modes/rpc/rpc-question-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-read-response-types.d.ts +9 -0
- package/dist/modes/rpc/rpc-session-command-types.d.ts +14 -1
- package/dist/modes/rpc/rpc-session-state-types.d.ts +3 -0
- package/dist/modes/rpc/rpc-session-state.js +2 -0
- package/dist/modes/rpc/rpc-types.d.ts +1 -0
- package/dist/modes/rpc/session-attachment-gate.js +1 -0
- package/dist/modes/rpc/session-binding.js +21 -18
- package/dist/modes/rpc/session-command-activity.js +1 -0
- package/dist/modes/rpc/session-event-fanout.d.ts +1 -1
- package/dist/modes/rpc/session-event-fanout.js +17 -9
- package/dist/modes/rpc/session-event-writer.js +22 -5
- package/dist/modes/rpc/session-extension-ui-requests.d.ts +2 -1
- package/dist/modes/rpc/session-extension-ui-requests.js +15 -10
- package/dist/modes/rpc/session-held.js +1 -0
- package/dist/modes/rpc/session-status-stream.d.ts +2 -1
- package/dist/modes/rpc/session-status-stream.js +8 -2
- package/dist/modes/rpc/session-status-subscriptions.d.ts +2 -1
- package/dist/modes/rpc/session-status-subscriptions.js +4 -0
- package/dist/modes/rpc/session-worker.js +5 -2
- package/dist/modes/rpc/snapshot-types.d.ts +29 -0
- package/dist/modes/rpc/snapshot-types.js +2 -0
- package/dist/modes/rpc/ui-answer-ledger.d.ts +13 -0
- package/dist/modes/rpc/ui-answer-ledger.js +34 -0
- package/dist/senpi +21 -3
- package/docs/mcp.md +20 -0
- package/docs/rpc.md +87 -11
- package/package.json +7 -6
- package/dist/bundle/chunks/azure-openai-responses-7I45DI72.js +0 -2
- package/dist/bundle/chunks/chunk-3LNSLJ7N.js +0 -2
- package/dist/bundle/chunks/chunk-6O4SEW2W.js +0 -5
- package/dist/bundle/chunks/chunk-7W7OJDIY.js +0 -410
- package/dist/bundle/chunks/chunk-DMI55M2N.js +0 -2
- package/dist/bundle/chunks/chunk-H3HNMY2W.js +0 -13
- package/dist/bundle/chunks/chunk-MSQCTH6V.js +0 -2
- package/dist/bundle/chunks/cli-main-HEKFFB5S.js +0 -3
- package/dist/bundle/chunks/dispatch-NYAULNVW.js +0 -9
- package/dist/bundle/chunks/google-generative-ai-UM5Y7T6B.js +0 -2
- package/dist/bundle/chunks/google-vertex-OKU2VQHL.js +0 -2
- package/dist/bundle/chunks/host-command-Z3WPHJOW.js +0 -2
- package/dist/bundle/chunks/interactive-mode-DEPQC6TX.js +0 -2
- package/dist/bundle/chunks/openai-responses-TNHQ6SJS.js +0 -3
- package/dist/bundle/chunks/rotation-stream-ZPVCFOVD.js +0 -2
- package/dist/bundle/chunks/rpc-mode-ORHBGBBV.js +0 -2
- package/dist/bundle/chunks/session-control-endpoint-36HAQSQO.js +0 -3
- package/dist/bundle/chunks/session-picker-25H5KNYP.js +0 -2
|
@@ -6,6 +6,9 @@ import { redactResolvedReferenceData } from "../../../config-reference-redaction
|
|
|
6
6
|
import { lockWithLossHandling } from "../../../file-lock.js";
|
|
7
7
|
import { isEphemeralIdentity } from "./config-identity-key.js";
|
|
8
8
|
import { collectAllPages } from "./expose/pagination.js";
|
|
9
|
+
import { listMcpTools } from "./tool-client.js";
|
|
10
|
+
import { isModernMcpClient } from "./modern/request.js";
|
|
11
|
+
import { hasSupportedModernToolSchemas } from "./modern/tool-schema.js";
|
|
9
12
|
const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
10
13
|
const EMPTY_CACHE = { version: 1, servers: {} };
|
|
11
14
|
export function getMcpCatalogCachePath(agentDir = getAgentDir()) {
|
|
@@ -36,7 +39,7 @@ export function cachedCatalogNeedsRefresh(cached, now = Date.now()) {
|
|
|
36
39
|
return now - cached.fetchedAt > CACHE_TTL_MS;
|
|
37
40
|
}
|
|
38
41
|
export async function collectServerCatalogForCache(connection, config, configHash, credentialIdentity) {
|
|
39
|
-
const tools = await collectAllPages((cursor) => connection.client
|
|
42
|
+
const tools = await collectAllPages((cursor) => listMcpTools(connection.client, cursor === undefined ? {} : { cursor }, {
|
|
40
43
|
timeout: config.requestTimeoutMs,
|
|
41
44
|
}));
|
|
42
45
|
const resources = await collectOptionalPages((cursor) => connection.client.listResources(cursor === undefined ? {} : { cursor }, {
|
|
@@ -50,6 +53,7 @@ export async function collectServerCatalogForCache(connection, config, configHas
|
|
|
50
53
|
}));
|
|
51
54
|
return {
|
|
52
55
|
configHash,
|
|
56
|
+
...(isModernMcpClient(connection.client) ? { modern: true } : {}),
|
|
53
57
|
credentialIdentity,
|
|
54
58
|
fetchedAt: Date.now(),
|
|
55
59
|
instructions: connection.client.getInstructions(),
|
|
@@ -128,7 +132,7 @@ function normalizeCachedServer(value) {
|
|
|
128
132
|
if (!isRecord(value) || typeof value.configHash !== "string" || typeof value.fetchedAt !== "number") {
|
|
129
133
|
return undefined;
|
|
130
134
|
}
|
|
131
|
-
const tools = normalizeTools(value.tools);
|
|
135
|
+
const tools = normalizeTools(value.tools, value.modern === true);
|
|
132
136
|
if (tools === undefined)
|
|
133
137
|
return undefined;
|
|
134
138
|
const resources = Array.isArray(value.resources) ? value.resources : [];
|
|
@@ -139,6 +143,7 @@ function normalizeCachedServer(value) {
|
|
|
139
143
|
const instructions = typeof value.instructions === "string" ? value.instructions : undefined;
|
|
140
144
|
return {
|
|
141
145
|
configHash: value.configHash,
|
|
146
|
+
...(value.modern === true ? { modern: true } : {}),
|
|
142
147
|
credentialIdentity: typeof value.credentialIdentity === "string" ? value.credentialIdentity : undefined,
|
|
143
148
|
fetchedAt: value.fetchedAt,
|
|
144
149
|
instructions,
|
|
@@ -148,19 +153,27 @@ function normalizeCachedServer(value) {
|
|
|
148
153
|
tools,
|
|
149
154
|
};
|
|
150
155
|
}
|
|
151
|
-
function normalizeTools(value) {
|
|
156
|
+
function normalizeTools(value, modern) {
|
|
152
157
|
if (!Array.isArray(value))
|
|
153
158
|
return undefined;
|
|
154
159
|
const tools = [];
|
|
155
160
|
for (const item of value) {
|
|
156
|
-
if (!isRecord(item) || typeof item.name !== "string"
|
|
161
|
+
if (!isRecord(item) || typeof item.name !== "string")
|
|
157
162
|
return undefined;
|
|
158
|
-
|
|
163
|
+
if (!isRecord(item.inputSchema) && !(modern && typeof item.inputSchema === "boolean"))
|
|
164
|
+
return undefined;
|
|
165
|
+
const tool = {
|
|
166
|
+
...(modern ? item : {}),
|
|
159
167
|
annotations: isRecord(item.annotations) ? item.annotations : undefined,
|
|
160
168
|
description: typeof item.description === "string" ? item.description : undefined,
|
|
161
169
|
inputSchema: item.inputSchema,
|
|
170
|
+
...(modern && (isRecord(item.outputSchema) || typeof item.outputSchema === "boolean")
|
|
171
|
+
? { outputSchema: item.outputSchema }
|
|
172
|
+
: {}),
|
|
162
173
|
name: item.name,
|
|
163
|
-
}
|
|
174
|
+
};
|
|
175
|
+
if (!modern || hasSupportedModernToolSchemas(tool))
|
|
176
|
+
tools.push(tool);
|
|
164
177
|
}
|
|
165
178
|
return tools;
|
|
166
179
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { McpListedTool as ListedTool } from "./tool-contracts.ts";
|
|
2
2
|
import type { McpCachedServerCatalog } from "./catalog-cache.ts";
|
|
3
3
|
import type { McpServerDeclaredConfig, McpSettings } from "./config-schema.ts";
|
|
4
4
|
import type { ServerConnection } from "./connection.ts";
|
|
@@ -6,12 +6,13 @@ import type { McpOutputArtifacts } from "./guard/output-guard.ts";
|
|
|
6
6
|
import type { McpEnsureFreshAuth } from "./health.ts";
|
|
7
7
|
import type { McpInvocationResolver } from "./invocation.ts";
|
|
8
8
|
import type { McpRequestOrigin } from "./request-origin.ts";
|
|
9
|
-
type ListedTool = Awaited<ReturnType<Client["listTools"]>>["tools"][number];
|
|
10
9
|
export interface McpToolCatalogEntry {
|
|
11
10
|
requestOrigin?: () => McpRequestOrigin | undefined;
|
|
12
11
|
server: string;
|
|
13
12
|
tool: string;
|
|
14
13
|
schema: ListedTool["inputSchema"];
|
|
14
|
+
outputSchema?: ListedTool["outputSchema"];
|
|
15
|
+
modern?: boolean;
|
|
15
16
|
description?: string;
|
|
16
17
|
annotations?: ListedTool["annotations"];
|
|
17
18
|
requestTimeoutMs: number;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { listMcpTools } from "./tool-client.js";
|
|
2
|
+
import { isModernMcpClient } from "./modern/request.js";
|
|
3
|
+
import { hasSupportedModernToolSchemas } from "./modern/tool-schema.js";
|
|
1
4
|
import { collectAllPages } from "./expose/pagination.js";
|
|
2
5
|
export async function collectToolCatalog(server, connection, config, options = {}) {
|
|
3
|
-
const result = await collectAllPages((cursor) => connection.client
|
|
6
|
+
const result = await collectAllPages((cursor) => listMcpTools(connection.client, cursor === undefined ? {} : { cursor }, { timeout: config.requestTimeoutMs }));
|
|
4
7
|
return result.items.map((tool) => ({
|
|
5
8
|
requestOrigin: options.requestOrigin,
|
|
6
9
|
annotations: tool.annotations,
|
|
@@ -13,6 +16,8 @@ export async function collectToolCatalog(server, connection, config, options = {
|
|
|
13
16
|
outputGuard: options.outputGuard,
|
|
14
17
|
requestTimeoutMs: config.requestTimeoutMs,
|
|
15
18
|
schema: tool.inputSchema,
|
|
19
|
+
outputSchema: tool.outputSchema,
|
|
20
|
+
modern: isModernMcpClient(connection.client),
|
|
16
21
|
server,
|
|
17
22
|
tool: tool.name,
|
|
18
23
|
}));
|
|
@@ -21,13 +26,23 @@ export async function collectToolCatalog(server, connection, config, options = {
|
|
|
21
26
|
* equal identities register identical definitions. */
|
|
22
27
|
export function mcpRegistrationIdentity(tools, catalog) {
|
|
23
28
|
return JSON.stringify([
|
|
24
|
-
tools.map((entry) => [
|
|
29
|
+
tools.map((entry) => [
|
|
30
|
+
entry.tool,
|
|
31
|
+
entry.description,
|
|
32
|
+
entry.schema,
|
|
33
|
+
entry.outputSchema,
|
|
34
|
+
entry.modern,
|
|
35
|
+
entry.annotations,
|
|
36
|
+
]),
|
|
25
37
|
catalog?.resources ?? [],
|
|
26
38
|
catalog?.prompts ?? [],
|
|
27
39
|
]);
|
|
28
40
|
}
|
|
29
41
|
export function cachedToolsToCatalogEntries(server, catalog, connection, requestTimeoutMs, ensureConnected, options = {}) {
|
|
30
|
-
|
|
42
|
+
const modern = connection.state === "connected" ? isModernMcpClient(connection.client) || undefined : catalog.modern;
|
|
43
|
+
return catalog.tools
|
|
44
|
+
.filter((tool) => !modern || hasSupportedModernToolSchemas(tool))
|
|
45
|
+
.map((tool) => ({
|
|
31
46
|
requestOrigin: options.requestOrigin,
|
|
32
47
|
annotations: tool.annotations,
|
|
33
48
|
agentDir: options.agentDir,
|
|
@@ -40,6 +55,8 @@ export function cachedToolsToCatalogEntries(server, catalog, connection, request
|
|
|
40
55
|
outputGuard: options.outputGuard,
|
|
41
56
|
requestTimeoutMs,
|
|
42
57
|
schema: tool.inputSchema,
|
|
58
|
+
outputSchema: tool.outputSchema,
|
|
59
|
+
modern,
|
|
43
60
|
server,
|
|
44
61
|
tool: tool.name,
|
|
45
62
|
}));
|
|
@@ -45,10 +45,8 @@ async function rejectPrivateElicitation() {
|
|
|
45
45
|
}
|
|
46
46
|
async function privateElicitation(client, params, signal, requestId, timeoutMs) {
|
|
47
47
|
const operation = legacyMcpOperation(client);
|
|
48
|
-
if (operation === "ambiguous")
|
|
49
|
-
|
|
50
|
-
throw new McpError(ErrorCode.InternalError, "Elicitation cannot be processed: ambiguous origin from concurrent legacy tools/call requests. Run these calls sequentially or use an MRTR server.", { reason: "ambiguous_legacy_origin" });
|
|
51
|
-
}
|
|
48
|
+
if (operation === "ambiguous")
|
|
49
|
+
return rejectPrivateElicitation();
|
|
52
50
|
const presenter = operation?.origin.privateForm;
|
|
53
51
|
if (!isRecord(params) ||
|
|
54
52
|
typeof params.message !== "string" ||
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { McpToolCatalogEntry } from "../catalog.ts";
|
|
2
2
|
import type { McpInvocation, McpInvocationError } from "../invocation.ts";
|
|
3
3
|
import type { McpToolDefinition } from "./register.ts";
|
|
4
|
+
import type { McpToolResult } from "../tool-contracts.ts";
|
|
4
5
|
export declare function callMcpTool(entry: McpToolCatalogEntry, args: Record<string, unknown>, signal: AbortSignal | undefined, onUpdate: Parameters<McpToolDefinition["execute"]>[3], label: string, invocation: McpInvocation | undefined): Promise<{
|
|
5
6
|
kind: "called";
|
|
6
7
|
entry: McpToolCatalogEntry;
|
|
7
|
-
result:
|
|
8
|
+
result: McpToolResult;
|
|
8
9
|
} | {
|
|
9
10
|
kind: "refused";
|
|
10
11
|
error: McpInvocationError;
|
|
@@ -4,6 +4,7 @@ import { ensureMcpToolCallConnection, withMcpRetriableFailedSendRetry, withMcpSe
|
|
|
4
4
|
import { runMcpConnectionLifecycleCall } from "../idle.js";
|
|
5
5
|
import { mcpRequestOptions } from "../request-origin.js";
|
|
6
6
|
import { McpMrtrError } from "../modern/errors.js";
|
|
7
|
+
import { callMcpToolRequest } from "../tool-client.js";
|
|
7
8
|
export async function callMcpTool(entry, args, signal, onUpdate, label, invocation) {
|
|
8
9
|
try {
|
|
9
10
|
return await runMcpConnectionLifecycleCall(entry.connection, () => withMcpSessionExpiryRetry(entry.connection, async () => {
|
|
@@ -31,7 +32,7 @@ export async function callMcpTool(entry, args, signal, onUpdate, label, invocati
|
|
|
31
32
|
if (prepared !== undefined && !prepared.isCurrent())
|
|
32
33
|
continue;
|
|
33
34
|
const current = prepared?.entry ?? entry;
|
|
34
|
-
const result = await current.connection.client
|
|
35
|
+
const result = await callMcpToolRequest(current.connection.client, { name: current.tool, arguments: args }, current.outputSchema, mcpRequestOptions(current.requestOrigin?.(), {
|
|
35
36
|
onprogress: (progress) => {
|
|
36
37
|
onUpdate?.(redactResolvedReferenceData({
|
|
37
38
|
content: [{ type: "text", text: formatProgress(label, progress) }],
|
|
@@ -18,7 +18,7 @@ export function buildMcpToolDefinitions(entries, warn) {
|
|
|
18
18
|
return mapMcpCatalogNames(entries, warn).map(({ entry, name }) => createMcpToolDefinition(entry, name));
|
|
19
19
|
}
|
|
20
20
|
function createMcpToolDefinition(entry, name) {
|
|
21
|
-
const converted = convertJsonSchemaToTypeBox(entry.schema);
|
|
21
|
+
const converted = convertJsonSchemaToTypeBox(entry.schema, entry.modern);
|
|
22
22
|
const label = `${entry.server}/${entry.tool}`;
|
|
23
23
|
registerDispatchIdentity(converted.schema, () => entry.invocation?.identity(entry));
|
|
24
24
|
return {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ImageContent, type TextContent } from "@earendil-works/pi-ai";
|
|
2
2
|
import { type TSchema } from "typebox";
|
|
3
3
|
import { buildMcpToolNames, type McpToolNameEntry } from "./naming.ts";
|
|
4
4
|
import { collectAllPages, type McpListPage, type McpPaginationResult } from "./pagination.ts";
|
|
@@ -62,7 +62,7 @@ export type McpMappedToolResult = {
|
|
|
62
62
|
content: McpMappedContentBlock[];
|
|
63
63
|
};
|
|
64
64
|
};
|
|
65
|
-
export declare function convertJsonSchemaToTypeBox(schema: unknown): SchemaConversionResult;
|
|
65
|
+
export declare function convertJsonSchemaToTypeBox(schema: unknown, modern?: boolean): SchemaConversionResult;
|
|
66
66
|
export declare function prepareOutputSchemaRetry(schema: unknown): OutputSchemaRetryResult;
|
|
67
67
|
export declare function mapMcpToolResult(result: McpToolResultLike): McpMappedToolResult;
|
|
68
68
|
//# sourceMappingURL=schema-compat.d.ts.map
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
import { registerToolArgumentValidator } from "@earendil-works/pi-ai";
|
|
1
2
|
import { Type } from "typebox";
|
|
3
|
+
import { compileModernSchema } from "../modern/tool-schema.js";
|
|
2
4
|
import { buildMcpToolNames } from "./naming.js";
|
|
3
5
|
import { collectAllPages } from "./pagination.js";
|
|
4
6
|
export { buildMcpToolNames, collectAllPages };
|
|
5
7
|
const PERMISSIVE_OBJECT_SCHEMA = { type: "object", properties: {} };
|
|
6
|
-
export function convertJsonSchemaToTypeBox(schema) {
|
|
8
|
+
export function convertJsonSchemaToTypeBox(schema, modern = false) {
|
|
9
|
+
if (modern && (typeof schema === "boolean" || isRecord(schema))) {
|
|
10
|
+
const validate = compileModernSchema(schema);
|
|
11
|
+
// TypeBox/tool APIs require an object container. allOf preserves the exact
|
|
12
|
+
// boolean constraint; provider-specific object adaptation happens in pi-ai.
|
|
13
|
+
const parameters = Type.Unsafe(typeof schema === "boolean" ? { allOf: [schema] } : structuredClone(schema));
|
|
14
|
+
registerToolArgumentValidator(parameters, validate);
|
|
15
|
+
return { schema: parameters, warnings: [] };
|
|
16
|
+
}
|
|
7
17
|
const warnings = [];
|
|
8
18
|
const resolved = resolveRefs(stripTopLevelSchemaKeys(schema), schema, new Set(), warnings);
|
|
9
19
|
if (warnings.length > 0) {
|
|
@@ -3,6 +3,7 @@ import { Check } from "typebox/value";
|
|
|
3
3
|
import { authorizeToolDispatch, hasDispatchAuthorizer } from "../permission-system/dispatch.js";
|
|
4
4
|
import { getDispatchIdentity } from "../permission-system/dispatch-metadata.js";
|
|
5
5
|
import { TimeoutError } from "./errors.js";
|
|
6
|
+
import { compileModernSchema, McpToolSchemaError } from "./modern/tool-schema.js";
|
|
6
7
|
import { safeTimer } from "./wrap.js";
|
|
7
8
|
export function createMcpInvocationResolver(scope) {
|
|
8
9
|
const identity = (entry) => ({
|
|
@@ -13,6 +14,8 @@ export function createMcpInvocationResolver(scope) {
|
|
|
13
14
|
entry.server,
|
|
14
15
|
entry.tool,
|
|
15
16
|
entry.schema,
|
|
17
|
+
entry.outputSchema,
|
|
18
|
+
entry.modern,
|
|
16
19
|
entry.description,
|
|
17
20
|
entry.annotations,
|
|
18
21
|
]),
|
|
@@ -66,7 +69,18 @@ export function createMcpInvocationResolver(scope) {
|
|
|
66
69
|
if (current === undefined)
|
|
67
70
|
return refuse("unavailable", "MCP tool is no longer available.");
|
|
68
71
|
// Validate the current raw schema, never the coercing preflight schema.
|
|
69
|
-
|
|
72
|
+
let validate;
|
|
73
|
+
try {
|
|
74
|
+
validate = current.modern
|
|
75
|
+
? compileModernSchema(current.schema)
|
|
76
|
+
: (value) => Check(Type.Unsafe(current.schema), value);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (!(error instanceof McpToolSchemaError))
|
|
80
|
+
throw error;
|
|
81
|
+
return refuse("schema_changed", `${error.code}: ${error.message}`, current);
|
|
82
|
+
}
|
|
83
|
+
if (!validate(args)) {
|
|
70
84
|
return refuse("schema_changed", "Arguments do not match the current MCP tool schema.", current);
|
|
71
85
|
}
|
|
72
86
|
const preparedIdentity = identity(current);
|
|
@@ -107,7 +121,7 @@ export function createMcpInvocationResolver(scope) {
|
|
|
107
121
|
const latest = scope.current(offered.tool);
|
|
108
122
|
return (latest !== undefined &&
|
|
109
123
|
identity(latest).metadata === preparedIdentity.metadata &&
|
|
110
|
-
|
|
124
|
+
validate(args) &&
|
|
111
125
|
(operationFence === undefined || operationFence()) &&
|
|
112
126
|
(permissionFence === undefined || permissionFence()));
|
|
113
127
|
},
|
|
@@ -15,6 +15,6 @@ export type MrtrClock = McpClock;
|
|
|
15
15
|
export declare const isModernMcpClient: (client: Client) => boolean;
|
|
16
16
|
export declare const legacyMcpFormsAdvertised: (client: Client) => boolean | undefined;
|
|
17
17
|
export declare function getModernDispatchGuard(params: unknown): ((credential?: string) => void) | undefined;
|
|
18
|
-
/** One instance-local adapter. Captured SDK requests retain ID allocation
|
|
18
|
+
/** One instance-local adapter. Captured SDK requests retain ID allocation; the caller supplies its era's result contract. */
|
|
19
19
|
export declare function installModernRequestAdapter(client: Client, protocol: ModernProtocolState, clock?: MrtrClock, readCredential?: () => string | undefined): void;
|
|
20
20
|
//# sourceMappingURL=request.d.ts.map
|
|
@@ -22,7 +22,7 @@ export function getModernDispatchGuard(params) {
|
|
|
22
22
|
? params[modernDispatchGuard]
|
|
23
23
|
: undefined;
|
|
24
24
|
}
|
|
25
|
-
/** One instance-local adapter. Captured SDK requests retain ID allocation
|
|
25
|
+
/** One instance-local adapter. Captured SDK requests retain ID allocation; the caller supplies its era's result contract. */
|
|
26
26
|
export function installModernRequestAdapter(client, protocol, clock = mcpElapsedClock, readCredential = () => undefined) {
|
|
27
27
|
const sdkRequest = client.request.bind(client);
|
|
28
28
|
states.set(client, protocol);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { InitializeResultSchema, LATEST_PROTOCOL_VERSION, } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import { ModernTransportError } from "./transport.js";
|
|
3
|
+
import { ModernSubscriptions } from "./subscriptions.js";
|
|
3
4
|
/** The SDK's local `initialize` answer, built from validated discovery; discovery must support the real wire version. */
|
|
4
5
|
export function modernInitializeResult(discovery, wireVersion) {
|
|
5
6
|
if (!discovery.supportedVersions.includes(wireVersion)) {
|
|
@@ -22,16 +23,22 @@ export function normalizeModernResult(message) {
|
|
|
22
23
|
export class ModernSdkBridge {
|
|
23
24
|
#transport;
|
|
24
25
|
#initializeResult;
|
|
26
|
+
#subscriptions;
|
|
25
27
|
#initialized = false;
|
|
26
28
|
constructor(transport, discovery, wireVersion) {
|
|
27
29
|
this.#initializeResult = modernInitializeResult(discovery, wireVersion);
|
|
28
30
|
this.#transport = transport;
|
|
31
|
+
this.#subscriptions = new ModernSubscriptions(transport.send.bind(transport), discovery.capabilities, true);
|
|
29
32
|
}
|
|
30
33
|
async start() {
|
|
31
34
|
this.#transport.onmessage = (message, extra) => {
|
|
32
|
-
this.
|
|
35
|
+
if (this.#subscriptions.incoming(message))
|
|
36
|
+
this.onmessage?.(normalizeModernResult(message), extra);
|
|
37
|
+
};
|
|
38
|
+
this.#transport.onclose = () => {
|
|
39
|
+
this.#subscriptions.dispose();
|
|
40
|
+
this.onclose?.();
|
|
33
41
|
};
|
|
34
|
-
this.#transport.onclose = () => this.onclose?.();
|
|
35
42
|
this.#transport.onerror = (error) => this.onerror?.(error);
|
|
36
43
|
await this.#transport.start();
|
|
37
44
|
}
|
|
@@ -46,9 +53,17 @@ export class ModernSdkBridge {
|
|
|
46
53
|
}
|
|
47
54
|
if ("method" in message && message.method === "notifications/initialized" && !("id" in message))
|
|
48
55
|
return;
|
|
49
|
-
|
|
56
|
+
this.#subscriptions.outgoing(message);
|
|
57
|
+
try {
|
|
58
|
+
await this.#transport.send(message, options);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
this.#subscriptions.failedSend(message);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
50
64
|
}
|
|
51
65
|
close() {
|
|
66
|
+
this.#subscriptions.dispose();
|
|
52
67
|
return this.#transport.close();
|
|
53
68
|
}
|
|
54
69
|
}
|
|
@@ -3,6 +3,7 @@ import { reapProcessTree } from "../process-tree.js";
|
|
|
3
3
|
import { discoveryReply, probeStdioEra, STDIO_PROBE_ID, StdioProbeSilence, } from "./era.js";
|
|
4
4
|
import { modernInitializeResult, normalizeModernResult } from "./sdk-bridge.js";
|
|
5
5
|
import { ModernTransportError } from "./transport.js";
|
|
6
|
+
import { ModernSubscriptions } from "./subscriptions.js";
|
|
6
7
|
import { sanitizeModernMessage } from "./diagnostics.js";
|
|
7
8
|
import { McpMrtrError } from "./errors.js";
|
|
8
9
|
import { getModernDispatchGuard } from "./request.js";
|
|
@@ -186,6 +187,17 @@ export function probeStdioTransport(transport, options, logger, timeoutMs, serve
|
|
|
186
187
|
const initializeResult = modernInitializeResult(discovery, version);
|
|
187
188
|
const deliver = transport.onmessage;
|
|
188
189
|
const live = new Set();
|
|
190
|
+
const subscriptions = new ModernSubscriptions((message, options) => transport.send(message, options), discovery.capabilities);
|
|
191
|
+
const end = transport.close.bind(transport);
|
|
192
|
+
transport.close = async () => {
|
|
193
|
+
subscriptions.dispose();
|
|
194
|
+
await end();
|
|
195
|
+
};
|
|
196
|
+
const onclose = transport.onclose;
|
|
197
|
+
transport.onclose = () => {
|
|
198
|
+
subscriptions.dispose();
|
|
199
|
+
onclose?.();
|
|
200
|
+
};
|
|
189
201
|
let initialized = false;
|
|
190
202
|
transport.onerror = () => {
|
|
191
203
|
// A parser error may quote a wire body; never forward it.
|
|
@@ -204,6 +216,14 @@ export function probeStdioTransport(transport, options, logger, timeoutMs, serve
|
|
|
204
216
|
}
|
|
205
217
|
if ("id" in message && message.id !== undefined && !live.delete(message.id))
|
|
206
218
|
return;
|
|
219
|
+
if (!subscriptions.incoming(message)) {
|
|
220
|
+
const id = "method" in message && message.method === "notifications/cancelled"
|
|
221
|
+
? message.params?.requestId
|
|
222
|
+
: undefined;
|
|
223
|
+
if (typeof id === "string" || typeof id === "number")
|
|
224
|
+
live.delete(id);
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
207
227
|
if ("method" in message && message.method === "notifications/progress") {
|
|
208
228
|
const token = message.params?.progressToken;
|
|
209
229
|
if ((typeof token !== "string" && typeof token !== "number") || !live.has(token))
|
|
@@ -227,12 +247,14 @@ export function probeStdioTransport(transport, options, logger, timeoutMs, serve
|
|
|
227
247
|
if (message.method === "notifications/initialized" && !("id" in message))
|
|
228
248
|
return;
|
|
229
249
|
if (message.method === "notifications/cancelled" && !("id" in message)) {
|
|
250
|
+
subscriptions.outgoing(message);
|
|
230
251
|
const id = message.params?.requestId;
|
|
231
252
|
if ((typeof id !== "string" && typeof id !== "number") || !live.delete(id))
|
|
232
253
|
return;
|
|
233
254
|
return send({ jsonrpc: "2.0", method: message.method, params: { requestId: id, reason: "MCP request canceled" } }, sendOptions);
|
|
234
255
|
}
|
|
235
256
|
getModernDispatchGuard(message.params)?.();
|
|
257
|
+
subscriptions.outgoing(message);
|
|
236
258
|
const request = modernizeRequest("id" in message ? message.id : 0, message.method, options.clientInfo, options.clientCapabilities, version, message.params);
|
|
237
259
|
if ("id" in message) {
|
|
238
260
|
live.add(message.id);
|
|
@@ -241,6 +263,7 @@ export function probeStdioTransport(transport, options, logger, timeoutMs, serve
|
|
|
241
263
|
}
|
|
242
264
|
catch {
|
|
243
265
|
live.delete(message.id);
|
|
266
|
+
subscriptions.failedSend(message);
|
|
244
267
|
throw new McpMrtrError("MCP_MRTR_TRANSPORT_FAILED");
|
|
245
268
|
}
|
|
246
269
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
2
|
+
import type { JSONRPCMessage } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import type { DiscoveryResult } from "./era.ts";
|
|
4
|
+
/** Connection-owned streams bypass the SDK's finite request timeout and MRTR consent lifecycle. */
|
|
5
|
+
export declare class ModernSubscriptions {
|
|
6
|
+
#private;
|
|
7
|
+
constructor(send: Transport["send"], capabilities: DiscoveryResult["capabilities"], sendCompletesStream?: boolean);
|
|
8
|
+
outgoing(message: JSONRPCMessage): void;
|
|
9
|
+
/** Returns true only for application messages that may reach the existing SDK notification handlers. */
|
|
10
|
+
incoming(message: JSONRPCMessage): boolean;
|
|
11
|
+
failedSend(message: JSONRPCMessage): void;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=subscriptions.d.ts.map
|