@ikuma.cloud/pix-mcp 0.0.2 → 0.0.3

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/README.md CHANGED
@@ -4,28 +4,17 @@ A small Pi MCP adapter: discover tools, load their schemas on demand, then call
4
4
  those tools natively. No scripting engine or model-provider-specific API is
5
5
  required.
6
6
 
7
- **Read [CONTRIBUTING.md](../../CONTRIBUTING.md) before making changes.**
7
+ ## Usage
8
8
 
9
- ## Development
10
-
11
- From the repository root:
12
-
13
- ```sh
14
- mise run mcp:dev
15
- mise run test --project pix-mcp
16
- mise run check
17
- ```
18
-
19
- The development task runs from `packages/mcp` and disables other extensions so
20
- another MCP adapter cannot collide with the `mcp` tool or flags. Pass arguments
21
- through the task, for example:
9
+ To load this package in an existing Pi installation:
22
10
 
23
11
  ```sh
24
- mise run mcp:dev --mcp-config /absolute/path/to/mcp.json
12
+ pi -e /absolute/path/to/pix/packages/mcp
25
13
  ```
26
14
 
27
- For an existing Pi installation, load this package with
28
- `pi --no-extensions -e /absolute/path/to/pix/packages/mcp`.
15
+ Disable any other MCP adapter that would collide with the `mcp` tool or flags,
16
+ but keep any permission-control extensions enabled. Review the configuration
17
+ and trust requirements below before connecting servers.
29
18
 
30
19
  ## Configuration and trust
31
20
 
@@ -61,8 +50,7 @@ contact remote services. Configuration trust is not an OS sandbox.
61
50
  "description": "Issue tracking tools",
62
51
  "timeout": 960000,
63
52
  "startupTimeoutMs": 30000,
64
- "catalogTimeoutMs": 30000,
65
- "approve": true
53
+ "catalogTimeoutMs": 30000
66
54
  }
67
55
  }
68
56
  }
@@ -91,7 +79,6 @@ URLs, and HTTP headers.
91
79
  | `description` | Discovery extension: optional summary, truncated to 500 characters |
92
80
  | `startupTimeoutMs` | pix extension: complete connection/initialization handshake deadline; default 30000 |
93
81
  | `catalogTimeoutMs` | pix extension: complete catalog snapshot deadline, including all pages; default 30000 |
94
- | `approve` | pix policy: require confirmation for every invocation, default `true` |
95
82
  | `disabled` | Skip the server's value validation and environment expansion when `true`; unknown fields are still errors |
96
83
 
97
84
  `command`, `args`, `cwd`, `env` values, `url`, and `headers` values expand `${VAR}`
@@ -118,14 +105,14 @@ reports that no valid servers remain. Disabled entries are omitted, not reported
118
105
  as failed connections. Correct the file and reload Pi to retry.
119
106
 
120
107
  Configuration trust still applies before any valid server is started or its
121
- metadata exposed. Per-call approval remains independent of configuration errors.
108
+ metadata exposed.
122
109
 
123
110
  ### Deadlines and migration
124
111
 
125
112
  All three deadline fields accept integers from 1 through 2,147,483,647 milliseconds
