pi-mcp-adapter 1.1.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.
@@ -0,0 +1,572 @@
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 │
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
+ │ │
338
+ │ 2. Get connection from ServerManager │
339
+ │ const connection = manager.getConnection(serverName); │
340
+ │ if (!connection || connection.status !== "connected") │
341
+ │ return error; │
342
+ │ │
343
+ │ 3. Call MCP server │
344
+ │ if (toolMeta.resourceUri) { │
345
+ │ // Resource tool - use readResource │
346
+ │ connection.client.readResource({ uri: resourceUri }); │
347
+ │ } else { │
348
+ │ // Regular tool - use callTool │
349
+ │ connection.client.callTool({ │
350
+ │ name: toolMeta.originalName, ◄── Original name! │
351
+ │ arguments: args ?? {} │
352
+ │ }); │
353
+ │ } │
354
+ └───────────────────────────┬───────────────────────────────────┘
355
+
356
+
357
+ ┌───────────────────────────────────────────────────────────────┐
358
+ │ MCP Protocol │
359
+ │ │
360
+ │ ┌─────────────────┐ ┌─────────────────────────────┐ │
361
+ │ │ Pi MCP Client │ ──────► │ MCP Server (xcodebuild) │ │
362
+ │ │ │ JSON │ │ │
363
+ │ │ callTool() │ RPC │ Validates args (JSON Schema)│ │
364
+ │ │ │ ◄────── │ Executes list_sims │ │
365
+ │ └─────────────────┘ └─────────────────────────────┘ │
366
+ │ │
367
+ │ Transport: stdio (stdin/stdout) or HTTP (StreamableHTTP/SSE) │
368
+ │ Validation: MCP server validates args, not Pi │
369
+ └───────────────────────────┬───────────────────────────────────┘
370
+
371
+
372
+ ┌───────────────────────────────────────────────────────────────┐
373
+ │ Content Transformation │
374
+ │ transformMcpContent() │
375
+ │ │
376
+ │ MCP Content Types Pi Content Types │
377
+ │ ───────────────── ──────────────── │
378
+ │ { type: "text", ──► { type: "text", │
379
+ │ text: "..." } text: "..." } │
380
+ │ │
381
+ │ { type: "image", ──► { type: "image", │
382
+ │ data: "base64", data: "base64", │
383
+ │ mimeType: "..." } mimeType: "..." } │
384
+ │ │
385
+ │ { type: "resource", ──► { type: "text", │
386
+ │ resource: {...} } text: "[Resource: uri]\n..." } │
387
+ │ │
388
+ │ { type: "resource ──► { type: "text", │
389
+ │ _link", text: "[Resource Link: name]\n │
390
+ │ uri: "..." } URI: uri" } │
391
+ │ │
392
+ │ { type: "audio", ──► { type: "text", │
393
+ │ ... } text: "[Audio content: mime]" } │
394
+ │ │
395
+ └───────────────────────────┬───────────────────────────────────┘
396
+
397
+
398
+ ┌───────────────────────────────────────────────────────────────┐
399
+ │ Back to LLM │
400
+ │ │
401
+ │ { │
402
+ │ content: [ │
403
+ │ { type: "text", text: "Available iOS Simulators:..." } │
404
+ │ ], │
405
+ │ details: { mode: "call", server: "xcodebuild", ... } │
406
+ │ } │
407
+ │ │
408
+ │ LLM receives the result and continues conversation │
409
+ └───────────────────────────────────────────────────────────────┘
410
+ ```
411
+
412
+ ## Lifecycle & Health Checks
413
+
414
+ ```
415
+ ┌─────────────────────────────────────────────────────────────────────────────┐
416
+ │ Session Start │
417
+ └─────────────────────────────────────────────────────────────────────────────┘
418
+
419
+
420
+ ┌─────────────────────────────────┐
421
+ │ initializeMcp() │
422
+ │ │
423
+ │ 1. Load config │
424
+ │ 2. Create ServerManager │
425
+ │ 3. Create LifecycleManager │
426
+ │ 4. Connect to each server │
427
+ │ 5. Collect tool metadata │
428
+ │ 6. Mark keep-alive servers │
429
+ │ 7. Start health checks │
430
+ │ 8. Set reconnect callback │
431
+ └─────────────────┬───────────────┘
432
+
433
+
434
+ ┌─────────────────────────────────────────────────────────────────────────────┐
435
+ │ Normal Operation │
436
+ │ │
437
+ │ ┌─────────────────────────────────────────────────────────────────────┐ │
438
+ │ │ Health Check Loop (30s) │ │
439
+ │ │ │ │
440
+ │ │ for each keep-alive server: │ │
441
+ │ │ if (status !== "connected"): │ │
442
+ │ │ try reconnect │ │
443
+ │ │ if success: call onReconnect callback │ │
444
+ │ │ → updates toolMetadata │ │
445
+ │ │ │ │
446
+ │ │ ┌──────────────────────────────────────────────────────────┐ │ │
447
+ │ │ │ Note: Reconnect callback updates tool metadata so │ │ │
448
+ │ │ │ the mcp proxy tool can find tools after reconnection. │ │ │
449
+ │ │ └──────────────────────────────────────────────────────────┘ │ │
450
+ │ │ │ │
451
+ │ └─────────────────────────────────────────────────────────────────────┘ │
452
+ │ │
453
+ │ ┌─────────────────────────────────────────────────────────────────────┐ │
454
+ │ │ /mcp Commands │ │
455
+ │ │ │ │
456
+ │ │ /mcp status - Show all servers and their connection status │ │
457
+ │ │ /mcp tools - List all available MCP tools │ │
458
+ │ │ /mcp reconnect - Force reconnect all servers, update metadata │ │
459
+ │ │ │ │
460
+ │ │ /mcp-auth <server> - Show OAuth setup instructions │ │
461
+ │ │ │ │
462
+ │ └─────────────────────────────────────────────────────────────────────┘ │
463
+ │ │
464
+ └─────────────────────────────────────────────────────────────────────────────┘
465
+
466
+ │ session_shutdown event
467
+
468
+ ┌─────────────────────────────────────────────────────────────────────────────┐
469
+ │ Graceful Shutdown │
470
+ │ │
471
+ │ 1. Clear health check interval │
472
+ │ 2. Close all MCP connections (client + transport) │
473
+ │ 3. Tool calls via mcp proxy return "not connected" error │
474
+ │ │
475
+ └─────────────────────────────────────────────────────────────────────────────┘
476
+ ```
477
+
478
+ ## File Structure
479
+
480
+ ```
481
+ ~/.pi/agent/extensions/pi-mcp-adapter/
482
+
483
+ ├── index.ts Entry point: unified mcp tool, commands, event handlers
484
+ │ - mcp({}) status, search, list, call modes
485
+ │ - /mcp and /mcp-auth commands
486
+ │ - tool metadata management
487
+
488
+ ├── types.ts Type definitions, formatToolName()
489
+ │ - McpTool, McpResource, McpContent
490
+ │ - ServerEntry, McpConfig, McpSettings
491
+
492
+ ├── config.ts Config loading, import merging
493
+ │ - Global, project, and imported configs
494
+ │ - Priority: project > global > imports
495
+
496
+ ├── server-manager.ts MCP connection management
497
+ │ - stdio transport
498
+ │ - HTTP transport (StreamableHTTP + SSE fallback)
499
+ │ - connection pooling and deduplication
500
+
501
+ ├── tool-registrar.ts Tool name collection (NOT registration!)
502
+ │ - collectToolNames() - builds name list
503
+ │ - transformMcpContent() - MCP → Pi content
504
+
505
+ ├── resource-tools.ts Resource tool name collection
506
+ │ - collectResourceToolNames()
507
+ │ - resourceNameToToolName()
508
+
509
+ ├── lifecycle.ts Health checks, reconnection
510
+ │ - keep-alive server tracking
511
+ │ - reconnect callback for metadata updates
512
+
513
+ ├── oauth-handler.ts OAuth token file reading
514
+ │ - getStoredTokens() from ~/.pi/agent/mcp-oauth/
515
+
516
+ ├── package.json Dependencies (@modelcontextprotocol/sdk)
517
+
518
+ └── tsconfig.json TypeScript configuration
519
+ ```
520
+
521
+ ## Key Design Decisions
522
+
523
+ ```
524
+ ┌─────────────────────────────────────────────────────────────────────────────┐
525
+ │ │
526
+ │ 1. SINGLE PROXY TOOL (token efficiency) │
527
+ │ ──────────────────────────────────── │
528
+ │ Only ONE tool ("mcp") is registered with Pi. │
529
+ │ LLM discovers MCP tools on-demand via search/list. │
530
+ │ Saves ~15,000 tokens for a server with 75 tools. │
531
+ │ │
532
+ │ mcp({ tool: "xcodebuild_list_sims" }) // call │
533
+ │ mcp({ search: "simulator" }) // search │
534
+ │ mcp({ server: "xcodebuild" }) // list │
535
+ │ │
536
+ │ 2. SCHEMA ON-DEMAND (describe mode + error enhancement) │
537
+ │ ──────────────────────────────────────────────────── │
538
+ │ Schemas stored in metadata, formatted to human-readable on request. │
539
+ │ - mcp({ describe: "tool" }) returns full description + parameters │
540
+ │ - Error responses include expected parameters to help self-correct │
541
+ │ MCP server still does final validation - we just help the LLM. │
542
+ │ │
543
+ │ 3. METADATA-BASED LOOKUP │
544
+ │ ──────────────────────── │
545
+ │ Tool metadata stored in Map<server, ToolMetadata[]> │
546
+ │ executeCall() looks up tool by prefixed name → finds server + original │
547
+ │ name → calls MCP server with original name. │
548
+ │ │
549
+ │ 4. HTTP TRANSPORT FALLBACK │
550
+ │ ──────────────────────── │
551
+ │ Try StreamableHTTP first (modern), fall back to SSE (legacy). │
552
+ │ Probe with a test connection, close it, create fresh for real use. │
553
+ │ │
554
+ │ 5. TOOL PREFIXING │
555
+ │ ─────────────── │
556
+ │ Default "server" prefix prevents tool name collisions. │
557
+ │ "short" removes -mcp suffix for cleaner names. │
558
+ │ "none" is risky but available for single-server setups. │
559
+ │ │
560
+ │ 6. CONFIG IMPORT │
561
+ │ ───────────── │
562
+ │ Can import from Cursor, Claude, VSCode, etc. │
563
+ │ Allows reusing existing MCP configurations. │
564
+ │ Priority: project > global > imports │
565
+ │ │
566
+ │ 7. RECONNECT CALLBACK │
567
+ │ ────────────────── │
568
+ │ Lifecycle manager notifies extension after auto-reconnect. │
569
+ │ Extension updates tool metadata so proxy can find tools. │
570
+ │ │
571
+ └─────────────────────────────────────────────────────────────────────────────┘
572
+ ```
package/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.1.0] - 2026-01-19
9
+
10
+ ### Changed
11
+
12
+ - **Search includes schemas by default** - Search results now include parameter schemas, reducing tool calls needed (search + call instead of search + describe + call)
13
+ - **Space-separated search terms match as OR** - `"navigate screenshot"` finds tools matching either word (like most search engines)
14
+ - **Suppress server stderr by default** - MCP server logs no longer clutter terminal on startup
15
+ - Use `includeSchemas: false` for compact output without schemas
16
+ - Use `debug: true` per-server to show stderr when troubleshooting
17
+
18
+ ## [1.0.0] - 2026-01-19
19
+
20
+ ### Added
21
+
22
+ - **Single unified `mcp` tool** with token-efficient architecture (~200 tokens vs ~15,000 for individual tools)
23
+ - **Five operation modes:**
24
+ - `mcp({})` - Show server status
25
+ - `mcp({ server: "name" })` - List tools from a server
26
+ - `mcp({ search: "query" })` - Search tools by name/description
27
+ - `mcp({ describe: "tool_name" })` - Show tool details and parameter schema
28
+ - `mcp({ tool: "name", args: {...} })` - Call a tool
29
+ - **Stdio transport** for local MCP servers (command + args)
30
+ - **HTTP transport** with automatic fallback (StreamableHTTP → SSE)
31
+ - **Config imports** from Cursor, Claude Code, Claude Desktop, VS Code, Windsurf, Codex
32
+ - **Resource tools** - MCP resources exposed as callable tools
33
+ - **OAuth support** - Token file-based authentication
34
+ - **Bearer token auth** - Static or environment variable tokens
35
+ - **Keep-alive connections** with automatic health checks and reconnection
36
+ - **Schema on-demand** - Parameter schemas shown in `describe` mode and error responses
37
+ - **Commands:**
38
+ - `/mcp` or `/mcp status` - Show server status
39
+ - `/mcp tools` - List all tools
40
+ - `/mcp reconnect` - Force reconnect all servers
41
+ - `/mcp-auth <server>` - Show OAuth setup instructions
42
+
43
+ ### Architecture
44
+
45
+ - Tools stored in metadata map, not registered individually with Pi
46
+ - MCP server validates arguments (no client-side schema conversion)
47
+ - Reconnect callback updates metadata after auto-reconnect
48
+ - Human-readable schema formatting for LLM consumption