pi-mcp-adapter 3.3.0 → 5.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 +95 -1
- package/README.md +78 -974
- package/cli.js +210 -0
- package/commands.ts +55 -4
- package/config.ts +308 -33
- package/direct-tool-surface.ts +9 -7
- package/direct-tools.ts +43 -29
- package/dist/config.d.ts +15 -4
- package/dist/config.js +317 -30
- package/dist/config.js.map +1 -1
- package/dist/elicitation-handler.d.ts +4 -0
- package/dist/elicitation-handler.js +14 -1
- package/dist/elicitation-handler.js.map +1 -1
- package/dist/mcp-auth-flow.d.ts +2 -0
- package/dist/mcp-auth-flow.js +12 -3
- package/dist/mcp-auth-flow.js.map +1 -1
- package/dist/mcp-auth.js +3 -1
- package/dist/mcp-auth.js.map +1 -1
- package/dist/metadata-cache.d.ts +15 -1
- package/dist/metadata-cache.js +76 -8
- package/dist/metadata-cache.js.map +1 -1
- package/dist/output-shape.d.ts +18 -5
- package/dist/output-shape.js +162 -18
- package/dist/output-shape.js.map +1 -1
- package/dist/package-mcp-loader.js +9 -5
- package/dist/package-mcp-loader.js.map +1 -1
- package/dist/project-server-trust.d.ts +17 -0
- package/dist/project-server-trust.js +209 -0
- package/dist/project-server-trust.js.map +1 -0
- package/dist/server-manager.d.ts +5 -0
- package/dist/server-manager.js +98 -26
- package/dist/server-manager.js.map +1 -1
- package/dist/session-recovery.js +4 -3
- package/dist/session-recovery.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/dist/types.d.ts +29 -2
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +5 -1
- package/dist/utils.js +16 -0
- package/dist/utils.js.map +1 -1
- package/{OAUTH.md → docs/auth.md} +66 -11
- package/docs/configuration.md +221 -0
- package/docs/extension-api.md +246 -0
- package/docs/pi-builtin-comparison.md +113 -0
- package/docs/prompts-and-ui.md +84 -0
- package/docs/scripting.md +131 -0
- package/docs/servers.md +142 -0
- package/docs/tools.md +259 -0
- package/elicitation-handler.ts +13 -1
- package/index.ts +268 -37
- package/init.ts +97 -46
- package/mcp-auth-flow.ts +13 -2
- package/mcp-auth.ts +3 -1
- package/mcp-code.ts +125 -77
- package/mcp-output-guard.ts +24 -5
- package/mcp-panel.ts +52 -4
- package/mcp-script-worker.mjs +6 -2
- package/mcp-setup-panel.ts +587 -303
- package/metadata-cache.ts +79 -8
- package/onboarding-state.ts +20 -0
- package/output-shape.ts +161 -22
- package/package-mcp-loader.ts +8 -5
- package/package.json +8 -6
- package/pi-builtin-mcp.ts +32 -0
- package/pi-signin-import.ts +147 -0
- package/project-server-trust.ts +8 -4
- package/prompts.ts +11 -3
- package/proxy-modes.ts +163 -138
- package/search-ranking.ts +12 -3
- package/server-manager.ts +101 -24
- package/session-recovery.ts +4 -3
- package/skills/mcp-scripting/SKILL.md +24 -30
- package/skills/mcp-scripting/references/jev.md +3 -0
- package/state.ts +2 -0
- package/types.ts +18 -2
- package/ui-server.ts +34 -32
- package/utils.ts +16 -1
package/direct-tools.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { describeFailure } from "./failure-backoff.ts";
|
|
|
8
8
|
import { abortable, throwIfAborted } from "./abort.ts";
|
|
9
9
|
import { formatSchema } from "./tool-metadata.ts";
|
|
10
10
|
import { resolveMcpResultContent, transformMcpResourceContents } from "./tool-registrar.ts";
|
|
11
|
-
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions } from "./mcp-output-guard.ts";
|
|
11
|
+
import { guardMcpOutput, guardedMcpDetails, resolveMcpOutputGuardOptions, scriptPipeHint } from "./mcp-output-guard.ts";
|
|
12
12
|
import { maybeStartUiSession, summarizeUiSessionResult, type UiSessionRuntime } from "./ui-session.ts";
|
|
13
13
|
import { isServerDisabled } from "./types.ts";
|
|
14
14
|
import { authenticate, supportsOAuth } from "./mcp-auth-flow.ts";
|
|
@@ -17,8 +17,8 @@ import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session
|
|
|
17
17
|
import { combineAbortSignals, isAbortError } from "./runtime-owner.ts";
|
|
18
18
|
import { callToolViaTaskSession } from "./mcp-tasks.ts";
|
|
19
19
|
import { callToolPausingForElicitation } from "./elicitation-handler.ts";
|
|
20
|
-
import {
|
|
21
|
-
import { ensureToolCallApproved } from "./tool-approval.ts";
|
|
20
|
+
import { observedOutputRecorder } from "./output-shape.ts";
|
|
21
|
+
import { ensureToolCallApproved, type ToolCallApprovalResult } from "./tool-approval.ts";
|
|
22
22
|
import { getInputRequiredNeedsUiDetails } from "./errors.ts";
|
|
23
23
|
|
|
24
24
|
type ClientCallToolResult = Awaited<ReturnType<Client["callTool"]>>;
|
|
@@ -129,8 +129,13 @@ type DirectToolExecute = (
|
|
|
129
129
|
export function createDirectToolExecutor(
|
|
130
130
|
getState: () => McpExtensionState | null,
|
|
131
131
|
getInitPromise: () => Promise<McpExtensionState> | null,
|
|
132
|
-
spec: DirectToolSpec
|
|
132
|
+
spec: DirectToolSpec,
|
|
133
|
+
// Deferred tools (Pi 0.99+) keep the server's structuredContent.
|
|
134
|
+
structured = false,
|
|
133
135
|
): DirectToolExecute {
|
|
136
|
+
const structuredContentOf = (result: ClientCallToolResult) => structured && result.structuredContent !== undefined
|
|
137
|
+
? { structuredContent: result.structuredContent as NonNullable<AgentToolResult["structuredContent"]> }
|
|
138
|
+
: {};
|
|
134
139
|
return async function execute(toolCallId, params, signal) {
|
|
135
140
|
throwIfAborted(signal);
|
|
136
141
|
let state = getState();
|
|
@@ -213,30 +218,6 @@ export function createDirectToolExecutor(
|
|
|
213
218
|
const annotations = spec.resourceUri
|
|
214
219
|
? undefined
|
|
215
220
|
: state.toolMetadata.get(spec.serverName)?.find(tool => !tool.resourceUri && tool.originalName === spec.originalName)?.annotations;
|
|
216
|
-
const approval = await ensureToolCallApproved(state, spec.serverName, {
|
|
217
|
-
name: spec.prefixedName,
|
|
218
|
-
originalName: spec.originalName,
|
|
219
|
-
description: spec.description,
|
|
220
|
-
...(spec.inputSchema !== undefined ? { inputSchema: spec.inputSchema } : {}),
|
|
221
|
-
...(spec.resourceUri !== undefined ? { resourceUri: spec.resourceUri } : {}),
|
|
222
|
-
...(spec.uiResourceUri !== undefined ? { uiResourceUri: spec.uiResourceUri } : {}),
|
|
223
|
-
...(spec.uiStreamMode !== undefined ? { uiStreamMode: spec.uiStreamMode } : {}),
|
|
224
|
-
...(annotations !== undefined ? { annotations } : {}),
|
|
225
|
-
}, normalizedParams, ownedSignal, spec.resourceUri ? "resource" : "direct");
|
|
226
|
-
if (approval.ok === false) {
|
|
227
|
-
const denied = approval.reason === "denied";
|
|
228
|
-
const message = denied
|
|
229
|
-
? `The user declined approval to run MCP tool "${spec.originalName}" on server "${spec.serverName}".`
|
|
230
|
-
: `MCP tool "${spec.originalName}" on server "${spec.serverName}" is approval-gated and requires an interactive session.`;
|
|
231
|
-
return {
|
|
232
|
-
content: [{ type: "text" as const, text: message }],
|
|
233
|
-
details: {
|
|
234
|
-
error: denied ? "approval_denied" : "approval_required",
|
|
235
|
-
server: spec.serverName,
|
|
236
|
-
tool: spec.originalName,
|
|
237
|
-
},
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
221
|
|
|
241
222
|
let uiSession: UiSessionRuntime | null = null;
|
|
242
223
|
const requestOptions = state.manager.getRequestOptions?.(spec.serverName, ownedSignal) ?? (ownedSignal ? { signal: ownedSignal } : undefined);
|
|
@@ -266,9 +247,35 @@ export function createDirectToolExecutor(
|
|
|
266
247
|
return state.manager.getConnection(spec.serverName);
|
|
267
248
|
};
|
|
268
249
|
|
|
250
|
+
let approval: ToolCallApprovalResult | undefined;
|
|
269
251
|
try {
|
|
252
|
+
// In flight from here so an idle check cannot close the server while the approval dialog is open.
|
|
270
253
|
state.manager.touch(spec.serverName);
|
|
271
254
|
state.manager.incrementInFlight(spec.serverName);
|
|
255
|
+
approval = await ensureToolCallApproved(state, spec.serverName, {
|
|
256
|
+
name: spec.prefixedName,
|
|
257
|
+
originalName: spec.originalName,
|
|
258
|
+
description: spec.description,
|
|
259
|
+
...(spec.inputSchema !== undefined ? { inputSchema: spec.inputSchema } : {}),
|
|
260
|
+
...(spec.resourceUri !== undefined ? { resourceUri: spec.resourceUri } : {}),
|
|
261
|
+
...(spec.uiResourceUri !== undefined ? { uiResourceUri: spec.uiResourceUri } : {}),
|
|
262
|
+
...(spec.uiStreamMode !== undefined ? { uiStreamMode: spec.uiStreamMode } : {}),
|
|
263
|
+
...(annotations !== undefined ? { annotations } : {}),
|
|
264
|
+
}, normalizedParams, ownedSignal, spec.resourceUri ? "resource" : "direct");
|
|
265
|
+
if (approval.ok === false) {
|
|
266
|
+
const denied = approval.reason === "denied";
|
|
267
|
+
const message = denied
|
|
268
|
+
? `The user declined approval to run MCP tool "${spec.originalName}" on server "${spec.serverName}".`
|
|
269
|
+
: `MCP tool "${spec.originalName}" on server "${spec.serverName}" is approval-gated and requires an interactive session.`;
|
|
270
|
+
return {
|
|
271
|
+
content: [{ type: "text" as const, text: message }],
|
|
272
|
+
details: {
|
|
273
|
+
error: denied ? "approval_denied" : "approval_required",
|
|
274
|
+
server: spec.serverName,
|
|
275
|
+
tool: spec.originalName,
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
272
279
|
|
|
273
280
|
if (spec.resourceUri) {
|
|
274
281
|
const result = await withSessionRecovery<ClientReadResourceResult>(
|
|
@@ -312,6 +319,7 @@ export function createDirectToolExecutor(
|
|
|
312
319
|
: null;
|
|
313
320
|
|
|
314
321
|
const requestMeta = withToolCallIdMeta(uiSession?.requestMeta, toolCallId);
|
|
322
|
+
const recordOutput = observedOutputRecorder(state, spec.serverName, spec.originalName);
|
|
315
323
|
const result = await withSessionRecovery<ClientCallToolResult>(
|
|
316
324
|
{
|
|
317
325
|
manager: state.manager,
|
|
@@ -339,7 +347,7 @@ export function createDirectToolExecutor(
|
|
|
339
347
|
},
|
|
340
348
|
);
|
|
341
349
|
uiSession?.sendToolResult(result as unknown as import("@modelcontextprotocol/client").CallToolResult);
|
|
342
|
-
if (!result.isError)
|
|
350
|
+
if (!result.isError) recordOutput(result as Record<string, unknown>);
|
|
343
351
|
|
|
344
352
|
if (result.isError) {
|
|
345
353
|
const content = resolveMcpResultContent(result as Record<string, unknown>, state.owner?.signal);
|
|
@@ -353,6 +361,7 @@ export function createDirectToolExecutor(
|
|
|
353
361
|
return {
|
|
354
362
|
content: guarded.content,
|
|
355
363
|
details: { error: "tool_error", server: spec.serverName, ...guardedMcpDetails(guarded) },
|
|
364
|
+
...structuredContentOf(result),
|
|
356
365
|
};
|
|
357
366
|
}
|
|
358
367
|
|
|
@@ -375,18 +384,23 @@ export function createDirectToolExecutor(
|
|
|
375
384
|
uiUrl: uiSummary.uiUrl,
|
|
376
385
|
...guardedMcpDetails(guarded),
|
|
377
386
|
},
|
|
387
|
+
...structuredContentOf(result),
|
|
378
388
|
};
|
|
379
389
|
}
|
|
380
390
|
|
|
381
391
|
const guarded = await guardMcpOutput(outputContent, {
|
|
382
392
|
...outputGuardOptions,
|
|
393
|
+
...scriptPipeHint(state.scriptTool, outputContent),
|
|
383
394
|
...(state.config.settings?.directToolResultDetails === "bounded" ? { rawMcpResult: result } : {}),
|
|
384
395
|
});
|
|
385
396
|
return {
|
|
386
397
|
content: guarded.content,
|
|
387
398
|
details: { server: spec.serverName, tool: spec.originalName, ...guardedMcpDetails(guarded) },
|
|
399
|
+
...structuredContentOf(result),
|
|
388
400
|
};
|
|
389
401
|
} catch (error) {
|
|
402
|
+
// Approval errors, such as an abort while the dialog is open, propagate unchanged.
|
|
403
|
+
if (!approval) throw error;
|
|
390
404
|
if (error instanceof SessionRecoveryAuthRequiredError) {
|
|
391
405
|
const message = error.authMessage ?? getDirectAuthRequiredMessage(state, spec.serverName);
|
|
392
406
|
uiSession?.sendToolCancelled(message);
|
package/dist/config.d.ts
CHANGED
|
@@ -5,10 +5,15 @@ export interface KnownServerPreset {
|
|
|
5
5
|
name: string;
|
|
6
6
|
summary: string;
|
|
7
7
|
entry: ServerEntry;
|
|
8
|
+
/** Offered only when one of these app paths exists; the local server is probed after adding. */
|
|
9
|
+
desktopApp?: {
|
|
10
|
+
paths: readonly string[];
|
|
11
|
+
enableSteps: string;
|
|
12
|
+
};
|
|
8
13
|
}
|
|
9
14
|
export declare const KNOWN_SERVER_PRESETS: readonly KnownServerPreset[];
|
|
10
15
|
interface ConfigSourceSpec {
|
|
11
|
-
id: "shared-global" | "agents-global" | "agents-nested-global" | "pi-global" | "shared-project-ancestor" | "pi-project-ancestor" | "shared-project" | "pi-project";
|
|
16
|
+
id: "shared-global" | "agents-global" | "agents-nested-global" | "pi-mcp-global" | "pi-global" | "shared-project-ancestor" | "pi-project-ancestor" | "shared-project" | "pi-mcp-project" | "pi-project";
|
|
12
17
|
label: string;
|
|
13
18
|
readPath: string;
|
|
14
19
|
writePath: string;
|
|
@@ -71,6 +76,7 @@ export interface McpDiscoverySummary {
|
|
|
71
76
|
totalServerCount: number;
|
|
72
77
|
fingerprint: string;
|
|
73
78
|
repoPrompt: RepoPromptDiscovery;
|
|
79
|
+
knownServerPresets: readonly KnownServerPreset[];
|
|
74
80
|
}
|
|
75
81
|
export interface McpStandardConfigSummary {
|
|
76
82
|
sources: ConfigDiscoverySource[];
|
|
@@ -87,12 +93,12 @@ export interface ConfigWritePreview {
|
|
|
87
93
|
}
|
|
88
94
|
export type SharedConfigTarget = "project" | "global";
|
|
89
95
|
export declare function getPiGlobalConfigPath(overridePath?: string): string;
|
|
90
|
-
export declare function
|
|
96
|
+
export declare function getPiMcpGlobalConfigPath(): string;
|
|
91
97
|
export declare function getGenericGlobalConfigPath(): string;
|
|
92
98
|
export declare function getProjectConfigPath(cwd?: string): string;
|
|
93
99
|
export declare function getProjectPiConfigPath(cwd?: string): string;
|
|
94
|
-
export declare function
|
|
95
|
-
export declare function getLegacyMcpMigrationNotices(cwd?: string, overridePath?: string
|
|
100
|
+
export declare function getProjectPiMcpConfigPath(cwd?: string): string;
|
|
101
|
+
export declare function getLegacyMcpMigrationNotices(cwd?: string, overridePath?: string): string[];
|
|
96
102
|
export declare function getSharedConfigPath(target: SharedConfigTarget, cwd?: string): string;
|
|
97
103
|
export declare function getConfigDiscoveryPaths(overridePath?: string, cwd?: string): ConfigDiscoveryPath[];
|
|
98
104
|
export declare function findAvailableImportConfigs(cwd?: string): DiscoveredImportConfig[];
|
|
@@ -114,6 +120,11 @@ export declare function loadMcpConfig(overridePath?: string, cwd?: string): McpC
|
|
|
114
120
|
export declare function loadMcpConfigWithSources(overridePath?: string, cwd?: string): LoadedMcpConfig;
|
|
115
121
|
export declare function resolveConfiguredClaudePluginMcp(config: McpConfig, cwd?: string): McpConfig;
|
|
116
122
|
export declare function discoverConfiguredClaudePluginSkills(config: McpConfig, cwd?: string): string[];
|
|
123
|
+
/** Returns why the entry is skipped when Pi would reject it or the adapter can't run it. */
|
|
124
|
+
export declare function translatePiMcpServer(name: string, value: unknown): {
|
|
125
|
+
entry: ServerEntry;
|
|
126
|
+
ignored: string[];
|
|
127
|
+
} | string;
|
|
117
128
|
export declare function writeSharedConfigText(filePath: string, text: string): void;
|
|
118
129
|
export declare function writeJevSemanticSearchConfig(overridePath: string | undefined, cwd: string, allowedServers: string[], effectiveJev?: unknown): {
|
|
119
130
|
path: string;
|