@geohar/pi-mcp-combiner 0.14.3 → 0.16.0-dev.1
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 +71 -48
- package/dist/client/config-ladder.d.ts +1 -1
- package/dist/client/config-ladder.d.ts.map +1 -1
- package/dist/client/control.d.ts +1 -1
- package/dist/client/control.d.ts.map +1 -1
- package/dist/client/elicitation.d.ts +4 -2
- package/dist/client/elicitation.d.ts.map +1 -1
- package/dist/client/elicitation.js +8 -2
- package/dist/client/elicitation.js.map +1 -1
- package/dist/client/footer.d.ts +1 -1
- package/dist/client/footer.d.ts.map +1 -1
- package/dist/client/panel.d.ts +1 -1
- package/dist/client/panel.d.ts.map +1 -1
- package/dist/client/panel.js +1 -1
- package/dist/client/panel.js.map +1 -1
- package/dist/client/prompts.d.ts +1 -1
- package/dist/client/prompts.d.ts.map +1 -1
- package/dist/client/proxy-tool.d.ts +1 -1
- package/dist/client/proxy-tool.d.ts.map +1 -1
- package/dist/client/resource-naming.d.ts +8 -0
- package/dist/client/resource-naming.d.ts.map +1 -0
- package/dist/client/resource-naming.js +33 -0
- package/dist/client/resource-naming.js.map +1 -0
- package/dist/client/settings.d.ts +5 -4
- package/dist/client/settings.d.ts.map +1 -1
- package/dist/client/settings.js +3 -3
- package/dist/client/settings.js.map +1 -1
- package/dist/client/tool-matching.d.ts +32 -0
- package/dist/client/tool-matching.d.ts.map +1 -0
- package/dist/client/tool-matching.js +43 -0
- package/dist/client/tool-matching.js.map +1 -0
- package/dist/client/types.d.ts +71 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +16 -0
- package/dist/client/types.js.map +1 -0
- package/dist/client/widget-support.d.ts +17 -0
- package/dist/client/widget-support.d.ts.map +1 -0
- package/dist/client/widget-support.js +89 -0
- package/dist/client/widget-support.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +109 -53
- package/dist/index.js.map +1 -1
- package/dist/{client/connection.d.ts → native/combiner-connection.d.ts} +46 -38
- package/dist/native/combiner-connection.d.ts.map +1 -0
- package/dist/native/combiner-connection.js +412 -0
- package/dist/native/combiner-connection.js.map +1 -0
- package/dist/native/index.d.ts +30 -0
- package/dist/native/index.d.ts.map +1 -0
- package/dist/native/index.js +61 -0
- package/dist/native/index.js.map +1 -0
- package/dist/native/resources.d.ts +18 -0
- package/dist/native/resources.d.ts.map +1 -0
- package/dist/native/resources.js +97 -0
- package/dist/native/resources.js.map +1 -0
- package/dist/native/tool-surface.d.ts +26 -0
- package/dist/native/tool-surface.d.ts.map +1 -0
- package/dist/native/tool-surface.js +113 -0
- package/dist/native/tool-surface.js.map +1 -0
- package/dist/pi.d.ts +19 -0
- package/dist/pi.d.ts.map +1 -1
- package/package.json +3 -5
- package/src/client/config-ladder.ts +1 -1
- package/src/client/control.ts +1 -1
- package/src/client/elicitation.ts +10 -2
- package/src/client/footer.ts +1 -1
- package/src/client/panel.ts +2 -2
- package/src/client/prompts.ts +1 -1
- package/src/client/proxy-tool.ts +1 -1
- package/src/client/resource-naming.ts +36 -0
- package/src/client/settings.ts +7 -6
- package/src/client/tool-matching.ts +69 -0
- package/src/client/types.ts +80 -0
- package/src/client/widget-support.ts +86 -0
- package/src/index.ts +109 -65
- package/src/native/combiner-connection.ts +483 -0
- package/src/native/index.ts +100 -0
- package/src/native/resources.ts +112 -0
- package/src/native/tool-surface.ts +147 -0
- package/src/pi.ts +16 -0
- package/dist/client/connection.d.ts.map +0 -1
- package/dist/client/connection.js +0 -332
- package/dist/client/connection.js.map +0 -1
- package/dist/client/direct-tools.d.ts +0 -41
- package/dist/client/direct-tools.d.ts.map +0 -1
- package/dist/client/direct-tools.js +0 -122
- package/dist/client/direct-tools.js.map +0 -1
- package/dist/client/resources.d.ts +0 -20
- package/dist/client/resources.d.ts.map +0 -1
- package/dist/client/resources.js +0 -119
- package/dist/client/resources.js.map +0 -1
- package/dist/client/script.d.ts +0 -10
- package/dist/client/script.d.ts.map +0 -1
- package/dist/client/script.js +0 -130
- package/dist/client/script.js.map +0 -1
- package/src/client/connection.ts +0 -373
- package/src/client/direct-tools.ts +0 -146
- package/src/client/resources.ts +0 -137
- package/src/client/script.ts +0 -150
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// NATIVE RESOURCE TOOLS : read_* tools for
|
|
2
|
+
// INTERACTIVE (mcp-app / ui://) resources — the parity half of legacy-client/
|
|
3
|
+
// resources.ts that pi's built-in read_mcp_resource deliberately does NOT cover
|
|
4
|
+
// (it skips ui:// listings and renders nothing).
|
|
5
|
+
//
|
|
6
|
+
// Parity contract with legacy read_<resource> tools:
|
|
7
|
+
// - SAME naming: read_<resourceNameToToolName(resource.name ?? uri)>
|
|
8
|
+
// - SAME attribution + project filtering: resourceServer() + `<server>_`/
|
|
9
|
+
// `<server>-` prefix matching against the per-project ServerFilter
|
|
10
|
+
// - SAME read behavior: connection.readResource(uri) → renderResourceResult
|
|
11
|
+
// (markup as text, json prettified, blobs as byte notes, 16KB guard)
|
|
12
|
+
// - SAME surfacing: append the combiner UI-host URL (this session's token),
|
|
13
|
+
// auto-open in the browser when a dialog-capable UI exists (uiAutoOpen)
|
|
14
|
+
// - idempotent registration; re-syncs on resources/list_changed (the
|
|
15
|
+
// connection's onToolsChanged hook covers both list-change notifications)
|
|
16
|
+
//
|
|
17
|
+
// TEXT/image resources are NOT re-registered here — pi's built-in
|
|
18
|
+
// read_mcp_resource + tool_search discovery covers them in native mode; that is
|
|
19
|
+
// the deliberate (documented) divergence from legacy, which registered one
|
|
20
|
+
// zero-arg tool per resource of every kind.
|
|
21
|
+
import { isInteractiveResource, openInBrowser, renderResourceResult } from "../client/widget-support.js";
|
|
22
|
+
import { resourceNameToToolName, resourceServer } from "../client/resource-naming.js";
|
|
23
|
+
/** Project server filter for resources — mirrors legacy filterResources
|
|
24
|
+
* attribution semantics (uri host first, `<server>_` name-prefix fallback). */
|
|
25
|
+
export function filterInteractiveResources(resources, filter) {
|
|
26
|
+
const interactive = resources.filter(isInteractiveResource);
|
|
27
|
+
if (!filter)
|
|
28
|
+
return interactive;
|
|
29
|
+
const matches = (r, entry) => resourceServer(r) === entry ||
|
|
30
|
+
(r.name ?? "").startsWith(`${entry}_`) ||
|
|
31
|
+
(r.name ?? "").startsWith(`${entry}-`);
|
|
32
|
+
if (filter.allow?.length)
|
|
33
|
+
return interactive.filter((r) => filter.allow.some((e) => matches(r, e)));
|
|
34
|
+
if (filter.deny?.length)
|
|
35
|
+
return interactive.filter((r) => !filter.deny.some((e) => matches(r, e)));
|
|
36
|
+
return interactive;
|
|
37
|
+
}
|
|
38
|
+
function toReadTool(toolName, resource, opts) {
|
|
39
|
+
const label = resource.name ?? resource.uri;
|
|
40
|
+
const url = opts.connection.uiUrlFor(resource.uri);
|
|
41
|
+
return {
|
|
42
|
+
name: toolName,
|
|
43
|
+
label: `MCP resource: ${label}`,
|
|
44
|
+
description: [
|
|
45
|
+
resource.description ?? `Read MCP resource ${resource.uri}`,
|
|
46
|
+
`uri: ${resource.uri}`,
|
|
47
|
+
resource.mimeType ? `type: ${resource.mimeType}` : undefined,
|
|
48
|
+
"interactive app resource — markup as text; the interactive widget opens from the URL appended to results",
|
|
49
|
+
]
|
|
50
|
+
.filter(Boolean)
|
|
51
|
+
.join(" | "),
|
|
52
|
+
promptSnippet: `Read MCP resource ${label}.`,
|
|
53
|
+
parameters: { type: "object", properties: {} },
|
|
54
|
+
exposure: "direct",
|
|
55
|
+
namespace: { name: "mcp_combiner", description: "mcp-combiner aggregated tools" },
|
|
56
|
+
execute: async (_toolCallId, _params, _signal, _onUpdate, ctx) => {
|
|
57
|
+
try {
|
|
58
|
+
const result = await opts.connection.readResource(resource.uri);
|
|
59
|
+
let text = renderResourceResult(result);
|
|
60
|
+
if (url) {
|
|
61
|
+
text = `${text}\n\ninteractive: ${url}`;
|
|
62
|
+
if (opts.uiAutoOpen !== false && ctx?.hasUI)
|
|
63
|
+
openInBrowser(url);
|
|
64
|
+
}
|
|
65
|
+
return { content: [{ type: "text", text }], details: { mode: "resource", uri: resource.uri, url: url || undefined } };
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
throw new Error(`${toolName}: resource read failed (${e instanceof Error ? e.message : String(e)})`);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Register read_* tools for the interactive resources (idempotent, like legacy).
|
|
74
|
+
* Returns the tool names registered this pass. */
|
|
75
|
+
export async function activateNativeResources(pi, opts, registered) {
|
|
76
|
+
let resources = [];
|
|
77
|
+
try {
|
|
78
|
+
resources = filterInteractiveResources(await opts.connection.listResources(true), opts.serverFilter);
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
opts.log("warn", `interactive resource discovery failed (${e instanceof Error ? e.message : String(e)})`);
|
|
82
|
+
return [];
|
|
83
|
+
}
|
|
84
|
+
const added = [];
|
|
85
|
+
for (const resource of resources) {
|
|
86
|
+
const toolName = `read_${resourceNameToToolName(resource.name ?? resource.uri)}`;
|
|
87
|
+
if (registered.has(toolName))
|
|
88
|
+
continue;
|
|
89
|
+
registered.add(toolName);
|
|
90
|
+
pi.registerTool(toReadTool(toolName, resource, opts));
|
|
91
|
+
added.push(toolName);
|
|
92
|
+
}
|
|
93
|
+
if (added.length)
|
|
94
|
+
opts.log("info", `native resources: ${added.length} interactive resource tool(s) registered`);
|
|
95
|
+
return added;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/native/resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "../pi.js";
|
|
2
|
+
import type { NativeCombinerConnection } from "./combiner-connection.js";
|
|
3
|
+
import type { ServerFilter } from "../client/config-ladder.js";
|
|
4
|
+
export type NativeToolSurfaceOptions = {
|
|
5
|
+
/** The resolved combiner connection (owns elicitation, filters, caches). */
|
|
6
|
+
connection: NativeCombinerConnection;
|
|
7
|
+
/** The per-project server filter (same object index.ts passes to applyFilter);
|
|
8
|
+
* applied defensively here too so a filter race never widens surface exposure. */
|
|
9
|
+
serverFilter?: ServerFilter;
|
|
10
|
+
/** The combiner block's directTools spec, as resolved from the ladder: a glob
|
|
11
|
+
* allowlist → "direct" exposure for matches; "search" → everything codemode. */
|
|
12
|
+
directSpec?: string[] | "search";
|
|
13
|
+
/** Warn when the direct-exposure set grows large (every declared schema rides in
|
|
14
|
+
* every request). Settings kill-switch: warnLargeDirectExposure (default true). */
|
|
15
|
+
warnLargeDirectExposure?: boolean;
|
|
16
|
+
/** Namespace shown in codemode's grouped listing (pi normalizes -/_ alike). */
|
|
17
|
+
namespaceName?: string;
|
|
18
|
+
/** Names that must never be shadowed by a combiner tool (pi builtins + ours). */
|
|
19
|
+
reserved?: readonly string[];
|
|
20
|
+
log: (level: "info" | "warn" | "error", message: string) => void;
|
|
21
|
+
};
|
|
22
|
+
/** Register the combiner's tools natively. Returns the names it registered (for
|
|
23
|
+
* status/panel surfaces). Idempotent by name — pi.registerTool replaces by name with
|
|
24
|
+
* a warning, so re-registration on list_changed must pass the same names. */
|
|
25
|
+
export declare function activateNativeTools(pi: ExtensionAPI, opts: NativeToolSurfaceOptions): Promise<string[]>;
|
|
26
|
+
//# sourceMappingURL=tool-surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-surface.d.ts","sourceRoot":"","sources":["../../src/native/tool-surface.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,YAAY,EAAkC,MAAM,UAAU,CAAA;AAC5E,OAAO,KAAK,EAAE,wBAAwB,EAAe,MAAM,0BAA0B,CAAA;AAErF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAM9D,MAAM,MAAM,wBAAwB,GAAG;IACnC,4EAA4E;IAC5E,UAAU,EAAE,wBAAwB,CAAA;IACpC;uFACmF;IACnF,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B;qFACiF;IACjF,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IAChC;wFACoF;IACpF,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,gFAAgF;IAChF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACnE,CAAA;AAwDD;;8EAE8E;AAC9E,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmC7G"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// NATIVE TOOL SURFACE : declares the combiner's tools
|
|
2
|
+
// to Pi FIRST-CLASS, via pi.registerTool with exposure/namespace/annotations — the
|
|
3
|
+
// replacement for client/proxy-tool.ts + client/script.ts + direct-tools.ts promotion.
|
|
4
|
+
//
|
|
5
|
+
// What this buys (the whole point of the native path):
|
|
6
|
+
//
|
|
7
|
+
// - every tool is declared under its own name (`github_search_code`), one hop,
|
|
8
|
+
// no mcp() wrapper and no mcpScript
|
|
9
|
+
// - exposure IS pi's native mechanism: `direct` for the daily drivers (declared to
|
|
10
|
+
// the model verbatim), `codemode` for the rest (callable from codemode scripts,
|
|
11
|
+
// listed only as a namespace — 4%-token cost since pi 1.0), so the combiner's
|
|
12
|
+
// 671 tools stay out of the declaration budget by default
|
|
13
|
+
// - annotations (readOnly/destructive hints) ride along, so pi-permission-system
|
|
14
|
+
// and other tool_call gates classify combiner calls without any adapter glue
|
|
15
|
+
// - tool_search / codemode searchTools() find undeclared ones by BM25, replacing
|
|
16
|
+
// directTools:"search" promotion with pi's own discovery
|
|
17
|
+
//
|
|
18
|
+
// Exposure mapping reuses the existing config vocabulary: the `combiner.directTools`
|
|
19
|
+
// allowlist in the mcp.json ladder means "these are direct" here; everything else is
|
|
20
|
+
// `codemode`. `directTools: "search"` degenerates to plain codemode (pi's tool_search
|
|
21
|
+
// replaces it). Per-project allow/deny keeps flowing combiner-side via applyFilter.
|
|
22
|
+
//
|
|
23
|
+
// Wire shape: register once at session_start (tools list is stable modulo
|
|
24
|
+
// list_changed, which re-registers on the same names). Tools the combiner offers
|
|
25
|
+
// during a session surface via the connection's onToolsChanged hook → activate again.
|
|
26
|
+
import { applyServerFilter, matchesGlob, RESERVED_TOOL_NAMES } from "../client/tool-matching.js";
|
|
27
|
+
function isRecord(v) {
|
|
28
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
29
|
+
}
|
|
30
|
+
/** Map a CallToolResult content block to pi's text-block contract. pi tool results
|
|
31
|
+
* are arrays of text blocks today; image/other blocks are summarized to text and the
|
|
32
|
+
* full result rides `details` for renderers (same shape the SDK client half uses). */
|
|
33
|
+
function textBlockOf(b) {
|
|
34
|
+
const block = isRecord(b) ? b : undefined;
|
|
35
|
+
if (block && block.type === "text") {
|
|
36
|
+
return { type: "text", text: String(block.text) };
|
|
37
|
+
}
|
|
38
|
+
const kind = block?.type ?? (block ? "content" : b);
|
|
39
|
+
return { type: "text", text: `[${String(kind)} block]` };
|
|
40
|
+
}
|
|
41
|
+
function toToolResult(call) {
|
|
42
|
+
const blocks = Array.isArray(call.content) ? call.content : [];
|
|
43
|
+
return { content: blocks.map((b) => textBlockOf(b)) };
|
|
44
|
+
}
|
|
45
|
+
/** Register the combiner's tools natively. */
|
|
46
|
+
const DIRECT_EXPOSURE_WARN_THRESHOLD = 50;
|
|
47
|
+
/** Turn one combiner ToolSummary into pi's ToolDefinition, plus the native-only fields
|
|
48
|
+
* pi 1.0 accepts on registerTool (exposure/namespace/annotations). */
|
|
49
|
+
function toNativeTool(sum, conn, exposure) {
|
|
50
|
+
const name = sum.name;
|
|
51
|
+
return {
|
|
52
|
+
name,
|
|
53
|
+
label: name,
|
|
54
|
+
description: sum.description ?? name,
|
|
55
|
+
parameters: sum.inputSchema ?? { type: "object", properties: {} },
|
|
56
|
+
// NATIVE-ONLY fields (pi ≥ 1.0 host contract): exposure decides how the tool is
|
|
57
|
+
// declared; namespace groups it in codemode's listing; annotations feed
|
|
58
|
+
// pi-permission-system's classification. Kept optional on ToolDefinition so the
|
|
59
|
+
// extension stays load-compatible with pi 0.99.x where these fields are ignored.
|
|
60
|
+
exposure,
|
|
61
|
+
namespace: { name: "mcp_combiner", description: "mcp-combiner aggregated tools" },
|
|
62
|
+
annotations: sum.annotations,
|
|
63
|
+
execute: async (_toolCallId, params, signal) => {
|
|
64
|
+
// The abort signal rides into the transport; the combiner can cancel
|
|
65
|
+
// upstream work, and widget holds respect it (notifications/cancelled).
|
|
66
|
+
void signal;
|
|
67
|
+
try {
|
|
68
|
+
const result = await conn.callTool(name, params);
|
|
69
|
+
return { ...toToolResult(result), details: result };
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
// pi's error convention: THROWING marks the call an error (no isError
|
|
73
|
+
// property on successful results).
|
|
74
|
+
throw e instanceof Error ? e : new Error(String(e));
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Register the combiner's tools natively. Returns the names it registered (for
|
|
80
|
+
* status/panel surfaces). Idempotent by name — pi.registerTool replaces by name with
|
|
81
|
+
* a warning, so re-registration on list_changed must pass the same names. */
|
|
82
|
+
export async function activateNativeTools(pi, opts) {
|
|
83
|
+
const registered = [];
|
|
84
|
+
const cachedNames = registered;
|
|
85
|
+
const tools = applyServerFilter(await opts.connection.listTools(true), opts.serverFilter);
|
|
86
|
+
const allowlist = Array.isArray(opts.directSpec) ? opts.directSpec : [];
|
|
87
|
+
const reserved = new Set([...(opts.reserved ?? []), ...RESERVED_TOOL_NAMES]);
|
|
88
|
+
const directNames = [];
|
|
89
|
+
for (const sum of tools) {
|
|
90
|
+
if (reserved.has(sum.name)) {
|
|
91
|
+
opts.log("warn", `skipping combiner tool "${sum.name}" — collides with a reserved name`);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Allowlist glob match → declared verbatim ("direct"); everything else rides
|
|
95
|
+
// codemode: callable from scripts, discoverable via tool_search/searchTools(),
|
|
96
|
+
// near-zero declaration cost. "search" degrades to the same codemode mapping
|
|
97
|
+
// (pi's tool_search replaces the adapter's search-promote semantics).
|
|
98
|
+
const exposure = allowlist.some((p) => matchesGlob(sum.name, p)) ? "direct" : "codemode";
|
|
99
|
+
if (exposure === "direct")
|
|
100
|
+
directNames.push(sum.name);
|
|
101
|
+
pi.registerTool(toNativeTool(sum, opts.connection, exposure));
|
|
102
|
+
cachedNames.push(sum.name);
|
|
103
|
+
}
|
|
104
|
+
if (directNames.length > DIRECT_EXPOSURE_WARN_THRESHOLD &&
|
|
105
|
+
opts.warnLargeDirectExposure !== false) {
|
|
106
|
+
opts.log("warn", `native mode: ${directNames.length} tools declared "direct" — every schema rides in every ` +
|
|
107
|
+
`request. Consider trimming the allowlist (directTools) or disabling this warning ` +
|
|
108
|
+
`with "warnLargeDirectExposure": false in extensions/mcp-combiner.json.`);
|
|
109
|
+
}
|
|
110
|
+
opts.log("info", `native tool surface: ${cachedNames.length} tools registered`);
|
|
111
|
+
return cachedNames;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=tool-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-surface.js","sourceRoot":"","sources":["../../src/native/tool-surface.ts"],"names":[],"mappings":"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"}
|
package/dist/pi.d.ts
CHANGED
|
@@ -128,6 +128,25 @@ export type ToolDefinition = {
|
|
|
128
128
|
}, options: ToolRenderResultOptions, theme: RenderTheme, context: {
|
|
129
129
|
[key: string]: unknown;
|
|
130
130
|
}) => TuiComponent;
|
|
131
|
+
/** NATIVE-exposure fields (pi ≥ 1.0 host contract; optional so 0.99.x hosts ignore
|
|
132
|
+
* them instead of erroring — unknown fields are dropped by the 0.99 loader):
|
|
133
|
+
* exposure — "direct" | "model-only" | "codemode" | "deferred" | "hidden":
|
|
134
|
+
* how the tool is declared to the model (codemode: callable from
|
|
135
|
+
* codemode scripts, listed as a namespace in the codemode tool's
|
|
136
|
+
* description — near-zero token cost as of pi 1.0)
|
|
137
|
+
* namespace — groups the tool in codemode's listing, like an MCP server
|
|
138
|
+
* annotations — MCP tool hints; reach pi.getAllTools() for permission gates */
|
|
139
|
+
exposure?: "direct" | "model-only" | "codemode" | "deferred" | "hidden";
|
|
140
|
+
namespace?: {
|
|
141
|
+
name: string;
|
|
142
|
+
description: string;
|
|
143
|
+
};
|
|
144
|
+
annotations?: {
|
|
145
|
+
readOnlyHint?: boolean;
|
|
146
|
+
destructiveHint?: boolean;
|
|
147
|
+
idempotentHint?: boolean;
|
|
148
|
+
openWorldHint?: boolean;
|
|
149
|
+
};
|
|
131
150
|
};
|
|
132
151
|
export type CommandSpec = {
|
|
133
152
|
description: string;
|
package/dist/pi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geohar/pi-mcp-combiner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0-dev.1",
|
|
4
4
|
"description": "Pi extension: run the mcp-combiner MCP aggregator via sharedserver and inject its tool-discovery directive. Pairs with pi-mcp-adapter, which makes the combiner's tools reachable from Pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
+
"@earendil-works/pi-mcp": "^1.0.0",
|
|
57
58
|
"@earendil-works/pi-tui": "^0.85.1",
|
|
58
59
|
"@types/node": "^22.0.0",
|
|
59
60
|
"typescript": "^5.6.0",
|
|
@@ -62,11 +63,8 @@
|
|
|
62
63
|
"engines": {
|
|
63
64
|
"node": ">=18.0.0"
|
|
64
65
|
},
|
|
65
|
-
"dependencies": {
|
|
66
|
-
"@modelcontextprotocol/client": "^2.0.0",
|
|
67
|
-
"@modelcontextprotocol/core": "^2.0.0"
|
|
68
|
-
},
|
|
69
66
|
"peerDependencies": {
|
|
67
|
+
"@earendil-works/pi-mcp": "^1.0.2",
|
|
70
68
|
"@earendil-works/pi-tui": "^0.85.1"
|
|
71
69
|
}
|
|
72
70
|
}
|
|
@@ -19,7 +19,7 @@ import { existsSync, readFileSync } from "node:fs"
|
|
|
19
19
|
import { homedir } from "node:os"
|
|
20
20
|
import { join } from "node:path"
|
|
21
21
|
import { agentDir } from "./settings.js"
|
|
22
|
-
import type { DirectToolsSpec } from "./
|
|
22
|
+
import type { DirectToolsSpec } from "./tool-matching.js"
|
|
23
23
|
|
|
24
24
|
export type ServerFilter = { allow?: string[]; deny?: string[] }
|
|
25
25
|
|
package/src/client/control.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// filter routes); the write side drives the combiner__* meta-tools through our own
|
|
5
5
|
// MCP client — one auth path, no second protocol.
|
|
6
6
|
|
|
7
|
-
import type { CombinerConnection } from "./
|
|
7
|
+
import type { CombinerConnection } from "./types.js"
|
|
8
8
|
|
|
9
9
|
export type HealthServer = { name?: string; status?: string; state?: string; transport?: string }
|
|
10
10
|
|
|
@@ -84,8 +84,15 @@ async function askProperty(
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/** Handle an elicitation request against Pi's UI. Never throws — a UI that can't
|
|
87
|
-
* answer declines, and the combiner applies its elicitUnavailable policy.
|
|
88
|
-
|
|
87
|
+
* answer declines, and the combiner applies its elicitUnavailable policy.
|
|
88
|
+
* `abort` (wired from the connection's elicitation handler signal) cancels between
|
|
89
|
+
* dialogs: a cancelled pending request must not keep prompting the user. */
|
|
90
|
+
export async function handleElicitation(
|
|
91
|
+
req: ElicitRequest,
|
|
92
|
+
elicitUi: ElicitUi,
|
|
93
|
+
abort?: AbortSignal,
|
|
94
|
+
): Promise<ElicitResponse> {
|
|
95
|
+
if (abort?.aborted) return { action: "cancel" }
|
|
89
96
|
if (!elicitUi.hasUI || !elicitUi.ui?.select || !elicitUi.ui.input) return REFUSE
|
|
90
97
|
|
|
91
98
|
const schema = isRecord(req.requestedSchema) ? req.requestedSchema : undefined
|
|
@@ -106,6 +113,7 @@ export async function handleElicitation(req: ElicitRequest, elicitUi: ElicitUi):
|
|
|
106
113
|
const entries = Object.entries(props).filter(([, v]) => isRecord(v))
|
|
107
114
|
const content: Record<string, ElicitValue> = {}
|
|
108
115
|
for (const [name, raw] of entries) {
|
|
116
|
+
if (abort?.aborted) return { action: "cancel" }
|
|
109
117
|
const label = entries.length === 1 ? header : `${header}: ${name}`
|
|
110
118
|
const value = await askProperty(elicitUi.ui, label, raw as Record<string, unknown>)
|
|
111
119
|
if (value === undefined) return REFUSE
|
package/src/client/footer.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// `mcp` (default, overridable via the mcpFooterKey setting) — the slot
|
|
5
5
|
// pi-mcp-adapter wrote and oh-my-posh-style footers aggregate into PI_STATUS.
|
|
6
6
|
|
|
7
|
-
import type { CombinerConnection } from "./
|
|
7
|
+
import type { CombinerConnection } from "./types.js"
|
|
8
8
|
import type { ExtensionUIContext } from "../pi.js"
|
|
9
9
|
import type { FooterStatus } from "./settings.js"
|
|
10
10
|
|
package/src/client/panel.ts
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import { spawn } from "node:child_process"
|
|
11
11
|
import { Container, Text, matchesKey, truncateToWidth, visibleWidth, type Component } from "@earendil-works/pi-tui"
|
|
12
|
-
import type { CombinerConnection, PromptSummary, ResourceSummary, ToolSummary } from "./
|
|
12
|
+
import type { CombinerConnection, PromptSummary, ResourceSummary, ToolSummary } from "./types.js"
|
|
13
13
|
import { metaToolCall } from "./control.js"
|
|
14
|
-
import { resourceServer } from "./
|
|
14
|
+
import { resourceServer } from "./resource-naming.js"
|
|
15
15
|
|
|
16
16
|
type RenderTheme = { fg: (color: string, text: string) => string }
|
|
17
17
|
|
package/src/client/prompts.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// passthrough) are ported from pi-mcp-adapter's prompts.ts (MIT, © 2026 Nico Bailon).
|
|
15
15
|
|
|
16
16
|
import type { ExtensionAPI } from "../pi.js"
|
|
17
|
-
import type { CombinerConnection, PromptSummary } from "./
|
|
17
|
+
import type { CombinerConnection, PromptSummary } from "./types.js"
|
|
18
18
|
|
|
19
19
|
// ── naming ──
|
|
20
20
|
|
package/src/client/proxy-tool.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { spawn } from "node:child_process"
|
|
14
14
|
import type { ToolCallContext, ToolDefinition } from "../pi.js"
|
|
15
|
-
import type { CombinerConnection, ToolSummary } from "./
|
|
15
|
+
import type { CombinerConnection, ToolSummary } from "./types.js"
|
|
16
16
|
import { compileSafeRegex, rankTools, regexMatches, type SearchableTool } from "./ranking.js"
|
|
17
17
|
import { renderDescribe, renderSearchHit, renderToolResult, textResult, toolUiResourceUri } from "./render.js"
|
|
18
18
|
import { proxyRenderers } from "./renderers.js"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Resource naming helpers — extracted from legacy-client/resources.ts during the
|
|
2
|
+
// Extracted during the legacy-client factoring so surfaces that survive the native migration (panel, widget
|
|
3
|
+
// resource attribution) don't import the deprecated legacy-client/ directory.
|
|
4
|
+
//
|
|
5
|
+
// These name the SAME way legacy read_<resource> tools always did (ported verbatim
|
|
6
|
+
// from pi-mcp-adapter, MIT © Nico Bailon); native widget resource support reuses the
|
|
7
|
+
// attribution logic, so panel counts and native read_* tools agree on server keys.
|
|
8
|
+
|
|
9
|
+
import type { ResourceSummary } from "./types.js"
|
|
10
|
+
|
|
11
|
+
/** Ported verbatim from pi-mcp-adapter's resource-tools.ts (MIT, © 2026 Nico Bailon). */
|
|
12
|
+
export function resourceNameToToolName(name: string): string {
|
|
13
|
+
let result = name
|
|
14
|
+
.replace(/[^a-zA-Z0-9]/g, "_")
|
|
15
|
+
.replace(/_+/g, "_")
|
|
16
|
+
.replace(/^_+/, "") // Remove leading underscores
|
|
17
|
+
.replace(/_+$/, "") // Remove trailing underscores
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
|
|
20
|
+
// Ensure we have a valid name
|
|
21
|
+
if (!result || /^\d/.test(result)) {
|
|
22
|
+
result = "resource" + (result ? "_" + result : "")
|
|
23
|
+
}
|
|
24
|
+
return result
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Attribute a resource to an upstream server for filtering: ui:// URIs carry the
|
|
28
|
+
* server as the host component (ui://todoist/…); otherwise fall back to the name's
|
|
29
|
+
* leading word before a dash/underscore. */
|
|
30
|
+
export function resourceServer(r: ResourceSummary): string | undefined {
|
|
31
|
+
const m = r.uri.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]+)/i)
|
|
32
|
+
if (m?.[1]) return m[1].split(".")[0]?.toLowerCase()
|
|
33
|
+
const name = r.name ?? r.uri
|
|
34
|
+
const head = name.split(/[-_]/, 1)[0]
|
|
35
|
+
return head ? head.toLowerCase() : undefined
|
|
36
|
+
}
|
package/src/client/settings.ts
CHANGED
|
@@ -21,8 +21,8 @@ export type CombinerSettings = {
|
|
|
21
21
|
toolName: string
|
|
22
22
|
/** "lazy" (default): connect on first mcp() call. "eager": connect at session_start. */
|
|
23
23
|
lazy: "lazy" | "eager"
|
|
24
|
-
/** Client-half gate. `true`: we are the MCP tool. `false`:
|
|
25
|
-
*
|
|
24
|
+
/** Client-half gate. `true`: we are the MCP tool. `false`: the process +
|
|
25
|
+
* instructions halves only, pi-mcp-adapter (if installed) owns MCP.
|
|
26
26
|
* `"auto"` (default): OFF when pi-mcp-adapter is detected installed, ON otherwise —
|
|
27
27
|
* so existing adapter users upgrade with zero behaviour change, while fresh
|
|
28
28
|
* installs get the one-package experience. Env PI_MCP_COMBINER_ADAPTER wins. */
|
|
@@ -39,11 +39,12 @@ export type CombinerSettings = {
|
|
|
39
39
|
* slot pi-mcp-adapter wrote and footers (oh-my-posh's PI_STATUS aggregate)
|
|
40
40
|
* already surface; rename only if something else claims it. */
|
|
41
41
|
mcpFooterKey: string
|
|
42
|
-
/** Register the trusted batching tool (<toolName>Script). Default true. */
|
|
43
|
-
scriptMode: boolean
|
|
44
42
|
/** Auto-open interactive widget URLs (Stage 2 holds + resource reads).
|
|
45
43
|
* Default true. */
|
|
46
44
|
uiAutoOpen: boolean
|
|
45
|
+
/** Warn when the direct-exposure set grows large (default threshold: 50 tools —
|
|
46
|
+
* every schema rides in every request). Default true. */
|
|
47
|
+
warnLargeDirectExposure: boolean
|
|
47
48
|
/** Explicit combiner base URL (e.g. "http://127.0.0.1:9741/mcp"). Env wins. */
|
|
48
49
|
url?: string
|
|
49
50
|
/** Notify (vs stderr-only) for connection lifecycle messages. */
|
|
@@ -58,8 +59,8 @@ export const DEFAULT_SETTINGS: CombinerSettings = {
|
|
|
58
59
|
prompts: true,
|
|
59
60
|
mcpFooterStatus: "full",
|
|
60
61
|
mcpFooterKey: "mcp",
|
|
61
|
-
scriptMode: true,
|
|
62
62
|
uiAutoOpen: true,
|
|
63
|
+
warnLargeDirectExposure: true,
|
|
63
64
|
notify: true,
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -102,7 +103,7 @@ export function loadSettings(path = settingsPath()): CombinerSettings {
|
|
|
102
103
|
}
|
|
103
104
|
if (typeof d.mcpFooterKey === "string" && d.mcpFooterKey.trim()) out.mcpFooterKey = d.mcpFooterKey.trim()
|
|
104
105
|
if (typeof d.uiAutoOpen === "boolean") out.uiAutoOpen = d.uiAutoOpen
|
|
105
|
-
if (typeof d.
|
|
106
|
+
if (typeof d.warnLargeDirectExposure === "boolean") out.warnLargeDirectExposure = d.warnLargeDirectExposure
|
|
106
107
|
if (typeof d.url === "string" && d.url.trim()) out.url = d.url.trim()
|
|
107
108
|
if (typeof d.notify === "boolean") out.notify = d.notify
|
|
108
109
|
return out
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Shared tool-name matching helpers — extracted from legacy-client/direct-tools.ts
|
|
2
|
+
// during the legacy-client factoring so the NATIVE tool surface (src/native/) and the
|
|
3
|
+
// client half (src/client/: config-ladder, panel) can use them without importing the
|
|
4
|
+
// deprecated legacy-client/ directory. When legacy-client/ is deleted, this file
|
|
5
|
+
// survives untouched.
|
|
6
|
+
//
|
|
7
|
+
// These are the stable contract:
|
|
8
|
+
// - tool names arrive with the combiner's baked `<server>_` prefix
|
|
9
|
+
// - server attribution is PREFIX-based (underscore-safe), not string equality
|
|
10
|
+
|
|
11
|
+
/** A combined-tool allowlist spec from the ladder's `combiner.directTools` key:
|
|
12
|
+
* a glob allowlist, or "search" (legacy adapter semantics — deprecated in the
|
|
13
|
+
* native mode, where tool_search replaces it). */
|
|
14
|
+
export type DirectToolsSpec = string[] | "search"
|
|
15
|
+
|
|
16
|
+
/** Names that must never be shadowed by a promoted/registered tool (pi builtins).
|
|
17
|
+
* Callers add their own tool names on top. */
|
|
18
|
+
export const RESERVED_TOOL_NAMES = ["read", "bash", "edit", "write", "grep", "find", "ls", "mcp", "glob"] as const
|
|
19
|
+
|
|
20
|
+
/** Apply a server allow/deny filter to a combined tool list. Server names may
|
|
21
|
+
* contain underscores (gws_georgeharker), so matching is by PREFIX — a tool
|
|
22
|
+
* belongs to entry E iff its name starts `E_` (subsumes first-segment equality). */
|
|
23
|
+
export function toolServerMatches(toolName: string, serverEntry: string): boolean {
|
|
24
|
+
return toolName.startsWith(`${serverEntry}_`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Apply a server allow/deny filter to a combined tool list (`<server>_` prefix,
|
|
28
|
+
* underscore-safe via toolServerMatches). */
|
|
29
|
+
export function applyServerFilter(
|
|
30
|
+
tools: ToolSummary[],
|
|
31
|
+
filter: { allow?: string[]; deny?: string[] } | undefined,
|
|
32
|
+
): ToolSummary[] {
|
|
33
|
+
if (!filter) return tools
|
|
34
|
+
if (filter.allow?.length) {
|
|
35
|
+
return tools.filter((t) => filter.allow!.some((e) => toolServerMatches(t.name, e)))
|
|
36
|
+
}
|
|
37
|
+
if (filter.deny?.length) {
|
|
38
|
+
return tools.filter((t) => !filter.deny!.some((e) => toolServerMatches(t.name, e)))
|
|
39
|
+
}
|
|
40
|
+
return tools
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** fnmatch-lite: `*` → any run, `?` → one char, everything else literal. */
|
|
44
|
+
export function globToRegExp(pattern: string): RegExp {
|
|
45
|
+
const escaped = pattern
|
|
46
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
47
|
+
.replace(/\*/g, ".*")
|
|
48
|
+
.replace(/\?/g, ".")
|
|
49
|
+
return new RegExp(`^${escaped}$`, "i")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function matchesGlob(name: string, pattern: string): boolean {
|
|
53
|
+
return globToRegExp(pattern).test(name)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Local shape of a combiner tool listing (kept structural — the two connection
|
|
57
|
+
// implementations share it; defined here so both src/client and src/native can
|
|
58
|
+
// import it without a connection.ts dependency).
|
|
59
|
+
export type ToolSummary = {
|
|
60
|
+
name: string
|
|
61
|
+
description?: string
|
|
62
|
+
inputSchema?: unknown
|
|
63
|
+
annotations?: {
|
|
64
|
+
readOnlyHint?: boolean
|
|
65
|
+
destructiveHint?: boolean
|
|
66
|
+
idempotentHint?: boolean
|
|
67
|
+
openWorldHint?: boolean
|
|
68
|
+
}
|
|
69
|
+
}
|