@esankhan3/anvil-agent-core 0.1.2 → 0.2.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/dist/__tests__/mcp-merged-executor.test.d.ts +2 -0
- package/dist/__tests__/mcp-merged-executor.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-merged-executor.test.js +221 -0
- package/dist/__tests__/mcp-merged-executor.test.js.map +1 -0
- package/dist/__tests__/mcp.test.js +21 -15
- package/dist/__tests__/mcp.test.js.map +1 -1
- package/dist/__tests__/model-catalog.test.d.ts +11 -0
- package/dist/__tests__/model-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/model-catalog.test.js +102 -0
- package/dist/__tests__/model-catalog.test.js.map +1 -0
- package/dist/__tests__/model-tier-resolver.test.d.ts +19 -0
- package/dist/__tests__/model-tier-resolver.test.d.ts.map +1 -0
- package/dist/__tests__/model-tier-resolver.test.js +97 -0
- package/dist/__tests__/model-tier-resolver.test.js.map +1 -0
- package/dist/adk-adapter.d.ts.map +1 -1
- package/dist/adk-adapter.js +11 -0
- package/dist/adk-adapter.js.map +1 -1
- package/dist/agent/session/__tests__/spawn-telemetry.test.js +39 -4
- package/dist/agent/session/__tests__/spawn-telemetry.test.js.map +1 -1
- package/dist/agent/session/adapter.d.ts +34 -0
- package/dist/agent/session/adapter.d.ts.map +1 -1
- package/dist/agent/session/adapter.js.map +1 -1
- package/dist/agent/session/default-adapter-factory.d.ts.map +1 -1
- package/dist/agent/session/default-adapter-factory.js +66 -2
- package/dist/agent/session/default-adapter-factory.js.map +1 -1
- package/dist/agent/session/language-model-bridge.d.ts.map +1 -1
- package/dist/agent/session/language-model-bridge.js +52 -1
- package/dist/agent/session/language-model-bridge.js.map +1 -1
- package/dist/agent/session/session.d.ts +16 -0
- package/dist/agent/session/session.d.ts.map +1 -1
- package/dist/agent/session/session.js +86 -2
- package/dist/agent/session/session.js.map +1 -1
- package/dist/gemini-adapter.d.ts.map +1 -1
- package/dist/gemini-adapter.js +11 -0
- package/dist/gemini-adapter.js.map +1 -1
- package/dist/gemini-cli-adapter.d.ts.map +1 -1
- package/dist/gemini-cli-adapter.js +10 -0
- package/dist/gemini-cli-adapter.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +64 -18
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +190 -26
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/index.d.ts +5 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +3 -8
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/merged-executor.d.ts +74 -0
- package/dist/mcp/merged-executor.d.ts.map +1 -0
- package/dist/mcp/merged-executor.js +198 -0
- package/dist/mcp/merged-executor.js.map +1 -0
- package/dist/mcp/pool.d.ts +71 -0
- package/dist/mcp/pool.d.ts.map +1 -0
- package/dist/mcp/pool.js +171 -0
- package/dist/mcp/pool.js.map +1 -0
- package/dist/mcp/tool-merger.d.ts +8 -5
- package/dist/mcp/tool-merger.d.ts.map +1 -1
- package/dist/mcp/tool-merger.js +8 -16
- package/dist/mcp/tool-merger.js.map +1 -1
- package/dist/model-catalog.d.ts +36 -0
- package/dist/model-catalog.d.ts.map +1 -0
- package/dist/model-catalog.js +102 -0
- package/dist/model-catalog.js.map +1 -0
- package/dist/model-tier-resolver.d.ts +61 -0
- package/dist/model-tier-resolver.d.ts.map +1 -0
- package/dist/model-tier-resolver.js +170 -0
- package/dist/model-tier-resolver.js.map +1 -0
- package/dist/ollama-adapter.d.ts.map +1 -1
- package/dist/ollama-adapter.js +6 -1
- package/dist/ollama-adapter.js.map +1 -1
- package/dist/opencode-adapter.d.ts +11 -0
- package/dist/opencode-adapter.d.ts.map +1 -1
- package/dist/opencode-adapter.js +13 -0
- package/dist/opencode-adapter.js.map +1 -1
- package/dist/openrouter-adapter.d.ts +15 -0
- package/dist/openrouter-adapter.d.ts.map +1 -1
- package/dist/openrouter-adapter.js +69 -19
- package/dist/openrouter-adapter.js.map +1 -1
- package/dist/provider-liveness.d.ts +5 -0
- package/dist/provider-liveness.d.ts.map +1 -1
- package/dist/provider-liveness.js +11 -15
- package/dist/provider-liveness.js.map +1 -1
- package/dist/registry.d.ts +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/upstream-error.d.ts.map +1 -1
- package/dist/upstream-error.js +11 -1
- package/dist/upstream-error.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp/client.js
CHANGED
|
@@ -1,36 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `McpAgentClient` — wraps the official MCP TypeScript SDK with the lifecycle
|
|
3
|
-
* Anvil's agent layer needs (lazy connect, tool listing
|
|
4
|
-
*
|
|
3
|
+
* Anvil's agent layer needs (lazy connect, namespaced tool listing, tool
|
|
4
|
+
* dispatch with cancellation, progress notifications, EOF reconnect, clean
|
|
5
|
+
* close).
|
|
5
6
|
*
|
|
6
|
-
* One instance per configured MCP server.
|
|
7
|
-
*
|
|
7
|
+
* One instance per configured MCP server. `McpClientPool` owns multiple
|
|
8
|
+
* instances per workspace and shares them across the agent's lifetime so
|
|
9
|
+
* resume turns don't re-pay the connect cost.
|
|
10
|
+
*
|
|
11
|
+
* Naming convention: tools are surfaced as `mcp__<server>__<tool>` (double
|
|
12
|
+
* underscore, matching Claude Code / Anthropic SDK). The bare tool name is
|
|
13
|
+
* sent to the server during dispatch.
|
|
8
14
|
*/
|
|
9
15
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
10
16
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
11
17
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
18
|
+
import { mkdirSync, createWriteStream } from 'node:fs';
|
|
19
|
+
import { join } from 'node:path';
|
|
20
|
+
import { homedir } from 'node:os';
|
|
12
21
|
import { VERSION } from '../version.js';
|
|
13
22
|
const CLIENT_NAME = 'anvil-agent';
|
|
23
|
+
/** Prefix every MCP-sourced tool with `mcp__<server>__` so it can never
|
|
24
|
+
* collide with a builtin and so the model recognizes the Claude-Code-
|
|
25
|
+
* established convention. */
|
|
26
|
+
export const MCP_NAME_PREFIX = 'mcp__';
|
|
27
|
+
export function mcpToolName(serverName, toolName) {
|
|
28
|
+
return `${MCP_NAME_PREFIX}${serverName}__${toolName}`;
|
|
29
|
+
}
|
|
14
30
|
export class McpAgentClient {
|
|
15
31
|
config;
|
|
16
32
|
client;
|
|
17
33
|
connected = false;
|
|
18
|
-
|
|
34
|
+
connecting;
|
|
35
|
+
stderrStream;
|
|
36
|
+
opts;
|
|
37
|
+
/** Tracks request ids cancelled via `cancelInFlight`. */
|
|
38
|
+
cancelControllers = new Set();
|
|
39
|
+
constructor(config, opts = {}) {
|
|
19
40
|
this.config = config;
|
|
41
|
+
this.opts = opts;
|
|
20
42
|
this.client = new Client({ name: CLIENT_NAME, version: VERSION }, { capabilities: {} });
|
|
43
|
+
this.wireProgressHandler();
|
|
21
44
|
}
|
|
45
|
+
// ── Connection lifecycle ───────────────────────────────────────────────
|
|
22
46
|
async connect() {
|
|
23
47
|
if (this.connected)
|
|
24
48
|
return;
|
|
49
|
+
// Coalesce concurrent first-use; every caller awaits the same promise.
|
|
50
|
+
if (this.connecting)
|
|
51
|
+
return this.connecting;
|
|
52
|
+
this.connecting = this._connect().finally(() => {
|
|
53
|
+
this.connecting = undefined;
|
|
54
|
+
});
|
|
55
|
+
return this.connecting;
|
|
56
|
+
}
|
|
57
|
+
async _connect() {
|
|
25
58
|
if (this.config.transport === 'stdio') {
|
|
26
59
|
if (!this.config.command) {
|
|
27
60
|
throw new Error(`MCP server "${this.config.name}" has stdio transport but no command`);
|
|
28
61
|
}
|
|
62
|
+
this.openStderrLog();
|
|
29
63
|
const transport = new StdioClientTransport({
|
|
30
64
|
command: this.config.command,
|
|
31
65
|
args: this.config.args ?? [],
|
|
32
66
|
env: this.config.env,
|
|
67
|
+
// Capture stderr so the protocol JSON on stdout isn't polluted +
|
|
68
|
+
// give the user something to grep when an MCP server misbehaves.
|
|
69
|
+
stderr: this.stderrStream ? 'pipe' : 'inherit',
|
|
33
70
|
});
|
|
71
|
+
if (this.stderrStream && transport.stderr) {
|
|
72
|
+
transport.stderr.pipe(this.stderrStream);
|
|
73
|
+
}
|
|
34
74
|
await this.client.connect(transport);
|
|
35
75
|
}
|
|
36
76
|
else {
|
|
@@ -44,49 +84,173 @@ export class McpAgentClient {
|
|
|
44
84
|
}
|
|
45
85
|
this.connected = true;
|
|
46
86
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
87
|
+
openStderrLog() {
|
|
88
|
+
if (this.stderrStream || this.config.transport !== 'stdio')
|
|
89
|
+
return;
|
|
90
|
+
const dir = this.opts.stderrLogDir ?? join(homedir(), '.anvil', 'mcp-logs');
|
|
91
|
+
try {
|
|
92
|
+
mkdirSync(dir, { recursive: true });
|
|
93
|
+
const suffix = this.opts.runId ? `-${this.opts.runId}` : '';
|
|
94
|
+
const path = join(dir, `${safeFileName(this.config.name)}${suffix}.log`);
|
|
95
|
+
this.stderrStream = createWriteStream(path, { flags: 'a' });
|
|
96
|
+
this.stderrStream.write(`\n--- mcp server "${this.config.name}" started ${new Date().toISOString()} ---\n`);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Log capture is best-effort; fall back to inherit (stderr to process).
|
|
100
|
+
this.stderrStream = undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── Tool discovery + dispatch ──────────────────────────────────────────
|
|
52
104
|
async listTools() {
|
|
53
105
|
if (!this.connected)
|
|
54
106
|
await this.connect();
|
|
55
107
|
const result = await this.client.listTools();
|
|
56
|
-
return result.tools.map((t) =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
return result.tools.map((t) => {
|
|
109
|
+
const ann = t.annotations;
|
|
110
|
+
const annotations = {
|
|
111
|
+
readOnly: ann?.readOnlyHint ?? heuristicReadOnly(t.name),
|
|
112
|
+
destructive: ann?.destructiveHint,
|
|
113
|
+
idempotent: ann?.idempotentHint,
|
|
114
|
+
openWorld: ann?.openWorldHint,
|
|
115
|
+
};
|
|
116
|
+
const namespaced = mcpToolName(this.config.name, t.name);
|
|
117
|
+
const description = decorateDescription(t.description ?? '', this.config.name, annotations);
|
|
118
|
+
return {
|
|
119
|
+
name: namespaced,
|
|
120
|
+
bareName: t.name,
|
|
121
|
+
serverName: this.config.name,
|
|
122
|
+
schema: {
|
|
123
|
+
name: namespaced,
|
|
124
|
+
description,
|
|
125
|
+
inputSchema: t.inputSchema ?? { type: 'object' },
|
|
126
|
+
},
|
|
127
|
+
annotations,
|
|
128
|
+
};
|
|
129
|
+
});
|
|
61
130
|
}
|
|
62
131
|
/**
|
|
63
132
|
* Dispatch a tool call. Accepts either the namespaced form
|
|
64
|
-
* (
|
|
65
|
-
*
|
|
133
|
+
* (`mcp__<server>__<tool>`) or the bare tool name. Cancellation is wired
|
|
134
|
+
* via an AbortController stored in `cancelControllers` — `cancelInFlight`
|
|
135
|
+
* aborts every pending call.
|
|
66
136
|
*/
|
|
67
|
-
async callTool(toolName, args) {
|
|
137
|
+
async callTool(toolName, args, signal) {
|
|
68
138
|
if (!this.connected)
|
|
69
139
|
await this.connect();
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
140
|
+
const bare = stripMcpPrefix(toolName, this.config.name);
|
|
141
|
+
const inner = new AbortController();
|
|
142
|
+
this.cancelControllers.add(inner);
|
|
143
|
+
if (signal) {
|
|
144
|
+
if (signal.aborted)
|
|
145
|
+
inner.abort(signal.reason);
|
|
146
|
+
else
|
|
147
|
+
signal.addEventListener('abort', () => inner.abort(signal.reason), { once: true });
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
// The SDK's callTool accepts an AbortSignal in the request options —
|
|
151
|
+
// it emits `notifications/cancelled` on the wire when fired.
|
|
152
|
+
const result = await this.client.callTool({ name: bare, arguments: args }, undefined, {
|
|
153
|
+
signal: inner.signal,
|
|
154
|
+
});
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
this.cancelControllers.delete(inner);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Abort every in-flight tool call. Used on agent kill. */
|
|
162
|
+
cancelInFlight(reason) {
|
|
163
|
+
for (const c of this.cancelControllers) {
|
|
164
|
+
try {
|
|
165
|
+
c.abort(reason ?? 'cancelled');
|
|
166
|
+
}
|
|
167
|
+
catch { /* ok */ }
|
|
168
|
+
}
|
|
169
|
+
this.cancelControllers.clear();
|
|
77
170
|
}
|
|
78
171
|
async close() {
|
|
79
|
-
|
|
172
|
+
this.cancelInFlight('client closed');
|
|
173
|
+
if (!this.connected) {
|
|
174
|
+
this.stderrStream?.end();
|
|
175
|
+
this.stderrStream = undefined;
|
|
80
176
|
return;
|
|
177
|
+
}
|
|
81
178
|
try {
|
|
82
179
|
await this.client.close();
|
|
83
180
|
}
|
|
84
181
|
finally {
|
|
85
182
|
this.connected = false;
|
|
183
|
+
this.stderrStream?.end();
|
|
184
|
+
this.stderrStream = undefined;
|
|
86
185
|
}
|
|
87
186
|
}
|
|
88
187
|
isConnected() {
|
|
89
188
|
return this.connected;
|
|
90
189
|
}
|
|
190
|
+
// ── Progress wiring ────────────────────────────────────────────────────
|
|
191
|
+
wireProgressHandler() {
|
|
192
|
+
if (!this.opts.onProgress)
|
|
193
|
+
return;
|
|
194
|
+
const onProgress = this.opts.onProgress;
|
|
195
|
+
// The MCP SDK exposes progress via notification handlers — register a
|
|
196
|
+
// generic one and re-emit through the caller's callback. The
|
|
197
|
+
// notification name space: `notifications/progress`.
|
|
198
|
+
const fallbackProgress = (ev) => onProgress(ev);
|
|
199
|
+
// setNotificationHandler is the public hook on the Client class —
|
|
200
|
+
// the SDK calls it for every server-initiated notification matching
|
|
201
|
+
// the schema's method.
|
|
202
|
+
try {
|
|
203
|
+
this.client.setNotificationHandler({ method: 'notifications/progress' }, (n) => {
|
|
204
|
+
const p = n.params ?? {};
|
|
205
|
+
fallbackProgress({
|
|
206
|
+
serverName: this.config.name,
|
|
207
|
+
toolName: String(p.progressToken ?? ''),
|
|
208
|
+
progress: typeof p.progress === 'number' ? p.progress : 0,
|
|
209
|
+
total: typeof p.total === 'number' ? p.total : undefined,
|
|
210
|
+
message: typeof p.message === 'string' ? p.message : undefined,
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// Older SDK versions may not expose setNotificationHandler the same way;
|
|
216
|
+
// progress is a nice-to-have, not a blocker.
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
221
|
+
function stripMcpPrefix(toolName, serverName) {
|
|
222
|
+
const prefix = `${MCP_NAME_PREFIX}${serverName}__`;
|
|
223
|
+
if (toolName.startsWith(prefix))
|
|
224
|
+
return toolName.slice(prefix.length);
|
|
225
|
+
// Legacy `<server>/<tool>` form — accept for backward compat with old
|
|
226
|
+
// tool-merger.ts callers that may still be hanging around.
|
|
227
|
+
const legacy = `${serverName}/`;
|
|
228
|
+
if (toolName.startsWith(legacy))
|
|
229
|
+
return toolName.slice(legacy.length);
|
|
230
|
+
return toolName;
|
|
231
|
+
}
|
|
232
|
+
function safeFileName(s) {
|
|
233
|
+
return s.replace(/[^a-zA-Z0-9_.-]+/g, '_');
|
|
234
|
+
}
|
|
235
|
+
const READONLY_VERBS = /^(read|get|list|search|find|query|describe|inspect|count|fetch|view|show)/i;
|
|
236
|
+
function heuristicReadOnly(toolName) {
|
|
237
|
+
// Fallback when the server hasn't declared `readOnlyHint`. Permissive on
|
|
238
|
+
// purpose — a misclassification merely surfaces the call to the dest./
|
|
239
|
+
// allowlist filter, which has the last word.
|
|
240
|
+
return READONLY_VERBS.test(toolName);
|
|
241
|
+
}
|
|
242
|
+
function decorateDescription(raw, serverName, annotations) {
|
|
243
|
+
// Tag the description with the server name + behavior hints so the model
|
|
244
|
+
// can pick between overlapping tools (filesystem-mcp:read vs builtin
|
|
245
|
+
// read_file). Best practice across Claude Code / Goose / Cursor.
|
|
246
|
+
const hints = [];
|
|
247
|
+
if (annotations.destructive)
|
|
248
|
+
hints.push('destructive');
|
|
249
|
+
else if (annotations.readOnly)
|
|
250
|
+
hints.push('read-only');
|
|
251
|
+
if (annotations.idempotent)
|
|
252
|
+
hints.push('idempotent');
|
|
253
|
+
const tag = hints.length > 0 ? ` [${hints.join(', ')}]` : '';
|
|
254
|
+
return `(via ${serverName} MCP${tag}) ${raw}`.trim();
|
|
91
255
|
}
|
|
92
256
|
//# sourceMappingURL=client.js.map
|
package/dist/mcp/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -3,10 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Companion to `code-search-mcp` (which is the MCP *server* Anvil already
|
|
5
5
|
* publishes). The client side lets Anvil's agent connect to OTHER MCP
|
|
6
|
-
* servers configured per project
|
|
6
|
+
* servers configured per project — surfacing their tools to non-Claude
|
|
7
|
+
* adapters too via `MergedToolExecutor`.
|
|
7
8
|
*/
|
|
8
9
|
export type { McpTransport, McpServerConfig, McpServerEntry, McpServersFile, } from './types.js';
|
|
9
10
|
export { loadMcpServers, findMcpConfigPath, type LoadMcpServersOptions, } from './config-loader.js';
|
|
10
|
-
export { McpAgentClient } from './client.js';
|
|
11
|
+
export { McpAgentClient, mcpToolName, MCP_NAME_PREFIX, type McpClientOpts, type McpToolDescriptor, type McpToolAnnotations, type McpProgressEvent, } from './client.js';
|
|
11
12
|
export { buildAgentToolset, type AgentToolset, } from './tool-merger.js';
|
|
13
|
+
export { McpClientPool, type McpClientPoolOpts, } from './pool.js';
|
|
14
|
+
export { MergedToolExecutor, type MergedToolExecutorOpts, } from './merged-executor.js';
|
|
12
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,KAAK,qBAAqB,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,EACjB,KAAK,YAAY,GAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,EACb,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,kBAAkB,EAClB,KAAK,sBAAsB,GAC5B,MAAM,sBAAsB,CAAC"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @esankhan3/anvil-agent-core/mcp — Model Context Protocol *client*-side helpers.
|
|
3
|
-
*
|
|
4
|
-
* Companion to `code-search-mcp` (which is the MCP *server* Anvil already
|
|
5
|
-
* publishes). The client side lets Anvil's agent connect to OTHER MCP
|
|
6
|
-
* servers configured per project.
|
|
7
|
-
*/
|
|
8
1
|
export { loadMcpServers, findMcpConfigPath, } from './config-loader.js';
|
|
9
|
-
export { McpAgentClient } from './client.js';
|
|
2
|
+
export { McpAgentClient, mcpToolName, MCP_NAME_PREFIX, } from './client.js';
|
|
10
3
|
export { buildAgentToolset, } from './tool-merger.js';
|
|
4
|
+
export { McpClientPool, } from './pool.js';
|
|
5
|
+
export { MergedToolExecutor, } from './merged-executor.js';
|
|
11
6
|
//# sourceMappingURL=index.js.map
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,cAAc,EACd,iBAAiB,GAElB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,WAAW,EACX,eAAe,GAKhB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,iBAAiB,GAElB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,GAEd,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,kBAAkB,GAEnB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MergedToolExecutor` — a `ToolExecutor` that exposes both the seven
|
|
3
|
+
* builtin tools and every tool advertised by an `McpClientPool`. The
|
|
4
|
+
* non-Claude adapters (Ollama, OpenRouter, OpenCode, OpenAI, Gemini, ADK)
|
|
5
|
+
* consume this as `config.toolExecutor` and gain MCP support transparently.
|
|
6
|
+
*
|
|
7
|
+
* Naming convention: builtins keep their bare names (`read_file`, `bash`);
|
|
8
|
+
* MCP tools are `mcp__<server>__<tool>`. The dispatch chain in `execute`
|
|
9
|
+
* routes by name.
|
|
10
|
+
*
|
|
11
|
+
* Per-stage `allowedTools` filtering supports two forms:
|
|
12
|
+
* - exact name: `"read_file"`, `"mcp__github__create_issue"`
|
|
13
|
+
* - per-server glob: `"mcp__github__*"` matches every tool from
|
|
14
|
+
* `github` server.
|
|
15
|
+
*
|
|
16
|
+
* Destructive-tier guard: if a MCP tool's annotations declare
|
|
17
|
+
* `destructive: true` AND the stage's allowlist doesn't explicitly name it
|
|
18
|
+
* (only matched by glob), it's hidden from `listSchemas`. Stages that need
|
|
19
|
+
* a destructive MCP tool must list it by full name. Prevents the model
|
|
20
|
+
* from being handed `mcp__filesystem__delete_file` just because the stage
|
|
21
|
+
* had `mcp__filesystem__*`.
|
|
22
|
+
*/
|
|
23
|
+
import type { ToolCall, ToolSchema } from '../types.js';
|
|
24
|
+
import type { ExecCtx, ToolExecutor, ToolResult } from '../tools/types.js';
|
|
25
|
+
import { BuiltinToolExecutor } from '../tools/builtin.js';
|
|
26
|
+
import type { McpClientPool } from './pool.js';
|
|
27
|
+
export interface MergedToolExecutorOpts {
|
|
28
|
+
builtin: BuiltinToolExecutor;
|
|
29
|
+
pool?: McpClientPool;
|
|
30
|
+
/** Stage-policy allow list. Pass-through of `req.allowedTools`. */
|
|
31
|
+
allowedTools?: string[];
|
|
32
|
+
/** Surface MCP call resolution onto telemetry / activity feed. */
|
|
33
|
+
onMcpCallStart?: (info: {
|
|
34
|
+
tool: string;
|
|
35
|
+
serverName: string;
|
|
36
|
+
}) => void;
|
|
37
|
+
onMcpCallEnd?: (info: {
|
|
38
|
+
tool: string;
|
|
39
|
+
serverName: string;
|
|
40
|
+
durationMs: number;
|
|
41
|
+
isError: boolean;
|
|
42
|
+
}) => void;
|
|
43
|
+
}
|
|
44
|
+
export declare class MergedToolExecutor implements ToolExecutor {
|
|
45
|
+
private readonly builtin;
|
|
46
|
+
private readonly pool?;
|
|
47
|
+
private readonly allowedExact;
|
|
48
|
+
private readonly allowedGlobs;
|
|
49
|
+
private readonly allowAllBuiltins;
|
|
50
|
+
private readonly onStart?;
|
|
51
|
+
private readonly onEnd?;
|
|
52
|
+
/** Lazily populated by `listSchemas` once MCP discovery has run. */
|
|
53
|
+
private mcpDescriptors;
|
|
54
|
+
constructor(opts: MergedToolExecutorOpts);
|
|
55
|
+
/**
|
|
56
|
+
* Returns the union of builtin + MCP tool schemas, filtered by the
|
|
57
|
+
* stage's allowlist. Builtin filtering is delegated to BuiltinToolExecutor
|
|
58
|
+
* (which was already wired with `allowedTools`); MCP filtering happens
|
|
59
|
+
* here.
|
|
60
|
+
*
|
|
61
|
+
* NOTE: synchronous; reads the pool's cached tool list. Callers MUST
|
|
62
|
+
* call `prime()` once (awaitable) before the first `listSchemas` so MCP
|
|
63
|
+
* discovery has completed. After that the cache is hot.
|
|
64
|
+
*/
|
|
65
|
+
listSchemas(): ToolSchema[];
|
|
66
|
+
/** Warm the MCP tool cache so a later sync `listSchemas` is complete. */
|
|
67
|
+
prime(): Promise<void>;
|
|
68
|
+
execute(call: ToolCall, ctx: ExecCtx): Promise<ToolResult>;
|
|
69
|
+
/** Show this descriptor at schema time? Apply destructive guard. */
|
|
70
|
+
private allowedForListing;
|
|
71
|
+
/** Allow this name at exec time? Defense-in-depth check vs listing. */
|
|
72
|
+
private allowedForExec;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=merged-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merged-executor.d.ts","sourceRoot":"","sources":["../../src/mcp/merged-executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG/C,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACtE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC3G;AAED,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA2C;IACpE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAyC;IAChE,oEAAoE;IACpE,OAAO,CAAC,cAAc,CAAoC;gBAE9C,IAAI,EAAE,sBAAsB;IAmBxC;;;;;;;;;OASG;IACH,WAAW,IAAI,UAAU,EAAE;IAU3B,yEAAyE;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA+ChE,oEAAoE;IACpE,OAAO,CAAC,iBAAiB;IAgBzB,uEAAuE;IACvE,OAAO,CAAC,cAAc;CAcvB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
export class MergedToolExecutor {
|
|
2
|
+
builtin;
|
|
3
|
+
pool;
|
|
4
|
+
allowedExact;
|
|
5
|
+
allowedGlobs;
|
|
6
|
+
allowAllBuiltins;
|
|
7
|
+
onStart;
|
|
8
|
+
onEnd;
|
|
9
|
+
/** Lazily populated by `listSchemas` once MCP discovery has run. */
|
|
10
|
+
mcpDescriptors = null;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.builtin = opts.builtin;
|
|
13
|
+
this.pool = opts.pool;
|
|
14
|
+
this.onStart = opts.onMcpCallStart;
|
|
15
|
+
this.onEnd = opts.onMcpCallEnd;
|
|
16
|
+
const allowed = opts.allowedTools ?? [];
|
|
17
|
+
this.allowedExact = new Set();
|
|
18
|
+
this.allowedGlobs = [];
|
|
19
|
+
this.allowAllBuiltins = allowed.length === 0;
|
|
20
|
+
for (const name of allowed) {
|
|
21
|
+
if (name.endsWith('__*') && name.startsWith('mcp__')) {
|
|
22
|
+
const serverName = name.slice('mcp__'.length, -3);
|
|
23
|
+
if (serverName.length > 0)
|
|
24
|
+
this.allowedGlobs.push({ serverName });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
this.allowedExact.add(name);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns the union of builtin + MCP tool schemas, filtered by the
|
|
33
|
+
* stage's allowlist. Builtin filtering is delegated to BuiltinToolExecutor
|
|
34
|
+
* (which was already wired with `allowedTools`); MCP filtering happens
|
|
35
|
+
* here.
|
|
36
|
+
*
|
|
37
|
+
* NOTE: synchronous; reads the pool's cached tool list. Callers MUST
|
|
38
|
+
* call `prime()` once (awaitable) before the first `listSchemas` so MCP
|
|
39
|
+
* discovery has completed. After that the cache is hot.
|
|
40
|
+
*/
|
|
41
|
+
listSchemas() {
|
|
42
|
+
const out = [...this.builtin.listSchemas()];
|
|
43
|
+
if (!this.mcpDescriptors)
|
|
44
|
+
return out;
|
|
45
|
+
for (const desc of this.mcpDescriptors) {
|
|
46
|
+
if (!this.allowedForListing(desc))
|
|
47
|
+
continue;
|
|
48
|
+
out.push(desc.schema);
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Warm the MCP tool cache so a later sync `listSchemas` is complete. */
|
|
53
|
+
async prime() {
|
|
54
|
+
if (!this.pool || this.mcpDescriptors)
|
|
55
|
+
return;
|
|
56
|
+
this.mcpDescriptors = await this.pool.discoverTools();
|
|
57
|
+
}
|
|
58
|
+
async execute(call, ctx) {
|
|
59
|
+
if (!call.name.startsWith('mcp__')) {
|
|
60
|
+
// Builtin path — BuiltinToolExecutor enforces its own allowlist.
|
|
61
|
+
return this.builtin.execute(call, ctx);
|
|
62
|
+
}
|
|
63
|
+
if (!this.pool) {
|
|
64
|
+
return {
|
|
65
|
+
isError: true,
|
|
66
|
+
content: `Tool "${call.name}" requires an MCP server but no pool is configured.`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!this.allowedForExec(call.name)) {
|
|
70
|
+
return {
|
|
71
|
+
isError: true,
|
|
72
|
+
content: `Tool "${call.name}" is not permitted in this stage.`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const serverName = ownerFor(call.name);
|
|
76
|
+
if (!serverName) {
|
|
77
|
+
return { isError: true, content: `Cannot parse MCP server from "${call.name}".` };
|
|
78
|
+
}
|
|
79
|
+
const started = Date.now();
|
|
80
|
+
this.onStart?.({ tool: call.name, serverName });
|
|
81
|
+
try {
|
|
82
|
+
const result = await this.pool.callTool(call.name, call.arguments ?? {}, ctx.abortSignal);
|
|
83
|
+
const flattened = flattenMcpContent(result);
|
|
84
|
+
this.onEnd?.({
|
|
85
|
+
tool: call.name,
|
|
86
|
+
serverName,
|
|
87
|
+
durationMs: Date.now() - started,
|
|
88
|
+
isError: flattened.isError,
|
|
89
|
+
});
|
|
90
|
+
return flattened;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
94
|
+
this.onEnd?.({
|
|
95
|
+
tool: call.name,
|
|
96
|
+
serverName,
|
|
97
|
+
durationMs: Date.now() - started,
|
|
98
|
+
isError: true,
|
|
99
|
+
});
|
|
100
|
+
return { isError: true, content: `MCP call failed: ${message}` };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── Filter logic ───────────────────────────────────────────────────────
|
|
104
|
+
/** Show this descriptor at schema time? Apply destructive guard. */
|
|
105
|
+
allowedForListing(desc) {
|
|
106
|
+
// Exact-match wins regardless of destructive flag.
|
|
107
|
+
if (this.allowedExact.has(desc.name))
|
|
108
|
+
return true;
|
|
109
|
+
if (this.allowAllBuiltins && !desc.annotations.destructive) {
|
|
110
|
+
// Empty allowlist means read-only fallback per BuiltinToolExecutor;
|
|
111
|
+
// mirror that for MCP tools so they aren't surfaced by default.
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const matchesGlob = this.allowedGlobs.some((g) => g.serverName === desc.serverName);
|
|
115
|
+
if (!matchesGlob)
|
|
116
|
+
return false;
|
|
117
|
+
// Glob match: hide destructive tools unless the stage names them
|
|
118
|
+
// explicitly.
|
|
119
|
+
if (desc.annotations.destructive)
|
|
120
|
+
return false;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
/** Allow this name at exec time? Defense-in-depth check vs listing. */
|
|
124
|
+
allowedForExec(name) {
|
|
125
|
+
if (this.allowAllBuiltins) {
|
|
126
|
+
// Match the listing default for empty allowlist.
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
if (this.allowedExact.has(name))
|
|
130
|
+
return true;
|
|
131
|
+
const owner = ownerFor(name);
|
|
132
|
+
if (!owner)
|
|
133
|
+
return false;
|
|
134
|
+
if (!this.allowedGlobs.some((g) => g.serverName === owner))
|
|
135
|
+
return false;
|
|
136
|
+
// Glob path: re-fetch annotations to gate destructive tools.
|
|
137
|
+
const desc = this.mcpDescriptors?.find((d) => d.name === name);
|
|
138
|
+
if (desc?.annotations.destructive)
|
|
139
|
+
return false;
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
144
|
+
function ownerFor(toolName) {
|
|
145
|
+
if (!toolName.startsWith('mcp__'))
|
|
146
|
+
return undefined;
|
|
147
|
+
// mcp__<server>__<tool>; server may contain underscores. We split on the
|
|
148
|
+
// FIRST `__` after the prefix that's followed by a tool name with no
|
|
149
|
+
// `__`. Simpler: match `mcp__([^_]+(?:_[^_]+)*)__`.
|
|
150
|
+
const rest = toolName.slice('mcp__'.length);
|
|
151
|
+
// Look for the LAST `__` so the server name eats the rest.
|
|
152
|
+
const idx = rest.lastIndexOf('__');
|
|
153
|
+
if (idx < 0)
|
|
154
|
+
return undefined;
|
|
155
|
+
return rest.slice(0, idx);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Collapse the MCP SDK's structured `content[]` result into the
|
|
159
|
+
* `ToolResult` shape the builtin executor uses. Text parts concatenate;
|
|
160
|
+
* image / resource parts surface as `[image: <mime>]` placeholders so the
|
|
161
|
+
* model isn't fed binary garbage.
|
|
162
|
+
*/
|
|
163
|
+
function flattenMcpContent(raw) {
|
|
164
|
+
if (!raw || typeof raw !== 'object') {
|
|
165
|
+
return { isError: false, content: String(raw ?? '') };
|
|
166
|
+
}
|
|
167
|
+
const r = raw;
|
|
168
|
+
const parts = [];
|
|
169
|
+
if (Array.isArray(r.content)) {
|
|
170
|
+
for (const block of r.content) {
|
|
171
|
+
if (!block || typeof block !== 'object')
|
|
172
|
+
continue;
|
|
173
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
174
|
+
parts.push(block.text);
|
|
175
|
+
}
|
|
176
|
+
else if (block.type === 'image') {
|
|
177
|
+
parts.push(`[image: ${block.mimeType ?? 'unknown'}]`);
|
|
178
|
+
}
|
|
179
|
+
else if (block.type === 'resource') {
|
|
180
|
+
parts.push(`[resource]`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
parts.push(`[${block.type ?? 'unknown'}]`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (parts.length === 0 && r.structuredContent !== undefined) {
|
|
188
|
+
try {
|
|
189
|
+
parts.push(JSON.stringify(r.structuredContent));
|
|
190
|
+
}
|
|
191
|
+
catch { /* ok */ }
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
isError: r.isError === true,
|
|
195
|
+
content: parts.join('\n').trim() || '(empty)',
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=merged-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merged-executor.js","sourceRoot":"","sources":["../../src/mcp/merged-executor.ts"],"names":[],"mappings":"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"}
|