@fitchmultz/pi-mcp-adapter 8.0.1 → 8.0.2

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +3 -3
  3. package/dist/app-bridge.bundle.js +13 -13
  4. package/dist/client-operations.d.ts +5 -0
  5. package/dist/client-operations.js +19 -0
  6. package/dist/commands.d.ts +1 -1
  7. package/dist/commands.js +3 -1
  8. package/dist/connection-runtime.d.ts +503 -0
  9. package/dist/connection-runtime.js +98 -0
  10. package/dist/direct-tools.js +1 -1
  11. package/dist/host-html-template.js +24 -12
  12. package/dist/index.js +36 -29
  13. package/dist/init.d.ts +1 -1
  14. package/dist/init.js +66 -38
  15. package/dist/lifecycle.d.ts +1 -1
  16. package/dist/lifecycle.js +1 -1
  17. package/dist/mcp-auth-flow.d.ts +2 -43
  18. package/dist/mcp-auth-flow.js +3 -138
  19. package/dist/mcp-callback-server.js +1 -1
  20. package/dist/mcp-code.d.ts +0 -1
  21. package/dist/mcp-code.js +20 -7
  22. package/dist/mcp-oauth-callback-config.d.ts +8 -0
  23. package/dist/mcp-oauth-callback-config.js +28 -0
  24. package/dist/mcp-oauth-provider.d.ts +1 -8
  25. package/dist/mcp-oauth-provider.js +2 -28
  26. package/dist/mcp-oauth-runtime.d.ts +83 -0
  27. package/dist/mcp-oauth-runtime.js +145 -0
  28. package/dist/mcp-output-guard.d.ts +1 -1
  29. package/dist/mcp-output-guard.js +5 -108
  30. package/dist/mcp-output-preview.d.ts +29 -0
  31. package/dist/mcp-output-preview.js +220 -0
  32. package/dist/mcp-panel.js +1 -2
  33. package/dist/mcp-script-worker.mjs +14 -2
  34. package/dist/metadata-cache.d.ts +1 -1
  35. package/dist/metadata-cache.js +56 -14
  36. package/dist/plain-result-reader.d.ts +7 -0
  37. package/dist/plain-result-reader.js +201 -0
  38. package/dist/prompts.js +1 -1
  39. package/dist/proxy-modes.d.ts +1 -1
  40. package/dist/proxy-modes.js +14 -5
  41. package/dist/public-types.d.ts +2 -0
  42. package/dist/public-types.js +2 -0
  43. package/dist/resource-tools.d.ts +0 -1
  44. package/dist/resource-tools.js +0 -13
  45. package/dist/server-manager.d.ts +4 -4
  46. package/dist/server-manager.js +25 -125
  47. package/dist/tool-loader.js +10 -4
  48. package/dist/tool-metadata.js +20 -3
  49. package/dist/tool-result-renderer.d.ts +1 -1
  50. package/dist/tool-result-renderer.js +10 -3
  51. package/dist/types.d.ts +1 -1
  52. package/dist/types.js +0 -3
  53. package/dist/ui-message-history.js +3 -2
  54. package/dist/ui-resource-handler.d.ts +2 -1
  55. package/dist/ui-resource-handler.js +4 -3
  56. package/dist/ui-server.js +2 -1
  57. package/dist/ui-session.js +2 -1
  58. package/dist/utils.d.ts +1 -0
  59. package/dist/utils.js +1 -0
  60. package/package.json +4 -4
