@geohar/pi-mcp-combiner 0.13.3 → 0.14.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 +227 -126
- package/dist/client/config-ladder.d.ts +62 -0
- package/dist/client/config-ladder.d.ts.map +1 -0
- package/dist/client/config-ladder.js +162 -0
- package/dist/client/config-ladder.js.map +1 -0
- package/dist/client/connection.d.ts +113 -0
- package/dist/client/connection.d.ts.map +1 -0
- package/dist/client/connection.js +332 -0
- package/dist/client/connection.js.map +1 -0
- package/dist/client/control.d.ts +17 -0
- package/dist/client/control.d.ts.map +1 -0
- package/dist/client/control.js +80 -0
- package/dist/client/control.js.map +1 -0
- package/dist/client/direct-tools.d.ts +41 -0
- package/dist/client/direct-tools.d.ts.map +1 -0
- package/dist/client/direct-tools.js +122 -0
- package/dist/client/direct-tools.js.map +1 -0
- package/dist/client/elicitation.d.ts +22 -0
- package/dist/client/elicitation.d.ts.map +1 -0
- package/dist/client/elicitation.js +93 -0
- package/dist/client/elicitation.js.map +1 -0
- package/dist/client/footer.d.ts +17 -0
- package/dist/client/footer.d.ts.map +1 -0
- package/dist/client/footer.js +99 -0
- package/dist/client/footer.js.map +1 -0
- package/dist/client/panel.d.ts +16 -0
- package/dist/client/panel.d.ts.map +1 -0
- package/dist/client/panel.js +426 -0
- package/dist/client/panel.js.map +1 -0
- package/dist/client/prompts.d.ts +30 -0
- package/dist/client/prompts.d.ts.map +1 -0
- package/dist/client/prompts.js +230 -0
- package/dist/client/prompts.js.map +1 -0
- package/dist/client/proxy-tool.d.ts +22 -0
- package/dist/client/proxy-tool.d.ts.map +1 -0
- package/dist/client/proxy-tool.js +225 -0
- package/dist/client/proxy-tool.js.map +1 -0
- package/dist/client/ranking.d.ts +21 -0
- package/dist/client/ranking.d.ts.map +1 -0
- package/dist/client/ranking.js +113 -0
- package/dist/client/ranking.js.map +1 -0
- package/dist/client/render.d.ts +28 -0
- package/dist/client/render.d.ts.map +1 -0
- package/dist/client/render.js +166 -0
- package/dist/client/render.js.map +1 -0
- package/dist/client/renderers.d.ts +31 -0
- package/dist/client/renderers.d.ts.map +1 -0
- package/dist/client/renderers.js +191 -0
- package/dist/client/renderers.js.map +1 -0
- package/dist/client/resources.d.ts +20 -0
- package/dist/client/resources.d.ts.map +1 -0
- package/dist/client/resources.js +119 -0
- package/dist/client/resources.js.map +1 -0
- package/dist/client/schema-signature.d.ts +3 -0
- package/dist/client/schema-signature.d.ts.map +1 -0
- package/dist/client/schema-signature.js +183 -0
- package/dist/client/schema-signature.js.map +1 -0
- package/dist/client/script.d.ts +10 -0
- package/dist/client/script.d.ts.map +1 -0
- package/dist/client/script.js +130 -0
- package/dist/client/script.js.map +1 -0
- package/dist/client/settings.d.ts +46 -0
- package/dist/client/settings.d.ts.map +1 -0
- package/dist/client/settings.js +81 -0
- package/dist/client/settings.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +333 -29
- package/dist/index.js.map +1 -1
- package/dist/pi.d.ts +82 -2
- package/dist/pi.d.ts.map +1 -1
- package/dist/pi.js +2 -1
- package/dist/pi.js.map +1 -1
- package/dist/sharedserver-resolve.d.ts.map +1 -1
- package/dist/sharedserver-resolve.js +2 -1
- package/dist/sharedserver-resolve.js.map +1 -1
- package/package.json +68 -57
- package/src/client/config-ladder.ts +221 -0
- package/src/client/connection.ts +373 -0
- package/src/client/control.ts +94 -0
- package/src/client/direct-tools.ts +146 -0
- package/src/client/elicitation.ts +115 -0
- package/src/client/footer.ts +108 -0
- package/src/client/panel.ts +478 -0
- package/src/client/prompts.ts +251 -0
- package/src/client/proxy-tool.ts +261 -0
- package/src/client/ranking.ts +130 -0
- package/src/client/render.ts +166 -0
- package/src/client/renderers.ts +211 -0
- package/src/client/resources.ts +137 -0
- package/src/client/schema-signature.ts +184 -0
- package/src/client/script.ts +150 -0
- package/src/client/settings.ts +109 -0
- package/src/index.ts +384 -32
- package/src/pi.ts +86 -6
- package/src/sharedserver-resolve.ts +10 -3
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// MCP resources → read_* Pi tools, compatible with pi-mcp-adapter's conventions.
|
|
2
|
+
//
|
|
3
|
+
// A resource is server-exposed content addressed by URI (the GET to tools' POST);
|
|
4
|
+
// each becomes a zero-parameter tool the model can call directly, named
|
|
5
|
+
// `read_<sanitized>` (resourceNameToToolName ported verbatim). Reads go through the
|
|
6
|
+
// combiner's proxied resources/read; text is guarded, binaries noted by size.
|
|
7
|
+
//
|
|
8
|
+
// Interactive mcp-app resources (mimeType `text/html;profile=mcp-app`, `ui://` URIs)
|
|
9
|
+
// are flagged in the tool description — read_* returns their markup as text; the
|
|
10
|
+
// interactive browser experience is the ext-apps host (later, see adapter-design.md).
|
|
11
|
+
import { renderResourceResult, textResult } from "./render.js";
|
|
12
|
+
import { openInBrowser } from "./proxy-tool.js";
|
|
13
|
+
import { callRenderer, resultRenderer } from "./renderers.js";
|
|
14
|
+
/** Ported verbatim from pi-mcp-adapter's resource-tools.ts (MIT, © 2026 Nico Bailon). */
|
|
15
|
+
export function resourceNameToToolName(name) {
|
|
16
|
+
let result = name
|
|
17
|
+
.replace(/[^a-zA-Z0-9]/g, "_")
|
|
18
|
+
.replace(/_+/g, "_")
|
|
19
|
+
.replace(/^_+/, "") // Remove leading underscores
|
|
20
|
+
.replace(/_+$/, "") // Remove trailing underscores
|
|
21
|
+
.toLowerCase();
|
|
22
|
+
// Ensure we have a valid name
|
|
23
|
+
if (!result || /^\d/.test(result)) {
|
|
24
|
+
result = "resource" + (result ? "_" + result : "");
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
export const MCP_APP_MIME = "text/html;profile=mcp-app";
|
|
29
|
+
/** True for interactive ext-apps resources: read_* returns their markup AND
|
|
30
|
+
* surfaces the combiner UI-host URL (which serves the live widget). */
|
|
31
|
+
export function isInteractiveResource(r) {
|
|
32
|
+
return r.mimeType === MCP_APP_MIME || r.uri.startsWith("ui://");
|
|
33
|
+
}
|
|
34
|
+
/** Attribute a resource to an upstream server for filtering: ui:// URIs carry the
|
|
35
|
+
* server as the host component (ui://todoist/…); otherwise fall back to the name's
|
|
36
|
+
* leading word before a dash/underscore. */
|
|
37
|
+
export function resourceServer(r) {
|
|
38
|
+
const m = r.uri.match(/^[a-z][a-z0-9+.-]*:\/\/([^/?#]+)/i);
|
|
39
|
+
if (m?.[1])
|
|
40
|
+
return m[1].split(".")[0]?.toLowerCase();
|
|
41
|
+
const name = r.name ?? r.uri;
|
|
42
|
+
const head = name.split(/[-_]/, 1)[0];
|
|
43
|
+
return head ? head.toLowerCase() : undefined;
|
|
44
|
+
}
|
|
45
|
+
/** Apply the project server filter to a resource list (mirrors tool filtering;
|
|
46
|
+
* attribution by uri host, with `_`/`-` name-prefix fallback for underscore-named
|
|
47
|
+
* servers whose resources carry the full prefixed name). */
|
|
48
|
+
export function filterResources(resources, filter) {
|
|
49
|
+
if (!filter)
|
|
50
|
+
return resources;
|
|
51
|
+
const matches = (r, entry) => resourceServer(r) === entry || (r.name ?? "").startsWith(`${entry}_`) || (r.name ?? "").startsWith(`${entry}-`);
|
|
52
|
+
if (filter.allow?.length) {
|
|
53
|
+
return resources.filter((r) => filter.allow.some((e) => matches(r, e)));
|
|
54
|
+
}
|
|
55
|
+
if (filter.deny?.length) {
|
|
56
|
+
return resources.filter((r) => !filter.deny.some((e) => matches(r, e)));
|
|
57
|
+
}
|
|
58
|
+
return resources;
|
|
59
|
+
}
|
|
60
|
+
/** Discover resources and register one read_* tool each. Idempotent; returns count. */
|
|
61
|
+
export async function syncResourceTools(register, connection, registered, filter, notify) {
|
|
62
|
+
let resources = [];
|
|
63
|
+
try {
|
|
64
|
+
resources = filterResources(await connection.listResources(), filter);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
notify(`resource discovery failed (${e instanceof Error ? e.message : String(e)})`, "warn");
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
for (const resource of resources) {
|
|
71
|
+
const label = resource.name ?? resource.uri;
|
|
72
|
+
const toolName = `read_${resourceNameToToolName(label)}`;
|
|
73
|
+
if (registered.has(toolName))
|
|
74
|
+
continue;
|
|
75
|
+
registered.add(toolName);
|
|
76
|
+
const interactive = isInteractiveResource(resource);
|
|
77
|
+
const description = [
|
|
78
|
+
resource.description ?? `Read MCP resource ${resource.uri}`,
|
|
79
|
+
`uri: ${resource.uri}`,
|
|
80
|
+
resource.mimeType ? `type: ${resource.mimeType}` : undefined,
|
|
81
|
+
interactive
|
|
82
|
+
? "interactive app resource — markup as text; the interactive widget opens from the URL appended to results"
|
|
83
|
+
: undefined,
|
|
84
|
+
]
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.join(" | ");
|
|
87
|
+
register({
|
|
88
|
+
name: toolName,
|
|
89
|
+
label: `MCP resource: ${label}`,
|
|
90
|
+
description,
|
|
91
|
+
promptSnippet: `Read MCP resource ${label}.`,
|
|
92
|
+
parameters: { type: "object", properties: {} },
|
|
93
|
+
renderCall: callRenderer(toolName, () => resource.uri),
|
|
94
|
+
renderResult: resultRenderer(() => toolName, toolName),
|
|
95
|
+
execute: async (_toolCallId, _params, _signal, _onUpdate, ctx) => {
|
|
96
|
+
try {
|
|
97
|
+
const result = await connection.readResource(resource.uri);
|
|
98
|
+
let text = renderResourceResult(result);
|
|
99
|
+
// Interactive resources: the combiner's UI host serves the
|
|
100
|
+
// widget for this session's token — surface + auto-open.
|
|
101
|
+
if (interactive) {
|
|
102
|
+
const url = connection.uiUrlFor(resource.uri);
|
|
103
|
+
if (url) {
|
|
104
|
+
text = `${text}\n\ninteractive: ${url}`;
|
|
105
|
+
if (ctx?.hasUI)
|
|
106
|
+
openInBrowser(url);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return textResult(text, { mode: "resource", uri: resource.uri });
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
throw new Error(`${toolName}: resource read failed (${e instanceof Error ? e.message : String(e)})`);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return resources.length;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/client/resources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-signature.d.ts","sourceRoot":"","sources":["../../src/client/schema-signature.ts"],"names":[],"mappings":"AAUA,4FAA4F;AAC5F,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA2HzE"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// TypeScript-shape rendering of JSON Schemas for tool `describe` output.
|
|
2
|
+
//
|
|
3
|
+
// Adapted (near-verbatim) from pi-mcp-adapter's ts-shape.ts — MIT, © 2026 Nico Bailon
|
|
4
|
+
// (https://github.com/nicobailon/pi-mcp-adapter). Self-contained by design: no
|
|
5
|
+
// dependencies on the rest of that package. Conformance cases: test/schema-signature.test.ts.
|
|
6
|
+
const UNSUPPORTED_KEYWORDS = ["if", "then", "else", "allOf", "not", "patternProperties", "additionalProperties"];
|
|
7
|
+
/** Renders the useful JSON Schema subset as TypeScript, or null for unsupported schemas. */
|
|
8
|
+
export function renderSchemaSignature(inputSchema) {
|
|
9
|
+
try {
|
|
10
|
+
if (!isSchema(inputSchema))
|
|
11
|
+
return null;
|
|
12
|
+
const definitions = new Map();
|
|
13
|
+
for (const key of ["$defs", "definitions"]) {
|
|
14
|
+
const rawDefinitions = inputSchema[key];
|
|
15
|
+
if (rawDefinitions === undefined)
|
|
16
|
+
continue;
|
|
17
|
+
if (!isSchema(rawDefinitions))
|
|
18
|
+
return null;
|
|
19
|
+
for (const [name, definition] of Object.entries(rawDefinitions)) {
|
|
20
|
+
if (!isSchema(definition))
|
|
21
|
+
return null;
|
|
22
|
+
definitions.set(`${key}/${decodePointerToken(name)}`, definition);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const aliases = new Map();
|
|
26
|
+
const usedAliases = new Set();
|
|
27
|
+
let aliasIndex = 0;
|
|
28
|
+
const aliasFor = (definitionKey) => {
|
|
29
|
+
let alias = aliases.get(definitionKey);
|
|
30
|
+
if (alias)
|
|
31
|
+
return alias;
|
|
32
|
+
const name = definitionKey.slice(definitionKey.indexOf("/") + 1);
|
|
33
|
+
alias = /^[A-Za-z_$][\w$]*$/.test(name) && !usedAliases.has(name) ? name : `Definition${++aliasIndex}`;
|
|
34
|
+
while (usedAliases.has(alias))
|
|
35
|
+
alias = `Definition${++aliasIndex}`;
|
|
36
|
+
aliases.set(definitionKey, alias);
|
|
37
|
+
usedAliases.add(alias);
|
|
38
|
+
return alias;
|
|
39
|
+
};
|
|
40
|
+
const render = (schema) => {
|
|
41
|
+
if (!isSchema(schema) || hasUnsupportedKeyword(schema))
|
|
42
|
+
return null;
|
|
43
|
+
if ("$ref" in schema) {
|
|
44
|
+
if (typeof schema.$ref !== "string")
|
|
45
|
+
return null;
|
|
46
|
+
const match = schema.$ref.match(/^#\/(\$defs|definitions)\/([^/]+)$/);
|
|
47
|
+
if (!match)
|
|
48
|
+
return null;
|
|
49
|
+
const definitionGroup = match[1];
|
|
50
|
+
const definitionName = match[2];
|
|
51
|
+
if (definitionGroup === undefined || definitionName === undefined)
|
|
52
|
+
return null;
|
|
53
|
+
const definitionKey = `${definitionGroup}/${decodePointerToken(definitionName)}`;
|
|
54
|
+
if (!definitions.has(definitionKey))
|
|
55
|
+
return null;
|
|
56
|
+
return aliasFor(definitionKey);
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(schema.enum)) {
|
|
59
|
+
const values = schema.enum.map(renderLiteral);
|
|
60
|
+
return values.every((value) => value !== null) ? values.join(" | ") : null;
|
|
61
|
+
}
|
|
62
|
+
if (Object.hasOwn(schema, "const"))
|
|
63
|
+
return renderLiteral(schema.const);
|
|
64
|
+
if (Array.isArray(schema.anyOf) || Array.isArray(schema.oneOf)) {
|
|
65
|
+
const variants = (schema.anyOf ?? schema.oneOf);
|
|
66
|
+
if (variants.length === 0)
|
|
67
|
+
return null;
|
|
68
|
+
const rendered = variants.map(render);
|
|
69
|
+
return rendered.every((value) => value !== null) ? rendered.join(" | ") : null;
|
|
70
|
+
}
|
|
71
|
+
if (schema.type === "object" || schema.properties !== undefined) {
|
|
72
|
+
if (schema.properties === undefined)
|
|
73
|
+
return "{}";
|
|
74
|
+
if (!isSchema(schema.properties))
|
|
75
|
+
return null;
|
|
76
|
+
const required = new Set(Array.isArray(schema.required)
|
|
77
|
+
? schema.required.filter((name) => typeof name === "string")
|
|
78
|
+
: []);
|
|
79
|
+
const properties = [];
|
|
80
|
+
for (const [name, property] of Object.entries(schema.properties)) {
|
|
81
|
+
const rendered = render(property);
|
|
82
|
+
if (rendered === null)
|
|
83
|
+
return null;
|
|
84
|
+
// Field descriptions are the model's primary guidance at
|
|
85
|
+
// describe-time (it never sees the raw schema on the proxy
|
|
86
|
+
// path) — thread them as comments; defaults inline too.
|
|
87
|
+
const prop = isSchema(property) ? property : {};
|
|
88
|
+
const notes = [];
|
|
89
|
+
if (!required.has(name) && prop.default !== undefined) {
|
|
90
|
+
notes.push(`default ${JSON.stringify(prop.default)}`);
|
|
91
|
+
}
|
|
92
|
+
if (typeof prop.description === "string" && prop.description) {
|
|
93
|
+
const oneLine = prop.description.replace(/\s+/g, " ").trim();
|
|
94
|
+
notes.push(oneLine.length > 90 ? `${oneLine.slice(0, 87)}…` : oneLine);
|
|
95
|
+
}
|
|
96
|
+
const comment = notes.length > 0 ? ` // ${notes.join(" — ")}` : "";
|
|
97
|
+
properties.push(`${formatPropertyName(name)}${required.has(name) ? "" : "?"}: ${rendered};${comment}`);
|
|
98
|
+
}
|
|
99
|
+
// Multi-line when annotations are present (readability beats the
|
|
100
|
+
// single-line compactness once comments exist).
|
|
101
|
+
if (properties.some((p) => p.includes("//"))) {
|
|
102
|
+
return properties.length === 0 ? "{}" : `{\n${properties.map((p) => ` ${p}`).join("\n")}\n}`;
|
|
103
|
+
}
|
|
104
|
+
return properties.length === 0 ? "{}" : `{ ${properties.join(" ")} }`;
|
|
105
|
+
}
|
|
106
|
+
if (schema.type === "array") {
|
|
107
|
+
if (schema.items === undefined)
|
|
108
|
+
return "unknown[]";
|
|
109
|
+
const item = render(schema.items);
|
|
110
|
+
return item === null ? null : `${needsParentheses(item) ? `(${item})` : item}[]`;
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(schema.type)) {
|
|
113
|
+
const types = schema.type.map(renderType);
|
|
114
|
+
return types.every((type) => type !== null) ? types.join(" | ") : null;
|
|
115
|
+
}
|
|
116
|
+
if (typeof schema.type === "string")
|
|
117
|
+
return renderType(schema.type);
|
|
118
|
+
return "unknown";
|
|
119
|
+
};
|
|
120
|
+
const root = render(inputSchema);
|
|
121
|
+
if (root === null)
|
|
122
|
+
return null;
|
|
123
|
+
const definitionsText = [];
|
|
124
|
+
for (const [key, alias] of aliases) {
|
|
125
|
+
const definition = definitions.get(key);
|
|
126
|
+
if (!definition)
|
|
127
|
+
return null;
|
|
128
|
+
const rendered = render(definition);
|
|
129
|
+
if (rendered === null)
|
|
130
|
+
return null;
|
|
131
|
+
definitionsText.push(`type ${alias} = ${rendered};`);
|
|
132
|
+
}
|
|
133
|
+
return definitionsText.length > 0 ? `${definitionsText.join("\n")}\n\n${root}` : root;
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function isSchema(value) {
|
|
140
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
141
|
+
}
|
|
142
|
+
function hasUnsupportedKeyword(schema) {
|
|
143
|
+
return UNSUPPORTED_KEYWORDS.some((keyword) => {
|
|
144
|
+
if (!Object.hasOwn(schema, keyword))
|
|
145
|
+
return false;
|
|
146
|
+
// `additionalProperties: false` is a closed-object constraint, not a shape that this renderer needs to understand.
|
|
147
|
+
return keyword !== "additionalProperties" || schema.additionalProperties !== false;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function decodePointerToken(token) {
|
|
151
|
+
return token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
152
|
+
}
|
|
153
|
+
function renderType(type) {
|
|
154
|
+
switch (type) {
|
|
155
|
+
case "string":
|
|
156
|
+
return "string";
|
|
157
|
+
case "number":
|
|
158
|
+
case "integer":
|
|
159
|
+
return "number";
|
|
160
|
+
case "boolean":
|
|
161
|
+
return "boolean";
|
|
162
|
+
case "null":
|
|
163
|
+
return "null";
|
|
164
|
+
case "object":
|
|
165
|
+
return "{}";
|
|
166
|
+
case "array":
|
|
167
|
+
return "unknown[]";
|
|
168
|
+
default:
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function renderLiteral(value) {
|
|
173
|
+
if (value === null || typeof value === "string" || typeof value === "boolean")
|
|
174
|
+
return JSON.stringify(value);
|
|
175
|
+
return typeof value === "number" && Number.isFinite(value) ? String(value) : null;
|
|
176
|
+
}
|
|
177
|
+
function formatPropertyName(name) {
|
|
178
|
+
return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
|
|
179
|
+
}
|
|
180
|
+
function needsParentheses(type) {
|
|
181
|
+
return type.includes(" | ");
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=schema-signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-signature.js","sourceRoot":"","sources":["../../src/client/schema-signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ToolDefinition } from "../pi.js";
|
|
2
|
+
import type { CombinerConnection } from "./connection.js";
|
|
3
|
+
export declare const DEFAULT_SCRIPT_TIMEOUT_MS = 30000;
|
|
4
|
+
export type ScriptToolDeps = {
|
|
5
|
+
connection: CombinerConnection;
|
|
6
|
+
/** Tool name for the batching tool — `${toolName}Script` ("mcpScript" in parity). */
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function createScriptTool(deps: ScriptToolDeps): ToolDefinition;
|
|
10
|
+
//# sourceMappingURL=script.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.d.ts","sourceRoot":"","sources":["../../src/client/script.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAe,MAAM,iBAAiB,CAAA;AAKtE,eAAO,MAAM,yBAAyB,QAAS,CAAA;AAK/C,MAAM,MAAM,cAAc,GAAG;IACzB,UAAU,EAAE,kBAAkB,CAAA;IAC9B,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAA;CACf,CAAA;AAyBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,CAkGrE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// The <toolName>Script batching tool — API parity with pi-mcp-adapter's
|
|
2
|
+
// mcpScript (MIT, © 2026 Nico Bailon; mcp-code.ts), reimplemented lean:
|
|
3
|
+
// scriptMode: `{code, timeoutMs?}` executing trusted JavaScript with
|
|
4
|
+
// `await tools.search/describe/call()` and `emit(value)` for user-visible output.
|
|
5
|
+
//
|
|
6
|
+
// Lean port: pi-mcp-adapter runs the code in a worker thread (mcp-code.ts) for hard
|
|
7
|
+
// timeout termination; we evaluate in-process with an AsyncFunction and race a timer.
|
|
8
|
+
// The trade-off is deliberate — trusted code, one loopback server — an abandoned
|
|
9
|
+
// call finishes harmlessly combiner-side, and the API surface (what agents write)
|
|
10
|
+
// is identical. Default timeout 30s, matching the adapter.
|
|
11
|
+
import { rankTools, regexMatches, compileSafeRegex } from "./ranking.js";
|
|
12
|
+
import { renderDescribe, renderSearchHit, renderToolResult, textResult } from "./render.js";
|
|
13
|
+
import { callRenderer, resultRenderer } from "./renderers.js";
|
|
14
|
+
export const DEFAULT_SCRIPT_TIMEOUT_MS = 30_000;
|
|
15
|
+
const MAX_SCRIPT_TIMEOUT_MS = 120_000;
|
|
16
|
+
const MAX_EMITTED_BLOCKS = 200;
|
|
17
|
+
const MAX_EMIT_CHARS = 16 * 1024;
|
|
18
|
+
const AsyncFunction = Object.getPrototypeOf(async () => {
|
|
19
|
+
/* capture */
|
|
20
|
+
}).constructor;
|
|
21
|
+
function serverOf(name) {
|
|
22
|
+
return name.split("_", 1)[0] ?? "";
|
|
23
|
+
}
|
|
24
|
+
function formatValue(value) {
|
|
25
|
+
if (typeof value === "string")
|
|
26
|
+
return value;
|
|
27
|
+
try {
|
|
28
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return "[unserializable value]";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function createScriptTool(deps) {
|
|
35
|
+
const { connection, name } = deps;
|
|
36
|
+
return {
|
|
37
|
+
name,
|
|
38
|
+
label: "MCP script (combiner)",
|
|
39
|
+
description: [
|
|
40
|
+
"Run trusted JavaScript that makes multiple MCP calls in one request.",
|
|
41
|
+
"API: const r = await tools.search('query', {limit}); await tools.describe('name');",
|
|
42
|
+
"await tools.call('name', {args}); emit(value) for user-visible output.",
|
|
43
|
+
"The final return value (or the last emitted value) becomes the tool result.",
|
|
44
|
+
].join(" "),
|
|
45
|
+
promptSnippet: "Batch multiple MCP calls with trusted JavaScript (tools.search/describe/call + emit).",
|
|
46
|
+
parameters: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
code: { type: "string", description: "JavaScript to run (await allowed)" },
|
|
50
|
+
timeoutMs: { type: "number", description: `Timeout in ms (default ${DEFAULT_SCRIPT_TIMEOUT_MS})` },
|
|
51
|
+
},
|
|
52
|
+
required: ["code"],
|
|
53
|
+
},
|
|
54
|
+
renderCall: callRenderer(name, (args) => {
|
|
55
|
+
const code = typeof args.code === "string" ? (args.code.trim().split("\n", 1)[0] ?? "") : "";
|
|
56
|
+
return code.length > 60 ? `${code.slice(0, 59)}…` : code;
|
|
57
|
+
}),
|
|
58
|
+
renderResult: resultRenderer(() => name, name),
|
|
59
|
+
execute: async (_toolCallId, params) => {
|
|
60
|
+
const p = params;
|
|
61
|
+
if (typeof p.code !== "string" || !p.code.trim()) {
|
|
62
|
+
throw new Error(`${name}: code must be a non-empty string`);
|
|
63
|
+
}
|
|
64
|
+
const timeoutMs = typeof p.timeoutMs === "number" && p.timeoutMs > 0
|
|
65
|
+
? Math.min(MAX_SCRIPT_TIMEOUT_MS, p.timeoutMs)
|
|
66
|
+
: DEFAULT_SCRIPT_TIMEOUT_MS;
|
|
67
|
+
const emitted = [];
|
|
68
|
+
let emittedChars = 0;
|
|
69
|
+
const emit = (value) => {
|
|
70
|
+
if (emitted.length >= MAX_EMITTED_BLOCKS)
|
|
71
|
+
return;
|
|
72
|
+
const text = formatValue(value).slice(0, MAX_EMIT_CHARS);
|
|
73
|
+
emittedChars += text.length;
|
|
74
|
+
emitted.push(text);
|
|
75
|
+
};
|
|
76
|
+
const tools = {
|
|
77
|
+
search: (query, opts) => {
|
|
78
|
+
const q = typeof query === "string" ? query : "";
|
|
79
|
+
const server = opts?.server;
|
|
80
|
+
return connection
|
|
81
|
+
.listTools()
|
|
82
|
+
.then((all) => {
|
|
83
|
+
const pool = server ? all.filter((t) => serverOf(t.name) === server) : all;
|
|
84
|
+
if (opts?.regex) {
|
|
85
|
+
const { re, error } = compileSafeRegex(q);
|
|
86
|
+
if (!re)
|
|
87
|
+
throw new Error(`bad regex: ${error}`);
|
|
88
|
+
return regexMatches(pool, re, opts?.limit ?? 12, opts?.offset ?? 0).map((m) => m.tool);
|
|
89
|
+
}
|
|
90
|
+
return rankTools(pool, q, opts?.limit ?? 12, opts?.offset ?? 0).map((m) => m.tool);
|
|
91
|
+
})
|
|
92
|
+
.then((tools) => tools.map((t) => renderSearchHit(t)))
|
|
93
|
+
.then((lines) => lines.join("\n"));
|
|
94
|
+
},
|
|
95
|
+
describe: (toolName) => connection
|
|
96
|
+
.listTools()
|
|
97
|
+
.then((all) => all.find((t) => t.name === toolName))
|
|
98
|
+
.then((t) => {
|
|
99
|
+
if (!t)
|
|
100
|
+
throw new Error(`no tool "${toolName}" — use tools.search first`);
|
|
101
|
+
return renderDescribe(t, serverOf(t.name));
|
|
102
|
+
}),
|
|
103
|
+
call: (toolName, args) => connection.callTool(toolName, args).then((r) => renderToolResult(r)),
|
|
104
|
+
};
|
|
105
|
+
try {
|
|
106
|
+
const fn = new AsyncFunction("tools", "emit", p.code);
|
|
107
|
+
const timer = new Promise((_, reject) => setTimeout(() => reject(new Error(`${name} timed out after ${timeoutMs}ms`)), timeoutMs));
|
|
108
|
+
let result;
|
|
109
|
+
try {
|
|
110
|
+
result = await Promise.race([fn(tools, emit), timer]);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
// nothing to clean — the timer's reject is inert once the race settled
|
|
114
|
+
}
|
|
115
|
+
const resultText = result === undefined ? "" : formatValue(result);
|
|
116
|
+
const text = [...emitted, resultText].filter((s) => s.length > 0).join("\n\n");
|
|
117
|
+
return textResult(text || "(no output — emit(value) or return a value)", {
|
|
118
|
+
mode: "script",
|
|
119
|
+
emitted: emitted.length,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
catch (e) {
|
|
123
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
124
|
+
const text = emitted.length ? `${emitted.join("\n\n")}\n\n${name}: ${msg}` : `${name}: ${msg}`;
|
|
125
|
+
throw new Error(text);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=script.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"script.js","sourceRoot":"","sources":["../../src/client/script.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type AdapterMode = boolean | "auto";
|
|
2
|
+
export type FooterStatus = "full" | "compact" | "off";
|
|
3
|
+
export type CombinerSettings = {
|
|
4
|
+
/** Tool name registered with Pi. Default "mcp" (parity with pi-mcp-adapter);
|
|
5
|
+
* rename (e.g. "combiner") to coexist while both are installed. */
|
|
6
|
+
toolName: string;
|
|
7
|
+
/** "lazy" (default): connect on first mcp() call. "eager": connect at session_start. */
|
|
8
|
+
lazy: "lazy" | "eager";
|
|
9
|
+
/** Client-half gate. `true`: we are the MCP tool. `false`: legacy mode — the
|
|
10
|
+
* process + instructions halves only, pi-mcp-adapter (if installed) owns MCP.
|
|
11
|
+
* `"auto"` (default): OFF when pi-mcp-adapter is detected installed, ON otherwise —
|
|
12
|
+
* so existing adapter users upgrade with zero behaviour change, while fresh
|
|
13
|
+
* installs get the one-package experience. Env PI_MCP_COMBINER_ADAPTER wins. */
|
|
14
|
+
adapter: AdapterMode;
|
|
15
|
+
/** Expose combiner resources as read_* tools. */
|
|
16
|
+
exposeResources: boolean;
|
|
17
|
+
/** Register combiner prompts as slash commands (adapter naming:
|
|
18
|
+
* mcp__<server>__<name>; prefixed with our toolName when renamed). */
|
|
19
|
+
prompts: boolean;
|
|
20
|
+
/** Footer status line: "full" = "N servers enabled (M ready) · T tools", "compact" = "MCP M/N",
|
|
21
|
+
* "off" = none. Same values as pi-mcp-adapter's mcpFooterStatus. */
|
|
22
|
+
mcpFooterStatus: FooterStatus;
|
|
23
|
+
/** The ctx.ui.setStatus key the footer publishes under. Default "mcp" — the
|
|
24
|
+
* slot pi-mcp-adapter wrote and footers (oh-my-posh's PI_STATUS aggregate)
|
|
25
|
+
* already surface; rename only if something else claims it. */
|
|
26
|
+
mcpFooterKey: string;
|
|
27
|
+
/** Register the trusted batching tool (<toolName>Script). Default true. */
|
|
28
|
+
scriptMode: boolean;
|
|
29
|
+
/** Auto-open interactive widget URLs (Stage 2 holds + resource reads).
|
|
30
|
+
* Default true. */
|
|
31
|
+
uiAutoOpen: boolean;
|
|
32
|
+
/** Explicit combiner base URL (e.g. "http://127.0.0.1:9741/mcp"). Env wins. */
|
|
33
|
+
url?: string;
|
|
34
|
+
/** Notify (vs stderr-only) for connection lifecycle messages. */
|
|
35
|
+
notify: boolean;
|
|
36
|
+
};
|
|
37
|
+
export declare const DEFAULT_SETTINGS: CombinerSettings;
|
|
38
|
+
/** Pi's agent dir: `$PI_CODING_AGENT_DIR` when set, else the first existing of the
|
|
39
|
+
* known defaults (~/.config/pi/agent on newer layouts, ~/.pi/agent on older). */
|
|
40
|
+
export declare function agentDir(): string;
|
|
41
|
+
/** The settings file path this extension reads. */
|
|
42
|
+
export declare function settingsPath(): string;
|
|
43
|
+
/** Load + validate the settings file; missing file or bad shape → defaults.
|
|
44
|
+
* Unknown keys are ignored (forward compat). */
|
|
45
|
+
export declare function loadSettings(path?: string): CombinerSettings;
|
|
46
|
+
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/client/settings.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,CAAA;AAE1C,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,CAAA;AAErD,MAAM,MAAM,gBAAgB,GAAG;IAC3B;wEACoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,wFAAwF;IACxF,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB;;;;qFAIiF;IACjF,OAAO,EAAE,WAAW,CAAA;IACpB,iDAAiD;IACjD,eAAe,EAAE,OAAO,CAAA;IACxB;2EACuE;IACvE,OAAO,EAAE,OAAO,CAAA;IAChB;yEACqE;IACrE,eAAe,EAAE,YAAY,CAAA;IAC7B;;oEAEgE;IAChE,YAAY,EAAE,MAAM,CAAA;IACpB,2EAA2E;IAC3E,UAAU,EAAE,OAAO,CAAA;IACnB;wBACoB;IACpB,UAAU,EAAE,OAAO,CAAA;IACnB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iEAAiE;IACjE,MAAM,EAAE,OAAO,CAAA;CAClB,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,gBAW9B,CAAA;AAED;kFACkF;AAClF,wBAAgB,QAAQ,IAAI,MAAM,CAMjC;AAED,mDAAmD;AACnD,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;iDACiD;AACjD,wBAAgB,YAAY,CAAC,IAAI,SAAiB,GAAG,gBAAgB,CA0BpE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Pi-specific settings for the mcp-combiner extension's client half.
|
|
2
|
+
//
|
|
3
|
+
// Standard file: `$PI_CODING_AGENT_DIR/extensions/mcp-combiner.json` — one place for
|
|
4
|
+
// the knobs that are about THIS extension in Pi, deliberately separate from the shared
|
|
5
|
+
// MCP config ladder (`.pi/mcp.json` & co. hold connection + per-project exposure; see
|
|
6
|
+
// config-ladder.ts). Read-only at extension load; changes take effect on /reload.
|
|
7
|
+
//
|
|
8
|
+
// Precedence: PI_MCP_COMBINER_* env > this file > built-in defaults.
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
export const DEFAULT_SETTINGS = {
|
|
13
|
+
toolName: "mcp",
|
|
14
|
+
lazy: "lazy",
|
|
15
|
+
adapter: "auto",
|
|
16
|
+
exposeResources: true,
|
|
17
|
+
prompts: true,
|
|
18
|
+
mcpFooterStatus: "full",
|
|
19
|
+
mcpFooterKey: "mcp",
|
|
20
|
+
scriptMode: true,
|
|
21
|
+
uiAutoOpen: true,
|
|
22
|
+
notify: true,
|
|
23
|
+
};
|
|
24
|
+
/** Pi's agent dir: `$PI_CODING_AGENT_DIR` when set, else the first existing of the
|
|
25
|
+
* known defaults (~/.config/pi/agent on newer layouts, ~/.pi/agent on older). */
|
|
26
|
+
export function agentDir() {
|
|
27
|
+
const env = process.env.PI_CODING_AGENT_DIR;
|
|
28
|
+
if (env && env.trim())
|
|
29
|
+
return env;
|
|
30
|
+
const candidates = [join(homedir(), ".config", "pi", "agent"), join(homedir(), ".pi", "agent")];
|
|
31
|
+
for (const c of candidates)
|
|
32
|
+
if (existsSync(c))
|
|
33
|
+
return c;
|
|
34
|
+
return candidates[0];
|
|
35
|
+
}
|
|
36
|
+
/** The settings file path this extension reads. */
|
|
37
|
+
export function settingsPath() {
|
|
38
|
+
return join(agentDir(), "extensions", "mcp-combiner.json");
|
|
39
|
+
}
|
|
40
|
+
/** Load + validate the settings file; missing file or bad shape → defaults.
|
|
41
|
+
* Unknown keys are ignored (forward compat). */
|
|
42
|
+
export function loadSettings(path = settingsPath()) {
|
|
43
|
+
const out = { ...DEFAULT_SETTINGS };
|
|
44
|
+
if (!existsSync(path))
|
|
45
|
+
return out;
|
|
46
|
+
let doc;
|
|
47
|
+
try {
|
|
48
|
+
doc = JSON.parse(readFileSync(path, "utf8"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return out; // malformed JSON → defaults; noisy parse errors help nobody at load time
|
|
52
|
+
}
|
|
53
|
+
if (typeof doc !== "object" || doc === null || Array.isArray(doc))
|
|
54
|
+
return out;
|
|
55
|
+
const d = doc;
|
|
56
|
+
if (typeof d.toolName === "string" && /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(d.toolName))
|
|
57
|
+
out.toolName = d.toolName;
|
|
58
|
+
if (d.lazy === "lazy" || d.lazy === "eager")
|
|
59
|
+
out.lazy = d.lazy;
|
|
60
|
+
if (d.adapter === "auto" || typeof d.adapter === "boolean")
|
|
61
|
+
out.adapter = d.adapter;
|
|
62
|
+
if (typeof d.exposeResources === "boolean")
|
|
63
|
+
out.exposeResources = d.exposeResources;
|
|
64
|
+
if (typeof d.prompts === "boolean")
|
|
65
|
+
out.prompts = d.prompts;
|
|
66
|
+
if (d.mcpFooterStatus === "full" || d.mcpFooterStatus === "compact" || d.mcpFooterStatus === "off") {
|
|
67
|
+
out.mcpFooterStatus = d.mcpFooterStatus;
|
|
68
|
+
}
|
|
69
|
+
if (typeof d.mcpFooterKey === "string" && d.mcpFooterKey.trim())
|
|
70
|
+
out.mcpFooterKey = d.mcpFooterKey.trim();
|
|
71
|
+
if (typeof d.uiAutoOpen === "boolean")
|
|
72
|
+
out.uiAutoOpen = d.uiAutoOpen;
|
|
73
|
+
if (typeof d.scriptMode === "boolean")
|
|
74
|
+
out.scriptMode = d.scriptMode;
|
|
75
|
+
if (typeof d.url === "string" && d.url.trim())
|
|
76
|
+
out.url = d.url.trim();
|
|
77
|
+
if (typeof d.notify === "boolean")
|
|
78
|
+
out.notify = d.notify;
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/client/settings.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAER,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAER,YAAY,EAKf,MAAM,SAAS,CAAA;AA4PhB,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA8b1D"}
|