@fitchmultz/pi-mcp-adapter 8.0.6 → 8.0.8

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 (87) hide show
  1. package/CHANGELOG.md +142 -8
  2. package/OAUTH.md +13 -16
  3. package/README.md +8 -8
  4. package/cli.js +67 -28
  5. package/dist/abort.js +18 -9
  6. package/dist/client-operations.js +4 -2
  7. package/dist/commands.js +77 -43
  8. package/dist/config.js +194 -105
  9. package/dist/connection-runtime.d.ts +2 -2
  10. package/dist/connection-runtime.js +29 -18
  11. package/dist/consent-manager.d.ts +2 -2
  12. package/dist/consent-manager.js +5 -2
  13. package/dist/direct-tools.d.ts +1 -1
  14. package/dist/direct-tools.js +13 -7
  15. package/dist/elicitation-handler.d.ts +2 -3
  16. package/dist/elicitation-handler.js +113 -58
  17. package/dist/gateway-arguments.d.ts +1 -1
  18. package/dist/gateway-arguments.js +90 -23
  19. package/dist/glimpse-ui.js +10 -5
  20. package/dist/host-html-template.d.ts +3 -1
  21. package/dist/host-html-template.js +9 -12
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +264 -119
  24. package/dist/init.d.ts +1 -3
  25. package/dist/init.js +91 -51
  26. package/dist/legacy-migration.d.ts +1 -1
  27. package/dist/legacy-migration.js +17 -12
  28. package/dist/lifecycle.d.ts +3 -3
  29. package/dist/lifecycle.js +33 -17
  30. package/dist/logger.d.ts +2 -2
  31. package/dist/logger.js +4 -2
  32. package/dist/mcp-auth-flow.js +150 -58
  33. package/dist/mcp-auth.d.ts +7 -7
  34. package/dist/mcp-auth.js +189 -138
  35. package/dist/mcp-callback-server.js +19 -8
  36. package/dist/mcp-code.js +168 -54
  37. package/dist/mcp-keyring-helper.cjs +57 -23
  38. package/dist/mcp-oauth-provider.d.ts +6 -7
  39. package/dist/mcp-oauth-provider.js +146 -72
  40. package/dist/mcp-oauth-runtime.js +29 -16
  41. package/dist/mcp-output-guard.js +193 -65
  42. package/dist/mcp-output-preview.js +41 -20
  43. package/dist/mcp-panel.d.ts +9 -9
  44. package/dist/mcp-panel.js +141 -70
  45. package/dist/mcp-script-worker.mjs +135 -43
  46. package/dist/mcp-setup-panel.d.ts +8 -8
  47. package/dist/mcp-setup-panel.js +130 -44
  48. package/dist/mcp-status.js +14 -7
  49. package/dist/mcp-trace.d.ts +10 -5
  50. package/dist/mcp-trace.js +127 -61
  51. package/dist/metadata-cache.d.ts +3 -4
  52. package/dist/metadata-cache.js +83 -43
  53. package/dist/npx-resolver.js +101 -60
  54. package/dist/onboarding-state.js +4 -2
  55. package/dist/plain-result-reader.js +78 -31
  56. package/dist/prompts.js +36 -20
  57. package/dist/proxy-modes.js +670 -193
  58. package/dist/resource-tools.js +30 -9
  59. package/dist/runtime-owner.js +36 -18
  60. package/dist/sampling-handler.d.ts +1 -2
  61. package/dist/sampling-handler.js +41 -21
  62. package/dist/search-ranking.d.ts +1 -1
  63. package/dist/search-ranking.js +67 -34
  64. package/dist/server-manager.d.ts +11 -11
  65. package/dist/server-manager.js +283 -166
  66. package/dist/session-recovery.js +113 -61
  67. package/dist/tool-approval.js +9 -3
  68. package/dist/tool-loader.js +154 -55
  69. package/dist/tool-metadata.d.ts +1 -1
  70. package/dist/tool-metadata.js +51 -23
  71. package/dist/tool-registrar.js +32 -10
  72. package/dist/tool-result-renderer.js +58 -33
  73. package/dist/types.d.ts +2 -2
  74. package/dist/types.js +39 -18
  75. package/dist/ui-message-history.js +33 -13
  76. package/dist/ui-resource-handler.d.ts +3 -3
  77. package/dist/ui-resource-handler.js +37 -21
  78. package/dist/ui-server.js +101 -43
  79. package/dist/ui-session.js +66 -29
  80. package/dist/ui-stream-types.js +14 -4
  81. package/dist/ui-tool-visibility.js +12 -6
  82. package/dist/unix-socket-transport.d.ts +1 -2
  83. package/dist/unix-socket-transport.js +19 -12
  84. package/dist/utils.d.ts +2 -0
  85. package/dist/utils.js +60 -35
  86. package/package.json +28 -2
  87. package/skills/mcp-scripting/SKILL.md +6 -6
