@fitchmultz/pi-mcp-adapter 5.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 +50 -0
- package/OAUTH.md +3 -3
- package/README.md +160 -88
- package/dist/app-bridge.bundle.js +75 -33
- package/dist/commands.js +9 -6
- package/dist/config.js +41 -16
- package/dist/direct-tools.d.ts +2 -4
- package/dist/direct-tools.js +21 -319
- package/dist/gateway-arguments.d.ts +33 -0
- package/dist/gateway-arguments.js +63 -0
- package/dist/index.js +181 -276
- package/dist/init.js +6 -20
- 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 +7 -6
- package/dist/mcp-code.js +98 -51
- package/dist/mcp-oauth-provider.d.ts +5 -5
- package/dist/mcp-oauth-provider.js +5 -5
- package/dist/mcp-output-guard.d.ts +57 -2
- package/dist/mcp-output-guard.js +129 -24
- package/dist/mcp-panel.d.ts +3 -3
- package/dist/mcp-panel.js +36 -99
- package/dist/mcp-script-worker.mjs +5 -2
- package/dist/mcp-setup-panel.d.ts +5 -4
- package/dist/mcp-setup-panel.js +15 -7
- package/dist/mcp-status.js +2 -1
- package/dist/mcp-trace.d.ts +1 -1
- package/dist/mcp-trace.js +1 -1
- package/dist/metadata-cache.d.ts +1 -1
- package/dist/metadata-cache.js +25 -88
- package/dist/npx-resolver.js +8 -4
- package/dist/prompts.d.ts +1 -1
- package/dist/prompts.js +1 -1
- package/dist/proxy-modes.d.ts +41 -7
- package/dist/proxy-modes.js +275 -490
- package/dist/resource-tools.d.ts +15 -0
- package/dist/resource-tools.js +26 -1
- package/dist/sampling-handler.js +5 -1
- package/dist/search-ranking.d.ts +0 -2
- package/dist/search-ranking.js +70 -137
- 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/state.d.ts +1 -1
- package/dist/tool-loader.d.ts +32 -0
- package/dist/tool-loader.js +152 -0
- package/dist/tool-metadata.d.ts +67 -0
- package/dist/tool-metadata.js +23 -17
- package/dist/tool-registrar.d.ts +4 -4
- package/dist/tool-registrar.js +18 -13
- package/dist/tool-result-renderer.d.ts +6 -3
- package/dist/tool-result-renderer.js +11 -6
- package/dist/types.d.ts +11 -36
- 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 +16 -4
- package/package.json +37 -96
- package/skills/mcp-scripting/SKILL.md +67 -20
- package/abort.ts +0 -34
- package/agent-dir.ts +0 -24
- package/app-bridge.bundle.js +0 -67
- package/banner.png +0 -0
- package/checkpoint.ts +0 -55
- package/commands.ts +0 -619
- package/config.ts +0 -1204
- package/consent-manager.ts +0 -25
- package/direct-tools.ts +0 -408
- package/dist/ts-shape.d.ts +0 -2
- package/dist/ts-shape.js +0 -147
- package/elicitation-handler.ts +0 -349
- package/error-signal.ts +0 -21
- package/glimpse-ui.ts +0 -80
- package/host-html-template.ts +0 -456
- package/index.ts +0 -900
- package/init.ts +0 -627
- 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 -386
- package/mcp-keyring-helper.cjs +0 -89
- package/mcp-oauth-provider.ts +0 -774
- package/mcp-output-guard.ts +0 -412
- package/mcp-panel.ts +0 -978
- package/mcp-script-worker.mjs +0 -128
- package/mcp-setup-panel.ts +0 -666
- package/mcp-status.ts +0 -109
- package/mcp-trace.ts +0 -295
- package/metadata-cache.ts +0 -333
- 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 -1361
- package/resource-tools.ts +0 -17
- package/runtime-owner.ts +0 -123
- package/sampling-handler.ts +0 -273
- package/scripts/build.mjs +0 -131
- package/scripts/prepare.mjs +0 -102
- package/search-ranking.ts +0 -196
- 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-metadata.ts +0 -235
- package/tool-registrar.ts +0 -69
- package/tool-result-renderer.ts +0 -286
- package/ts-shape.ts +0 -145
- package/tsconfig.build.json +0 -13
- package/tsconfig.json +0 -16
- package/types.ts +0 -810
- 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 -309
package/dist/types.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface McpServerStatusSnapshot {
|
|
|
13
13
|
readonly name: string;
|
|
14
14
|
readonly status: McpServerRuntimeStatus;
|
|
15
15
|
readonly toolCount: number;
|
|
16
|
+
/** False means the server has not been discovered, rather than an empty inventory. */
|
|
17
|
+
readonly catalogKnown?: boolean;
|
|
16
18
|
readonly resourceCount?: number;
|
|
17
19
|
readonly failedAgoSeconds?: number;
|
|
18
20
|
readonly disabled: boolean;
|
|
@@ -30,21 +32,10 @@ type SdkTool = ListToolsResult["tools"][number];
|
|
|
30
32
|
type SdkResource = ListResourcesResult["resources"][number];
|
|
31
33
|
type SdkPrompt = ListPromptsResult["prompts"][number];
|
|
32
34
|
type SdkPromptArgument = NonNullable<SdkPrompt["arguments"]>[number];
|
|
33
|
-
export interface McpTool {
|
|
34
|
-
name: SdkTool["name"];
|
|
35
|
-
title?: SdkTool["title"];
|
|
36
|
-
description?: SdkTool["description"];
|
|
35
|
+
export interface McpTool extends Omit<SdkTool, "inputSchema"> {
|
|
37
36
|
inputSchema?: SdkTool["inputSchema"];
|
|
38
|
-
annotations?: SdkTool["annotations"];
|
|
39
|
-
_meta?: SdkTool["_meta"];
|
|
40
|
-
}
|
|
41
|
-
export interface McpResource {
|
|
42
|
-
uri: SdkResource["uri"];
|
|
43
|
-
name: SdkResource["name"];
|
|
44
|
-
description?: SdkResource["description"];
|
|
45
|
-
mimeType?: SdkResource["mimeType"];
|
|
46
|
-
_meta?: SdkResource["_meta"];
|
|
47
37
|
}
|
|
38
|
+
export type McpResource = SdkResource;
|
|
48
39
|
export interface McpPromptArgument {
|
|
49
40
|
name: SdkPromptArgument["name"];
|
|
50
41
|
description?: SdkPromptArgument["description"];
|
|
@@ -327,7 +318,7 @@ export interface McpSettings {
|
|
|
327
318
|
/** Freeze direct-tool registration after the initial sync. Automatic metadata updates
|
|
328
319
|
* (reconnects, lazy-connect, tool-list-changed) won't rebuild the system prompt,
|
|
329
320
|
* preserving the prompt-cache prefix. The agent rediscovers explicitly via
|
|
330
|
-
* mcp({ connect: "server" }). Default: false. */
|
|
321
|
+
* mcp({ action: "connect", server: "server" }). Default: false. */
|
|
331
322
|
freezeDirectTools?: boolean;
|
|
332
323
|
autoAuth?: boolean;
|
|
333
324
|
sampling?: boolean;
|
|
@@ -411,15 +402,14 @@ export interface McpAdapterOptions {
|
|
|
411
402
|
onToolCall?: (event: McpToolCallEvent) => Promise<void>;
|
|
412
403
|
}
|
|
413
404
|
export type ServerDefinition = ServerEntry;
|
|
414
|
-
export interface ToolMetadata {
|
|
405
|
+
export interface ToolMetadata extends Omit<McpTool, "name" | "description"> {
|
|
415
406
|
name: string;
|
|
416
407
|
originalName: string;
|
|
417
408
|
description: string;
|
|
418
409
|
resourceUri?: string;
|
|
410
|
+
resourceDescriptor?: McpResource;
|
|
419
411
|
uiResourceUri?: string;
|
|
420
412
|
uiVisibility?: UiToolVisibility[];
|
|
421
|
-
inputSchema?: unknown;
|
|
422
|
-
annotations?: McpTool["annotations"];
|
|
423
413
|
uiStreamMode?: UiStreamMode;
|
|
424
414
|
}
|
|
425
415
|
export interface PromptMetadata {
|
|
@@ -430,16 +420,9 @@ export interface PromptMetadata {
|
|
|
430
420
|
description: string;
|
|
431
421
|
arguments: McpPromptArgument[];
|
|
432
422
|
}
|
|
433
|
-
export interface DirectToolSpec {
|
|
423
|
+
export interface DirectToolSpec extends Omit<ToolMetadata, "name"> {
|
|
434
424
|
serverName: string;
|
|
435
|
-
originalName: string;
|
|
436
425
|
prefixedName: string;
|
|
437
|
-
description: string;
|
|
438
|
-
inputSchema?: unknown;
|
|
439
|
-
annotations?: McpTool["annotations"];
|
|
440
|
-
resourceUri?: string;
|
|
441
|
-
uiResourceUri?: string;
|
|
442
|
-
uiStreamMode?: UiStreamMode;
|
|
443
426
|
}
|
|
444
427
|
export interface ServerProvenance {
|
|
445
428
|
path: string;
|
|
@@ -450,20 +433,12 @@ export interface McpAuthResult {
|
|
|
450
433
|
ok: boolean;
|
|
451
434
|
message?: string;
|
|
452
435
|
}
|
|
453
|
-
export interface CachedTool {
|
|
454
|
-
name: string;
|
|
455
|
-
description?: string;
|
|
456
|
-
inputSchema?: unknown;
|
|
457
|
-
annotations?: McpTool["annotations"];
|
|
436
|
+
export interface CachedTool extends McpTool {
|
|
458
437
|
uiResourceUri?: string;
|
|
459
438
|
uiVisibility?: UiToolVisibility[];
|
|
460
|
-
uiStreamMode?:
|
|
461
|
-
}
|
|
462
|
-
export interface CachedResource {
|
|
463
|
-
uri: string;
|
|
464
|
-
name: string;
|
|
465
|
-
description?: string;
|
|
439
|
+
uiStreamMode?: UiStreamMode;
|
|
466
440
|
}
|
|
441
|
+
export type CachedResource = McpResource;
|
|
467
442
|
export interface CachedPrompt {
|
|
468
443
|
name: string;
|
|
469
444
|
title?: string;
|
|
@@ -7,10 +7,10 @@ interface ReadUiResourceOptions {
|
|
|
7
7
|
onNeedsAuth?: SessionRecoveryDeps["onNeedsAuth"];
|
|
8
8
|
}
|
|
9
9
|
export declare class UiResourceHandler {
|
|
10
|
+
private log;
|
|
10
11
|
private manager;
|
|
11
12
|
private config;
|
|
12
|
-
|
|
13
|
-
constructor(manager: McpServerManager, config?: McpConfig | undefined);
|
|
13
|
+
constructor(manager: McpServerManager, config?: McpConfig);
|
|
14
14
|
readUiResource(serverName: string, uri: string, options?: ReadUiResourceOptions): Promise<UiResourceContent>;
|
|
15
15
|
private getListResourceMeta;
|
|
16
16
|
}
|
|
@@ -4,10 +4,10 @@ import { logger } from "./logger.js";
|
|
|
4
4
|
import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
|
|
5
5
|
import { isServerDisabled } from "./types.js";
|
|
6
6
|
export class UiResourceHandler {
|
|
7
|
+
log = logger.child({ component: "UiResourceHandler" });
|
|
7
8
|
manager;
|
|
8
9
|
config;
|
|
9
|
-
|
|
10
|
-
constructor(manager, config = undefined) {
|
|
10
|
+
constructor(manager, config) {
|
|
11
11
|
this.manager = manager;
|
|
12
12
|
this.config = config;
|
|
13
13
|
}
|
package/dist/ui-server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import http from "node:http";
|
|
1
|
+
import http, {} from "node:http";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -10,7 +10,7 @@ import { logger } from "./logger.js";
|
|
|
10
10
|
import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
|
|
11
11
|
import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.js";
|
|
12
12
|
import { extractUiToolVisibility, isUiToolCallableByApp } from "./ui-tool-visibility.js";
|
|
13
|
-
import { createUiModelContextUpdate, extractUiPromptText, getVisualizationStreamEnvelope, isServerDisabled, } from "./types.js";
|
|
13
|
+
import { createUiModelContextUpdate, extractUiPromptText, getVisualizationStreamEnvelope, isServerDisabled, isToolAllowed, resolveToolPrefix, } from "./types.js";
|
|
14
14
|
const MAX_BODY_SIZE = 2 * 1024 * 1024;
|
|
15
15
|
const ABANDONED_GRACE_MS = 60_000;
|
|
16
16
|
const WATCHDOG_INTERVAL_MS = 5_000;
|
|
@@ -299,9 +299,10 @@ export async function startUiServer(options) {
|
|
|
299
299
|
sendJson(res, 503, { ok: false, error: `Server "${options.serverName}" is disabled` });
|
|
300
300
|
return;
|
|
301
301
|
}
|
|
302
|
+
const definition = options.config?.mcpServers[options.serverName] ?? connection.definition;
|
|
302
303
|
const toolDefinitions = Array.isArray(connection.tools) ? connection.tools : [];
|
|
303
304
|
const toolDefinition = toolDefinitions.find((tool) => tool.name === callParams.name);
|
|
304
|
-
if (!toolDefinition) {
|
|
305
|
+
if (!toolDefinition || !isToolAllowed(callParams.name, options.serverName, resolveToolPrefix(definition, options.config?.settings?.toolPrefix), definition?.includeTools, definition?.excludeTools)) {
|
|
305
306
|
sendJson(res, 403, { ok: false, error: `MCP tool "${callParams.name}" is not callable by apps` });
|
|
306
307
|
return;
|
|
307
308
|
}
|
|
@@ -10,17 +10,17 @@ export declare const uiStreamModeSchema: z.ZodEnum<{
|
|
|
10
10
|
}>;
|
|
11
11
|
export type UiStreamMode = z.infer<typeof uiStreamModeSchema>;
|
|
12
12
|
export declare const visualizationStreamPhaseSchema: z.ZodEnum<{
|
|
13
|
-
shell: "shell";
|
|
14
|
-
narrative: "narrative";
|
|
15
|
-
structure: "structure";
|
|
16
13
|
detail: "detail";
|
|
14
|
+
narrative: "narrative";
|
|
17
15
|
settled: "settled";
|
|
16
|
+
shell: "shell";
|
|
17
|
+
structure: "structure";
|
|
18
18
|
}>;
|
|
19
19
|
export type VisualizationStreamPhase = z.infer<typeof visualizationStreamPhaseSchema>;
|
|
20
20
|
export declare const visualizationStreamFrameTypeSchema: z.ZodEnum<{
|
|
21
|
-
patch: "patch";
|
|
22
21
|
checkpoint: "checkpoint";
|
|
23
22
|
final: "final";
|
|
23
|
+
patch: "patch";
|
|
24
24
|
}>;
|
|
25
25
|
export type VisualizationStreamFrameType = z.infer<typeof visualizationStreamFrameTypeSchema>;
|
|
26
26
|
export declare const visualizationStreamStatusSchema: z.ZodEnum<{
|
|
@@ -42,16 +42,16 @@ export declare const visualizationStreamEnvelopeSchema: z.ZodObject<{
|
|
|
42
42
|
streamId: z.ZodString;
|
|
43
43
|
sequence: z.ZodNumber;
|
|
44
44
|
frameType: z.ZodEnum<{
|
|
45
|
-
patch: "patch";
|
|
46
45
|
checkpoint: "checkpoint";
|
|
47
46
|
final: "final";
|
|
47
|
+
patch: "patch";
|
|
48
48
|
}>;
|
|
49
49
|
phase: z.ZodEnum<{
|
|
50
|
-
shell: "shell";
|
|
51
|
-
narrative: "narrative";
|
|
52
|
-
structure: "structure";
|
|
53
50
|
detail: "detail";
|
|
51
|
+
narrative: "narrative";
|
|
54
52
|
settled: "settled";
|
|
53
|
+
shell: "shell";
|
|
54
|
+
structure: "structure";
|
|
55
55
|
}>;
|
|
56
56
|
status: z.ZodEnum<{
|
|
57
57
|
error: "error";
|
|
@@ -2,12 +2,12 @@ import type { Transport } from "@modelcontextprotocol/client";
|
|
|
2
2
|
import type { JSONRPCMessage } from "@modelcontextprotocol/client";
|
|
3
3
|
/** MCP JSONL transport for an explicitly configured Unix-domain socket. */
|
|
4
4
|
export declare class UnixSocketClientTransport implements Transport {
|
|
5
|
-
private readonly socketPath;
|
|
6
5
|
private socket;
|
|
7
6
|
private readonly readBuffer;
|
|
8
7
|
onclose?: () => void;
|
|
9
8
|
onerror?: (error: Error) => void;
|
|
10
9
|
onmessage?: (message: JSONRPCMessage) => void;
|
|
10
|
+
private readonly socketPath;
|
|
11
11
|
constructor(socketPath: string);
|
|
12
12
|
start(): Promise<void>;
|
|
13
13
|
close(): Promise<void>;
|
|
@@ -2,12 +2,12 @@ import { createConnection } from "node:net";
|
|
|
2
2
|
import { ReadBuffer, serializeMessage } from "@modelcontextprotocol/client";
|
|
3
3
|
/** MCP JSONL transport for an explicitly configured Unix-domain socket. */
|
|
4
4
|
export class UnixSocketClientTransport {
|
|
5
|
-
socketPath;
|
|
6
5
|
socket;
|
|
7
6
|
readBuffer = new ReadBuffer();
|
|
8
7
|
onclose;
|
|
9
8
|
onerror;
|
|
10
9
|
onmessage;
|
|
10
|
+
socketPath;
|
|
11
11
|
constructor(socketPath) {
|
|
12
12
|
this.socketPath = socketPath;
|
|
13
13
|
}
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { McpConfig, ServerEntry } from "./types.ts";
|
|
3
|
+
export declare const ADAPTER_VERSION: string;
|
|
3
4
|
export declare function normalizeRequestTimeoutMs(timeoutMs: number | undefined): number | undefined;
|
|
4
5
|
export declare function openUrl(pi: ExtensionAPI, url: string, browser?: string, signal?: AbortSignal): Promise<void>;
|
|
5
6
|
export declare function openPath(pi: ExtensionAPI, targetPath: string): Promise<void>;
|
package/dist/utils.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { homedir, platform } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
5
|
+
function readAdapterVersion() {
|
|
6
|
+
// Source modules sit beside package.json; compiled modules sit one level down in dist/.
|
|
7
|
+
for (const path of ["./package.json", "../package.json"]) {
|
|
8
|
+
try {
|
|
9
|
+
const manifest = JSON.parse(readFileSync(new URL(path, import.meta.url), "utf8"));
|
|
10
|
+
if (manifest.name === "@fitchmultz/pi-mcp-adapter" && typeof manifest.version === "string")
|
|
11
|
+
return manifest.version;
|
|
12
|
+
}
|
|
13
|
+
catch { }
|
|
14
|
+
}
|
|
15
|
+
return "0.0.0";
|
|
16
|
+
}
|
|
17
|
+
export const ADAPTER_VERSION = readAdapterVersion();
|
|
4
18
|
export function normalizeRequestTimeoutMs(timeoutMs) {
|
|
5
19
|
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0
|
|
6
20
|
? timeoutMs
|
|
@@ -246,11 +260,9 @@ export function truncateAtWord(text, target) {
|
|
|
246
260
|
return truncated + "...";
|
|
247
261
|
}
|
|
248
262
|
export function normalizeDirectToolInputSchema(schema) {
|
|
249
|
-
|
|
250
|
-
? schema
|
|
263
|
+
return schema && typeof schema === "object" && !Array.isArray(schema)
|
|
264
|
+
? structuredClone(schema)
|
|
251
265
|
: { type: "object", properties: {} };
|
|
252
|
-
const { $schema, additionalProperties, ...normalized } = inputSchema;
|
|
253
|
-
return normalized;
|
|
254
266
|
}
|
|
255
267
|
export function formatAuthRequiredMessage(config, serverName, defaultMessage) {
|
|
256
268
|
const template = config.settings?.authRequiredMessage;
|
package/package.json
CHANGED
|
@@ -1,42 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fitchmultz/pi-mcp-adapter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Fitch's independently maintained MCP adapter for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
|
-
"
|
|
11
|
-
"default": "./index.ts"
|
|
10
|
+
"default": "./dist/index.js"
|
|
12
11
|
},
|
|
13
12
|
"./types": {
|
|
14
13
|
"types": "./dist/types.d.ts",
|
|
15
|
-
"
|
|
16
|
-
"default": "./types.ts"
|
|
14
|
+
"default": "./dist/types.js"
|
|
17
15
|
}
|
|
18
16
|
},
|
|
19
17
|
"license": "MIT",
|
|
20
18
|
"author": "Mitch Fultz",
|
|
21
|
-
"contributors": [
|
|
19
|
+
"contributors": [
|
|
20
|
+
"Nico Bailon"
|
|
21
|
+
],
|
|
22
22
|
"homepage": "https://github.com/fitchmultz/pi-mcp-adapter",
|
|
23
23
|
"bugs": "https://github.com/fitchmultz/pi-mcp-adapter/issues",
|
|
24
|
-
"publishConfig": {
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
25
27
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
28
|
+
"node": ">=24.0.0"
|
|
27
29
|
},
|
|
28
30
|
"bin": {
|
|
29
31
|
"fitch-mcp-adapter": "cli.js"
|
|
30
32
|
},
|
|
31
33
|
"scripts": {
|
|
32
34
|
"build": "node ./scripts/build.mjs",
|
|
35
|
+
"build:bridge": "node ./scripts/build-app-bridge.mjs",
|
|
33
36
|
"prepare": "node ./scripts/prepare.mjs",
|
|
37
|
+
"check:compat": "node scripts/compat-host.mjs && npm run build && npm run typecheck && vitest run --exclude __tests__/interactive-visualizer-server.test.ts && npm run test:oauth && node scripts/compat-package-smoke.mjs",
|
|
34
38
|
"typecheck": "tsc --noEmit",
|
|
35
|
-
"test": "vitest run",
|
|
39
|
+
"test": "vitest run && npm run test:oauth",
|
|
36
40
|
"test:watch": "vitest",
|
|
37
|
-
"test:
|
|
38
|
-
"test:oauth": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --import tsx --test --test-concurrency=1 mcp-auth.test.ts mcp-auth-flow.test.ts mcp-callback-server.test.ts mcp-oauth-provider.test.ts",
|
|
39
|
-
"test:oauth-provider": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --import tsx --test mcp-oauth-provider.test.ts",
|
|
41
|
+
"test:oauth": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --test --test-concurrency=1 mcp-auth.test.ts mcp-auth-flow.test.ts mcp-callback-server.test.ts mcp-oauth-provider.test.ts",
|
|
40
42
|
"test:conformance": "bash conformance/run.sh"
|
|
41
43
|
},
|
|
42
44
|
"repository": {
|
|
@@ -65,92 +67,31 @@
|
|
|
65
67
|
},
|
|
66
68
|
"files": [
|
|
67
69
|
"dist",
|
|
68
|
-
"docs/client-metadata.json",
|
|
69
|
-
"scripts/build.mjs",
|
|
70
|
-
"scripts/prepare.mjs",
|
|
71
|
-
"tsconfig.build.json",
|
|
72
|
-
"tsconfig.json",
|
|
73
70
|
"cli.js",
|
|
74
|
-
"agent-dir.ts",
|
|
75
|
-
"legacy-migration.ts",
|
|
76
|
-
"index.ts",
|
|
77
|
-
"error-signal.ts",
|
|
78
|
-
"state.ts",
|
|
79
|
-
"utils.ts",
|
|
80
|
-
"abort.ts",
|
|
81
|
-
"runtime-owner.ts",
|
|
82
|
-
"checkpoint.ts",
|
|
83
|
-
"tool-metadata.ts",
|
|
84
|
-
"ts-shape.ts",
|
|
85
|
-
"search-ranking.ts",
|
|
86
|
-
"tool-approval.ts",
|
|
87
|
-
"init.ts",
|
|
88
|
-
"ui-session.ts",
|
|
89
|
-
"proxy-modes.ts",
|
|
90
|
-
"direct-tools.ts",
|
|
91
|
-
"commands.ts",
|
|
92
|
-
"prompts.ts",
|
|
93
|
-
"onboarding-state.ts",
|
|
94
|
-
"mcp-setup-panel.ts",
|
|
95
|
-
"types.ts",
|
|
96
|
-
"ui-stream-types.ts",
|
|
97
|
-
"ui-tool-visibility.ts",
|
|
98
|
-
"config.ts",
|
|
99
|
-
"server-manager.ts",
|
|
100
|
-
"unix-socket-transport.ts",
|
|
101
|
-
"session-recovery.ts",
|
|
102
|
-
"sampling-handler.ts",
|
|
103
|
-
"elicitation-handler.ts",
|
|
104
|
-
"tool-registrar.ts",
|
|
105
|
-
"tool-result-renderer.ts",
|
|
106
|
-
"mcp-output-guard.ts",
|
|
107
|
-
"mcp-code.ts",
|
|
108
|
-
"mcp-script-worker.mjs",
|
|
109
|
-
"resource-tools.ts",
|
|
110
|
-
"lifecycle.ts",
|
|
111
|
-
"mcp-status.ts",
|
|
112
|
-
"metadata-cache.ts",
|
|
113
|
-
"host-html-template.ts",
|
|
114
|
-
"ui-resource-handler.ts",
|
|
115
|
-
"consent-manager.ts",
|
|
116
|
-
"ui-server.ts",
|
|
117
|
-
"glimpse-ui.ts",
|
|
118
|
-
"npx-resolver.ts",
|
|
119
|
-
"mcp-auth.ts",
|
|
120
|
-
"mcp-keyring-helper.cjs",
|
|
121
|
-
"mcp-oauth-provider.ts",
|
|
122
|
-
"mcp-callback-server.ts",
|
|
123
|
-
"mcp-auth-flow.ts",
|
|
124
|
-
"mcp-panel.ts",
|
|
125
|
-
"panel-keys.ts",
|
|
126
|
-
"mcp-trace.ts",
|
|
127
|
-
"logger.ts",
|
|
128
|
-
"app-bridge.bundle.js",
|
|
129
|
-
"banner.png",
|
|
130
71
|
"skills",
|
|
72
|
+
"docs/client-metadata.json",
|
|
131
73
|
"README.md",
|
|
132
74
|
"OAUTH.md",
|
|
133
75
|
"CHANGELOG.md",
|
|
134
76
|
"LICENSE"
|
|
135
77
|
],
|
|
136
78
|
"dependencies": {
|
|
137
|
-
"@modelcontextprotocol/client": "2.
|
|
138
|
-
"@modelcontextprotocol/core": "2.
|
|
139
|
-
"@modelcontextprotocol/ext-apps": "
|
|
140
|
-
"@
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"open": "
|
|
144
|
-
"smol-toml": "
|
|
145
|
-
"strip-json-comments": "
|
|
146
|
-
"zod": "
|
|
79
|
+
"@modelcontextprotocol/client": "2.1.0",
|
|
80
|
+
"@modelcontextprotocol/core": "2.1.0",
|
|
81
|
+
"@modelcontextprotocol/ext-apps": "2.0.0",
|
|
82
|
+
"@napi-rs/keyring": "2.1.0",
|
|
83
|
+
"cross-spawn": "7.0.6",
|
|
84
|
+
"minisearch": "7.2.0",
|
|
85
|
+
"open": "11.0.4",
|
|
86
|
+
"smol-toml": "1.9.0",
|
|
87
|
+
"strip-json-comments": "5.0.3",
|
|
88
|
+
"zod": "4.6.5"
|
|
147
89
|
},
|
|
148
90
|
"peerDependencies": {
|
|
149
91
|
"@earendil-works/pi-ai": "*",
|
|
150
92
|
"@earendil-works/pi-coding-agent": "*",
|
|
151
93
|
"@earendil-works/pi-tui": "*",
|
|
152
|
-
"typebox": "*"
|
|
153
|
-
"zod": "^3.25.0 || ^4.0.0"
|
|
94
|
+
"typebox": "*"
|
|
154
95
|
},
|
|
155
96
|
"peerDependenciesMeta": {
|
|
156
97
|
"@earendil-works/pi-ai": {
|
|
@@ -167,16 +108,16 @@
|
|
|
167
108
|
}
|
|
168
109
|
},
|
|
169
110
|
"devDependencies": {
|
|
170
|
-
"@earendil-works/pi-ai": "0.
|
|
171
|
-
"@earendil-works/pi-coding-agent": "0.
|
|
172
|
-
"@earendil-works/pi-tui": "0.
|
|
173
|
-
"@modelcontextprotocol/
|
|
174
|
-
"@modelcontextprotocol/server": "2.0.0",
|
|
111
|
+
"@earendil-works/pi-ai": "0.87.1",
|
|
112
|
+
"@earendil-works/pi-coding-agent": "0.87.1",
|
|
113
|
+
"@earendil-works/pi-tui": "0.87.1",
|
|
114
|
+
"@modelcontextprotocol/server": "2.1.0",
|
|
175
115
|
"@types/cross-spawn": "6.0.6",
|
|
176
|
-
"@types/node": "
|
|
177
|
-
"
|
|
178
|
-
"typebox": "1.3.
|
|
179
|
-
"typescript": "
|
|
180
|
-
"vitest": "
|
|
181
|
-
}
|
|
116
|
+
"@types/node": "24.19.0",
|
|
117
|
+
"esbuild": "0.28.2",
|
|
118
|
+
"typebox": "1.3.34",
|
|
119
|
+
"typescript": "7.0.2",
|
|
120
|
+
"vitest": "5.0.2"
|
|
121
|
+
},
|
|
122
|
+
"packageManager": "npm@12.1.0"
|
|
182
123
|
}
|
|
@@ -1,38 +1,85 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mcp-scripting
|
|
3
|
-
description: Write mcp_script JavaScript for discovering, inspecting, and calling MCP tools.
|
|
3
|
+
description: Write mcp_script JavaScript for discovering, inspecting, and calling MCP tools, resources, and saved results.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# MCP scripting
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use `mcp_script` for MCP calls with loops, filtering, chaining, fan-out, or other logic between calls. Pass ordinary JavaScript as its `code` argument. For a single call, use an already loaded typed tool. Use `mcp_search({ query, server?, limit?, offset? })` to discover and load typed tools for the next request, or explicit `mcp` actions for gateway-only workflows. Discovery never executes a search hit.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Discover, inspect, then call
|
|
11
11
|
|
|
12
12
|
```js
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const found = await tools.search({ query: "search issues", server: "github" });
|
|
14
|
+
if (found.error) return found;
|
|
15
|
+
emit(found.coverage);
|
|
16
|
+
for (const item of found.items) {
|
|
17
|
+
emit(await tools.describe({ path: item.path, server: item.server }));
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Read the returned descriptors and choose the tool that matches the task. Do not call the first ranked hit without checking its identity and schema. In a subsequent script, use its exact returned path and schema-correct arguments:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
const results = [];
|
|
25
|
+
for (const query of ["is:open label:bug", "is:open label:docs"]) {
|
|
26
|
+
const result = await tools.call("github_search_issues", { query });
|
|
27
|
+
if (!result.ok) return result;
|
|
28
|
+
results.push({ query, data: result.data });
|
|
29
|
+
}
|
|
30
|
+
return results;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API and return shapes
|
|
34
|
+
|
|
35
|
+
- `await tools.search({ query, server?, limit?, offset? })` returns `{ items, total, hasMore, nextOffset, coverage }`. Items carry `path`, `name`, `server`, optional `description`, and `score`. Discovery failures return `{ error, coverage }`. Script search defaults to **12** items, maximum **100**, with zero-based item offsets. The separate `mcp_search` loader defaults to **5**.
|
|
36
|
+
- `coverage` is `{ complete, knownServers, unknownServers }`. Global search covers known catalogs without starting every lazy server. Select an uncached server to discover it. Script search does not activate typed tools.
|
|
37
|
+
- `await tools.describe({ path, server? })` returns the complete tool descriptor with `path`, `server`, original `name`, and all server-supplied fields, including `inputSchema`, `outputSchema`, `title`, `annotations`, and `_meta` when present. It never substitutes `inputTypeScript`. Failures return `{ path, error: { code, message, suggestions? } }`. Supply `server` to disambiguate a name.
|
|
38
|
+
- `await tools.call(path, args, server?)` returns `{ ok: true, data, resultRef? }` or `{ ok: false, error: { code, message, ... }, data?, resultRef? }`. `data` is the **raw MCP result**, including raw error-result data when available. Tools usually return `{ content, structuredContent?, isError?, ... }`; resource reads return `{ contents, ... }`.
|
|
39
|
+
- If a flat path is ambiguous, call `tools.call(descriptor.name, args, descriptor.server)` with the exact original name and server returned by describe.
|
|
40
|
+
- `await tools.resources({ server, limit?, offset? })` returns `{ mode: "resources", server, items, total, hasMore, nextOffset }`, or `{ error: { code, message } }`. Items preserve resource descriptors, including the exact `uri`, name, title, MIME type, description, icons, and `_meta` when supplied; pages default to 12, maximum 100.
|
|
41
|
+
- `await tools.readResource({ server, uri })` returns the same call envelope as `tools.call`, with raw resource contents in `data.contents`. Resources are separate from typed functions. Legacy `read_<resource>` call aliases remain compatible, but prefer this URI-based API.
|
|
42
|
+
- `await tools.readResult({ ref, path?, fields?, offset?, limit? })` returns `{ content, details }`, not a call envelope. `content` contains readback text; `details` contains `ref`, `offset`, `nextOffset`, `totalCharacters`, and the selected `path` when supplied. Failures contain `details.error` and `details.message`.
|
|
43
|
+
- `emit(value)` adds model-visible output before the final `return`; `console` output is captured too.
|
|
44
|
+
|
|
45
|
+
Treat `structuredContent` as structured data even alongside text or image blocks. Only parse a text block as JSON when the server documents that format. Handle `ok: false`: ordinary failed calls do not stop a script automatically. A call-capture failure stops dependent work. An ambiguous outcome requires provider readback before considering another write; never blindly repeat a call or rerun its whole script.
|
|
16
46
|
|
|
17
|
-
|
|
18
|
-
if (details.error) return details;
|
|
47
|
+
## Saved-result readback
|
|
19
48
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
49
|
+
Structured, media, resource, oversized, and extra-field results retain a raw artifact with a model-visible result reference. Small plain-text-only results stay inline. To inspect an existing reference without another MCP call:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
const page = await tools.readResult({
|
|
53
|
+
ref: "/returned/result/path",
|
|
54
|
+
path: "/structuredContent/rows",
|
|
55
|
+
fields: ["id", "title"],
|
|
56
|
+
offset: 0,
|
|
57
|
+
limit: 12000,
|
|
58
|
+
});
|
|
59
|
+
return page;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`path` is an RFC 6901 JSON Pointer. `fields` retains immediate keys on the selected object or every object in a selected array. Selection precedes paging. `offset` and `limit` are **zero-based character positions in the selected, pretty-printed JSON**, not rows, lines, or bytes. The default limit is 12,000 characters; output byte/line caps still apply. Continue with `details.nextOffset` until it is `null`. References must identify existing adapter artifacts in the host's output directory. Readback never re-calls the server and is not a general filesystem API.
|
|
63
|
+
|
|
64
|
+
Gateway equivalents require explicit actions:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
mcp({ action: "search", query: "search issues", server: "github" })
|
|
68
|
+
mcp({ action: "describe", tool: "github_search_issues" })
|
|
69
|
+
mcp({ action: "call", tool: "github_search_issues", args: { query: "is:open" } })
|
|
70
|
+
mcp({ action: "resources", server: "docs" })
|
|
71
|
+
mcp({ action: "read-resource", server: "docs", uri: "docs://guide" })
|
|
72
|
+
mcp({ action: "read-result", ref: "/returned/result/path", path: "/structuredContent" })
|
|
24
73
|
```
|
|
25
74
|
|
|
26
|
-
|
|
75
|
+
Gateway search returns schemas without activating functions; use it when only `mcp` is allowed. New gateway calls use object `args`. Optional v5 mode fields and JSON-string arguments are only a stored-call ingress compatibility path.
|
|
27
76
|
|
|
28
|
-
|
|
29
|
-
2. Inspect the exact returned path with `await tools.describe({ path })`. Arguments are described by `inputTypeScript` when representable, otherwise by the original JSON Schema in `inputSchema`; only one is included.
|
|
30
|
-
3. Call it with `tools.call(path, args)`.
|
|
77
|
+
## Execution rules
|
|
31
78
|
|
|
32
|
-
|
|
79
|
+
`tools` is a non-enumerable proxy: `Object.keys(tools)` throws. Use `tools.search` for discovery. Known flat paths support `tools.github_search_issues(args)` or `tools["server_tool-name"](args)`. Proxy API and promise/serialization names are reserved (`search`, `describe`, `call`, `resources`, `listResources`, `readResource`, `readResult`, `then`, `catch`, `finally`, `toJSON`, `toString`, `valueOf`); use `tools.call("exact-path", args)` for collisions.
|
|
33
80
|
|
|
34
|
-
|
|
81
|
+
Await every operation, including all promises started with `Promise.all`, before returning. Calls use the shared authentication, approval, filtering, cancellation, and capture path. Resources honor `exposeResources` and include/exclude policy. Raw results are cloned into the worker before model-facing rendering; reduce them before emitting to avoid unnecessary context. Result details include a concise search/describe/call trace and saved-result references.
|
|
35
82
|
|
|
36
|
-
|
|
83
|
+
The default overall script timeout is 30 seconds unless the host overrides or disables it; an explicit per-script `timeoutMs` wins. Individual MCP request deadlines still apply. The local worker terminates on timeout or cancellation, including infinite loops. This is trusted agent-authored local orchestration, not provider-native programmatic tool calling or an isolation boundary; Codex native PTC is not implied.
|
|
37
84
|
|
|
38
|
-
|
|
85
|
+
The worker exposes no Node, filesystem, or network globals such as `process`, `Buffer`, or `fetch`. Use normal JavaScript loops and Promise utilities; fluent helpers such as `tools.find(...).one()`, `tools.parallel(...)`, and `tools.retry(...)` do not exist. Run Pi in an isolated environment if you need isolation.
|
package/abort.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export function throwIfAborted(signal?: AbortSignal): void {
|
|
2
|
-
if (!signal?.aborted) return;
|
|
3
|
-
throw signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason ?? "MCP request aborted"));
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export async function abortable<T>(promise: Promise<T>, signal?: AbortSignal): Promise<T> {
|
|
7
|
-
if (!signal) return promise;
|
|
8
|
-
throwIfAborted(signal);
|
|
9
|
-
return await new Promise<T>((resolve, reject) => {
|
|
10
|
-
let settled = false;
|
|
11
|
-
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
12
|
-
const onAbort = () => {
|
|
13
|
-
if (settled) return;
|
|
14
|
-
settled = true;
|
|
15
|
-
cleanup();
|
|
16
|
-
reject(signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason ?? "MCP request aborted")));
|
|
17
|
-
};
|
|
18
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
19
|
-
promise.then(
|
|
20
|
-
value => {
|
|
21
|
-
if (settled) return;
|
|
22
|
-
settled = true;
|
|
23
|
-
cleanup();
|
|
24
|
-
resolve(value);
|
|
25
|
-
},
|
|
26
|
-
error => {
|
|
27
|
-
if (settled) return;
|
|
28
|
-
settled = true;
|
|
29
|
-
cleanup();
|
|
30
|
-
reject(error);
|
|
31
|
-
},
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
}
|
package/agent-dir.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
2
|
-
import { join, resolve } from "node:path";
|
|
3
|
-
|
|
4
|
-
export function getAgentDir(): string {
|
|
5
|
-
const configured = process.env.PI_CODING_AGENT_DIR?.trim();
|
|
6
|
-
if (!configured) {
|
|
7
|
-
return join(homedir(), ".pi", "agent");
|
|
8
|
-
}
|
|
9
|
-
if (configured === "~") {
|
|
10
|
-
return homedir();
|
|
11
|
-
}
|
|
12
|
-
if (configured.startsWith("~/")) {
|
|
13
|
-
return resolve(homedir(), configured.slice(2));
|
|
14
|
-
}
|
|
15
|
-
return resolve(configured);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function getAgentPath(...segments: string[]): string {
|
|
19
|
-
return join(getAgentDir(), ...segments);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function getAdapterPath(...segments: string[]): string {
|
|
23
|
-
return getAgentPath("fitch-mcp-adapter", ...segments);
|
|
24
|
-
}
|