@qusic/pi-dynamic-mcp 0.20261015.0 → 0.20261016.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/README.md +1 -1
- package/dynamic-mcp.ts +10 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Small [Pi](https://github.com/earendil-works/pi) extensions for personal use, pu
|
|
|
4
4
|
|
|
5
5
|
| Extension | npm | Install | Description |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
|
-
| [compact-filter](./compact-filter.ts) | [](https://www.npmjs.com/package/@qusic/pi-compact-filter) | `pi install npm:@qusic/pi-compact-filter` |
|
|
7
|
+
| [compact-filter](./compact-filter.ts) | [](https://www.npmjs.com/package/@qusic/pi-compact-filter) | `pi install npm:@qusic/pi-compact-filter` | Keep Pi compaction file lists scoped to the current summary window. |
|
|
8
8
|
| [copilot-sync](./copilot-sync.ts) | [](https://www.npmjs.com/package/@qusic/pi-copilot-sync) | `pi install npm:@qusic/pi-copilot-sync` | Sync live GitHub Copilot model capabilities into Pi. |
|
|
9
9
|
| [copilot2api](./copilot2api.ts) | [](https://www.npmjs.com/package/@qusic/pi-copilot2api) | `pi install npm:@qusic/pi-copilot2api` | Add copilot2api as a native Pi provider with live model discovery. |
|
|
10
10
|
| [dynamic-mcp](./dynamic-mcp.ts) | [](https://www.npmjs.com/package/@qusic/pi-dynamic-mcp) | `pi install npm:@qusic/pi-dynamic-mcp` | Dynamically manage MCP servers for the current Pi session. |
|
package/dynamic-mcp.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// npm-description: Dynamically manage MCP servers for the current Pi session.
|
|
2
2
|
// npm-keywords: mcp, model-context-protocol, dynamic-mcp, session-scoped, stdio, streamable-http
|
|
3
3
|
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
4
5
|
import { StringEnum, Type } from "@earendil-works/pi-ai";
|
|
5
6
|
import type { ExtensionAPI, McpServerConfig } from "@earendil-works/pi-coding-agent";
|
|
6
7
|
|
|
@@ -24,36 +25,38 @@ const parameters = Type.Object({
|
|
|
24
25
|
});
|
|
25
26
|
|
|
26
27
|
export default function (pi: ExtensionAPI) {
|
|
27
|
-
const managed = new Map<string,
|
|
28
|
+
const managed = new Map<string, McpServerConfig>();
|
|
28
29
|
|
|
29
30
|
pi.registerTool({
|
|
30
31
|
name: "mcp",
|
|
31
32
|
label: "MCP",
|
|
32
33
|
description:
|
|
33
|
-
"Manage session MCP servers: add(name, config) with command/args (stdio) or url (HTTP), remove(name), or list(). list shows
|
|
34
|
+
"Manage session MCP servers: add(name, config) with command/args (stdio) or url (HTTP), remove(name), or list(). list shows server configs managed by this tool, not connection status. env and headers support ${VAR}.",
|
|
34
35
|
parameters,
|
|
35
36
|
async execute(_id, { action, name, config }) {
|
|
36
37
|
let text: string;
|
|
37
38
|
if (action === "list") {
|
|
38
|
-
text =
|
|
39
|
+
text = JSON.stringify(Object.fromEntries(managed), null, 2);
|
|
39
40
|
} else if (!name) {
|
|
40
41
|
throw new Error("Server name is required");
|
|
41
42
|
} else if (action === "remove") {
|
|
42
|
-
if (!managed.has(name)) throw new Error(`Server "${name}"
|
|
43
|
+
if (!managed.has(name)) throw new Error(`Server "${name}" is not managed by this tool`);
|
|
43
44
|
pi.unregisterMcpServer(name);
|
|
44
45
|
managed.delete(name);
|
|
45
46
|
text = `Removed "${name}"`;
|
|
46
47
|
} else {
|
|
47
48
|
if (!config || Boolean(config.command) === Boolean(config.url)) {
|
|
48
|
-
throw new Error("Provide
|
|
49
|
+
throw new Error("Provide exactly one of command (stdio) or url (HTTP) in config");
|
|
49
50
|
}
|
|
50
51
|
const common = { description: config.description, timeout: config.timeout };
|
|
51
52
|
const serverConfig: McpServerConfig = config.url
|
|
52
53
|
? { ...common, url: config.url, headers: config.headers }
|
|
53
54
|
: { ...common, command: config.command!, args: config.args, cwd: config.cwd, env: config.env };
|
|
55
|
+
const duplicate = [...managed].find(([, existing]) => isDeepStrictEqual(existing, serverConfig));
|
|
56
|
+
if (duplicate) throw new Error(`Server "${duplicate[0]}" is already registered with an identical config`);
|
|
54
57
|
pi.registerMcpServer(name, serverConfig);
|
|
55
|
-
managed.set(name,
|
|
56
|
-
text = `Registered "${name}"
|
|
58
|
+
managed.set(name, structuredClone(serverConfig));
|
|
59
|
+
text = `Registered "${name}". Use codemode to find and call its tools.`;
|
|
57
60
|
}
|
|
58
61
|
return { content: [{ type: "text", text }], details: undefined };
|
|
59
62
|
},
|