@@ -1,63 +1,130 @@
1
1
  import { Type } from "typebox";
2
2
  import { MAX_PAGE_SIZE, MAX_TOOL_NAME_LENGTH } from "./search-ranking.js";
3
- const actions = ["status", "search", "list", "describe", "call", "connect", "instructions", "resources", "read-resource", "read-result", "auth-start", "auth-complete", "ui-messages"];
3
+ const actions = [
4
+ "status",
5
+ "search",
6
+ "list",
7
+ "describe",
8
+ "call",
9
+ "connect",
10
+ "instructions",
11
+ "resources",
12
+ "read-resource",
13
+ "read-result",
14
+ "auth-start",
15
+ "auth-complete",
16
+ "ui-messages",
17
+ ];
4
18
  const requirements = {
5
- search: ["query"], list: ["server"], describe: ["tool"], call: ["tool"],
6
- connect: ["server"], instructions: ["server"], resources: ["server"],
7
- "read-resource": ["server", "uri"], "read-result": ["ref"], "auth-start": ["server"], "auth-complete": ["server"],
19
+ search: ["query"],
20
+ list: ["server"],
21
+ describe: ["tool"],
22
+ call: ["tool"],
23
+ connect: ["server"],
24
+ instructions: ["server"],
25
+ resources: ["server"],
26
+ "read-resource": ["server", "uri"],
27
+ "read-result": ["ref"],
28
+ "auth-start": ["server"],
29
+ "auth-complete": ["server"],
8
30
  };
9
31
  export const gatewayParameters = Type.Object({
10
32
  action: Type.Unsafe({ type: "string", enum: [...actions] }),
11
33
  server: Type.Optional(Type.String({ description: "MCP server; required for server and resource actions." })),
12
- tool: Type.Optional(Type.String({ maxLength: MAX_TOOL_NAME_LENGTH, description: "Exact tool name for call or describe. Use server to disambiguate." })),
13
- args: Type.Optional(Type.Object({}, { additionalProperties: true, description: "Tool arguments, or {redirectUrl} for auth-complete." })),
34
+ tool: Type.Optional(Type.String({
35
+ maxLength: MAX_TOOL_NAME_LENGTH,
36
+ description: "Exact tool name for call or describe. Use server to disambiguate.",
37
+ })),
38
+ args: Type.Optional(Type.Object({}, {
39
+ additionalProperties: true,
40
+ description: "Tool arguments, or {redirectUrl} for auth-complete.",
41
+ })),
14
42
  query: Type.Optional(Type.String({ description: "Search terms. Prefer mcp_search to discover and load tools." })),
15
43
  includeSchemas: Type.Optional(Type.Boolean({ description: "Include complete schemas in search results (default true)." })),
16
- limit: Type.Optional(Type.Integer({ minimum: 1, description: "Page size (default 12, max 100); for read-result, characters of selected JSON." })),
17
- offset: Type.Optional(Type.Integer({ minimum: 0, description: "Zero-based item offset; for read-result, character offset in selected JSON." })),
44
+ limit: Type.Optional(Type.Integer({
45
+ minimum: 1,
46
+ description: "Page size (default 12, max 100); for read-result, characters of selected JSON.",
47
+ })),
48
+ offset: Type.Optional(Type.Integer({
49
+ minimum: 0,
50
+ description: "Zero-based item offset; for read-result, character offset in selected JSON.",
51
+ })),
18
52
  uri: Type.Optional(Type.String({ description: "Exact MCP resource URI for read-resource." })),
19
- ref: Type.Optional(Type.String({ description: "Saved result reference returned by an earlier MCP call; read-result never calls the server again." })),
20
- path: Type.Optional(Type.String({ description: "JSON Pointer into a saved result, e.g. /structuredContent/rows." })),
21
- fields: Type.Optional(Type.Array(Type.String(), { description: "Immediate object fields to retain when reading a saved result." })),
53
+ ref: Type.Optional(Type.String({
54
+ description: "Saved result reference returned by an earlier MCP call; read-result never calls the server again.",
55
+ })),
56
+ path: Type.Optional(Type.String({
57
+ description: "JSON Pointer into a saved result, e.g. /structuredContent/rows.",
58
+ })),
59
+ fields: Type.Optional(Type.Array(Type.String(), {
60
+ description: "Immediate object fields to retain when reading a saved result.",
61
+ })),
22
62
  }, {
23
63
  additionalProperties: false,
24
64
  allOf: [
25
- ...Object.entries(requirements).map(([action, required]) => ({ if: { properties: { action: { const: action } } }, then: { required } })),
26
- { if: { properties: { action: { enum: ["search", "list", "connect", "resources"] } } }, then: { properties: { limit: { maximum: MAX_PAGE_SIZE } } } },
65
+ ...Object.entries(requirements).map(([action, required]) => ({
66
+ if: { properties: { action: { const: action } } },
67
+ then: { required },
68
+ })),
69
+ {
70
+ if: { properties: { action: { enum: ["search", "list", "connect", "resources"] } } },
71
+ then: { properties: { limit: { maximum: MAX_PAGE_SIZE } } },
72
+ },
27
73
  ],
28
74
  });
