pi-mcp-adapter 2.34.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/README.md +58 -7
- package/bearer-command-resolver.ts +193 -0
- package/cli.js +56 -5
- package/commands.ts +22 -5
- package/config.ts +38 -6
- package/direct-tool-surface.ts +15 -22
- package/direct-tools.ts +12 -5
- package/dist/abort.d.ts +2 -0
- package/dist/abort.js +36 -0
- package/dist/abort.js.map +1 -0
- package/dist/bearer-command-resolver.d.ts +6 -0
- package/dist/bearer-command-resolver.js +194 -0
- package/dist/bearer-command-resolver.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +43 -6
- package/dist/config.js.map +1 -1
- package/dist/consent-manager.d.ts +18 -0
- package/dist/consent-manager.js +88 -0
- package/dist/consent-manager.js.map +1 -0
- package/dist/elicitation-handler.d.ts +17 -0
- package/dist/elicitation-handler.js +316 -0
- package/dist/elicitation-handler.js.map +1 -0
- package/dist/errors.d.ts +131 -0
- package/dist/errors.js +278 -0
- package/dist/errors.js.map +1 -0
- package/dist/http-ca.d.ts +8 -0
- package/dist/http-ca.js +88 -0
- package/dist/http-ca.js.map +1 -0
- package/dist/jev-client.d.ts +14 -0
- package/dist/jev-client.js +314 -0
- package/dist/jev-client.js.map +1 -0
- package/dist/jev-contracts.d.ts +77 -0
- package/dist/jev-contracts.js +2 -0
- package/dist/jev-contracts.js.map +1 -0
- package/dist/jev-key-store.d.ts +22 -0
- package/dist/jev-key-store.js +85 -0
- package/dist/jev-key-store.js.map +1 -0
- package/dist/json-schema-validator.d.ts +2 -0
- package/dist/json-schema-validator.js +55 -0
- package/dist/json-schema-validator.js.map +1 -0
- package/dist/lifecycle.d.ts +56 -0
- package/dist/lifecycle.js +410 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/logger.d.ts +51 -0
- package/dist/logger.js +131 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp-auth-fetch.d.ts +26 -0
- package/dist/mcp-auth-fetch.js +103 -0
- package/dist/mcp-auth-fetch.js.map +1 -0
- package/dist/mcp-auth-flow.d.ts +118 -0
- package/dist/mcp-auth-flow.js +1098 -0
- package/dist/mcp-auth-flow.js.map +1 -0
- package/dist/mcp-auth.d.ts +168 -0
- package/dist/mcp-auth.js +1117 -0
- package/dist/mcp-auth.js.map +1 -0
- package/dist/mcp-bearer-store.js +7 -140
- package/dist/mcp-bearer-store.js.map +1 -1
- package/dist/mcp-callback-server.d.ts +53 -0
- package/dist/mcp-callback-server.js +441 -0
- package/dist/mcp-callback-server.js.map +1 -0
- package/dist/mcp-oauth-provider.d.ts +148 -0
- package/dist/mcp-oauth-provider.js +689 -0
- package/dist/mcp-oauth-provider.js.map +1 -0
- package/dist/mcp-probe.d.ts +6 -0
- package/dist/mcp-probe.js +166 -0
- package/dist/mcp-probe.js.map +1 -0
- package/dist/mcp-tasks.d.ts +102 -0
- package/dist/mcp-tasks.js +369 -0
- package/dist/mcp-tasks.js.map +1 -0
- package/dist/mcp-trace.d.ts +95 -0
- package/dist/mcp-trace.js +242 -0
- package/dist/mcp-trace.js.map +1 -0
- package/dist/metadata-cache.js +2 -11
- package/dist/metadata-cache.js.map +1 -1
- package/dist/npx-resolver.d.ts +6 -0
- package/dist/npx-resolver.js +505 -0
- package/dist/npx-resolver.js.map +1 -0
- package/dist/request-headers-command.d.ts +10 -0
- package/dist/request-headers-command.js +312 -0
- package/dist/request-headers-command.js.map +1 -0
- package/dist/runtime-owner.d.ts +13 -0
- package/dist/runtime-owner.js +97 -0
- package/dist/runtime-owner.js.map +1 -0
- package/dist/sampling-handler.d.ts +17 -0
- package/dist/sampling-handler.js +203 -0
- package/dist/sampling-handler.js.map +1 -0
- package/dist/secure-keyring.d.ts +11 -0
- package/dist/secure-keyring.js +172 -0
- package/dist/secure-keyring.js.map +1 -0
- package/dist/server-manager.d.ts +157 -0
- package/dist/server-manager.js +1743 -0
- package/dist/server-manager.js.map +1 -0
- package/dist/session-approvals.d.ts +34 -0
- package/dist/session-approvals.js +140 -0
- package/dist/session-approvals.js.map +1 -0
- package/dist/session-recovery.d.ts +26 -0
- package/dist/session-recovery.js +142 -0
- package/dist/session-recovery.js.map +1 -0
- package/dist/state.d.ts +73 -0
- package/dist/state.js +2 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -1
- package/dist/ui-resource-handler.d.ts +17 -0
- package/dist/ui-resource-handler.js +219 -0
- package/dist/ui-resource-handler.js.map +1 -0
- package/dist/unix-socket-transport.d.ts +15 -0
- package/dist/unix-socket-transport.js +85 -0
- package/dist/unix-socket-transport.js.map +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +13 -0
- package/dist/utils.js.map +1 -1
- package/elicitation-handler.ts +29 -19
- package/examples/jev-accessibility-loop.mjs +85 -0
- package/examples/jev-semantic-filter.mjs +34 -0
- package/index.ts +48 -5
- package/init.ts +6 -19
- package/jev-client.ts +246 -0
- package/jev-contracts.ts +53 -0
- package/jev-key-store.ts +79 -0
- package/lifecycle.ts +14 -3
- package/mcp-bearer-store.ts +7 -142
- package/mcp-code.ts +119 -11
- package/mcp-output-guard.ts +4 -0
- package/mcp-references.ts +5 -3
- package/mcp-script-worker.mjs +5 -0
- package/mcp-tasks.ts +467 -0
- package/metadata-cache.ts +2 -13
- package/namespace-tools.ts +1 -1
- package/package.json +16 -8
- package/proxy-modes.ts +316 -166
- package/request-headers-command.ts +6 -3
- package/search-ranking.ts +38 -7
- package/secure-keyring.ts +170 -0
- package/semantic-search.ts +184 -0
- package/server-manager.ts +293 -50
- package/session-approvals.ts +14 -0
- package/skills/mcp-scripting/SKILL.md +2 -0
- package/state.ts +3 -1
- package/tool-approval.ts +26 -4
- package/tool-metadata.ts +6 -14
- package/tool-registrar.ts +8 -6
- package/tool-result-renderer.ts +4 -1
- package/types.ts +53 -0
- package/ui-server.ts +17 -9
- package/utils.ts +16 -0
package/direct-tool-surface.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Check, Errors } from "typebox/value";
|
|
2
2
|
import type { DirectToolSpec, McpConfig, ToolPrefix } from "./types.ts";
|
|
3
|
-
import { createToolSelectorCandidateIndex, formatToolName, getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.ts";
|
|
3
|
+
import { createToolSelectorCandidateIndex, formatToolName, getToolNameCandidates, isServerDisabled, isToolAllowed, resolveToolPrefix, resolveUniqueNameOwnership } from "./types.ts";
|
|
4
4
|
import type { MetadataCache } from "./metadata-cache.ts";
|
|
5
5
|
import { isServerCacheValid, parseDirectToolSelectors } from "./metadata-cache.ts";
|
|
6
6
|
export { getMissingConfiguredDirectToolServers } from "./metadata-cache.ts";
|
|
@@ -28,14 +28,14 @@ export function prepareDirectToolArguments(inputSchema: unknown, args: unknown):
|
|
|
28
28
|
for (const [name, propertySchema] of Object.entries(properties)) {
|
|
29
29
|
if (!Object.hasOwn(input, name) || typeof input[name] !== "string"
|
|
30
30
|
|| !propertySchema || typeof propertySchema !== "object" || Array.isArray(propertySchema)) continue;
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
// A valid string may be intentional (for example, string | object).
|
|
32
|
+
// Only recover JSON when the advertised property rejects the raw value.
|
|
33
|
+
if (Check(propertySchema as never, input[name])) continue;
|
|
33
34
|
try {
|
|
34
35
|
const parsed: unknown = JSON.parse(input[name] as string);
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (matches) {
|
|
36
|
+
const isContainer = Array.isArray(parsed)
|
|
37
|
+
|| (parsed !== null && typeof parsed === "object");
|
|
38
|
+
if (isContainer && Check(propertySchema as never, parsed)) {
|
|
39
39
|
prepared ??= { ...input };
|
|
40
40
|
prepared[name] = parsed;
|
|
41
41
|
}
|
|
@@ -73,8 +73,6 @@ export function resolveDirectTools(
|
|
|
73
73
|
const specs: DirectToolSpec[] = [];
|
|
74
74
|
if (!cache) return specs;
|
|
75
75
|
|
|
76
|
-
const seenNames = new Set<string>();
|
|
77
|
-
|
|
78
76
|
const envSelection = envOverride ? parseDirectToolSelectors(envOverride) : null;
|
|
79
77
|
const globalDirect = config.settings?.directTools;
|
|
80
78
|
|
|
@@ -139,11 +137,6 @@ export function resolveDirectTools(
|
|
|
139
137
|
console.warn(`MCP: skipping direct tool "${prefixedName}" (collides with builtin)`);
|
|
140
138
|
continue;
|
|
141
139
|
}
|
|
142
|
-
if (seenNames.has(prefixedName)) {
|
|
143
|
-
console.warn(`MCP: skipping duplicate direct tool "${prefixedName}" from "${serverName}"`);
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
seenNames.add(prefixedName);
|
|
147
140
|
specs.push({
|
|
148
141
|
...(lazy ? { lazy: true } : {}),
|
|
149
142
|
serverName,
|
|
@@ -166,11 +159,6 @@ export function resolveDirectTools(
|
|
|
166
159
|
console.warn(`MCP: skipping direct resource tool "${prefixedName}" (collides with builtin)`);
|
|
167
160
|
continue;
|
|
168
161
|
}
|
|
169
|
-
if (seenNames.has(prefixedName)) {
|
|
170
|
-
console.warn(`MCP: skipping duplicate direct resource tool "${prefixedName}" from "${serverName}"`);
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
seenNames.add(prefixedName);
|
|
174
162
|
specs.push({
|
|
175
163
|
...(lazy ? { lazy: true } : {}),
|
|
176
164
|
serverName,
|
|
@@ -183,11 +171,16 @@ export function resolveDirectTools(
|
|
|
183
171
|
}
|
|
184
172
|
}
|
|
185
173
|
|
|
186
|
-
|
|
174
|
+
const ownership = resolveUniqueNameOwnership(specs, (spec) => spec.prefixedName);
|
|
175
|
+
for (const [name, colliding] of ownership.collisions) {
|
|
176
|
+
console.warn(`MCP: skipping colliding direct name "${name}" from ${colliding.map((spec) => `"${spec.serverName}"`).join(", ")}`);
|
|
177
|
+
}
|
|
178
|
+
const uniqueSpecs = ownership.unique;
|
|
179
|
+
for (const spec of uniqueSpecs) reservedNames?.add(spec.prefixedName);
|
|
187
180
|
|
|
188
181
|
const emittedSpecs = unavailableServers.size === 0
|
|
189
|
-
?
|
|
190
|
-
:
|
|
182
|
+
? uniqueSpecs
|
|
183
|
+
: uniqueSpecs.filter((spec) => !unavailableServers.has(spec.serverName));
|
|
191
184
|
|
|
192
185
|
// Lazy specs cost nothing at turn start, so they do not count toward the advisory.
|
|
193
186
|
const eagerCount = emittedSpecs.filter((spec) => !spec.lazy).length;
|
package/direct-tools.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { DirectToolSpec, McpContent } from "./types.ts";
|
|
|
5
5
|
import { lazyConnect, getFailureAgeSeconds, clearFailure } from "./init.ts";
|
|
6
6
|
import { abortable, throwIfAborted } from "./abort.ts";
|
|
7
7
|
import { formatSchema } from "./tool-metadata.ts";
|
|
8
|
-
import { resolveMcpResultContent,
|
|
8
|
+
import { resolveMcpResultContent, transformMcpResourceContents } from "./tool-registrar.ts";
|
|
9
9
|
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
|
|
10
10
|
import { maybeStartUiSession, summarizeUiSessionResult, type UiSessionRuntime } from "./ui-session.ts";
|
|
11
11
|
import { isServerDisabled } from "./types.ts";
|
|
@@ -13,6 +13,7 @@ import { authenticate, supportsOAuth } from "./mcp-auth-flow.ts";
|
|
|
13
13
|
import { formatAuthRequiredMessage, normalizeToolArguments, resolveServerUrl } from "./utils.ts";
|
|
14
14
|
import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.ts";
|
|
15
15
|
import { combineAbortSignals, isAbortError } from "./runtime-owner.ts";
|
|
16
|
+
import { callToolViaTaskSession } from "./mcp-tasks.ts";
|
|
16
17
|
import { ensureToolCallApproved } from "./tool-approval.ts";
|
|
17
18
|
import { getInputRequiredNeedsUiDetails } from "./errors.ts";
|
|
18
19
|
|
|
@@ -310,6 +311,15 @@ export function createDirectToolExecutor(
|
|
|
310
311
|
spec.serverName,
|
|
311
312
|
async (conn) => {
|
|
312
313
|
await state.manager.ensureListen?.(spec.serverName, conn);
|
|
314
|
+
if (conn.taskSession) {
|
|
315
|
+
return await callToolViaTaskSession(conn.taskSession, {
|
|
316
|
+
name: spec.originalName,
|
|
317
|
+
args: normalizedParams ?? {},
|
|
318
|
+
meta: uiSession?.requestMeta,
|
|
319
|
+
signal: ownedSignal,
|
|
320
|
+
requestTimeoutMs: requestOptions?.timeout,
|
|
321
|
+
}) as unknown as ClientCallToolResult;
|
|
322
|
+
}
|
|
313
323
|
return abortable(conn.client.callTool({
|
|
314
324
|
name: spec.originalName,
|
|
315
325
|
arguments: normalizedParams,
|
|
@@ -320,14 +330,11 @@ export function createDirectToolExecutor(
|
|
|
320
330
|
uiSession?.sendToolResult(result as unknown as import("@modelcontextprotocol/client").CallToolResult);
|
|
321
331
|
|
|
322
332
|
if (result.isError) {
|
|
323
|
-
const
|
|
324
|
-
const content = transformMcpContent(mcpContent, state.owner?.signal);
|
|
333
|
+
const content = resolveMcpResultContent(result as Record<string, unknown>, state.owner?.signal);
|
|
325
334
|
const outputContent = content.length > 0 ? content : [{ type: "text" as const, text: "(empty result)" }];
|
|
326
|
-
const schemaText = spec.inputSchema ? `\n\nExpected parameters:\n${formatSchema(spec.inputSchema)}` : "";
|
|
327
335
|
const guarded = await guardMcpOutput(outputContent, {
|
|
328
336
|
...outputGuardOptions,
|
|
329
337
|
prefix: "Error: ",
|
|
330
|
-
suffix: schemaText,
|
|
331
338
|
emptyTextFallback: "Tool execution failed",
|
|
332
339
|
...(state.config.settings?.directToolResultDetails === "bounded" ? { rawMcpResult: result } : {}),
|
|
333
340
|
});
|
package/dist/abort.d.ts
ADDED
package/dist/abort.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function throwIfAborted(signal) {
|
|
2
|
+
if (!signal?.aborted)
|
|
3
|
+
return;
|
|
4
|
+
throw signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason ?? "MCP request aborted"));
|
|
5
|
+
}
|
|
6
|
+
export async function abortable(promise, signal) {
|
|
7
|
+
if (!signal)
|
|
8
|
+
return promise;
|
|
9
|
+
throwIfAborted(signal);
|
|
10
|
+
return await new Promise((resolve, reject) => {
|
|
11
|
+
let settled = false;
|
|
12
|
+
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
13
|
+
const onAbort = () => {
|
|
14
|
+
if (settled)
|
|
15
|
+
return;
|
|
16
|
+
settled = true;
|
|
17
|
+
cleanup();
|
|
18
|
+
reject(signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason ?? "MCP request aborted")));
|
|
19
|
+
};
|
|
20
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
21
|
+
promise.then(value => {
|
|
22
|
+
if (settled)
|
|
23
|
+
return;
|
|
24
|
+
settled = true;
|
|
25
|
+
cleanup();
|
|
26
|
+
resolve(value);
|
|
27
|
+
}, error => {
|
|
28
|
+
if (settled)
|
|
29
|
+
return;
|
|
30
|
+
settled = true;
|
|
31
|
+
cleanup();
|
|
32
|
+
reject(error);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=abort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../abort.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,CAAC,MAAM,EAAE,OAAO;QAAE,OAAO;IAC7B,MAAM,MAAM,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,qBAAqB,CAAC,CAAC,CAAC;AACnH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,OAAmB,EAAE,MAAoB;IAC1E,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAC5B,cAAc,CAAC,MAAM,CAAC,CAAC;IACvB,OAAO,MAAM,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC9C,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACnE,MAAM,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC;QACrH,CAAC,CAAC;QACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CACV,KAAK,CAAC,EAAE;YACN,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,KAAK,CAAC,EAAE;YACN,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const DEFAULT_TTL_MS = 5 * 60_000;
|
|
3
|
+
const ENV_TTL_MS = "PI_MCP_ADAPTER_BEARER_COMMAND_TTL_MS";
|
|
4
|
+
const COMMAND_TIMEOUT_MS = 10_000;
|
|
5
|
+
const COMMAND_MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
6
|
+
const USE_PROCESS_GROUP = process.platform !== "win32";
|
|
7
|
+
function resolveDefaultTtlMs() {
|
|
8
|
+
const parsed = Number(process.env[ENV_TTL_MS] || DEFAULT_TTL_MS);
|
|
9
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : DEFAULT_TTL_MS;
|
|
10
|
+
}
|
|
11
|
+
function abortReason(signal) {
|
|
12
|
+
return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
13
|
+
}
|
|
14
|
+
function runCommand(command, context, signal) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
let output = Buffer.alloc(0);
|
|
17
|
+
let settled = false;
|
|
18
|
+
let terminating = false;
|
|
19
|
+
const child = spawn(command.slice(1), {
|
|
20
|
+
shell: true,
|
|
21
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
22
|
+
windowsHide: true,
|
|
23
|
+
detached: USE_PROCESS_GROUP,
|
|
24
|
+
});
|
|
25
|
+
const kill = async () => {
|
|
26
|
+
if (child.pid === undefined)
|
|
27
|
+
return;
|
|
28
|
+
if (!USE_PROCESS_GROUP) {
|
|
29
|
+
await new Promise((resolveKill, rejectKill) => {
|
|
30
|
+
const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
31
|
+
stdio: "ignore",
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
});
|
|
34
|
+
killer.on("error", () => rejectKill(new Error("Failed to stop bearer token command")));
|
|
35
|
+
killer.on("close", code => {
|
|
36
|
+
if (code === 0 || code === 128)
|
|
37
|
+
resolveKill();
|
|
38
|
+
else
|
|
39
|
+
rejectKill(new Error(`Failed to stop bearer token command: taskkill exited with code ${code ?? "unknown"}`));
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
process.kill(-child.pid, "SIGKILL");
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.code !== "ESRCH")
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const finish = (error, token) => {
|
|
53
|
+
if (settled)
|
|
54
|
+
return;
|
|
55
|
+
settled = true;
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
signal.removeEventListener("abort", onAbort);
|
|
58
|
+
if (error !== undefined)
|
|
59
|
+
reject(error);
|
|
60
|
+
else
|
|
61
|
+
resolve(token);
|
|
62
|
+
};
|
|
63
|
+
const terminate = async (error) => {
|
|
64
|
+
if (settled || terminating)
|
|
65
|
+
return;
|
|
66
|
+
terminating = true;
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
signal.removeEventListener("abort", onAbort);
|
|
69
|
+
try {
|
|
70
|
+
await kill();
|
|
71
|
+
finish(error);
|
|
72
|
+
}
|
|
73
|
+
catch (cleanupError) {
|
|
74
|
+
finish(cleanupError);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const onAbort = () => {
|
|
78
|
+
void terminate(abortReason(signal));
|
|
79
|
+
};
|
|
80
|
+
const timer = setTimeout(() => {
|
|
81
|
+
void terminate(new Error(`Failed to resolve ${context}: command timed out after ${COMMAND_TIMEOUT_MS}ms`));
|
|
82
|
+
}, COMMAND_TIMEOUT_MS);
|
|
83
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
84
|
+
if (signal.aborted) {
|
|
85
|
+
onAbort();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
child.on("error", () => {
|
|
89
|
+
if (!terminating)
|
|
90
|
+
finish(new Error(`Failed to resolve ${context}: command failed to start`));
|
|
91
|
+
});
|
|
92
|
+
child.stdout.on("data", (chunk) => {
|
|
93
|
+
if (settled || terminating)
|
|
94
|
+
return;
|
|
95
|
+
output = Buffer.concat([output, Buffer.from(chunk)]);
|
|
96
|
+
if (output.byteLength > COMMAND_MAX_OUTPUT_BYTES) {
|
|
97
|
+
void terminate(new Error(`Failed to resolve ${context}: command output exceeded 1 MiB`));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
child.on("close", code => {
|
|
101
|
+
if (settled || terminating)
|
|
102
|
+
return;
|
|
103
|
+
if (code !== 0) {
|
|
104
|
+
finish(new Error(`Failed to resolve ${context}: command exited with code ${code ?? "unknown"}`));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const token = output.toString("utf8").trim();
|
|
108
|
+
if (!token) {
|
|
109
|
+
finish(new Error(`Failed to resolve ${context}: command returned empty output`));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
finish(undefined, token);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Resolve and periodically refresh one command-backed bearer token. */
|
|
117
|
+
export class BearerCommandResolver {
|
|
118
|
+
#command;
|
|
119
|
+
#context;
|
|
120
|
+
#ttlMs;
|
|
121
|
+
#cached;
|
|
122
|
+
#failure;
|
|
123
|
+
#inflight;
|
|
124
|
+
constructor(command, context, ttlMs = resolveDefaultTtlMs()) {
|
|
125
|
+
this.#command = command;
|
|
126
|
+
this.#context = context;
|
|
127
|
+
this.#ttlMs = ttlMs;
|
|
128
|
+
}
|
|
129
|
+
resolve(signal) {
|
|
130
|
+
if (signal?.aborted)
|
|
131
|
+
return Promise.reject(abortReason(signal));
|
|
132
|
+
const now = Date.now();
|
|
133
|
+
if (this.#cached !== undefined && now < this.#cached.expiresAt) {
|
|
134
|
+
return Promise.resolve(this.#cached.token);
|
|
135
|
+
}
|
|
136
|
+
if (this.#failure !== undefined && now < this.#failure.retryAt) {
|
|
137
|
+
return this.#cached !== undefined
|
|
138
|
+
? Promise.resolve(this.#cached.token)
|
|
139
|
+
: Promise.reject(this.#failure.error);
|
|
140
|
+
}
|
|
141
|
+
let inflight = this.#inflight;
|
|
142
|
+
if (inflight === undefined) {
|
|
143
|
+
const controller = new AbortController();
|
|
144
|
+
let current;
|
|
145
|
+
const promise = runCommand(this.#command, this.#context, controller.signal)
|
|
146
|
+
.then(token => {
|
|
147
|
+
this.#cached = { token, expiresAt: Date.now() + this.#ttlMs };
|
|
148
|
+
this.#failure = undefined;
|
|
149
|
+
return token;
|
|
150
|
+
})
|
|
151
|
+
.catch(error => {
|
|
152
|
+
// Request cancellation is not a helper outage. Do not let one
|
|
153
|
+
// cancelled request suppress refresh attempts for the next caller.
|
|
154
|
+
if (!controller.signal.aborted) {
|
|
155
|
+
this.#failure = { error, retryAt: Date.now() + this.#ttlMs };
|
|
156
|
+
}
|
|
157
|
+
if (this.#cached !== undefined)
|
|
158
|
+
return this.#cached.token;
|
|
159
|
+
throw error;
|
|
160
|
+
})
|
|
161
|
+
.finally(() => {
|
|
162
|
+
if (this.#inflight === current)
|
|
163
|
+
this.#inflight = undefined;
|
|
164
|
+
});
|
|
165
|
+
current = { controller, promise, waiters: 0 };
|
|
166
|
+
this.#inflight = current;
|
|
167
|
+
inflight = current;
|
|
168
|
+
}
|
|
169
|
+
return this.#wait(inflight, signal);
|
|
170
|
+
}
|
|
171
|
+
#wait(inflight, signal) {
|
|
172
|
+
inflight.waiters++;
|
|
173
|
+
let onAbort;
|
|
174
|
+
const result = signal === undefined
|
|
175
|
+
? inflight.promise
|
|
176
|
+
: Promise.race([
|
|
177
|
+
inflight.promise,
|
|
178
|
+
new Promise((_resolve, reject) => {
|
|
179
|
+
onAbort = () => reject(abortReason(signal));
|
|
180
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
181
|
+
}),
|
|
182
|
+
]);
|
|
183
|
+
return result.finally(() => {
|
|
184
|
+
if (onAbort)
|
|
185
|
+
signal.removeEventListener("abort", onAbort);
|
|
186
|
+
inflight.waiters--;
|
|
187
|
+
if (this.#inflight === inflight && inflight.waiters === 0) {
|
|
188
|
+
this.#inflight = undefined;
|
|
189
|
+
inflight.controller.abort(signal?.reason);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=bearer-command-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bearer-command-resolver.js","sourceRoot":"","sources":["../bearer-command-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export declare function cloneMcpConfig(config: McpConfig): McpConfig;
|
|
|
101
101
|
export declare function loadMcpConfig(overridePath?: string, cwd?: string): McpConfig;
|
|
102
102
|
export declare function resolveConfiguredClaudePluginMcp(config: McpConfig, cwd?: string): McpConfig;
|
|
103
103
|
export declare function discoverConfiguredClaudePluginSkills(config: McpConfig, cwd?: string): string[];
|
|
104
|
+
export declare function writeSharedConfigText(filePath: string, text: string): void;
|
|
104
105
|
export interface ServerDisabledOverrideResult {
|
|
105
106
|
path: string;
|
|
106
107
|
changed: boolean;
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// config.ts - Config loading with import support
|
|
2
|
-
import { existsSync, readFileSync, realpathSync, statSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
|
|
2
|
+
import { chmodSync, existsSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { parse as parseToml } from "smol-toml";
|
|
@@ -9,6 +9,7 @@ import { getAgentPluginSummaries, loadAgentPluginConfigs } from "./agent-plugin-
|
|
|
9
9
|
import { cloneBuiltInAgentPluginEntry, isBuiltInAgentPlugin, mergeBuiltInAgentPluginEntries } from "./agent-plugin-provenance.js";
|
|
10
10
|
import { loadClaudePluginBundles } from "./claude-plugin-loader.js";
|
|
11
11
|
import { loadPackageMcpConfigs } from "./package-mcp-loader.js";
|
|
12
|
+
import { validateJevSettings } from "./jev-client.js";
|
|
12
13
|
import { formatServerNamespace, isServerDisabled } from "./types.js";
|
|
13
14
|
import { parseJsonWithComments, toStringRecord } from "./utils.js";
|
|
14
15
|
const GENERIC_GLOBAL_CONFIG_PATH = join(homedir(), ".config", "mcp", "mcp.json");
|
|
@@ -696,10 +697,20 @@ function validateConfig(raw) {
|
|
|
696
697
|
return {
|
|
697
698
|
mcpServers: toServerEntries(raw.mcpServers ?? raw["mcp-servers"]),
|
|
698
699
|
...(Array.isArray(raw.imports) ? { imports: raw.imports } : {}),
|
|
699
|
-
...(raw.settings !== undefined ? { settings: raw.settings } : {}),
|
|
700
|
+
...(raw.settings !== undefined ? { settings: parseSettings(raw.settings) } : {}),
|
|
700
701
|
...(raw.claudePlugins !== undefined ? { claudePlugins: parseClaudePlugins(raw.claudePlugins) } : {}),
|
|
701
702
|
};
|
|
702
703
|
}
|
|
704
|
+
function parseSettings(value) {
|
|
705
|
+
if (!isRecord(value))
|
|
706
|
+
throw new Error("settings must be an object");
|
|
707
|
+
const settings = { ...value };
|
|
708
|
+
if (value.jev !== undefined) {
|
|
709
|
+
validateJevSettings(value.jev);
|
|
710
|
+
settings.jev = value.jev;
|
|
711
|
+
}
|
|
712
|
+
return settings;
|
|
713
|
+
}
|
|
703
714
|
function parseClaudePlugins(value) {
|
|
704
715
|
if (!Array.isArray(value)) {
|
|
705
716
|
console.warn("Invalid claudePlugins config: expected an array");
|
|
@@ -970,11 +981,37 @@ function readRawConfigObject(filePath) {
|
|
|
970
981
|
return {};
|
|
971
982
|
}
|
|
972
983
|
}
|
|
984
|
+
function writeConfigText(writePath, text) {
|
|
985
|
+
let mode;
|
|
986
|
+
try {
|
|
987
|
+
writePath = realpathSync(writePath);
|
|
988
|
+
mode = statSync(writePath).mode & 0o777;
|
|
989
|
+
}
|
|
990
|
+
catch { }
|
|
991
|
+
mkdirSync(dirname(writePath), { recursive: true });
|
|
992
|
+
const tmpPath = `${writePath}.${process.pid}.tmp`;
|
|
993
|
+
rmSync(tmpPath, { force: true });
|
|
994
|
+
try {
|
|
995
|
+
writeFileSync(tmpPath, text, mode === undefined ? "utf-8" : { encoding: "utf-8", mode });
|
|
996
|
+
if (mode !== undefined)
|
|
997
|
+
chmodSync(tmpPath, mode);
|
|
998
|
+
renameSync(tmpPath, writePath);
|
|
999
|
+
}
|
|
1000
|
+
catch (error) {
|
|
1001
|
+
try {
|
|
1002
|
+
rmSync(tmpPath, { force: true });
|
|
1003
|
+
}
|
|
1004
|
+
catch { }
|
|
1005
|
+
throw error;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
973
1008
|
function writeRawConfigObject(filePath, raw) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1009
|
+
writeConfigText(filePath, `${JSON.stringify(raw, null, 2)}\n`);
|
|
1010
|
+
}
|
|
1011
|
+
export function writeSharedConfigText(filePath, text) {
|
|
1012
|
+
if (!isRecord(parseJsonWithComments(text)))
|
|
1013
|
+
throw new Error("top-level value must be an object");
|
|
1014
|
+
writeConfigText(filePath, text);
|
|
978
1015
|
}
|
|
979
1016
|
function getServersObject(raw) {
|
|
980
1017
|
const existing = raw.mcpServers ?? raw["mcp-servers"] ?? {};
|