@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 +30 -35
- package/mcp.schema.json +1 -7
- package/package.json +1 -1
- package/src/config.ts +5 -5
- package/src/index.ts +12 -36
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
|
-
|
|
7
|
+
## Usage
|
|
8
8
|
|
|
9
|
-
|
|
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
|
-
|
|
12
|
+
pi -e /absolute/path/to/pix/packages/mcp
|
|
25
13
|
```
|
|
26
14
|
|
|
27
|
-
|
|
28
|
-
|
|
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.
|
|
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
|
|
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
|
-
###
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
241
|
-
|
|
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
|
|
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
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
|
-
|
|
254
|
-
|
|
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
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
292
|
-
|
|
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(
|