126
113
  (Node's timer-safe maximum). Each defaults independently to 30 seconds. Setting
127
114
  `"timeout": 960000` permits a 16-minute tool call without lengthening startup or
128
- discovery. The call clock starts after invocation approval and connection startup;
115
+ discovery. The call clock starts after connection startup;
129
116
  progress does not reset it. Catalog deadlines cover all pages of one snapshot;
130
117
  a subsequent list-change refresh starts a new deadline.
131
118
 
@@ -146,14 +133,22 @@ Upstream proxies and servers may still impose their own limits.
146
133
  The 120-second call ceiling is removed. This is a configuration migration, not a
147
134
  promise to finish a remote operation within its deadline.
148
135
 
149
- ### Invocation approval
136
+ ### Tool-call control
137
+
138
+ Like Pi's built-in tools, loaded MCP tools execute without adapter-specific
139
+ permission prompts in both interactive and headless sessions. Native calls pass
140
+ through Pi's normal `tool_call` and `tool_result` hooks. For approvals or access
141
+ policies, install a Pi extension that handles `tool_call` so it can manage MCP
142
+ and other tools together. Server annotations do not bypass those hooks.
143
+ Configuration trust above is separate: it authorizes startup, not individual calls.
150
144
 
151
- Tool invocation requires confirmation independently of config trust. In headless
152
- mode, calls fail closed unless the reviewed configuration explicitly sets
153
- `"approve": false` for that server. Native calls still pass through Pi's normal
154
- tool hooks. Server annotations never grant permission. Child stderr and raw SDK
155
- errors are not printed because they can contain credentials; debug a failing
156
- server separately in a trusted environment.
145
+ **Migration from 0.0.2:** Remove the server-level `approve` field. Entries that
146
+ still contain it are rejected with migration guidance rather than silently
147
+ ignoring an existing policy. If you relied on `approve: true`, configure an
148
+ external permission extension before removing it.
149
+
150
+ Child stderr and raw SDK errors are not printed because they can contain
151
+ credentials; debug a failing server separately in a trusted environment.
157
152
 
158
153
  ## Discovery and execution
159
154
 
@@ -180,10 +175,9 @@ Selection is tied to the current schema fingerprint: use `search`/`load`, not
180
175
  Pi's generic tool-name toggles, to enable a native MCP tool.
181
176
 
182
177
  Native names include a readable server/tool prefix and a deterministic hash to
183
- avoid normalization collisions. Independent, preapproved native calls can run
184
- concurrently. Calls requiring confirmation run sequentially to avoid overlapping
185
- approval dialogs. Discovered tools stay active until session shutdown or a server
186
- catalog change.
178
+ avoid normalization collisions. Independent native calls can run concurrently;
179
+ permission extensions must coordinate any shared approval UI. Discovered tools
180
+ stay active until session shutdown or a server catalog change.
187
181
  Changed and removed definitions are withdrawn; changed tools require loading
188
182
  again. Unsupported input schemas or metadata, name collisions, and task-only
189
183
  tools are counted as `unsupportedTools` in discovery results. An unsupported
@@ -237,5 +231,6 @@ OAuth, legacy SSE transport, MCP prompts/resources APIs, sampling, elicitation,
237
231
  MCP apps, task execution, semantic search, scripting, config UI, and persistent
238
232
  catalog caching. Use a fuller adapter when those capabilities are required.
239
233
 
240
- Tests use local stdio/HTTP fixture servers and isolated Pi configuration, without
241
- model requests or personal credentials.
234
+ ## Contributing
235
+
236
+ Read [CONTRIBUTING.md](CONTRIBUTING.md) before making changes.
package/mcp.schema.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "title": "pix-mcp configuration",
4
- "description": "A Claude-style connection subset with pix-specific approval and lifecycle options. Environment expansion and HTTP URL/header validation also occur at runtime.",
4
+ "description": "A Claude-style connection subset with pix-specific discovery and lifecycle options. Environment expansion and HTTP URL/header validation also occur at runtime.",
5
5
  "type": "object",
6
6
  "required": ["mcpServers"],
7
7
  "additionalProperties": false,
@@ -43,11 +43,6 @@
43
43
  "$ref": "#/$defs/timeout",
44
44
  "description": "pix extension: one complete catalog snapshot, including all pages."
45
45
  },
46
- "approve": {
47
- "type": "boolean",
48
- "default": true,
49
- "description": "pix extension: require confirmation for every tool invocation."
50
- },
51
46
  "disabled": { "const": false }
52
47
  }
53
48
  },
@@ -108,7 +103,6 @@
108
103
  "timeout": true,
109
104
  "startupTimeoutMs": true,
110
105
  "catalogTimeoutMs": true,
111
- "approve": true,
112
106
  "disabled": { "type": "boolean" }
113
107
  },
114
108
  "if": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikuma.cloud/pix-mcp",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
package/src/config.ts CHANGED
@@ -9,7 +9,6 @@ export interface CommonServer {
9
9
  timeout: number;
10
10
  startupTimeoutMs: number;
11
11
  catalogTimeoutMs: number;
12
- approve: boolean;
13
12
  }
14
13
  export type ServerConfig = CommonServer &
