pi-mcp-adapter 2.1.2 → 2.2.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/ARCHITECTURE.md DELETED
@@ -1,630 +0,0 @@
1
- # Pi MCP Adapter - Architecture
2
-
3
- ## High-Level Overview
4
-
5
- ```
6
- ┌─────────────────────────────────────────────────────────────────────────────┐
7
- │ PI CODING AGENT │
8
- │ ┌───────────────────────────────────────────────────────────────────────┐ │
9
- │ │ Tool Registry │ │
10
- │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │
11
- │ │ │ read │ │ write │ │ bash │ │ mcp │ │ │
12
- │ │ │ (builtin) │ │ (builtin) │ │ (builtin) │ │ (MCP proxy) │ │ │
13
- │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────────┘ │ │
14
- │ │ │ │
15
- │ │ Only ONE tool registered for all MCP servers! │ │
16
- │ │ ~200 tokens vs ~15,000 tokens for 75 individual tools │ │
17
- │ │ │ │
18
- │ └───────────────────────────────────────────────────────────────────────┘ │
19
- │ ▲ │
20
- │ │ pi.registerTool("mcp", ...) │
21
- │ ┌──────────────────────────────────┴────────────────────────────────────┐ │
22
- │ │ PI MCP ADAPTER EXTENSION │ │
23
- │ │ ┌────────────┐ ┌─────────────────┐ ┌───────────────────────────┐ │ │
24
- │ │ │ Config │ │ Server Manager │ │ Tool Metadata │ │ │
25
- │ │ │ Loader │──│ (connections) │──│ (for search/lookup) │ │ │
26
- │ │ └────────────┘ └─────────────────┘ └───────────────────────────┘ │ │
27
- │ └───────────────────────────────────────────────────────────────────────┘ │
28
- └─────────────────────────────────────────────────────────────────────────────┘
29
- │
30
- ┌─────────────────┼─────────────────┐
31
- │ │ │
32
- ▼ ▼ ▼
33
- ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
34
- │ MCP Server │ │ MCP Server │ │ MCP Server │
35
- │ (stdio) │ │ (HTTP) │ │ (stdio) │
36
- │ │ │ │ │ │
37
- │ xcodebuild │ │ remote-api │ │ github │
38
- └─────────────┘ └─────────────┘ └─────────────┘
39
- ```
40
-
41
- ## Token Efficiency Design
42
-
43
- ```
44
- ┌─────────────────────────────────────────────────────────────────────────────┐
45
- │ OLD APPROACH (rejected) │
46
- │ │
47
- │ Register each MCP tool individually with Pi: │
48
- │ │
49
- │ - xcodebuild_list_sims (~200 tokens) │
50
- │ - xcodebuild_build_sim (~200 tokens) │
51
- │ - xcodebuild_tap (~200 tokens) │
52
- │ - ... 72 more tools ... │
53
- │ │
54
- │ Total: ~15,000 tokens just for tool definitions! │
55
- │ Problem: Burns context window, slow, expensive │
56
- │ │
57
- └─────────────────────────────────────────────────────────────────────────────┘
58
-
59
- ┌─────────────────────────────────────────────────────────────────────────────┐
60
- │ NEW APPROACH (implemented) │
61
- │ │
62
- │ Single unified `mcp` proxy tool: │
63
- │ │
64
- │ - mcp({ }) → Show server status │
65
- │ - mcp({ server: "name" }) → List tools from server │
66
- │ - mcp({ search: "search" }) → Search for tools │
67
- │ - mcp({ tool: "name", args }) → Call a tool │
68
- │ │
69
- │ Total: ~200 tokens for the proxy tool! │
70
- │ LLM discovers tools on-demand via search/list │
71
- │ │
72
- └─────────────────────────────────────────────────────────────────────────────┘
73
- ```
74
-
75
- ## Config Loading Flow
76
-
77
- ```
78
- ┌─────────────────────────┐
79
- │ loadMcpConfig() │
80
- └───────────┬─────────────┘
81
- │
82
- ┌─────────────────────┼─────────────────────┐
83
- │ │ │
84
- ▼ ▼ ▼
85
- ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
86
- │ Global Config │ │ Import Sources │ │ Project Config │
87
- │ │ │ │ │ │
88
- │ ~/.pi/agent/ │ │ ~/.cursor/ │ │ .pi/mcp.json │
89
- │ mcp.json │ │ mcp.json │ │ (in project) │
90
- │ │ │ │ │ │
91
- │ PRIORITY: 2 │ │ ~/.claude/ │ │ PRIORITY: 1 │
92
- │ (base config) │ │ claude_desktop │ │ (overrides all) │
93
- │ │ │ _config.json │ │ │
94
- └─────────┬─────────┘ │ │ └─────────┬─────────┘
95
- │ │ ~/.windsurf/ │ │
96
- │ │ mcp.json │ │
97
- │ │ │ │
98
- │ │ .vscode/mcp.json │ │
99
- │ │ │ │
100
- │ │ PRIORITY: 3 │ │
101
- │ │ (only if not in │ │
102
- │ │ global config) │ │
103
- │ └─────────┬─────────┘ │
104
- │ │ │
105
- └──────────┬──────────┴──────────┬──────────┘
106
- │ │
107
- ▼ ▼
108
- ┌─────────────────────────────────────┐
109
- │ Merged McpConfig │
110
- │ │
111
- │ { │
112
- │ mcpServers: { │
113
- │ "xcodebuild": {...}, │
114
- │ "github": {...}, │
115
- │ "imported-server": {...} │
116
- │ }, │
117
- │ settings: { │
118
- │ toolPrefix: "server" │
119
- │ } │
120
- │ } │
121
- └─────────────────────────────────────┘
122
- ```
123
-
124
- ## Connection Establishment
125
-
126
- ```
127
- ┌─────────────────────────────────────────────────────────────────────────────┐
128
- │ McpServerManager.connect() │
129
- └─────────────────────────────────────────────────────────────────────────────┘
130
- │
131
- ▼
132
- ┌─────────────────────────────────┐
133
- │ Check: Already connecting? │
134
- │ (dedupe concurrent attempts) │
135
- └─────────────────┬───────────────┘
136
- │ No
137
- ▼
138
- ┌─────────────────────────────────┐
139
- │ Check: Existing healthy │
140
- │ connection? (reuse if so) │
141
- └─────────────────┬───────────────┘
142
- │ No
143
- ▼
144
- ┌─────────────────────────────────┐
145
- │ Has command? ──────────────── │ ─── Yes ──┐
146
- └─────────────────┬───────────────┘ │
147
- │ No │
148
- ▼ ▼
149
- ┌─────────────────────────────────┐ ┌────────────────────┐
150
- │ Has URL? │ │ Create Stdio │
151
- └─────────────────┬───────────────┘ │ Transport │
152
- │ Yes │ │
153
- ▼ │ - spawn process │
154
- ┌───────────────────────────────────────┐ │ - connect stdin/ │
155
- │ HTTP Transport Selection │ │ stdout │
156
- │ │ └─────────┬──────────┘
157
- │ ┌─────────────────────────────────┐ │ │
158
- │ │ Try StreamableHTTP first │ │ │
159
- │ │ (modern MCP servers) │ │ │
160
- │ └───────────────┬─────────────────┘ │ │
161
- │ │ │ │
162
- │ Success? │ │ │
163
- │ │ │ │ │
164
- │ ┌─────┴──────┴──────┐ │ │
165
- │ │ Yes │ No │ │
166
- │ ▼ ▼ │ │
167
- │ ┌────────┐ ┌──────────────┐ │ │
168
- │ │ Use │ │ Fallback to │ │ │
169
- │ │ Stream │ │ SSE Transport│ │ │
170
- │ │ able │ │ (legacy) │ │ │
171
- │ │ HTTP │ └──────┬───────┘ │ │
172
- │ └───┬────┘ │ │ │
173
- │ │ │ │ │
174
- └──────┼────────────────┼───────────────┘ │
175
- │ │ │
176
- └────────┬───────┴────────────────────────────┘
177
- │
178
- ▼
179
- ┌───────────────────────────────────────┐
180
- │ client.connect(transport) │
181
- └───────────────────┬───────────────────┘
182
- │
183
- ┌─────────────┴─────────────┐
184
- │ │
185
- ▼ ▼
186
- ┌───────────────────┐ ┌───────────────────┐
187
- │ listTools() │ │ listResources() │
188
- │ (with cursor │ │ (with cursor │
189
- │ pagination) │ │ pagination) │
190
- └─────────┬─────────┘ └─────────┬─────────┘
191
- │ │
192
- └─────────────┬─────────────┘
193
- │
194
- ▼
195
- ┌───────────────────────────────────────┐
196
- │ ServerConnection │
197
- │ { │
198
- │ client, │
199
- │ transport, │
200
- │ tools: McpTool[], │
201
- │ resources: McpResource[], │
202
- │ status: "connected" | "closed" │
203
- │ } │
204
- └───────────────────────────────────────┘
205
- ```
206
-
207
- ## Tool Metadata Collection (NOT Registration)
208
-
209
- ```
210
- ┌─────────────────────────────────────────────────────────────────────────────┐
211
- │ MCP Server Tool Definition │
212
- │ │
213
- │ { │
214
- │ name: "list_sims", │
215
- │ description: "Lists available iOS simulators", │
216
- │ inputSchema: { ... } ◄─── NOT converted (MCP server validates) │
217
- │ } │
218
- └─────────────────────────────────────────────────────────────────────────────┘
219
- │
220
- ▼
221
- ┌─────────────────────────────────────────────────────────────────────────────┐
222
- │ Tool Name Formatting │
223
- │ formatToolName() │
224
- │ │
225
- │ Server: "xcodebuild" Tool: "list_sims" │
226
- │ │
227
- │ prefix: "server" ──► "xcodebuild_list_sims" │
228
- │ prefix: "short" ──► "xcodebuild_list_sims" (strips -mcp suffix) │
229
- │ prefix: "none" ──► "list_sims" (collision risk!) │
230
- │ │
231
- └─────────────────────────────────────────────────────────────────────────────┘
232
- │
233
- ▼
234
- ┌─────────────────────────────────────────────────────────────────────────────┐
235
- │ Tool Metadata (stored in Map) │
236
- │ NOT registered with Pi! │
237
- │ │
238
- │ toolMetadata.set("xcodebuild", [ │
239
- │ { │
240
- │ name: "xcodebuild_list_sims", ◄─── Prefixed name (for lookup) │
241
- │ originalName: "list_sims", ◄─── Original MCP tool name │
242
- │ description: "Lists available iOS simulators", │
243
- │ }, │
244
- │ { │
245
- │ name: "xcodebuild_get_simulators", │
246
- │ originalName: "get_simulators", │
247
- │ description: "Read resource: xcodebuildmcp://simulators", │
248
- │ resourceUri: "xcodebuildmcp://simulators", ◄─── Resource tools │
249
- │ }, │
250
- │ // ... more tools │
251
- │ ]); │
252
- │ │
253
- └─────────────────────────────────────────────────────────────────────────────┘
254
- ```
255
-
256
- ## How the LLM Uses MCP Tools
257
-
258
- ```
259
- ┌─────────────────────────────────────────────────────────────────────────────┐
260
- │ LLM SEES (single tool in system prompt): │
261
- │ │
262
- │ ┌─────────────────────────────────────────────────────────────────────┐ │
263
- │ │ Tool: mcp │ │
264
- │ │ Description: MCP gateway - connect to MCP servers and call tools. │ │
265
- │ │ │ │
266
- │ │ Usage: │ │
267
- │ │ mcp({ }) → Show server status │ │
268
- │ │ mcp({ server: "name" }) → List tools from server │ │
269
- │ │ mcp({ search: "query" }) → Search for tools │ │
270
- │ │ mcp({ describe: "tool_name" }) → Show tool parameters │ │
271
- │ │ mcp({ tool: "name", args: {...} })→ Call a tool │ │
272
- │ │ │ │
273
- │ │ Parameters: │ │
274
- │ │ tool?: string - Tool name to call │ │
275
- │ │ args?: object - Arguments for tool call │ │
276
- │ │ describe?: string - Tool name to describe (shows parameters) │ │
277
- │ │ search?: string - Search (space-separated words OR'd) │ │
278
- │ │ server?: string - Filter to specific server │ │
279
- │ │ regex?: boolean - Treat as regex instead of OR'd words │ │
280
- │ │ includeSchemas?: boolean - Include schemas (default: true) │ │
281
- │ └─────────────────────────────────────────────────────────────────────┘ │
282
- │ │
283
- │ ~200 tokens total (vs ~15,000 for 75 individual tools) │
284
- │ │
285
- └─────────────────────────────────────────────────────────────────────────────┘
286
- │
287
- │ LLM workflow:
288
- ▼
289
- ┌─────────────────────────────────────────────────────────────────────────────┐
290
- │ │
291
- │ 1. LLM calls mcp({}) to see what servers are available │
292
- │ → Returns: "MCP: 1/1 servers, 75 tools\n✓ xcodebuild (75 tools)" │
293
- │ │
294
- │ 2. LLM calls mcp({ search: "simulator" }) to find relevant tools │
295
- │ → Returns: "Found 5 tools matching 'simulator':\n- xcodebuild_..." │
296
- │ │
297
- │ 3. LLM calls mcp({ describe: "xcodebuild_boot_sim" }) to see parameters │
298
- │ → Returns: "Parameters:\n simulatorId (string) *required*\n ..." │
299
- │ │
300
- │ 4. LLM calls mcp({ tool: "xcodebuild_boot_sim", args: {...} }) to execute │
301
- │ → Returns: "Simulator booted successfully" │
302
- │ │
303
- │ Note: Step 3 is optional - LLM can skip it and learn from error messages │
304
- │ which include the expected parameter schema. │
305
- │ │
306
- └─────────────────────────────────────────────────────────────────────────────┘
307
- ```
308
-
309
- ## Tool Execution Flow
310
-
311
- ```
312
- ┌────────────────────────┐
313
- │ LLM decides to call: │
314
- │ mcp({ │
315
- │ tool: "xcodebuild_ │
316
- │ list_sims" │
317
- │ }) │
318
- └───────────┬────────────┘
319
- │
320
- ▼
321
- ┌───────────────────────────────────────────────────────────────┐
322
- │ Pi Tool Executor │
323
- │ │
324
- │ Looks up "mcp" in Tool Registry │
325
- │ Finds the unified MCP proxy tool │
326
- └───────────────────────────┬───────────────────────────────────┘
327
- │
328
- ▼
329
- ┌───────────────────────────────────────────────────────────────┐
330
- │ mcp tool execute() - executeCall() │
331
- │ │
332
- │ 1. Look up tool in toolMetadata (may be from cache) │
333
- │ for (const [server, metadata] of toolMetadata) { │
334
- │ const found = metadata.find(m => m.name === toolName); │
335
- │ if (found) { serverName = server; toolMeta = found; } │
336
- │ } │
337
- │ If not found: try prefix-match → lazy connect candidate │
338
- │ │
339
- │ 2. Ensure connection (lazy connect if needed) │
340
- │ const connection = manager.getConnection(serverName); │
341
- │ if (!connection || status !== "connected") │
342
- │ → check failure backoff (60s) │
343
- │ → connect, refresh metadata, re-resolve toolMeta │
344
- │ │
345
- │ 3. Call MCP server (with in-flight tracking) │
346
- │ incrementInFlight() + touch() │
347
- │ if (toolMeta.resourceUri) { │
348
- │ connection.client.readResource({ uri: resourceUri }); │
349
- │ } else { │
350
- │ connection.client.callTool({ │
351
- │ name: toolMeta.originalName, ◄── Original name! │
352
- │ arguments: args ?? {} │
353
- │ }); │
354
- │ } │
355
- │ finally { decrementInFlight() + touch() } │
356
- └───────────────────────────┬───────────────────────────────────┘
357
- │
358
- ▼
359
- ┌───────────────────────────────────────────────────────────────┐
360
- │ MCP Protocol │
361
- │ │
362
- │ ┌─────────────────┐ ┌─────────────────────────────┐ │
363
- │ │ Pi MCP Client │ ──────► │ MCP Server (xcodebuild) │ │
364
- │ │ │ JSON │ │ │
365
- │ │ callTool() │ RPC │ Validates args (JSON Schema)│ │
366
- │ │ │ ◄────── │ Executes list_sims │ │
367
- │ └─────────────────┘ └─────────────────────────────┘ │
368
- │ │
369
- │ Transport: stdio (stdin/stdout) or HTTP (StreamableHTTP/SSE) │
370
- │ Validation: MCP server validates args, not Pi │
371
- └───────────────────────────┬───────────────────────────────────┘
372
- │
373
- ▼
374
- ┌───────────────────────────────────────────────────────────────┐
375
- │ Content Transformation │
376
- │ transformMcpContent() │
377
- │ │
378
- │ MCP Content Types Pi Content Types │
379
- │ ───────────────── ──────────────── │
380
- │ { type: "text", ──► { type: "text", │
381
- │ text: "..." } text: "..." } │
382
- │ │
383
- │ { type: "image", ──► { type: "image", │
384
- │ data: "base64", data: "base64", │
385
- │ mimeType: "..." } mimeType: "..." } │
386
- │ │
387
- │ { type: "resource", ──► { type: "text", │
388
- │ resource: {...} } text: "[Resource: uri]\n..." } │
389
- │ │
390
- │ { type: "resource ──► { type: "text", │
391
- │ _link", text: "[Resource Link: name]\n │
392
- │ uri: "..." } URI: uri" } │
393
- │ │
394
- │ { type: "audio", ──► { type: "text", │
395
- │ ... } text: "[Audio content: mime]" } │
396
- │ │
397
- └───────────────────────────┬───────────────────────────────────┘
398
- │
399
- ▼
400
- ┌───────────────────────────────────────────────────────────────┐
401
- │ Back to LLM │
402
- │ │
403
- │ { │
404
- │ content: [ │
405
- │ { type: "text", text: "Available iOS Simulators:..." } │
406
- │ ], │
407
- │ details: { mode: "call", server: "xcodebuild", ... } │
408
- │ } │
409
- │ │
410
- │ LLM receives the result and continues conversation │
411
- └───────────────────────────────────────────────────────────────┘
412
- ```
413
-
414
- ## Lifecycle & Health Checks
415
-
416
- Servers support three lifecycle modes:
417
-
418
- - **lazy** (default): Don't connect at startup. Connect on first tool call. Subject to idle timeout (default 10 minutes). Cached metadata enables search/list without connections.
419
- - **eager**: Connect at startup. No idle timeout by default. If the connection drops, reconnects on next use (like lazy).
420
- - **keep-alive**: Connect at startup. No idle timeout. Auto-reconnects via health checks if the connection drops.
421
-
422
- ```
423
- ┌─────────────────────────────────────────────────────────────────────────────┐
424
- │ Session Start │
425
- └─────────────────────────────────────────────────────────────────────────────┘
426
- │
427
- ▼
428
- ┌─────────────────────────────────┐
429
- │ initializeMcp() │
430
- │ │
431
- │ 1. Load config │
432
- │ 2. Create ServerManager │
433
- │ 3. Create LifecycleManager │
434
- │ 4. Load metadata cache │
435
- │ 5. Register all servers with │
436
- │ lifecycle manager │
437
- │ 6. Reconstruct toolMetadata │
438
- │ from cache (no connection) │
439
- │ 7. Connect only eager + │
440
- │ keep-alive servers │
441
- │ (or all on first-run │
442
- │ bootstrap) │
443
- │ 8. Start health checks │
444
- │ 9. Set reconnect/idle callbacks │
445
- └─────────────────┬───────────────┘
446
- │
447
- ▼
448
- ┌─────────────────────────────────────────────────────────────────────────────┐
449
- │ Normal Operation │
450
- │ │
451
- │ ┌─────────────────────────────────────────────────────────────────────┐ │
452
- │ │ Health Check Loop (30s) │ │
453
- │ │ │ │
454
- │ │ for each keep-alive server: │ │
455
- │ │ if (status !== "connected"): │ │
456
- │ │ try reconnect → onReconnect → updates toolMetadata + cache │ │
457
- │ │ │ │
458
- │ │ for each non-keep-alive server: │ │
459
- │ │ if idle > timeout and inFlight == 0: │ │
460
- │ │ close connection → onIdleShutdown │ │
461
- │ │ (toolMetadata preserved for search/list) │ │
462
- │ │ │ │
463
- │ └─────────────────────────────────────────────────────────────────────┘ │
464
- │ │
465
- │ ┌─────────────────────────────────────────────────────────────────────┐ │
466
- │ │ Lazy Connection (on tool call) │ │
467
- │ │ │ │
468
- │ │ executeCall() finds tool in cached metadata but no connection: │ │
469
- │ │ 1. Check failure backoff (60s) │ │
470
- │ │ 2. Connect server │ │
471
- │ │ 3. Refresh metadata from live connection │ │
472
- │ │ 4. Re-resolve tool (may have changed since cache) │ │
473
- │ │ 5. Execute tool call with in-flight tracking │ │
474
- │ │ │ │
475
- │ │ Prefix-match fallback: if tool name has a server prefix but │ │
476
- │ │ no metadata, try connecting the matching server │ │
477
- │ │ │ │
478
- │ └─────────────────────────────────────────────────────────────────────┘ │
479
- │ │
480
- │ ┌─────────────────────────────────────────────────────────────────────┐ │
481
- │ │ /mcp Commands │ │
482
- │ │ │ │
483
- │ │ /mcp status - Show all servers and connection status │ │
484
- │ │ /mcp tools - List all available MCP tools │ │
485
- │ │ /mcp reconnect - Force reconnect all servers │ │
486
- │ │ /mcp reconnect <name> - Connect or reconnect a single server │ │
487
- │ │ │ │
488
- │ │ /mcp-auth <server> - Show OAuth setup instructions │ │
489
- │ │ │ │
490
- │ └─────────────────────────────────────────────────────────────────────┘ │
491
- │ │
492
- └─────────────────────────────────────────────────────────────────────────────┘
493
- │
494
- │ session_shutdown event
495
- ▼
496
- ┌─────────────────────────────────────────────────────────────────────────────┐
497
- │ Graceful Shutdown │
498
- │ │
499
- │ 1. Flush metadata cache for all connected servers │
500
- │ 2. Clear health check interval │
501
- │ 3. Close all MCP connections (client + transport) │
502
- │ │
503
- └─────────────────────────────────────────────────────────────────────────────┘
504
- ```
505
-
506
- ## File Structure
507
-
508
- ```
509
- ~/.pi/agent/extensions/pi-mcp-adapter/
510
- │
511
- ├── index.ts Entry point: unified mcp tool, commands, event handlers
512
- │ - mcp({}) status, search, list, call modes
513
- │ - /mcp and /mcp-auth commands
514
- │ - tool metadata management
515
- │
516
- ├── types.ts Type definitions, formatToolName()
517
- │ - McpTool, McpResource, McpContent
518
- │ - ServerEntry, McpConfig, McpSettings
519
- │
520
- ├── config.ts Config loading, import merging
521
- │ - Global, project, and imported configs
522
- │ - Priority: project > global > imports
523
- │
524
- ├── server-manager.ts MCP connection management
525
- │ - stdio transport
526
- │ - HTTP transport (StreamableHTTP + SSE fallback)
527
- │ - connection pooling and deduplication
528
- │
529
- ├── tool-registrar.ts MCP content transformation
530
- │ - transformMcpContent() - MCP → Pi content
531
- │
532
- ├── resource-tools.ts Resource name utilities
533
- │ - resourceNameToToolName()
534
- │
535
- ├── metadata-cache.ts Persistent tool/resource metadata cache
536
- │ - Per-server cache at ~/.pi/agent/mcp-cache.json
537
- │ - Config hashing, staleness checks, reconstruction
538
- │ - Read-merge-write for multi-session safety
539
- │
540
- ├── npx-resolver.ts npx binary resolution (skip npm parent process)
541
- │ - Probes ~/.npm/_npx/ cache directly
542
- │ - Persistent cache at ~/.pi/agent/mcp-npx-cache.json
543
- │ - JS detection (extension + shebang)
544
- │
545
- ├── lifecycle.ts Health checks, reconnection, idle timeout
546
- │ - keep-alive server tracking + auto-reconnect
547
- │ - Idle timeout for lazy/eager servers
548
- │ - Per-server and global timeout settings
549
- │
550
- ├── oauth-handler.ts OAuth token file reading
551
- │ - getStoredTokens() from ~/.pi/agent/mcp-oauth/
552
- │
553
- ├── package.json Dependencies (@modelcontextprotocol/sdk)
554
- │
555
- └── tsconfig.json TypeScript configuration
556
- ```
557
-
558
- ## Key Design Decisions
559
-
560
- ```
561
- ┌─────────────────────────────────────────────────────────────────────────────┐
562
- │ │
563
- │ 1. SINGLE PROXY TOOL (token efficiency) │
564
- │ ──────────────────────────────────── │
565
- │ Only ONE tool ("mcp") is registered with Pi. │
566
- │ LLM discovers MCP tools on-demand via search/list. │
567
- │ Saves ~15,000 tokens for a server with 75 tools. │
568
- │ │
569
- │ mcp({ tool: "xcodebuild_list_sims" }) // call │
570
- │ mcp({ search: "simulator" }) // search │
571
- │ mcp({ server: "xcodebuild" }) // list │
572
- │ │
573
- │ 2. SCHEMA ON-DEMAND (describe mode + error enhancement) │
574
- │ ──────────────────────────────────────────────────── │
575
- │ Schemas stored in metadata, formatted to human-readable on request. │
576
- │ - mcp({ describe: "tool" }) returns full description + parameters │
577
- │ - Error responses include expected parameters to help self-correct │
578
- │ MCP server still does final validation - we just help the LLM. │
579
- │ │
580
- │ 3. METADATA-BASED LOOKUP │
581
- │ ──────────────────────── │
582
- │ Tool metadata stored in Map<server, ToolMetadata[]> │
583
- │ executeCall() looks up tool by prefixed name → finds server + original │
584
- │ name → calls MCP server with original name. │
585
- │ │
586
- │ 4. HTTP TRANSPORT FALLBACK │
587
- │ ──────────────────────── │
588
- │ Try StreamableHTTP first (modern), fall back to SSE (legacy). │
589
- │ Probe with a test connection, close it, create fresh for real use. │
590
- │ │
591
- │ 5. TOOL PREFIXING │
592
- │ ─────────────── │
593
- │ Default "server" prefix prevents tool name collisions. │
594
- │ "short" removes -mcp suffix for cleaner names. │
595
- │ "none" is risky but available for single-server setups. │
596
- │ │
597
- │ 6. CONFIG IMPORT │
598
- │ ───────────── │
599
- │ Can import from Cursor, Claude, VSCode, etc. │
600
- │ Allows reusing existing MCP configurations. │
601
- │ Priority: project > global > imports │
602
- │ │
603
- │ 7. RECONNECT CALLBACK │
604
- │ ────────────────── │
605
- │ Lifecycle manager notifies extension after auto-reconnect. │
606
- │ Extension updates tool metadata so proxy can find tools. │
607
- │ │
608
- │ 8. LAZY BY DEFAULT │
609
- │ ─────────────── │
610
- │ All servers default to lifecycle: "lazy". They only connect │
611
- │ when a tool call needs them. Cached metadata enables │
612
- │ search/list/describe without live connections. Idle servers │
613
- │ are disconnected after 10 minutes (configurable). │
614
- │ │
615
- │ 9. METADATA CACHE │
616
- │ ────────────── │
617
- │ ~/.pi/agent/mcp-cache.json stores per-server tool/resource │
618
- │ metadata with config hash validation and 7-day staleness. │
619
- │ Cache stores original MCP names (not prefixed) — toolPrefix │
620
- │ changes never invalidate the cache. Read-merge-write with │
621
- │ per-process tmp files for multi-session safety. │
622
- │ │
623
- │ 10. NPX RESOLUTION │
624
- │ ─────────────── │
625
- │ npx-based servers resolve to direct binary paths, eliminating │
626
- │ the ~143 MB npm parent process per server. Probes ~/.npm/_npx/ │
627
- │ cache directly. JS files run via node, others executed directly. │
628
- │ │
629
- └─────────────────────────────────────────────────────────────────────────────┘
630
- ```