29
75
  /** Migrate stored v5 calls before host validation; the advertised schema stays explicit. */
30
76
  export function prepareGatewayArguments(input) {
31
- if (!input || typeof input !== "object" || Array.isArray(input))
77
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
32
78
  throw new Error("MCP arguments must be an object");
79
+ }
33
80
  const value = input;
34
81
  let action = value.action;
35
82
  const result = { ...value };
36
83
  if (action === undefined) {
37
- action = value.tool ? "call" : value.connect ? "connect" : value.describe ? "describe" : value.instructions ? "instructions" : value.search !== undefined ? "search" : value.server ? "list" : "status";
38
- if (action === "connect")
84
+ action = value.tool
85
+ ? "call"
86
+ : value.connect
87
+ ? "connect"
88
+ : value.describe
89
+ ? "describe"
90
+ : value.instructions
91
+ ? "instructions"
92
+ : value.search !== undefined
93
+ ? "search"
94
+ : value.server
95
+ ? "list"
96
+ : "status";
97
+ if (action === "connect") {
39
98
  result.server = value.connect;
40
- if (action === "describe")
99
+ }
100
+ if (action === "describe") {
41
101
  result.tool = value.describe;
42
- if (action === "instructions")
102
+ }
103
+ if (action === "instructions") {
43
104
  result.server = value.instructions;
44
- if (action === "search")
105
+ }
106
+ if (action === "search") {
45
107
  result.query = value.search;
108
+ }
46
109
  }
47
- for (const key of ["connect", "describe", "instructions", "search"])
110
+ for (const key of ["connect", "describe", "instructions", "search"]) {
48
111
  delete result[key];
49
- if (!actions.includes(action))
112
+ }
113
+ if (!actions.includes(action)) {
50
114
  throw new Error(`Unknown MCP action: ${String(action)}`);
115
+ }
51
116
  result.action = action;
52
117
  if (typeof result.args === "string") {
53
118
  result.args = result.args === "" ? undefined : JSON.parse(result.args);
54
119
  }
55
- if (result.args !== undefined && (!result.args || typeof result.args !== "object" || Array.isArray(result.args))) {
120
+ if (result.args !== undefined &&
121
+ (!result.args || typeof result.args !== "object" || Array.isArray(result.args))) {
56
122
  throw new Error("Invalid args: expected a JSON object");
57
123
  }
58
124
  for (const field of requirements[action] ?? []) {
59
- if (typeof result[field] !== "string" || (field !== "query" && result[field] === ""))
125
+ if (typeof result[field] !== "string" || (field !== "query" && result[field] === "")) {
60
126
  throw new Error(`${action} requires ${field}`);
127
+ }
61
128
  }
62
129
  return result;
63
130
  }
@@ -14,8 +14,9 @@ import { createRequire } from "node:module";
14
14
  let glimpseAvailable = null;
15
15
  let resolvedBinaryPath = null;
