@fitchmultz/pi-mcp-adapter 6.0.0 → 7.0.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 +26 -0
- package/README.md +12 -8
- package/dist/app-bridge.bundle.js +14 -14
- package/dist/config.js +41 -16
- package/dist/gateway-arguments.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.js +2 -2
- package/dist/mcp-auth-flow.js +2 -2
- package/dist/mcp-auth.d.ts +1 -1
- package/dist/mcp-auth.js +3 -3
- package/dist/mcp-code.d.ts +6 -6
- package/dist/mcp-code.js +11 -10
- package/dist/mcp-oauth-provider.d.ts +5 -5
- package/dist/mcp-oauth-provider.js +5 -5
- package/dist/mcp-output-guard.d.ts +1 -1
- package/dist/mcp-panel.d.ts +2 -2
- package/dist/mcp-panel.js +2 -2
- package/dist/mcp-setup-panel.d.ts +5 -4
- package/dist/mcp-setup-panel.js +15 -7
- package/dist/mcp-trace.d.ts +1 -1
- package/dist/mcp-trace.js +1 -1
- package/dist/npx-resolver.js +8 -4
- package/dist/proxy-modes.d.ts +2 -2
- package/dist/proxy-modes.js +9 -9
- package/dist/sampling-handler.js +1 -0
- package/dist/search-ranking.js +6 -2
- package/dist/server-manager.d.ts +2 -2
- package/dist/server-manager.js +44 -27
- package/dist/session-recovery.d.ts +7 -4
- package/dist/session-recovery.js +76 -10
- package/dist/tool-metadata.d.ts +43 -43
- package/dist/tool-result-renderer.d.ts +3 -3
- package/dist/tool-result-renderer.js +3 -3
- package/dist/ui-resource-handler.d.ts +2 -2
- package/dist/ui-resource-handler.js +2 -2
- package/dist/ui-server.js +4 -3
- package/dist/ui-stream-types.d.ts +8 -8
- package/dist/unix-socket-transport.d.ts +1 -1
- package/dist/unix-socket-transport.js +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +14 -0
- package/package.json +34 -98
- package/abort.ts +0 -34
- package/agent-dir.ts +0 -24
- package/app-bridge.bundle.js +0 -109
- package/banner.png +0 -0
- package/checkpoint.ts +0 -55
- package/commands.ts +0 -622
- package/config.ts +0 -1204
- package/consent-manager.ts +0 -25
- package/direct-tools.ts +0 -75
- package/elicitation-handler.ts +0 -349
- package/error-signal.ts +0 -21
- package/gateway-arguments.ts +0 -73
- package/glimpse-ui.ts +0 -80
- package/host-html-template.ts +0 -456
- package/index.ts +0 -767
- package/init.ts +0 -613
- package/legacy-migration.ts +0 -47
- package/lifecycle.ts +0 -165
- package/logger.ts +0 -127
- package/mcp-auth-flow.ts +0 -975
- package/mcp-auth.ts +0 -793
- package/mcp-callback-server.ts +0 -450
- package/mcp-code.ts +0 -412
- package/mcp-keyring-helper.cjs +0 -89
- package/mcp-oauth-provider.ts +0 -774
- package/mcp-output-guard.ts +0 -530
- package/mcp-panel.ts +0 -907
- package/mcp-script-worker.mjs +0 -131
- package/mcp-setup-panel.ts +0 -666
- package/mcp-status.ts +0 -110
- package/mcp-trace.ts +0 -295
- package/metadata-cache.ts +0 -271
- package/npx-resolver.ts +0 -488
- package/onboarding-state.ts +0 -58
- package/panel-keys.ts +0 -37
- package/prompts.ts +0 -337
- package/proxy-modes.ts +0 -1109
- package/resource-tools.ts +0 -52
- package/runtime-owner.ts +0 -123
- package/sampling-handler.ts +0 -276
- package/scripts/build-app-bridge.mjs +0 -15
- package/scripts/build.mjs +0 -132
- package/scripts/prepare.mjs +0 -103
- package/search-ranking.ts +0 -132
- package/server-manager.ts +0 -1320
- package/session-recovery.ts +0 -316
- package/state.ts +0 -64
- package/tool-approval.ts +0 -78
- package/tool-loader.ts +0 -153
- package/tool-metadata.ts +0 -240
- package/tool-registrar.ts +0 -74
- package/tool-result-renderer.ts +0 -294
- package/tsconfig.build.json +0 -13
- package/tsconfig.json +0 -16
- package/types.ts +0 -785
- package/ui-resource-handler.ts +0 -249
- package/ui-server.ts +0 -808
- package/ui-session.ts +0 -568
- package/ui-stream-types.ts +0 -89
- package/ui-tool-visibility.ts +0 -25
- package/unix-socket-transport.ts +0 -85
- package/utils.ts +0 -307
package/dist/config.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// config.ts - Config loading with import support
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync, renameSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync, renameSync, statSync, chmodSync } from "node:fs";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
3
4
|
import { homedir } from "node:os";
|
|
4
5
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
7
|
import { parse as parseToml } from "smol-toml";
|
|
6
8
|
import stripJsonComments from "strip-json-comments";
|
|
7
9
|
import { getAdapterPath } from "./agent-dir.js";
|
|
@@ -367,6 +369,14 @@ function mergeServerMaps(base, next) {
|
|
|
367
369
|
delete baseEntry.oauth;
|
|
368
370
|
}
|
|
369
371
|
}
|
|
372
|
+
// Stdio env belongs to the program that received it, not just the server name.
|
|
373
|
+
if (existing?.command && ((definition.command !== undefined && definition.command !== existing.command)
|
|
374
|
+
|| (definition.args !== undefined && !isDeepStrictEqual(definition.args, existing.args ?? []))
|
|
375
|
+
|| (definition.cwd !== undefined && definition.cwd !== existing.cwd))) {
|
|
376
|
+
if (baseEntry === existing)
|
|
377
|
+
baseEntry = { ...existing };
|
|
378
|
+
delete baseEntry.env;
|
|
379
|
+
}
|
|
370
380
|
merged[name] = { ...baseEntry, ...definition };
|
|
371
381
|
}
|
|
372
382
|
return merged;
|
|
@@ -533,8 +543,10 @@ function mergeOpenCodeConfigs(base, next) {
|
|
|
533
543
|
delete safeBase.cwd;
|
|
534
544
|
}
|
|
535
545
|
}
|
|
546
|
+
if (Object.hasOwn(override, "cwd") && override.cwd !== safeBase.cwd)
|
|
547
|
+
delete safeBase.environment;
|
|
536
548
|
const mergedEntry = { ...safeBase, ...override };
|
|
537
|
-
for (const field of ["
|
|
549
|
+
for (const field of ["headers", "oauth"]) {
|
|
538
550
|
const baseField = safeBase[field];
|
|
539
551
|
const nextField = override[field];
|
|
540
552
|
if (baseField && typeof baseField === "object" && !Array.isArray(baseField)
|
|
@@ -714,24 +726,37 @@ function buildConfigWritePreview(filePath, nextRaw) {
|
|
|
714
726
|
function readRawConfigObject(filePath) {
|
|
715
727
|
if (!existsSync(filePath))
|
|
716
728
|
return {};
|
|
729
|
+
let raw;
|
|
717
730
|
try {
|
|
718
|
-
|
|
719
|
-
return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
731
|
+
raw = parseJsonConfig(readFileSync(filePath, "utf-8"));
|
|
720
732
|
}
|
|
721
|
-
catch {
|
|
722
|
-
|
|
733
|
+
catch (error) {
|
|
734
|
+
throw new Error(`Cannot read MCP config at ${filePath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
735
|
+
}
|
|
736
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
737
|
+
throw new Error(`Invalid MCP config at ${filePath}: expected an object`);
|
|
723
738
|
}
|
|
739
|
+
return raw;
|
|
724
740
|
}
|
|
725
741
|
function writeRawConfigObject(filePath, raw) {
|
|
726
742
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
727
|
-
const
|
|
728
|
-
|
|
743
|
+
const existingMode = existsSync(filePath) ? statSync(filePath).mode & 0o7777 : undefined;
|
|
744
|
+
const tmpPath = `${filePath}.${randomUUID()}.tmp`;
|
|
745
|
+
writeFileSync(tmpPath, `${JSON.stringify(raw, null, 2)}\n`, {
|
|
746
|
+
encoding: "utf-8",
|
|
747
|
+
mode: existingMode ?? 0o666,
|
|
748
|
+
flag: "wx",
|
|
749
|
+
});
|
|
750
|
+
if (existingMode !== undefined)
|
|
751
|
+
chmodSync(tmpPath, existingMode);
|
|
729
752
|
renameSync(tmpPath, filePath);
|
|
730
753
|
}
|
|
731
|
-
function getServersObject(raw) {
|
|
732
|
-
const existing = raw.mcpServers
|
|
754
|
+
function getServersObject(raw, filePath) {
|
|
755
|
+
const existing = raw.mcpServers !== undefined ? raw.mcpServers
|
|
756
|
+
: raw["mcp-servers"] !== undefined ? raw["mcp-servers"]
|
|
757
|
+
: {};
|
|
733
758
|
if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
|
|
734
|
-
|
|
759
|
+
throw new Error(`Invalid MCP config at ${filePath}: mcpServers must be an object`);
|
|
735
760
|
}
|
|
736
761
|
return existing;
|
|
737
762
|
}
|
|
@@ -886,7 +911,7 @@ export function previewCompatibilityImports(importKinds, overridePath) {
|
|
|
886
911
|
const currentImports = Array.isArray(raw.imports) ? raw.imports.filter((value) => typeof value === "string") : [];
|
|
887
912
|
const merged = [...new Set([...currentImports, ...importKinds])];
|
|
888
913
|
const nextRaw = { ...raw, imports: merged };
|
|
889
|
-
setServersObject(nextRaw, getServersObject(nextRaw));
|
|
914
|
+
setServersObject(nextRaw, getServersObject(nextRaw, targetPath));
|
|
890
915
|
return buildConfigWritePreview(targetPath, nextRaw);
|
|
891
916
|
}
|
|
892
917
|
export function ensureCompatibilityImports(importKinds, overridePath) {
|
|
@@ -899,7 +924,7 @@ export function ensureCompatibilityImports(importKinds, overridePath) {
|
|
|
899
924
|
return { path: targetPath, added: [] };
|
|
900
925
|
}
|
|
901
926
|
raw.imports = merged;
|
|
902
|
-
const servers = getServersObject(raw);
|
|
927
|
+
const servers = getServersObject(raw, targetPath);
|
|
903
928
|
setServersObject(raw, servers);
|
|
904
929
|
writeRawConfigObject(targetPath, raw);
|
|
905
930
|
return { path: targetPath, added };
|
|
@@ -923,14 +948,14 @@ export function writeStarterProjectConfig(cwd = process.cwd()) {
|
|
|
923
948
|
export function previewSharedServerEntry(filePath, serverName, entry) {
|
|
924
949
|
const raw = readRawConfigObject(filePath);
|
|
925
950
|
const nextRaw = { ...raw };
|
|
926
|
-
const servers = getServersObject(nextRaw);
|
|
951
|
+
const servers = getServersObject(nextRaw, filePath);
|
|
927
952
|
servers[serverName] = entry;
|
|
928
953
|
setServersObject(nextRaw, servers);
|
|
929
954
|
return buildConfigWritePreview(filePath, nextRaw);
|
|
930
955
|
}
|
|
931
956
|
export function writeSharedServerEntry(filePath, serverName, entry) {
|
|
932
957
|
const raw = readRawConfigObject(filePath);
|
|
933
|
-
const servers = getServersObject(raw);
|
|
958
|
+
const servers = getServersObject(raw, filePath);
|
|
934
959
|
servers[serverName] = entry;
|
|
935
960
|
setServersObject(raw, servers);
|
|
936
961
|
writeRawConfigObject(filePath, raw);
|
|
@@ -991,7 +1016,7 @@ export function writeDirectToolsConfig(changes, provenance) {
|
|
|
991
1016
|
}
|
|
992
1017
|
for (const [filePath, entries] of byPath) {
|
|
993
1018
|
const raw = readRawConfigObject(filePath);
|
|
994
|
-
const servers = getServersObject(raw);
|
|
1019
|
+
const servers = getServersObject(raw, filePath);
|
|
995
1020
|
for (const { name, value } of entries) {
|
|
996
1021
|
// Keep inherited connection details in their source file.
|
|
997
1022
|
servers[name] = { ...servers[name], directTools: value };
|
|
@@ -15,7 +15,7 @@ export type GatewayArguments = {
|
|
|
15
15
|
fields?: string[];
|
|
16
16
|
};
|
|
17
17
|
export declare const gatewayParameters: Type.TObject<{
|
|
18
|
-
action: Type.TUnsafe<"
|
|
18
|
+
action: Type.TUnsafe<"auth-complete" | "auth-start" | "call" | "connect" | "describe" | "instructions" | "list" | "read-resource" | "read-result" | "resources" | "search" | "status" | "ui-messages">;
|
|
19
19
|
server: Type.TOptional<Type.TString>;
|
|
20
20
|
tool: Type.TOptional<Type.TString>;
|
|
21
21
|
args: Type.TOptional<Type.TObject<{}>>;
|
package/dist/index.js
CHANGED
|
@@ -552,7 +552,7 @@ function installMcpAdapter(pi, options) {
|
|
|
552
552
|
: params.server ? (ready.toolMetadata.get(params.server) ?? []).filter(tool => !tool.resourceUri).map(tool => ({ server: params.server, tool })).sort((a, b) => a.tool.name.localeCompare(b.tool.name)) : [];
|
|
553
553
|
const page = paginate(matches, params.offset ?? 0, params.limit ?? 5);
|
|
554
554
|
const tools = toolLoader.activate(page.items);
|
|
555
|
-
const result = executeSearch(ready, params.query, params.server, tools.length < page.items.length, params.limit ?? 5, params.offset);
|
|
555
|
+
const result = executeSearch(ready, params.query, params.server, tools.length < page.items.length, params.limit ?? 5, params.offset, "mcp_search");
|
|
556
556
|
const guarded = await guardMcpOutput([
|
|
557
557
|
...result.content,
|
|
558
558
|
{ type: "text", text: tools.length ? `Loaded for the next request: ${JSON.stringify(tools)}` : "No direct tools loaded. Use mcp action call or tools.call in mcp_script with the returned exact names." },
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -4,8 +4,6 @@ import { hasPendingAuth } from "./mcp-auth-flow.ts";
|
|
|
4
4
|
export type ReconnectCallback = (serverName: string) => void;
|
|
5
5
|
export type ReconnectFailureCallback = (serverName: string, error: unknown) => void;
|
|
6
6
|
export declare class McpLifecycleManager {
|
|
7
|
-
private readonly manager;
|
|
8
|
-
private readonly hasPendingAuthForServer;
|
|
9
7
|
private keepAliveServers;
|
|
10
8
|
private allServers;
|
|
11
9
|
private serverSettings;
|
|
@@ -23,6 +21,8 @@ export declare class McpLifecycleManager {
|
|
|
23
21
|
pauseForCheckpoint(): () => void;
|
|
24
22
|
private healthSignal;
|
|
25
23
|
private removeHealthAbortListener;
|
|
24
|
+
private readonly manager;
|
|
25
|
+
private readonly hasPendingAuthForServer;
|
|
26
26
|
constructor(manager: McpServerManager, hasPendingAuthForServer?: typeof hasPendingAuth);
|
|
27
27
|
setReconnectCallback(callback: ReconnectCallback): void;
|
|
28
28
|
setReconnectFailureCallback(callback: ReconnectFailureCallback): void;
|
package/dist/lifecycle.js
CHANGED
|
@@ -3,8 +3,6 @@ import { hasPendingAuth } from "./mcp-auth-flow.js";
|
|
|
3
3
|
import { logger } from "./logger.js";
|
|
4
4
|
import { formatTerminalError, sanitizeTerminalText } from "./utils.js";
|
|
5
5
|
export class McpLifecycleManager {
|
|
6
|
-
manager;
|
|
7
|
-
hasPendingAuthForServer;
|
|
8
6
|
keepAliveServers = new Map();
|
|
9
7
|
allServers = new Map();
|
|
10
8
|
serverSettings = new Map();
|
|
@@ -31,6 +29,8 @@ export class McpLifecycleManager {
|
|
|
31
29
|
}
|
|
32
30
|
healthSignal;
|
|
33
31
|
removeHealthAbortListener;
|
|
32
|
+
manager;
|
|
33
|
+
hasPendingAuthForServer;
|
|
34
34
|
constructor(manager, hasPendingAuthForServer = hasPendingAuth) {
|
|
35
35
|
this.manager = manager;
|
|
36
36
|
this.hasPendingAuthForServer = hasPendingAuthForServer;
|
package/dist/mcp-auth-flow.js
CHANGED
|
@@ -9,7 +9,7 @@ import { McpOAuthProvider, issuersMatch, loopbackRedirectsMatch, validateOAuthCl
|
|
|
9
9
|
import { ensureCallbackServer, waitForCallback, cancelPendingCallback, stopCallbackServer, releaseCallbackServer, takeCallbackResult, } from "./mcp-callback-server.js";
|
|
10
10
|
import { getAuthForUrl, clearAllCredentials, clearClientInfo, clearTokens, clearCodeVerifier, getOAuthState, clearOAuthState, getAuthBaseDir, } from "./mcp-auth.js";
|
|
11
11
|
import { isServerDisabled, isNonInteractiveOAuth, validateServerProtocolConfig } from "./types.js";
|
|
12
|
-
import { formatTerminalError, interpolateEnvRecord, interpolateEnvVars, normalizeRequestTimeoutMs } from "./utils.js";
|
|
12
|
+
import { ADAPTER_VERSION, formatTerminalError, interpolateEnvRecord, interpolateEnvVars, normalizeRequestTimeoutMs } from "./utils.js";
|
|
13
13
|
import { abortable, throwIfAborted } from "./abort.js";
|
|
14
14
|
import { combineAbortSignals, isAbortError } from "./runtime-owner.js";
|
|
15
15
|
function applyConfiguredScope(discovery, config) {
|
|
@@ -255,7 +255,7 @@ async function probeAuthDiscovery(serverUrl, definition, signal) {
|
|
|
255
255
|
const timeout = normalizeRequestTimeoutMs(definition?.requestTimeoutMs) ?? 5000;
|
|
256
256
|
const discoverySignal = combineAbortSignals(signal, AbortSignal.timeout(Math.ceil(timeout)));
|
|
257
257
|
let discovery = {};
|
|
258
|
-
const client = new Client({ name: "pi-mcp-auth-discovery", version:
|
|
258
|
+
const client = new Client({ name: "pi-mcp-auth-discovery", version: ADAPTER_VERSION }, {
|
|
259
259
|
versionNegotiation: { mode: definition?.protocolVersion ?? "auto" },
|
|
260
260
|
...(isNonInteractiveOAuth(definition?.oauth)
|
|
261
261
|
? { capabilities: { extensions: { [definition?.oauth && definition.oauth.crossAppAccess
|
package/dist/mcp-auth.d.ts
CHANGED
|
@@ -51,8 +51,8 @@ export interface AuthStorageOptions {
|
|
|
51
51
|
baseDir?: string;
|
|
52
52
|
}
|
|
53
53
|
export declare class OAuthCredentialStoreError extends Error {
|
|
54
|
-
readonly operation: 'read' | 'write' | 'remove';
|
|
55
54
|
readonly code = "OAUTH_CREDENTIAL_STORE_UNAVAILABLE";
|
|
55
|
+
readonly operation: 'read' | 'write' | 'remove';
|
|
56
56
|
constructor(message: string, operation: 'read' | 'write' | 'remove', cause: unknown);
|
|
57
57
|
}
|
|
58
58
|
export type OAuthCredentialStatus = {
|
package/dist/mcp-auth.js
CHANGED
|
@@ -15,8 +15,8 @@ import { createRequire } from 'module';
|
|
|
15
15
|
import { readFileSync, existsSync, rmSync } from 'fs';
|
|
16
16
|
import { dirname, join } from 'path';
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
|
-
import { getAdapterPath, getAgentPath } from
|
|
19
|
-
import { resolveConfiguredOAuthDir } from
|
|
18
|
+
import { getAdapterPath, getAgentPath } from './agent-dir.js';
|
|
19
|
+
import { resolveConfiguredOAuthDir } from './config.js';
|
|
20
20
|
const require = createRequire(import.meta.url);
|
|
21
21
|
const AUTH_SECRET_SERVICE = 'fitch-mcp-adapter.oauth';
|
|
22
22
|
const LEGACY_AUTH_SECRET_SERVICE = 'pi-mcp-adapter.oauth';
|
|
@@ -30,8 +30,8 @@ const TEST_LINUX_KEYRING_RECOVERY_ENV = 'PI_MCP_ADAPTER_TEST_LINUX_KEYRING_RECOV
|
|
|
30
30
|
const KEYRING_RECOVERY_TIMEOUT_MS = 10_000;
|
|
31
31
|
const AUTH_CHUNK_MANIFEST_KEY = '__piMcpAdapterOAuthChunked';
|
|
32
32
|
export class OAuthCredentialStoreError extends Error {
|
|
33
|
-
operation;
|
|
34
33
|
code = 'OAUTH_CREDENTIAL_STORE_UNAVAILABLE';
|
|
34
|
+
operation;
|
|
35
35
|
constructor(message, operation, cause) {
|
|
36
36
|
super(isAndroidKeyringLoadFailure(cause)
|
|
37
37
|
? `${message}. Android/Termux: @napi-rs/keyring could not load a native binding. Persistent OAuth requires a supported platform with an OS credential store; no plaintext fallback is used.`
|
package/dist/mcp-code.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ export declare const runMcpScript: typeof runMcpScriptOperation;
|
|
|
6
6
|
declare function runMcpScriptOperation(state: McpExtensionState, code: string, timeoutMs?: number | null, getPiTools?: () => ToolInfo[], signal?: AbortSignal, toolCallId?: string, beforeDispatch?: (signal: AbortSignal | undefined, operation: McpOperationContext) => Promise<void>): Promise<{
|
|
7
7
|
content: ContentBlock[];
|
|
8
8
|
details: {
|
|
9
|
+
mode: string;
|
|
10
|
+
resultRefs?: string[];
|
|
11
|
+
error?: "aborted" | "call_capture_failed" | "script_error" | "timeout";
|
|
12
|
+
message?: string | undefined;
|
|
13
|
+
timeoutMs: number | null;
|
|
14
|
+
recovery?: {} | null;
|
|
9
15
|
calls?: ({
|
|
10
16
|
operation: "call";
|
|
11
17
|
path: string;
|
|
@@ -41,12 +47,6 @@ declare function runMcpScriptOperation(state: McpExtensionState, code: string, t
|
|
|
41
47
|
error: string;
|
|
42
48
|
durationMs: number;
|
|
43
49
|
})[];
|
|
44
|
-
recovery?: {} | null;
|
|
45
|
-
timeoutMs: number | null;
|
|
46
|
-
error?: "aborted" | "timeout" | "call_capture_failed" | "script_error";
|
|
47
|
-
message?: string | undefined;
|
|
48
|
-
resultRefs?: string[];
|
|
49
|
-
mode: string;
|
|
50
50
|
};
|
|
51
51
|
}>;
|
|
52
52
|
export {};
|
package/dist/mcp-code.js
CHANGED
|
@@ -122,7 +122,7 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
122
122
|
? Math.max(0, Date.now() - startedAt)
|
|
123
123
|
: operation.durationMs,
|
|
124
124
|
}));
|
|
125
|
-
|
|
125
|
+
const pendingOperations = new Set();
|
|
126
126
|
const resultRefs = new Set();
|
|
127
127
|
const payloadNotices = new Set();
|
|
128
128
|
const recordCall = async (path, dispatch) => {
|
|
@@ -149,11 +149,11 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
149
149
|
: textFromContent(result.content);
|
|
150
150
|
calls[index] = {
|
|
151
151
|
operation: "call", path, ok: false, error: errorCode, durationMs: Date.now() - startedAt, startedAt,
|
|
152
|
-
...(
|
|
152
|
+
...(details.recovery !== undefined ? { recovery: details.recovery } : {}),
|
|
153
153
|
};
|
|
154
154
|
if (errorCode === "call_capture_failed")
|
|
155
155
|
throw new McpScriptCaptureError(details.recovery, message);
|
|
156
|
-
if (
|
|
156
|
+
if (details.recovery !== undefined)
|
|
157
157
|
output.push({ type: "text", text: message });
|
|
158
158
|
return {
|
|
159
159
|
ok: false,
|
|
@@ -301,7 +301,7 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
301
301
|
reject(new Error(message.message));
|
|
302
302
|
return;
|
|
303
303
|
}
|
|
304
|
-
|
|
304
|
+
const operation = (async () => {
|
|
305
305
|
let envelope;
|
|
306
306
|
if (message.type === "call") {
|
|
307
307
|
envelope = await callTool(message.id, message.path, message.args, message.server);
|
|
@@ -332,7 +332,9 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
332
332
|
}
|
|
333
333
|
const response = { type: "result", id: message.id, envelope };
|
|
334
334
|
activeWorker.postMessage(response);
|
|
335
|
-
})()
|
|
335
|
+
})();
|
|
336
|
+
pendingOperations.add(operation);
|
|
337
|
+
void operation.catch(reject).finally(() => pendingOperations.delete(operation));
|
|
336
338
|
});
|
|
337
339
|
activeWorker.once("error", reject);
|
|
338
340
|
activeWorker.once("exit", (code) => {
|
|
@@ -345,7 +347,6 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
345
347
|
return;
|
|
346
348
|
const timeoutError = new McpScriptTimeoutError(resolvedTimeoutMs);
|
|
347
349
|
timer = setTimeout(() => {
|
|
348
|
-
callsSnapshot = snapshotCalls();
|
|
349
350
|
timeoutController.abort(timeoutError);
|
|
350
351
|
void activeWorker.terminate();
|
|
351
352
|
reject(timeoutError);
|
|
@@ -354,7 +355,6 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
354
355
|
const aborted = externalSignal
|
|
355
356
|
? new Promise((_resolve, reject) => {
|
|
356
357
|
const onAbort = () => {
|
|
357
|
-
callsSnapshot = snapshotCalls();
|
|
358
358
|
void activeWorker.terminate();
|
|
359
359
|
reject(abortReasonError(externalSignal.reason));
|
|
360
360
|
};
|
|
@@ -387,14 +387,15 @@ async function runMcpScriptOperation(state, code, timeoutMs = DEFAULT_MCP_SCRIPT
|
|
|
387
387
|
finally {
|
|
388
388
|
clearTimeout(timer);
|
|
389
389
|
removeAbortListener();
|
|
390
|
-
|
|
391
|
-
// (deadline, abort, or early return). Snapshot before aborting stragglers.
|
|
392
|
-
callsSnapshot ??= snapshotCalls();
|
|
390
|
+
worker?.removeAllListeners("message");
|
|
393
391
|
// A script may finish without awaiting every call; abort leftovers so
|
|
394
392
|
// parent-side dispatches do not outlive the script.
|
|
395
393
|
timeoutController.abort(new Error("mcp_script finished"));
|
|
394
|
+
// Let cancelled dispatches report whether an outcome is known before taking the trace.
|
|
395
|
+
await Promise.allSettled(pendingOperations);
|
|
396
396
|
await worker?.terminate();
|
|
397
397
|
}
|
|
398
|
+
const callsSnapshot = snapshotCalls();
|
|
398
399
|
// Snapshot before the asynchronous output guard; the terminated worker can no longer emit.
|
|
399
400
|
const guarded = await guardMcpOutput([...(output.length > 0 ? output : [{ type: "text", text: "(no output)" }]), ...[...payloadNotices].map(text => ({ type: "text", text })), ...[...resultRefs].map(ref => ({ type: "text", text: formatMcpResultReference(ref) }))], resolveMcpOutputGuardOptions(state.config.settings, state.outputDirectory));
|
|
400
401
|
return {
|
|
@@ -49,11 +49,6 @@ export interface McpOAuthCallbacks {
|
|
|
49
49
|
* Implements the OAuthClientProvider interface from the MCP SDK.
|
|
50
50
|
*/
|
|
51
51
|
export declare class McpOAuthProvider implements OAuthClientProvider {
|
|
52
|
-
private serverName;
|
|
53
|
-
private serverUrl;
|
|
54
|
-
private config;
|
|
55
|
-
private callbacks;
|
|
56
|
-
private storageOptions;
|
|
57
52
|
private readonly redirectUrlSnapshot;
|
|
58
53
|
readonly clientMetadataUrl?: string;
|
|
59
54
|
private readonly controller;
|
|
@@ -66,6 +61,11 @@ export declare class McpOAuthProvider implements OAuthClientProvider {
|
|
|
66
61
|
private flowDiscoveryState;
|
|
67
62
|
private flowIssuerMismatch;
|
|
68
63
|
private flowState;
|
|
64
|
+
private serverName;
|
|
65
|
+
private serverUrl;
|
|
66
|
+
private config;
|
|
67
|
+
private callbacks;
|
|
68
|
+
private storageOptions;
|
|
69
69
|
constructor(serverName: string, serverUrl: string, config: McpOAuthConfig, callbacks: McpOAuthCallbacks, storageOptions?: AuthStorageOptions, runtimeSignal?: AbortSignal, initialState?: string);
|
|
70
70
|
private get isNonInteractive();
|
|
71
71
|
private get discoveredIssuer();
|
|
@@ -152,11 +152,6 @@ function addAuthorizationParams(authorizationUrl, params) {
|
|
|
152
152
|
* Implements the OAuthClientProvider interface from the MCP SDK.
|
|
153
153
|
*/
|
|
154
154
|
export class McpOAuthProvider {
|
|
155
|
-
serverName;
|
|
156
|
-
serverUrl;
|
|
157
|
-
config;
|
|
158
|
-
callbacks;
|
|
159
|
-
storageOptions;
|
|
160
155
|
redirectUrlSnapshot;
|
|
161
156
|
clientMetadataUrl;
|
|
162
157
|
controller = new AbortController();
|
|
@@ -169,6 +164,11 @@ export class McpOAuthProvider {
|
|
|
169
164
|
flowDiscoveryState;
|
|
170
165
|
flowIssuerMismatch = false;
|
|
171
166
|
flowState;
|
|
167
|
+
serverName;
|
|
168
|
+
serverUrl;
|
|
169
|
+
config;
|
|
170
|
+
callbacks;
|
|
171
|
+
storageOptions;
|
|
172
172
|
constructor(serverName, serverUrl, config, callbacks, storageOptions = {}, runtimeSignal, initialState) {
|
|
173
173
|
this.serverName = serverName;
|
|
174
174
|
this.serverUrl = serverUrl;
|
|
@@ -94,11 +94,11 @@ export declare function readMcpResult(input: ReadMcpResultInput, options?: McpOu
|
|
|
94
94
|
text: string;
|
|
95
95
|
}[];
|
|
96
96
|
details: {
|
|
97
|
-
path?: string;
|
|
98
97
|
ref: string;
|
|
99
98
|
offset: number;
|
|
100
99
|
nextOffset: number | null;
|
|
101
100
|
totalCharacters: number;
|
|
101
|
+
path?: string;
|
|
102
102
|
error?: never;
|
|
103
103
|
message?: never;
|
|
104
104
|
};
|
package/dist/mcp-panel.d.ts
CHANGED
|
@@ -2,8 +2,6 @@ import { type PanelKeybindings } from "./panel-keys.ts";
|
|
|
2
2
|
import type { McpConfig, McpPanelCallbacks, McpPanelResult, ServerProvenance } from "./types.ts";
|
|
3
3
|
import { type MetadataCache } from "./metadata-cache.ts";
|
|
4
4
|
declare class McpPanel {
|
|
5
|
-
private callbacks;
|
|
6
|
-
private done;
|
|
7
5
|
private noticeLines;
|
|
8
6
|
private prefix;
|
|
9
7
|
private servers;
|
|
@@ -25,6 +23,8 @@ declare class McpPanel {
|
|
|
25
23
|
private keys;
|
|
26
24
|
private static readonly MAX_VISIBLE;
|
|
27
25
|
private static readonly INACTIVITY_MS;
|
|
26
|
+
private callbacks;
|
|
27
|
+
private done;
|
|
28
28
|
constructor(config: McpConfig, cache: MetadataCache | null, provenance: Map<string, ServerProvenance>, callbacks: McpPanelCallbacks, tui: {
|
|
29
29
|
requestRender(): void;
|
|
30
30
|
}, done: (result: McpPanelResult) => void, options?: {
|
package/dist/mcp-panel.js
CHANGED
|
@@ -93,8 +93,6 @@ function estimateTokens(tool) {
|
|
|
93
93
|
return Math.ceil((tool.name.length + descLen + schemaLen) / 4) + 10;
|
|
94
94
|
}
|
|
95
95
|
class McpPanel {
|
|
96
|
-
callbacks;
|
|
97
|
-
done;
|
|
98
96
|
noticeLines;
|
|
99
97
|
prefix;
|
|
100
98
|
servers = [];
|
|
@@ -116,6 +114,8 @@ class McpPanel {
|
|
|
116
114
|
keys;
|
|
117
115
|
static MAX_VISIBLE = 12;
|
|
118
116
|
static INACTIVITY_MS = 60_000;
|
|
117
|
+
callbacks;
|
|
118
|
+
done;
|
|
119
119
|
constructor(config, cache, provenance, callbacks, tui, done, options = {}) {
|
|
120
120
|
this.callbacks = callbacks;
|
|
121
121
|
this.done = done;
|
|
@@ -31,10 +31,6 @@ export interface SetupPanelOptions {
|
|
|
31
31
|
keybindings?: PanelKeybindings;
|
|
32
32
|
}
|
|
33
33
|
export declare class McpSetupPanel {
|
|
34
|
-
private discovery;
|
|
35
|
-
private callbacks;
|
|
36
|
-
private options;
|
|
37
|
-
private done;
|
|
38
34
|
private screen;
|
|
39
35
|
private actionCursor;
|
|
40
36
|
private importCursor;
|
|
@@ -47,6 +43,10 @@ export declare class McpSetupPanel {
|
|
|
47
43
|
private keys;
|
|
48
44
|
private inactivityTimeout;
|
|
49
45
|
private static readonly INACTIVITY_MS;
|
|
46
|
+
private discovery;
|
|
47
|
+
private callbacks;
|
|
48
|
+
private options;
|
|
49
|
+
private done;
|
|
50
50
|
constructor(discovery: McpDiscoverySummary, callbacks: SetupPanelCallbacks, options: SetupPanelOptions, tui: {
|
|
51
51
|
requestRender(): void;
|
|
52
52
|
}, done: () => void);
|
|
@@ -72,6 +72,7 @@ export declare class McpSetupPanel {
|
|
|
72
72
|
private previewWidth;
|
|
73
73
|
private getActionPreview;
|
|
74
74
|
private formatPreview;
|
|
75
|
+
private previewOrError;
|
|
75
76
|
private formatWritePreview;
|
|
76
77
|
private padLine;
|
|
77
78
|
invalidate(): void;
|
package/dist/mcp-setup-panel.js
CHANGED
|
@@ -38,10 +38,6 @@ function wrapText(text, width) {
|
|
|
38
38
|
return lines.length > 0 ? lines : [""];
|
|
39
39
|
}
|
|
40
40
|
export class McpSetupPanel {
|
|
41
|
-
discovery;
|
|
42
|
-
callbacks;
|
|
43
|
-
options;
|
|
44
|
-
done;
|
|
45
41
|
screen;
|
|
46
42
|
actionCursor = 0;
|
|
47
43
|
importCursor = 0;
|
|
@@ -54,6 +50,10 @@ export class McpSetupPanel {
|
|
|
54
50
|
keys;
|
|
55
51
|
inactivityTimeout = null;
|
|
56
52
|
static INACTIVITY_MS = 60_000;
|
|
53
|
+
discovery;
|
|
54
|
+
callbacks;
|
|
55
|
+
options;
|
|
56
|
+
done;
|
|
57
57
|
constructor(discovery, callbacks, options, tui, done) {
|
|
58
58
|
this.discovery = discovery;
|
|
59
59
|
this.callbacks = callbacks;
|
|
@@ -361,7 +361,7 @@ export class McpSetupPanel {
|
|
|
361
361
|
lines.push(this.padLine(fg(this.t.muted, `… ${actions.length - end} more below`), innerW));
|
|
362
362
|
}
|
|
363
363
|
lines.push(this.padLine("", innerW));
|
|
364
|
-
const preview = this.getActionPreview(this.getSelectedAction(),
|
|
364
|
+
const preview = this.previewOrError(width => this.getActionPreview(this.getSelectedAction(), width), innerW);
|
|
365
365
|
for (const line of preview) {
|
|
366
366
|
lines.push(this.padLine(line, innerW));
|
|
367
367
|
}
|
|
@@ -384,8 +384,7 @@ export class McpSetupPanel {
|
|
|
384
384
|
}
|
|
385
385
|
lines.push(this.padLine("", innerW));
|
|
386
386
|
const selected = this.discovery.imports.filter((entry) => this.selectedImports.has(entry.kind)).map((entry) => entry.kind);
|
|
387
|
-
const
|
|
388
|
-
for (const line of this.formatWritePreview("Compatibility import write preview", preview, [], this.previewWidth(innerW))) {
|
|
387
|
+
for (const line of this.previewOrError(width => this.formatWritePreview("Compatibility import write preview", this.callbacks.previewImports(selected), [], width), innerW)) {
|
|
389
388
|
lines.push(this.padLine(line, innerW));
|
|
390
389
|
}
|
|
391
390
|
return lines;
|
|
@@ -522,6 +521,15 @@ export class McpSetupPanel {
|
|
|
522
521
|
}
|
|
523
522
|
return preview;
|
|
524
523
|
}
|
|
524
|
+
previewOrError(preview, innerW) {
|
|
525
|
+
const width = this.previewWidth(innerW);
|
|
526
|
+
try {
|
|
527
|
+
return preview(width);
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
return this.formatPreview([`Cannot preview write: ${error instanceof Error ? error.message : String(error)}`], width);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
525
533
|
formatWritePreview(title, preview, intro = [], width = DESKTOP_PREVIEW_WIDTH) {
|
|
526
534
|
const lines = [];
|
|
527
535
|
for (const line of intro) {
|
package/dist/mcp-trace.d.ts
CHANGED
|
@@ -52,7 +52,6 @@ export declare function createMcpTraceEvent(direction: McpTraceDirection, server
|
|
|
52
52
|
durationMs?: number;
|
|
53
53
|
}): McpTraceEvent;
|
|
54
54
|
export declare class McpTraceWriter {
|
|
55
|
-
private readonly options;
|
|
56
55
|
private readonly maxBytes;
|
|
57
56
|
private readonly maxEvents;
|
|
58
57
|
private readonly append;
|
|
@@ -65,6 +64,7 @@ export declare class McpTraceWriter {
|
|
|
65
64
|
private initializationFailed;
|
|
66
65
|
private persistenceError;
|
|
67
66
|
private readonly fileReady;
|
|
67
|
+
private readonly options;
|
|
68
68
|
constructor(options: McpTraceWriterOptions);
|
|
69
69
|
get filePath(): string;
|
|
70
70
|
get isDisabled(): boolean;
|
package/dist/mcp-trace.js
CHANGED
|
@@ -73,7 +73,6 @@ export function createMcpTraceEvent(direction, server, transport, message, statu
|
|
|
73
73
|
return event;
|
|
74
74
|
}
|
|
75
75
|
export class McpTraceWriter {
|
|
76
|
-
options;
|
|
77
76
|
maxBytes;
|
|
78
77
|
maxEvents;
|
|
79
78
|
append;
|
|
@@ -86,6 +85,7 @@ export class McpTraceWriter {
|
|
|
86
85
|
initializationFailed = false;
|
|
87
86
|
persistenceError;
|
|
88
87
|
fileReady;
|
|
88
|
+
options;
|
|
89
89
|
constructor(options) {
|
|
90
90
|
this.options = options;
|
|
91
91
|
this.maxBytes = boundedPositiveInteger(options.maxBytes, DEFAULT_MCP_TRACE_MAX_BYTES);
|
package/dist/npx-resolver.js
CHANGED
|
@@ -17,13 +17,15 @@ export async function resolveNpxBinary(command, args, signal) {
|
|
|
17
17
|
if (!parsed)
|
|
18
18
|
return null;
|
|
19
19
|
const packageSpec = parsePackageSpec(parsed.packageSpec);
|
|
20
|
+
if (!packageSpec)
|
|
21
|
+
return null;
|
|
20
22
|
const cacheKey = JSON.stringify([command, ...args]);
|
|
21
23
|
const cache = loadCache();
|
|
22
24
|
const cached = cache?.entries?.[cacheKey];
|
|
23
25
|
if (cached
|
|
24
26
|
&& Date.now() - cached.resolvedAt < CACHE_TTL_MS
|
|
25
27
|
&& existsSync(cached.resolvedBin)
|
|
26
|
-
&& (!packageSpec
|
|
28
|
+
&& (!packageSpec.exactVersion || cached.packageVersion === packageSpec.exactVersion)) {
|
|
27
29
|
return { binPath: cached.resolvedBin, extraArgs: parsed.extraArgs, isJs: cached.isJs };
|
|
28
30
|
}
|
|
29
31
|
const resolved = resolveFromNpmCache(parsed.packageSpec, parsed.binName);
|
|
@@ -289,11 +291,13 @@ function parsePackageSpec(spec) {
|
|
|
289
291
|
if (!packageName)
|
|
290
292
|
return null;
|
|
291
293
|
const normalizedVersion = requestedVersion?.replace(/^=/, "").replace(/^v/i, "");
|
|
294
|
+
// Let npm resolve ranges and tags rather than choosing an arbitrary cached version.
|
|
295
|
+
if (requestedVersion !== undefined && (!normalizedVersion || !EXACT_PACKAGE_VERSION_RE.test(normalizedVersion))) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
292
298
|
return {
|
|
293
299
|
packageName,
|
|
294
|
-
...(normalizedVersion
|
|
295
|
-
? { exactVersion: normalizedVersion }
|
|
296
|
-
: {}),
|
|
300
|
+
...(normalizedVersion ? { exactVersion: normalizedVersion } : {}),
|
|
297
301
|
};
|
|
298
302
|
}
|
|
299
303
|
function defaultBinName(packageName) {
|
package/dist/proxy-modes.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare function executeStatus(state: McpExtensionState): ProxyToolResult
|
|
|
9
9
|
export declare function executeAuthStart(state: McpExtensionState, serverName: string, signal?: AbortSignal): Promise<ProxyToolResult>;
|
|
10
10
|
export declare function executeAuthComplete(state: McpExtensionState, serverName: string, input?: string, signal?: AbortSignal): Promise<ProxyToolResult>;
|
|
11
11
|
export declare function executeDescribe(state: McpExtensionState, toolName: string, serverFilter?: string): ProxyToolResult;
|
|
12
|
-
export declare function executeSearch(state: McpExtensionState, query: string, server?: string, includeSchemas?: boolean, limit?: number, offset?: number): ProxyToolResult;
|
|
12
|
+
export declare function executeSearch(state: McpExtensionState, query: string, server?: string, includeSchemas?: boolean, limit?: number, offset?: number, caller?: "mcp" | "mcp_search"): ProxyToolResult;
|
|
13
13
|
export declare function executeList(state: McpExtensionState, server: string, limit?: number, offset?: number): ProxyToolResult;
|
|
14
14
|
export declare function executeInstructions(state: McpExtensionState, server: string): ProxyToolResult;
|
|
15
15
|
export declare function executeConnect(state: McpExtensionState, serverName: string, signal?: AbortSignal, limit?: number, offset?: number): Promise<ProxyToolResult>;
|
|
@@ -63,10 +63,10 @@ export declare function prepareMcpConnection(state: McpExtensionState, serverNam
|
|
|
63
63
|
recoverAuthConnection?: never;
|
|
64
64
|
autoAuthAttempted?: never;
|
|
65
65
|
} | {
|
|
66
|
+
error?: never;
|
|
66
67
|
connection: ServerConnection;
|
|
67
68
|
recoverAuthConnection: (serverName: string, signal?: AbortSignal, challenge?: import("./session-recovery.ts").AuthChallengeContext) => Promise<ServerConnection | undefined>;
|
|
68
69
|
autoAuthAttempted: () => boolean;
|
|
69
|
-
error?: never;
|
|
70
70
|
}>;
|
|
71
71
|
export declare function executeCall(state: McpExtensionState, toolName: string, args?: Record<string, unknown>, serverOverride?: string, getPiTools?: () => ToolInfo[], signal?: AbortSignal, identity?: McpToolCallIdentity, beforeDispatch?: (signal: AbortSignal | undefined, operation: McpOperationContext) => Promise<void>, options?: ExecuteCallOptions): Promise<ProxyToolResult>;
|
|
72
72
|
export {};
|