@pi-unipi/mcp 2.6.0 → 2.6.2
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/package.json +8 -4
- package/src/bridge/client.ts +0 -15
- package/src/config/manager.ts +0 -38
- package/src/config/schema.ts +0 -27
- package/src/config/sync.ts +0 -29
- package/src/index.ts +1 -1
- package/src/tui/add-overlay.ts +6 -6
- package/src/types.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/mcp",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"test": "npx tsx --test tests/**/*.test.ts"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@pi-unipi/core": "2.6.
|
|
33
|
+
"@pi-unipi/core": "2.6.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -41,8 +41,12 @@
|
|
|
41
41
|
"@types/node": "^25.6.0"
|
|
42
42
|
},
|
|
43
43
|
"pi": {
|
|
44
|
-
"extensions": [
|
|
45
|
-
|
|
44
|
+
"extensions": [
|
|
45
|
+
"./src/index.ts"
|
|
46
|
+
],
|
|
47
|
+
"skills": [
|
|
48
|
+
"./skills"
|
|
49
|
+
],
|
|
46
50
|
"prompts": [],
|
|
47
51
|
"themes": []
|
|
48
52
|
}
|
package/src/bridge/client.ts
CHANGED
|
@@ -47,8 +47,6 @@ interface PendingRequest {
|
|
|
47
47
|
export interface McpClientOptions {
|
|
48
48
|
/** Per-request timeout in ms (default: MCP_DEFAULTS.STARTUP_TIMEOUT_MS) */
|
|
49
49
|
timeoutMs?: number;
|
|
50
|
-
/** Working directory for the spawned process */
|
|
51
|
-
cwd?: string;
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
/**
|
|
@@ -65,11 +63,9 @@ export class McpClient {
|
|
|
65
63
|
private connected = false;
|
|
66
64
|
private stderrBuffer = "";
|
|
67
65
|
private readonly timeoutMs: number;
|
|
68
|
-
private readonly cwd?: string;
|
|
69
66
|
|
|
70
67
|
constructor(options?: McpClientOptions) {
|
|
71
68
|
this.timeoutMs = options?.timeoutMs ?? MCP_DEFAULTS.STARTUP_TIMEOUT_MS;
|
|
72
|
-
this.cwd = options?.cwd;
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
/**
|
|
@@ -91,7 +87,6 @@ export class McpClient {
|
|
|
91
87
|
this.process = spawn(command, args, {
|
|
92
88
|
stdio: ["pipe", "pipe", "pipe"],
|
|
93
89
|
env: mergedEnv,
|
|
94
|
-
cwd: this.cwd,
|
|
95
90
|
});
|
|
96
91
|
|
|
97
92
|
this.process.on("error", (err) => {
|
|
@@ -230,21 +225,11 @@ export class McpClient {
|
|
|
230
225
|
this.cleanup();
|
|
231
226
|
}
|
|
232
227
|
|
|
233
|
-
/** Whether the client is currently connected */
|
|
234
|
-
get isConnected(): boolean {
|
|
235
|
-
return this.connected;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
228
|
/** Process ID of the spawned MCP server, or undefined if not connected */
|
|
239
229
|
get pid(): number | undefined {
|
|
240
230
|
return this.process?.pid;
|
|
241
231
|
}
|
|
242
232
|
|
|
243
|
-
/** Captured stderr output */
|
|
244
|
-
get stderr(): string {
|
|
245
|
-
return this.stderrBuffer;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
233
|
// ── Internal methods ────────────────────────────────────────────
|
|
249
234
|
|
|
250
235
|
private ensureConnected(): void {
|
package/src/config/manager.ts
CHANGED
|
@@ -11,7 +11,6 @@ import * as os from "node:os";
|
|
|
11
11
|
import type {
|
|
12
12
|
McpConfig,
|
|
13
13
|
McpMetadata,
|
|
14
|
-
McpAuth,
|
|
15
14
|
ResolvedServer,
|
|
16
15
|
ServerSource,
|
|
17
16
|
} from "../types.js";
|
|
@@ -123,15 +122,6 @@ export function loadMetadata(dir: string): McpMetadata {
|
|
|
123
122
|
};
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
/**
|
|
127
|
-
* Load auth data (auth.json) from a directory.
|
|
128
|
-
* Returns empty object if file doesn't exist.
|
|
129
|
-
*/
|
|
130
|
-
export function loadAuth(dir: string): McpAuth {
|
|
131
|
-
const filePath = path.join(dir, "auth.json");
|
|
132
|
-
return readJsonFile<McpAuth>(filePath) ?? {};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
125
|
// ── Config saving ─────────────────────────────────────────────────
|
|
136
126
|
|
|
137
127
|
/**
|
|
@@ -150,14 +140,6 @@ export function saveMetadata(dir: string, meta: McpMetadata): void {
|
|
|
150
140
|
writeJsonFile(filePath, meta);
|
|
151
141
|
}
|
|
152
142
|
|
|
153
|
-
/**
|
|
154
|
-
* Save auth data (auth.json) with chmod 600.
|
|
155
|
-
*/
|
|
156
|
-
export function saveAuth(dir: string, auth: McpAuth): void {
|
|
157
|
-
const filePath = path.join(dir, "auth.json");
|
|
158
|
-
writeJsonFile(filePath, auth, 0o600);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
143
|
// ── Config merging ────────────────────────────────────────────────
|
|
162
144
|
|
|
163
145
|
/**
|
|
@@ -220,26 +202,6 @@ export function resolveServers(
|
|
|
220
202
|
}));
|
|
221
203
|
}
|
|
222
204
|
|
|
223
|
-
/**
|
|
224
|
-
* Merge auth.json env vars into a server definition at spawn time.
|
|
225
|
-
* Auth env vars are added to the server's env, but don't override
|
|
226
|
-
* explicitly set values in mcp-config.json.
|
|
227
|
-
*/
|
|
228
|
-
export function mergeEnvWithAuth(
|
|
229
|
-
serverDef: McpConfig["mcpServers"][string],
|
|
230
|
-
auth: Record<string, string>,
|
|
231
|
-
): McpConfig["mcpServers"][string] {
|
|
232
|
-
if (Object.keys(auth).length === 0) return serverDef;
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
...serverDef,
|
|
236
|
-
env: {
|
|
237
|
-
...auth,
|
|
238
|
-
...(serverDef.env ?? {}),
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
205
|
/**
|
|
244
206
|
* Load both global and project configs and resolve servers.
|
|
245
207
|
* Convenience wrapper around the individual load + resolve functions.
|
package/src/config/schema.ts
CHANGED
|
@@ -85,30 +85,3 @@ export function validateMcpConfig(config: unknown): ValidationResult {
|
|
|
85
85
|
|
|
86
86
|
return { valid: errors.length === 0, errors };
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Create a minimal server definition template for a new server.
|
|
91
|
-
*/
|
|
92
|
-
export function createServerTemplate(
|
|
93
|
-
name: string,
|
|
94
|
-
command: string,
|
|
95
|
-
args: string[],
|
|
96
|
-
envVars?: string[],
|
|
97
|
-
): McpConfig {
|
|
98
|
-
const env: Record<string, string> = {};
|
|
99
|
-
if (envVars) {
|
|
100
|
-
for (const v of envVars) {
|
|
101
|
-
env[v] = "";
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
mcpServers: {
|
|
107
|
-
[name]: {
|
|
108
|
-
command,
|
|
109
|
-
args,
|
|
110
|
-
env: Object.keys(env).length > 0 ? env : undefined,
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
};
|
|
114
|
-
}
|
package/src/config/sync.ts
CHANGED
|
@@ -319,15 +319,6 @@ function enrichWithInstallInfo(entries: CatalogEntry[]): CatalogEntry[] {
|
|
|
319
319
|
});
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
/**
|
|
323
|
-
* Check if enough time has passed since last sync.
|
|
324
|
-
*/
|
|
325
|
-
function shouldSync(lastSyncAt: string | null, intervalMs: number): boolean {
|
|
326
|
-
if (!lastSyncAt) return true;
|
|
327
|
-
const elapsed = Date.now() - new Date(lastSyncAt).getTime();
|
|
328
|
-
return elapsed >= intervalMs;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
322
|
/**
|
|
332
323
|
* Sync the MCP server catalog from GitHub.
|
|
333
324
|
* Parses the awesome-mcp-servers README, enriches with install info,
|
|
@@ -394,23 +385,3 @@ export function loadCatalog(): CatalogData {
|
|
|
394
385
|
};
|
|
395
386
|
}
|
|
396
387
|
}
|
|
397
|
-
|
|
398
|
-
/**
|
|
399
|
-
* Sync if enough time has passed since last sync.
|
|
400
|
-
* Returns null if no sync was needed, or the catalog data if synced.
|
|
401
|
-
*/
|
|
402
|
-
export async function syncIfNeeded(): Promise<CatalogData | null> {
|
|
403
|
-
const configDir = getGlobalConfigDir();
|
|
404
|
-
const meta = loadMetadata(configDir);
|
|
405
|
-
|
|
406
|
-
if (!shouldSync(meta.sync.lastSyncAt, meta.sync.syncIntervalMs)) {
|
|
407
|
-
return null;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
try {
|
|
411
|
-
return await syncCatalog();
|
|
412
|
-
} catch {
|
|
413
|
-
// Sync failed — return null, will use cached/seed data
|
|
414
|
-
return null;
|
|
415
|
-
}
|
|
416
|
-
}
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "@pi-unipi/core";
|
|
17
17
|
import type { ResolvedServer } from "./types.js";
|
|
18
18
|
import { loadAndResolve, getGlobalConfigDir } from "./config/manager.js";
|
|
19
|
-
import { syncCatalog
|
|
19
|
+
import { syncCatalog } from "./config/sync.js";
|
|
20
20
|
import { ServerRegistry } from "./bridge/registry.js";
|
|
21
21
|
import { compareCodeUnits } from "./bridge/translator.js";
|
|
22
22
|
import { renderMcpAddOverlay } from "./tui/add-overlay.js";
|
package/src/tui/add-overlay.ts
CHANGED
|
@@ -353,7 +353,7 @@ export function renderMcpAddOverlay(params?: {
|
|
|
353
353
|
return;
|
|
354
354
|
}
|
|
355
355
|
// Arrow keys + j/k navigate list while searching
|
|
356
|
-
if (matchesKey(data, Key.down) || data === "
|
|
356
|
+
if (matchesKey(data, Key.down) || data === "j") {
|
|
357
357
|
if (state.selectedIndex < state.filteredServers.length - 1) {
|
|
358
358
|
state.selectedIndex++;
|
|
359
359
|
ensureVisible();
|
|
@@ -361,7 +361,7 @@ export function renderMcpAddOverlay(params?: {
|
|
|
361
361
|
}
|
|
362
362
|
return;
|
|
363
363
|
}
|
|
364
|
-
if (matchesKey(data, Key.up) || data === "
|
|
364
|
+
if (matchesKey(data, Key.up) || data === "k") {
|
|
365
365
|
if (state.selectedIndex > 0) {
|
|
366
366
|
state.selectedIndex--;
|
|
367
367
|
ensureVisible();
|
|
@@ -370,13 +370,13 @@ export function renderMcpAddOverlay(params?: {
|
|
|
370
370
|
return;
|
|
371
371
|
}
|
|
372
372
|
// PgUp/PgDn also work in search
|
|
373
|
-
if (data
|
|
373
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
374
374
|
state.selectedIndex = Math.min(state.filteredServers.length - 1, state.selectedIndex + lastListHeight);
|
|
375
375
|
ensureVisible();
|
|
376
376
|
refresh();
|
|
377
377
|
return;
|
|
378
378
|
}
|
|
379
|
-
if (data
|
|
379
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
380
380
|
state.selectedIndex = Math.max(0, state.selectedIndex - lastListHeight);
|
|
381
381
|
ensureVisible();
|
|
382
382
|
refresh();
|
|
@@ -463,13 +463,13 @@ export function renderMcpAddOverlay(params?: {
|
|
|
463
463
|
return;
|
|
464
464
|
}
|
|
465
465
|
// PageDown / PageUp
|
|
466
|
-
if (data
|
|
466
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
467
467
|
state.selectedIndex = Math.min(listLen - 1, state.selectedIndex + lastListHeight);
|
|
468
468
|
ensureVisible();
|
|
469
469
|
refresh();
|
|
470
470
|
return;
|
|
471
471
|
}
|
|
472
|
-
if (data
|
|
472
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
473
473
|
state.selectedIndex = Math.max(0, state.selectedIndex - lastListHeight);
|
|
474
474
|
ensureVisible();
|
|
475
475
|
refresh();
|
package/src/types.ts
CHANGED
|
@@ -46,12 +46,6 @@ export interface McpMetadata {
|
|
|
46
46
|
sync: SyncConfig;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/** Per-server auth data (auth.json) */
|
|
50
|
-
export interface McpAuth {
|
|
51
|
-
/** Map of server name → environment variable key-value pairs */
|
|
52
|
-
[serverName: string]: Record<string, string>;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
49
|
/** Single entry from the MCP server catalog */
|
|
56
50
|
export interface CatalogEntry {
|
|
57
51
|
/** Unique identifier (e.g. "github/github-mcp-server") */
|