15
14
  (
@@ -133,6 +132,11 @@ function parseServer(
133
132
  "timeoutMs",
134
133
  "Removed; use timeout for tool calls, startupTimeoutMs for initialization, and catalogTimeoutMs for discovery (milliseconds).",
135
134
  );
135
+ if (Object.hasOwn(server, "approve"))
136
+ invalid(
137
+ "approve",
138
+ "Removed; delete approve and use a Pi tool_call extension for permission controls.",
139
+ );
136
140
  const allowed = new Set([
137
141
  "type",
138
142
  "command",
@@ -145,7 +149,6 @@ function parseServer(
145
149
  "timeout",
146
150
  "startupTimeoutMs",
147
151
  "catalogTimeoutMs",
148
- "approve",
149
152
  "disabled",
150
153
  ]);
151
154
  if (Object.keys(server).some((key) => !allowed.has(key)))
@@ -156,8 +159,6 @@ function parseServer(
156
159
  if (server.disabled !== undefined && typeof server.disabled !== "boolean")
157
160
  invalid("disabled", "Expected a boolean.");
158
161
  if (server.disabled === true) return undefined;
159
- if (server.approve !== undefined && typeof server.approve !== "boolean")
160
- invalid("approve", "Expected a boolean.");
161
162
  const common: CommonServer = {
162
163
  name,
163
164
  description:
@@ -167,7 +168,6 @@ function parseServer(
167
168
  timeout: timeout(server.timeout, "timeout"),
168
169
  startupTimeoutMs: timeout(server.startupTimeoutMs, "startupTimeoutMs"),
169
170
  catalogTimeoutMs: timeout(server.catalogTimeoutMs, "catalogTimeoutMs"),
170
- approve: server.approve !== false,
171
171
  };
172
172
  const type =
173
173
  server.type === undefined && server.command !== undefined
package/src/index.ts CHANGED
@@ -250,46 +250,22 @@ export default function mcp(pi: ExtensionAPI) {
250
250
  description:
251
251
  tool.description || `Call ${tool.name} on ${config.name}.`,
252
252
  parameters,
253
- // Approval dialogs share Pi's UI. Only preapproved calls may overlap.
254
- executionMode: config.approve ? "sequential" : "parallel",
255
- async execute(_id, params, signal, _onUpdate, ctx) {
253
+ executionMode: "parallel",
254
+ async execute(_id, params, signal) {
256
255
  current(owner);
257
256
  signal?.throwIfAborted();
258
- const verify = () => {
259
- current(owner);
260
- if (
261
- owner.entries.get(item.name)?.fingerprint !==
262
- item.fingerprint ||
263
- owner.loaded.get(item.name) !== item.fingerprint ||
264
- !pi.getActiveTools().includes(item.name)
265
- ) {
266
- throw new Error(
267
- "MCP tool is unavailable or changed. Discover it again.",
268
- );
269
- }
270
- };
271
- verify();
272
- if (!validator.Check(params))
273
- throw new Error("Arguments do not match the MCP input schema.");
274
- if (config.approve) {
275
- if (!ctx.hasUI)
276
- throw new Error(
277
- "MCP approval required. Use an interactive session or explicitly set approve:false for this trusted server.",
278
- );
279
- const input = JSON.stringify(params, null, 2);
280
- if (input.length > 8000)
281
- throw new Error(
282
- "MCP arguments are too large for the approval dialog.",
283
- );
284
- const allowed = await ctx.ui.confirm(
285
- `Call ${config.name}/${tool.name}?`,
286
- input,
287
- signal ? { signal } : undefined,
257
+ if (
258
+ owner.entries.get(item.name)?.fingerprint !==
259
+ item.fingerprint ||
260
+ owner.loaded.get(item.name) !== item.fingerprint ||
261
+ !pi.getActiveTools().includes(item.name)
262
+ ) {
263
+ throw new Error(
264
+ "MCP tool is unavailable or changed. Discover it again.",
288
265
  );
289
- if (!allowed) throw new Error("MCP tool call denied.");
290
266
  }
291
- signal?.throwIfAborted();
292
- verify();
267
+ if (!validator.Check(params))
268
+ throw new Error("Arguments do not match the MCP input schema.");
293
269
  const connection = owner.connections.get(config.name);
294
270
  if (!connection) throw new Error("MCP connection unavailable.");
295
271
  const result = await connection.call(