16
16
  export function isGlimpseAvailable() {
17
- if (glimpseAvailable !== null)
17
+ if (glimpseAvailable !== null) {
18
18
  return glimpseAvailable;
19
+ }
19
20
  if (platform() !== "darwin") {
20
21
  glimpseAvailable = false;
21
22
  return false;
@@ -33,16 +34,18 @@ function getGlimpseBinaryPath() {
33
34
  const require = createRequire(import.meta.url);
34
35
  const glimpseuiPath = require.resolve("glimpseui");
35
36
  const binaryPath = join(dirname(glimpseuiPath), "glimpse");
36
- if (existsSync(binaryPath))
37
+ if (existsSync(binaryPath)) {
37
38
  return binaryPath;
39
+ }
38
40
  }
39
41
  catch { }
40
42
  // Global npm install
41
43
  try {
42
44
  const globalRoot = execFileSync("npm", ["root", "-g"], { encoding: "utf-8" }).trim();
43
45
  const binaryPath = join(globalRoot, "glimpseui", "src", "glimpse");
44
- if (existsSync(binaryPath))
46
+ if (existsSync(binaryPath)) {
45
47
  return binaryPath;
48
+ }
46
49
  }
47
50
  catch { }
48
51
  return null;
@@ -59,15 +62,17 @@ export async function openGlimpseWindow(html, options) {
59
62
  title: options.title,
60
63
  });
61
64
  win.on("closed", () => {
62
- if (!active)
65
+ if (!active) {
63
66
  return;
67
+ }
64
68
  active = false;
65
69
  options.onClosed();
66
70
  });
67
71
  return {
68
72
  close: () => {
69
- if (!active)
73
+ if (!active) {
70
74
  return;
75
+ }
71
76
  active = false;
72
77
  win.close();
73
78
  },
@@ -12,4 +12,6 @@ export interface HostHtmlTemplateInput {
12
12
  appBridgeModuleUrl?: string;
13
13
  }
14
14
  export declare function buildHostHtmlTemplate(input: HostHtmlTemplateInput): string;
15
- export declare function buildCspMetaContent(csp: UiResourceCsp | undefined): string;
15
+ export declare function buildCspMetaContent(csp?: {
16
+ [K in keyof UiResourceCsp]?: unknown;
17
+ }): string;
@@ -397,31 +397,28 @@ export function buildCspMetaContent(csp) {
397
397
  toDirective("font-src", ["'self'"], resourceDomains),
398
398
  toDirective("img-src", ["'self'", "data:"], resourceDomains),
399
399
  toDirective("media-src", ["'self'", "data:"], resourceDomains),
400
- connectDomains.length > 0
401
- ? `connect-src ${connectDomains.join(" ")}`
402
- : "connect-src 'none'",
403
- frameDomains.length > 0
404
- ? `frame-src ${frameDomains.join(" ")}`
405
- : "frame-src 'none'",
400
+ connectDomains.length > 0 ? `connect-src ${connectDomains.join(" ")}` : "connect-src 'none'",
401
+ frameDomains.length > 0 ? `frame-src ${frameDomains.join(" ")}` : "frame-src 'none'",
406
402
  "worker-src 'none'",
407
403
  "object-src 'none'",
408
- baseUriDomains.length > 0
409
- ? `base-uri ${baseUriDomains.join(" ")}`
410
- : "base-uri 'self'",
404
+ baseUriDomains.length > 0 ? `base-uri ${baseUriDomains.join(" ")}` : "base-uri 'self'",
411
405
  ].join("; ");
412
406
  }
413
407
  function toDirective(name, trustedSources, domains) {
414
408
  return `${name} ${[...new Set([...trustedSources, ...domains])].join(" ")}`;
415
409
  }
416
410
  function sanitizeCspDomains(domains) {
417
- if (!Array.isArray(domains))
411
+ if (!Array.isArray(domains)) {
418
412
  return [];
419
- return [...new Set(domains.filter((domain) => typeof domain === "string" &&
413
+ }
414
+ return [
415
+ ...new Set(domains.filter((domain) => typeof domain === "string" &&
420
416
  domain.length > 0 &&
421
417
  // HTTP headers must be printable ASCII; rejecting all other code points also
422
418
  // excludes every C0/C1 control character before Node serializes the policy.
423
419
  /^[\x21-\x7E]+$/.test(domain) &&
424
- !/[;'"]/.test(domain)))];
420
+ !/[;'"]/.test(domain))),
421
+ ];
425
422
  }
426
423
  function safeInlineJSON(value) {
427
424
  return JSON.stringify(value)
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import type { McpAdapterOptions } from "./types.ts";
3
- export type { McpAdapterOptions, McpOperationContext, McpToolCallEvent, McpToolCallIdentity } from "./types.ts";
3
+ export type { McpAdapterOptions, McpOperationContext, McpToolCallEvent, McpToolCallIdentity, } from "./types.ts";
4
4
  export { MCP_STATUS_EVENT, MCP_STATUS_SNAPSHOT_VERSION, type McpServerRuntimeStatus, type McpServerStatusSnapshot, type McpStatusSnapshot, } from "./types.ts";
5
5
  export declare function createMcpAdapter(options?: McpAdapterOptions): (pi: ExtensionAPI) => void;
6
6
  declare const _default: (pi: ExtensionAPI) => void;