@@ -1,6 +1,4 @@
1
- import { getToolUiResourceUri } from "@modelcontextprotocol/ext-apps/app-bridge";
2
1
  import { formatToolName, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.js";
3
- import { resourceNameToToolName } from "./resource-tools.js";
4
2
  import { extractToolUiStreamMode } from "./utils.js";
5
3
  import { extractUiToolVisibility, isUiToolVisibleToModel } from "./ui-tool-visibility.js";
6
4
  export function buildToolMetadata(tools, resources, definition, serverName, prefix) {
@@ -24,7 +22,13 @@ export function buildToolMetadata(tools, resources, definition, serverName, pref
24
22
  }
25
23
  let uiResourceUri;
26
24
  try {
27
- uiResourceUri = getToolUiResourceUri({ _meta: tool._meta });
25
+ // MCP Apps metadata must also be readable from the cache before loading the SDK.
26
+ const uri = tool._meta?.ui?.resourceUri;
27
+ const resourceUri = uri === undefined ? tool._meta?.["ui/resourceUri"] : uri;
28
+ if (typeof resourceUri === "string" && resourceUri.startsWith("ui://"))
29
+ uiResourceUri = resourceUri;
30
+ else if (resourceUri !== undefined)
31
+ failedTools.push(tool.name);
28
32
  }
29
33
  catch {
30
34
  failedTools.push(tool.name);
@@ -197,3 +201,16 @@ function appendSchemaAnnotations(parts, schema) {
197
201
  parts.push(`[default: ${JSON.stringify(schema.default)}]`);
198
202
  }
199
203
  }
204
+ function resourceNameToToolName(name) {
205
+ let result = name
206
+ .replace(/[^a-zA-Z0-9]/g, "_")
207
+ .replace(/_+/g, "_")
208
+ .replace(/^_+/, "") // Remove leading underscores
209
+ .replace(/_+$/, "") // Remove trailing underscores
210
+ .toLowerCase();
211
+ // Ensure we have a valid name
212
+ if (!result || /^\d/.test(result)) {
213
+ result = "resource" + (result ? "_" + result : "");
214
+ }
215
+ return result;
216
+ }
@@ -1,4 +1,4 @@
1
- import { type AgentToolResult, type Theme, type ToolRenderResultOptions } from "@earendil-works/pi-coding-agent";
1
+ import type { AgentToolResult, Theme, ToolRenderResultOptions } from "@earendil-works/pi-coding-agent";
2
2
  import { type Component, Text } from "@earendil-works/pi-tui";
3
3
  type McpToolResultDetails = Record<string, unknown> & {
4
4
  error?: unknown;
@@ -1,5 +1,4 @@
1
- import { keyHint } from "@earendil-works/pi-coding-agent";
2
- import { Text } from "@earendil-works/pi-tui";
1
+ import { getKeybindings, Text } from "@earendil-works/pi-tui";
3
2
  const plainTheme = {
4
3
  fg: (_name, text) => text,
5
4
  bold: (text) => text,
@@ -54,6 +53,14 @@ class CollapsibleText {
54
53
  }
55
54
  invalidate() { }
56
55
  }
56
+ // Read the shared TUI keybinding registry without importing the entire host SDK.
57
+ function expandHint(theme) {
58
+ const keys = getKeybindings().getKeys("app.tools.expand").join("/")
59
+ .split("/").map(key => key.split("+")
60
+ .map(part => process.platform === "darwin" && part.toLowerCase() === "alt" ? "option" : part)
61
+ .join("+")).join("/");
62
+ return theme.fg("dim", keys) + theme.fg("muted", " to expand");
63
+ }
57
64
  function truncateText(value, maxChars) {
58
65
  if (value.length <= maxChars)
59
66
  return value;
@@ -225,5 +232,5 @@ export function renderMcpToolResult(result, options, theme, context) {
225
232
  ...(identity ? [activeTheme.fg("muted", identity)] : []),
226
233
  ...display.lines.map((line) => activeTheme.fg("toolOutput", line)),
227
234
  ].join("\n");
228
- return new CollapsibleText(output, expanded, DEFAULT_MAX_COLLAPSED_LINES + (identity ? 1 : 0), activeTheme.fg("muted", "…"), activeTheme.fg("muted", `(${keyHint("app.tools.expand", "to expand")})`), display.truncated);
235
+ return new CollapsibleText(output, expanded, DEFAULT_MAX_COLLAPSED_LINES + (identity ? 1 : 0), activeTheme.fg("muted", "…"), activeTheme.fg("muted", `(${expandHint(activeTheme)})`), display.truncated);
229
236
  }
package/dist/types.d.ts CHANGED
@@ -104,7 +104,7 @@ export interface UiHostContext {
104
104
  [key: string]: unknown;
105
105
  }
106
106
  export type UiDisplayMode = "inline" | "fullscreen" | "pip";
107
- export { UI_STREAM_HOST_CONTEXT_KEY, UI_STREAM_REQUEST_META_KEY, UI_STREAM_RESULT_PATCH_METHOD, SERVER_STREAM_RESULT_PATCH_METHOD, UI_STREAM_STRUCTURED_CONTENT_KEY, uiStreamModeSchema, visualizationStreamPhaseSchema, visualizationStreamFrameTypeSchema, visualizationStreamStatusSchema, uiStreamHostContextSchema, visualizationStreamEnvelopeSchema, uiStreamCallToolResultSchema, uiStreamResultPatchNotificationSchema, serverStreamResultPatchNotificationSchema, getUiStreamHostContext, getVisualizationStreamEnvelope, type UiStreamMode, type VisualizationStreamPhase, type VisualizationStreamFrameType, type VisualizationStreamStatus, type UiStreamHostContext, type VisualizationStreamEnvelope, type UiStreamCallToolResult, type UiStreamResultPatchNotification, type ServerStreamResultPatchNotification, type UiStreamSummary, } from "./ui-stream-types.ts";
107
+ export type { UiStreamMode, VisualizationStreamPhase, VisualizationStreamFrameType, VisualizationStreamStatus, UiStreamHostContext, VisualizationStreamEnvelope, UiStreamCallToolResult, UiStreamResultPatchNotification, ServerStreamResultPatchNotification, UiStreamSummary, } from "./ui-stream-types.ts";
108
108
  export interface UiMessageParams {
109
109
  role?: string;
110
110
  content?: unknown[];
package/dist/types.js CHANGED
@@ -1,9 +1,6 @@
1
1
  /** Versioned shared-event-bus channel for read-only MCP runtime snapshots. */
2
2
  export const MCP_STATUS_EVENT = "fitch-mcp-adapter/status/v1";
3
3
  export const MCP_STATUS_SNAPSHOT_VERSION = 1;
4
- // Re-export stream types from the shared lightweight module.
5
- // This allows the example package to import stream schemas without pulling the full types.ts dependency graph.
6
- export { UI_STREAM_HOST_CONTEXT_KEY, UI_STREAM_REQUEST_META_KEY, UI_STREAM_RESULT_PATCH_METHOD, SERVER_STREAM_RESULT_PATCH_METHOD, UI_STREAM_STRUCTURED_CONTENT_KEY, uiStreamModeSchema, visualizationStreamPhaseSchema, visualizationStreamFrameTypeSchema, visualizationStreamStatusSchema, uiStreamHostContextSchema, visualizationStreamEnvelopeSchema, uiStreamCallToolResultSchema, uiStreamResultPatchNotificationSchema, serverStreamResultPatchNotificationSchema, getUiStreamHostContext, getVisualizationStreamEnvelope, } from "./ui-stream-types.js";
7
4
  /**
8
5
  * Extract prompt text from either legacy MCP UI message shapes or native AppBridge user messages.
9
6
  */
@@ -1,8 +1,9 @@
1
- import { appendFileSync, createReadStream, mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
1
+ import { createReadStream, mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { randomBytes } from "node:crypto";
5
5
  import { createInterface } from "node:readline";
6
+ import { appendPlainOutput } from "./plain-result-reader.js";
6
7
  /** Private append-only history; failed writes stay owned in memory, never silently discarded. */
7
8
  export function createUiMessageHistory(outputDirectory) {
8
9
  const messages = { prompts: [], intents: [], notifications: [], contexts: [] };
@@ -26,7 +27,7 @@ export function createUiMessageHistory(outputDirectory) {
26
27
  }
27
28
  const line = JSON.stringify({ category, value }) + "\n";
28
29
  // ponytail: synchronous append owns acceptance order; upgrade to an awaited serial writer if local disk latency becomes material.
29
- appendFileSync(messages.historyRef, line, { flush: true });
30
+ appendPlainOutput(messages.historyRef, line);
30
31
  messages.historyBytes += Buffer.byteLength(line);
31
32
  messages.historyCount++;
32
33
  return undefined;
@@ -1,6 +1,7 @@
1
- import { type SessionRecoveryDeps } from "./session-recovery.ts";
1
+ import type { SessionRecoveryDeps } from "./session-recovery.ts";
2
2
  import type { McpServerManager } from "./server-manager.ts";
3
3
  import { type McpConfig, type UiResourceContent } from "./types.ts";
4
+ export declare const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
4
5
  interface ReadUiResourceOptions {
5
6
  config?: McpConfig;
6
7
  signal?: AbortSignal;
@@ -1,8 +1,7 @@
1
- import { RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/app-bridge";
2
- import { UrlElicitationRequiredError } from "@modelcontextprotocol/client";
3
1
  import { logger } from "./logger.js";
4
- import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
5
2
  import { isServerDisabled } from "./types.js";
3
+ // MCP Apps resource media type; metadata reads must not import the app bridge.
4
+ export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
6
5
  export class UiResourceHandler {
7
6
  log = logger.child({ component: "UiResourceHandler" });
8
7
  manager;
@@ -12,6 +11,8 @@ export class UiResourceHandler {
12
11
  this.config = config;
13
12
  }
14
13
  async readUiResource(serverName, uri, options = {}) {
14
+ const { UrlElicitationRequiredError } = await import("@modelcontextprotocol/client");
15
+ const { SessionRecoveryAuthRequiredError, withSessionRecovery } = await import("./session-recovery.js");
15
16
  const log = this.log.child({ server: serverName, uri });
16
17
  if (!uri.startsWith("ui://")) {
17
18
  throw new Error(`Invalid UI resource "${uri}": URI must start with ui://`);
package/dist/ui-server.js CHANGED
@@ -11,7 +11,8 @@ import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session
11
11
  import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.js";
12
12
  import { extractUiToolVisibility, isUiToolCallableByApp } from "./ui-tool-visibility.js";
13
13
  import { createUiMessageHistory } from "./ui-message-history.js";
14
- import { createUiModelContextUpdate, extractUiPromptText, getVisualizationStreamEnvelope, isServerDisabled, isToolAllowed, resolveToolPrefix, } from "./types.js";
14
+ import { createUiModelContextUpdate, extractUiPromptText, isServerDisabled, isToolAllowed, resolveToolPrefix, } from "./types.js";
15
+ import { getVisualizationStreamEnvelope } from "./ui-stream-types.js";
15
16
  const MAX_BODY_SIZE = 2 * 1024 * 1024;
16
17
  const ABANDONED_GRACE_MS = 60_000;
17
18
  const WATCHDOG_INTERVAL_MS = 5_000;
@@ -2,7 +2,8 @@ import { execFile } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import net from "node:net";
4
4
  import { UrlElicitationRequiredError } from "@modelcontextprotocol/client";
5
- import { createUiModelContextUpdate, extractUiPromptText, UI_STREAM_HOST_CONTEXT_KEY, UI_STREAM_REQUEST_META_KEY, UI_STREAM_STRUCTURED_CONTENT_KEY, } from "./types.js";
5
+ import { createUiModelContextUpdate, extractUiPromptText, } from "./types.js";
6
+ import { UI_STREAM_HOST_CONTEXT_KEY, UI_STREAM_REQUEST_META_KEY, UI_STREAM_STRUCTURED_CONTENT_KEY } from "./ui-stream-types.js";
6
7
  import { logger } from "./logger.js";
7
8
  import { startUiServer } from "./ui-server.js";
8
9
  import { isGlimpseAvailable, openGlimpseWindow } from "./glimpse-ui.js";
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import type { McpConfig, ServerEntry } from "./types.ts";
3
3
  export declare const ADAPTER_VERSION: string;
4
+ export declare const DEFAULT_MCP_SCRIPT_TIMEOUT_MS = 30000;
4
5
  export declare function normalizeRequestTimeoutMs(timeoutMs: number | undefined): number | undefined;
5
6
  export declare function openUrl(pi: ExtensionAPI, url: string, browser?: string, signal?: AbortSignal): Promise<void>;
6
7
  export declare function openPath(pi: ExtensionAPI, targetPath: string): Promise<void>;
package/dist/utils.js CHANGED
@@ -15,6 +15,7 @@ function readAdapterVersion() {
15
15
  return "0.0.0";
16
16
  }
17
17
  export const ADAPTER_VERSION = readAdapterVersion();
18
+ export const DEFAULT_MCP_SCRIPT_TIMEOUT_MS = 30_000;
18
19
  export function normalizeRequestTimeoutMs(timeoutMs) {
19
20
  return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0
20
21
  ? timeoutMs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitchmultz/pi-mcp-adapter",
3
- "version": "8.0.1",
3
+ "version": "8.0.2",
4
4
  "description": "Token-efficient MCP adapter for the Pi coding agent",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -10,8 +10,8 @@
10
10
  "default": "./dist/index.js"
11
11
  },
12
12
  "./types": {
13
- "types": "./dist/types.d.ts",
14
- "default": "./dist/types.js"
13
+ "types": "./dist/public-types.d.ts",
14
+ "default": "./dist/public-types.js"
15
15
  }
16
16
  },
17
17
  "license": "MIT",
@@ -82,7 +82,7 @@
82
82
  "open": "11.0.4",
83
83
  "smol-toml": "1.9.1",
84
84
  "strip-json-comments": "5.0.3",
85
- "zod": "4.6.5"
85
+ "zod": "4.6.7"
86
86
  },
87
87
  "peerDependencies": {
88
88
  "@earendil-works/pi-ai": "*",