agent.libx.js 0.93.22 → 0.93.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.js +8 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp.client.d.ts +33 -6
- package/dist/mcp.client.js +56 -23
- package/dist/mcp.client.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp.client.d.ts
CHANGED
|
@@ -178,15 +178,31 @@ interface McpCatalogOptions extends McpToolSearchOptions {
|
|
|
178
178
|
keepWarm?: boolean;
|
|
179
179
|
/** Warm-client pool. Default: a shared process-lifetime `McpPool` (only used when `keepWarm`). */
|
|
180
180
|
pool?: McpPool;
|
|
181
|
+
/** Negative cache: after a server fails/times out discovery, skip it for this long so it never
|
|
182
|
+
* re-floors a turn at the deadline. Default 60s; the server is re-probed once the cooldown lapses. */
|
|
183
|
+
failureCooldownMs?: number;
|
|
184
|
+
/** Shared failure-cooldown map (configKey → until-epoch-ms). Default: a process-lifetime singleton. */
|
|
185
|
+
failures?: Map<string, number>;
|
|
186
|
+
/** Discovery policy on a cache MISS:
|
|
187
|
+
* - `'connect'` (default): synchronously connect+list (deadline-bounded) — blocks until ready.
|
|
188
|
+
* - `'cache-only'`: NEVER block the turn — serve only cached servers, and kick uncached discovery
|
|
189
|
+
* to the background (so it's warm next turn). Pair with a boot/timer `warmMcpCatalog` so the
|
|
190
|
+
* first turn is already a cache hit. */
|
|
191
|
+
discover?: 'connect' | 'cache-only';
|
|
181
192
|
}
|
|
182
193
|
/**
|
|
183
194
|
* Lazy + cached MCP mount. Builds the `ToolSearch`/`McpCall` pair from the CACHED catalog when one
|
|
184
|
-
* exists — connecting NOTHING. On a cache miss it connects once (parallel, deadline-
|
|
185
|
-
* caches, then disconnects (or keeps warm if `keepWarm`). A server is connected only
|
|
186
|
-
* tools is actually invoked via `McpCall` (memoized per turn; reused from the warm
|
|
195
|
+
* exists — connecting NOTHING. On a cache miss it (by default) connects once (parallel, deadline-
|
|
196
|
+
* bounded), lists, caches, then disconnects (or keeps warm if `keepWarm`). A server is connected only
|
|
197
|
+
* when one of its tools is actually invoked via `McpCall` (memoized per turn; reused from the warm
|
|
198
|
+
* pool if enabled). A server that fails/times out is negative-cached (`failureCooldownMs`) so it
|
|
199
|
+
* never re-floors a later turn.
|
|
187
200
|
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
201
|
+
* For zero turn-path latency even on a cold process, set `discover: 'cache-only'` and call
|
|
202
|
+
* `warmMcpCatalog` at boot + on a timer: the turn then NEVER synchronously connects — it serves
|
|
203
|
+
* cached servers and warms the rest in the background.
|
|
204
|
+
*
|
|
205
|
+
* Per-turn cost: a turn using NO MCP tool → 0 connections; a turn using one → exactly one.
|
|
190
206
|
*/
|
|
191
207
|
declare function mountMcpCatalog(servers?: Record<string, McpServerConfig>, opts?: McpCatalogOptions): Promise<{
|
|
192
208
|
tools: AgentTool[];
|
|
@@ -195,5 +211,16 @@ declare function mountMcpCatalog(servers?: Record<string, McpServerConfig>, opts
|
|
|
195
211
|
connect(name: string): Promise<McpClient>;
|
|
196
212
|
close(): Promise<void>;
|
|
197
213
|
}>;
|
|
214
|
+
/**
|
|
215
|
+
* Off-turn catalog warm-up: do the one cold discovery pass (connect + list, parallel, deadline-
|
|
216
|
+
* bounded) so a later `mountMcpCatalog(..., { discover: 'cache-only' })` is a cache HIT. Call at
|
|
217
|
+
* server boot and on a timer (cadence < the catalog TTL). Cache hits cost nothing; down servers are
|
|
218
|
+
* negative-cached so turns never touch them. Returns which servers warmed vs failed.
|
|
219
|
+
*/
|
|
220
|
+
declare function warmMcpCatalog(servers?: Record<string, McpServerConfig>, opts?: McpCatalogOptions): Promise<{
|
|
221
|
+
warmed: string[];
|
|
222
|
+
failed: string[];
|
|
223
|
+
toolCount: number;
|
|
224
|
+
}>;
|
|
198
225
|
|
|
199
|
-
export { type HttpServerSpec, HttpTransport, McpAuthError, type McpCatalogOptions, type McpCatalogStore, McpClient, McpPool, type McpServerConfig, type McpTransport, MemMcpCatalog, type MountedMcp, type StdioServerSpec, StdioTransport, mcpConfigKey, mountMcpCatalog, mountMcpDeferred, mountMcpServer, mountMcpServers };
|
|
226
|
+
export { type HttpServerSpec, HttpTransport, McpAuthError, type McpCatalogOptions, type McpCatalogStore, McpClient, McpPool, type McpServerConfig, type McpTransport, MemMcpCatalog, type MountedMcp, type StdioServerSpec, StdioTransport, mcpConfigKey, mountMcpCatalog, mountMcpDeferred, mountMcpServer, mountMcpServers, warmMcpCatalog };
|
package/dist/mcp.client.js
CHANGED
|
@@ -507,31 +507,53 @@ var McpPool = class {
|
|
|
507
507
|
};
|
|
508
508
|
var defaultCatalog = new MemMcpCatalog();
|
|
509
509
|
var defaultPool = new McpPool();
|
|
510
|
-
|
|
510
|
+
var defaultFailures = /* @__PURE__ */ new Map();
|
|
511
|
+
var bgInflight = /* @__PURE__ */ new Set();
|
|
512
|
+
var DEFAULT_FAILURE_COOLDOWN_MS = 6e4;
|
|
513
|
+
async function connectAndList(name, cfg, key, opts) {
|
|
511
514
|
const catalog = opts.catalog ?? defaultCatalog;
|
|
512
515
|
const pool = opts.pool ?? defaultPool;
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
516
|
+
const failures = opts.failures ?? defaultFailures;
|
|
517
|
+
const client = new McpClient(buildTransport(cfg));
|
|
518
|
+
try {
|
|
519
|
+
const specs = await withTimeout((async () => {
|
|
520
|
+
await client.connect();
|
|
521
|
+
return client.listTools();
|
|
522
|
+
})(), opts.mountTimeoutMs, name);
|
|
523
|
+
catalog.set(key, specs);
|
|
524
|
+
failures.delete(key);
|
|
525
|
+
if (opts.keepWarm && !cfg.url) pool.put(key, client);
|
|
526
|
+
else await client.close().catch(() => {
|
|
527
|
+
});
|
|
528
|
+
return { name, cfg, key, specs };
|
|
529
|
+
} catch (e) {
|
|
530
|
+
await client.close().catch(() => {
|
|
531
|
+
});
|
|
532
|
+
failures.set(key, Date.now() + (opts.failureCooldownMs ?? DEFAULT_FAILURE_COOLDOWN_MS));
|
|
533
|
+
logMountFailure(name, e);
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async function discoverOne(name, cfg, opts) {
|
|
538
|
+
const catalog = opts.catalog ?? defaultCatalog;
|
|
539
|
+
const failures = opts.failures ?? defaultFailures;
|
|
540
|
+
const key = mcpConfigKey(cfg);
|
|
541
|
+
const cached = catalog.get(key);
|
|
542
|
+
if (cached) return { name, cfg, key, specs: cached };
|
|
543
|
+
const until = failures.get(key);
|
|
544
|
+
if (until && until > Date.now()) return null;
|
|
545
|
+
if (opts.discover === "cache-only") {
|
|
546
|
+
if (!bgInflight.has(key)) {
|
|
547
|
+
bgInflight.add(key);
|
|
548
|
+
void connectAndList(name, cfg, key, opts).finally(() => bgInflight.delete(key));
|
|
533
549
|
}
|
|
534
|
-
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
return connectAndList(name, cfg, key, opts);
|
|
553
|
+
}
|
|
554
|
+
async function mountMcpCatalog(servers = {}, opts = {}) {
|
|
555
|
+
const pool = opts.pool ?? defaultPool;
|
|
556
|
+
const discovered = (await Promise.all(validEntries(servers).map(([name, cfg]) => discoverOne(name, cfg, opts)))).filter(Boolean);
|
|
535
557
|
const byName = new Map(discovered.map((d) => [d.name, d]));
|
|
536
558
|
const inflight = /* @__PURE__ */ new Map();
|
|
537
559
|
const live = [];
|
|
@@ -568,6 +590,16 @@ async function mountMcpCatalog(servers = {}, opts = {}) {
|
|
|
568
590
|
};
|
|
569
591
|
return { ...search, connect, close };
|
|
570
592
|
}
|
|
593
|
+
async function warmMcpCatalog(servers = {}, opts = {}) {
|
|
594
|
+
const entries = validEntries(servers);
|
|
595
|
+
const discovered = (await Promise.all(entries.map(([name, cfg]) => discoverOne(name, cfg, { ...opts, discover: "connect" })))).filter(Boolean);
|
|
596
|
+
const warmedNames = new Set(discovered.map((d) => d.name));
|
|
597
|
+
return {
|
|
598
|
+
warmed: discovered.map((d) => d.name),
|
|
599
|
+
failed: entries.map(([n]) => n).filter((n) => !warmedNames.has(n)),
|
|
600
|
+
toolCount: discovered.reduce((s, d) => s + d.specs.length, 0)
|
|
601
|
+
};
|
|
602
|
+
}
|
|
571
603
|
export {
|
|
572
604
|
HttpTransport,
|
|
573
605
|
McpAuthError,
|
|
@@ -579,6 +611,7 @@ export {
|
|
|
579
611
|
mountMcpCatalog,
|
|
580
612
|
mountMcpDeferred,
|
|
581
613
|
mountMcpServer,
|
|
582
|
-
mountMcpServers
|
|
614
|
+
mountMcpServers,
|
|
615
|
+
warmMcpCatalog
|
|
583
616
|
};
|
|
584
617
|
//# sourceMappingURL=mcp.client.js.map
|
package/dist/mcp.client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.client.ts","../src/logging.ts","../src/relevance.ts","../src/mcp.ts"],"sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { forComponent } from './logging';\nimport { mcpToolsToAgentTools, makeMcpToolSearchFromMounted, makeLazyMcpToolSearch, type McpToolSpec, type McpToolSearchOptions } from './mcp';\nimport type { AgentTool } from './tools';\n\nconst log = forComponent('mcp');\n\n/**\n * Real MCP (Model Context Protocol) client — node-only, deliberately kept OUT of the edge-safe\n * `src/index.ts` entry. It speaks JSON-RPC 2.0 over a transport (stdio child process or HTTP),\n * performs the `initialize` handshake + `tools/list` discovery, then hands `(specs, callTool)` to\n * the pure `src/mcp.ts` adapter — so the browser/edge build keeps working without importing this.\n */\n\nconst PROTOCOL_VERSION = '2025-06-18';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** A JSON-RPC 2.0 transport: request (awaits a result), notify (fire-and-forget), close. */\nexport interface McpTransport {\n start(): Promise<void>;\n request(method: string, params?: unknown): Promise<any>;\n notify(method: string, params?: unknown): Promise<void>;\n close(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// stdio transport — newline-delimited JSON-RPC over a spawned child's stdin/stdout.\n// ---------------------------------------------------------------------------\nexport interface StdioServerSpec {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n timeoutMs?: number;\n}\n\nexport class StdioTransport implements McpTransport {\n private proc?: ChildProcess;\n private buf = '';\n private nextId = 1;\n private pending = new Map<number, { resolve: (v: any) => void; reject: (e: any) => void; timer: ReturnType<typeof setTimeout> }>();\n\n constructor(private spec: StdioServerSpec) {}\n\n async start(): Promise<void> {\n const { command, args = [], env, cwd } = this.spec;\n const proc = spawn(command, args, { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...env }, cwd });\n this.proc = proc;\n proc.stdout!.setEncoding('utf8');\n proc.stdout!.on('data', (chunk: string) => this.onData(chunk));\n proc.stderr!.setEncoding('utf8');\n proc.stderr!.on('data', (chunk: string) => log.debug(`[${command}] stderr:`, chunk.trimEnd())); // server diagnostics\n proc.on('exit', (code) => this.failAll(new Error(`MCP server \"${command}\" exited (code ${code})`)));\n proc.on('error', (e) => this.failAll(e instanceof Error ? e : new Error(String(e))));\n }\n\n private onData(chunk: string): void {\n this.buf += chunk;\n let nl: number;\n while ((nl = this.buf.indexOf('\\n')) >= 0) {\n const line = this.buf.slice(0, nl).trim();\n this.buf = this.buf.slice(nl + 1);\n if (!line) continue;\n try { this.dispatch(JSON.parse(line)); }\n catch (e) { log.debug('dropping non-JSON line from MCP server:', line, e); } // never throw out of the stream handler\n }\n }\n\n private dispatch(msg: any): void {\n // We're a minimal client: only correlate responses to our requests; ignore server→client calls.\n if (msg?.id == null || !this.pending.has(msg.id)) return;\n const p = this.pending.get(msg.id)!;\n this.pending.delete(msg.id);\n clearTimeout(p.timer);\n if (msg.error) p.reject(new Error(msg.error?.message ?? JSON.stringify(msg.error)));\n else p.resolve(msg.result);\n }\n\n private failAll(e: Error): void {\n for (const p of this.pending.values()) { clearTimeout(p.timer); p.reject(e); }\n this.pending.clear();\n }\n\n private write(msg: unknown): void {\n if (!this.proc?.stdin) throw new Error('MCP stdio transport not started');\n this.proc.stdin.write(JSON.stringify(msg) + '\\n');\n }\n\n request(method: string, params?: unknown): Promise<any> {\n const id = this.nextId++;\n const timeoutMs = this.spec.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`MCP request \"${method}\" timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try { this.write({ jsonrpc: '2.0', id, method, params }); }\n catch (e) { clearTimeout(timer); this.pending.delete(id); reject(e); }\n });\n }\n\n async notify(method: string, params?: unknown): Promise<void> {\n this.write({ jsonrpc: '2.0', method, params });\n }\n\n async close(): Promise<void> {\n this.failAll(new Error('MCP transport closed'));\n try { this.proc?.stdin?.end(); } catch (e) { log.debug('stdin end failed', e); }\n this.proc?.kill();\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP transport — Streamable HTTP: POST JSON-RPC, parse JSON or an SSE response.\n// ---------------------------------------------------------------------------\nexport interface HttpServerSpec {\n url: string;\n headers?: Record<string, string>;\n /** Sugar over `headers` → `Authorization: Bearer <token>`. The headless-friendly path (no OAuth loopback);\n * inject a static token (from env / VFS secret) per our CLAUDE.md rule preferring API keys for cron/edge. */\n bearerToken?: string;\n timeoutMs?: number;\n}\n\n/** Thrown when an HTTP MCP server rejects auth (401/403). Carries `needsAuth` so callers can surface a hint\n * (\"set bearerToken / headers\") instead of a generic mount failure — without attempting an interactive flow. */\nexport class McpAuthError extends Error {\n needsAuth = true;\n constructor(public status: number, public serverName?: string) {\n super(`MCP server${serverName ? ` \"${serverName}\"` : ''} requires authentication (HTTP ${status}) — set bearerToken or headers`);\n this.name = 'McpAuthError';\n }\n}\n\nexport class HttpTransport implements McpTransport {\n private nextId = 1;\n private sessionId?: string;\n private fetchImpl: typeof fetch;\n\n constructor(private spec: HttpServerSpec, fetchImpl?: typeof fetch) {\n this.fetchImpl = fetchImpl ?? fetch;\n }\n\n async start(): Promise<void> {}\n\n request(method: string, params?: unknown): Promise<any> {\n return this.post({ jsonrpc: '2.0', id: this.nextId++, method, params }, false);\n }\n\n async notify(method: string, params?: unknown): Promise<void> {\n await this.post({ jsonrpc: '2.0', method, params }, true);\n }\n\n private async post(msg: unknown, isNotify: boolean): Promise<any> {\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream',\n ...(this.spec.bearerToken ? { authorization: `Bearer ${this.spec.bearerToken}` } : {}),\n ...this.spec.headers, // explicit headers win — lets a caller override the bearer sugar if needed\n ...(this.sessionId ? { 'mcp-session-id': this.sessionId } : {}),\n };\n const resp = await this.fetchImpl(this.spec.url, {\n method: 'POST', headers, body: JSON.stringify(msg),\n signal: AbortSignal.timeout(this.spec.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n });\n const sid = resp.headers.get('mcp-session-id');\n if (sid) this.sessionId = sid; // adopt the server-assigned session for subsequent calls\n if (resp.status === 401 || resp.status === 403) throw new McpAuthError(resp.status);\n if (!resp.ok) throw new Error(`MCP HTTP ${resp.status} ${resp.statusText}`);\n if (isNotify) return;\n const ct = resp.headers.get('content-type') ?? '';\n const data = ct.includes('text/event-stream') ? parseSseResponse(await resp.text()) : await resp.json();\n if (data?.error) throw new Error(data.error?.message ?? JSON.stringify(data.error));\n return data?.result;\n }\n\n async close(): Promise<void> {}\n}\n\n/** Pull the JSON-RPC response object out of an SSE body (the first `data:` payload that carries one). */\nfunction parseSseResponse(body: string): any {\n for (const line of body.split('\\n')) {\n const trimmed = line.trimStart();\n if (!trimmed.startsWith('data:')) continue;\n try {\n const obj = JSON.parse(trimmed.slice(5).trim());\n if (obj && (obj.result !== undefined || obj.error !== undefined)) return obj;\n } catch (e) { log.debug('skipping unparseable SSE data line', e); }\n }\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Client — handshake + discovery on top of a transport.\n// ---------------------------------------------------------------------------\nexport class McpClient {\n constructor(public transport: McpTransport, private clientInfo = { name: 'agent.libx.js', version: '0' }) {}\n\n /** `initialize` handshake → `notifications/initialized`. Returns the server's init result. */\n async connect(): Promise<{ serverInfo?: { name?: string; version?: string }; capabilities?: any }> {\n await this.transport.start();\n const result = await this.transport.request('initialize', {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: this.clientInfo,\n });\n await this.transport.notify('notifications/initialized');\n return result ?? {};\n }\n\n async listTools(): Promise<McpToolSpec[]> {\n const r = await this.transport.request('tools/list');\n return Array.isArray(r?.tools) ? r.tools : [];\n }\n\n async callTool(name: string, args: unknown): Promise<unknown> {\n return this.transport.request('tools/call', { name, arguments: args ?? {} });\n }\n\n async listResources(): Promise<Array<{ uri: string; name?: string; mimeType?: string }>> {\n const r = await this.transport.request('resources/list');\n return Array.isArray(r?.resources) ? r.resources : [];\n }\n\n async readResource(uri: string): Promise<any> {\n return this.transport.request('resources/read', { uri });\n }\n\n async close(): Promise<void> {\n await this.transport.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Config-driven mounting — Claude-style `mcpServers: { name: {...} }`.\n// ---------------------------------------------------------------------------\n/** One server: stdio (`command`+`args`+`env`) OR http (`url`+`headers`). `disabled` skips it. */\nexport interface McpServerConfig {\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n url?: string;\n headers?: Record<string, string>;\n /** `Authorization: Bearer <token>` sugar for http servers (headless-friendly; no OAuth flow). */\n bearerToken?: string;\n /** Auth strategy for http servers. `'oauth'` → the CLI resolves a token via the attended OAuth flow\n * (cli/mcpOAuth.ts) and injects it as `bearerToken` at mount; the core never runs the flow. Default none. */\n auth?: 'oauth' | 'none';\n timeoutMs?: number;\n disabled?: boolean;\n}\n\nexport interface MountedMcp {\n name: string;\n client: McpClient;\n tools: AgentTool[];\n /** Raw tool specs discovered at mount (already fetched internally) — exposed so deferred-mount\n * glue (`makeMcpToolSearchFromMounted`) needn't re-call `tools/list`. */\n specs: McpToolSpec[];\n serverInfo?: { name?: string; version?: string };\n}\n\n/** Build the transport for a server config (http when `url`, else stdio). Shared by every mount path. */\nfunction buildTransport(cfg: McpServerConfig): McpTransport {\n return cfg.url\n ? new HttpTransport({ url: cfg.url, headers: cfg.headers, bearerToken: cfg.bearerToken, timeoutMs: cfg.timeoutMs })\n : new StdioTransport({ command: cfg.command!, args: cfg.args, env: cfg.env, cwd: cfg.cwd, timeoutMs: cfg.timeoutMs });\n}\n\n/** Race `p` against `ms` (a per-server mount deadline). `ms` falsy/≤0 → no deadline. The caller\n * closes the half-open client on rejection so a hung server leaks nothing. */\nfunction withTimeout<T>(p: Promise<T>, ms: number | undefined, label: string): Promise<T> {\n if (!ms || ms <= 0) return p;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`MCP \"${label}\" mount exceeded ${ms}ms`)), ms);\n (timer as any).unref?.();\n p.then((v) => { clearTimeout(timer); resolve(v); }, (e) => { clearTimeout(timer); reject(e); });\n });\n}\n\n/** Connect + discover + adapt, with optional per-server deadline; closes the client if it fails. */\nasync function mountWithDeadline(name: string, cfg: McpServerConfig, mountTimeoutMs?: number): Promise<MountedMcp> {\n const client = new McpClient(buildTransport(cfg));\n try {\n return await withTimeout((async () => {\n const init = await client.connect();\n const specs = await client.listTools();\n const tools = mcpToolsToAgentTools(specs, (tool, a) => client.callTool(tool, a), `mcp__${name}__`);\n return { name, client, tools, specs, serverInfo: init?.serverInfo } as MountedMcp;\n })(), mountTimeoutMs, name);\n } catch (e) {\n await client.close().catch((err) => log.debug(`close after failed mount of \"${name}\": ${err}`));\n throw e;\n }\n}\n\n/** Connect one server, discover its tools, and adapt them to prefixed AgentTools (`mcp__<name>__`). */\nexport function mountMcpServer(name: string, cfg: McpServerConfig): Promise<MountedMcp> {\n return mountWithDeadline(name, cfg);\n}\n\n/** Drop disabled/incomplete entries, warning on the incomplete ones. */\nfunction validEntries(servers: Record<string, McpServerConfig>): Array<[string, McpServerConfig]> {\n return Object.entries(servers).filter(([name, cfg]) => {\n if (!cfg || cfg.disabled) return false;\n if (!cfg.command && !cfg.url) { log.warn(`MCP server \"${name}\" needs a command (stdio) or url (http) — skipping`); return false; }\n return true;\n });\n}\n\n/** Log a mount failure (auth vs generic) without throwing — one broken server never blocks startup. */\nfunction logMountFailure(name: string, e: any): void {\n if (e instanceof McpAuthError) log.warn(`MCP \"${name}\" needs-auth: HTTP ${e.status} — set bearerToken or headers in its config; skipping`);\n else log.error(`MCP server \"${name}\" failed to mount: ${e?.message ?? e}`); // logged, then skipped\n}\n\n/**\n * Mount every configured server in PARALLEL (one slow/dead server no longer serializes the rest);\n * each may carry a `mountTimeoutMs` deadline. A server that fails is logged and skipped.\n */\nexport async function mountMcpServers(servers: Record<string, McpServerConfig> = {}, opts: { mountTimeoutMs?: number } = {}): Promise<MountedMcp[]> {\n const entries = validEntries(servers);\n const settled = await Promise.allSettled(entries.map(([name, cfg]) => mountWithDeadline(name, cfg, opts.mountTimeoutMs)));\n const out: MountedMcp[] = [];\n settled.forEach((r, i) => {\n const name = entries[i][0];\n if (r.status === 'fulfilled') { out.push(r.value); log.info(`MCP \"${name}\" mounted — ${r.value.tools.length} tool(s)${r.value.serverInfo?.name ? ` from ${r.value.serverInfo.name}` : ''}`); }\n else logMountFailure(name, r.reason);\n });\n return out;\n}\n\n/**\n * One-shot deferred MCP mount: connect every entry (failures dropped, never block startup) and\n * fold the survivors into a single `ToolSearch`/`McpCall` pair via `makeMcpToolSearchFromMounted`.\n * The node-only counterpart to that edge-safe helper — returns `mounted` too so callers can close\n * the clients on shutdown. Eager: it connects all servers up front. For lazy connect + a cached\n * catalog (zero connections on a turn that uses no MCP tool), use `mountMcpCatalog`.\n */\nexport async function mountMcpDeferred(\n servers: Record<string, McpServerConfig> = {},\n options?: McpToolSearchOptions & { mountTimeoutMs?: number },\n): Promise<{ tools: AgentTool[]; serverNames: string[]; toolCount: number; mounted: MountedMcp[] }> {\n const mounted = await mountMcpServers(servers, { mountTimeoutMs: options?.mountTimeoutMs });\n return { ...makeMcpToolSearchFromMounted(mounted, options), mounted };\n}\n\n// ---------------------------------------------------------------------------\n// Lazy connect + catalog cache — defer the CONNECTION, not just the schemas.\n// ---------------------------------------------------------------------------\n/** A persistent tool catalog: lets `mountMcpCatalog` build `ToolSearch` WITHOUT connecting when a\n * fresh entry exists. The lib defines the interface; the consumer supplies the store (RAM/disk).\n * Key = a hash of the server's resolved config (see `mcpConfigKey`). TTL/versioning is the store's. */\nexport interface McpCatalogStore {\n get(key: string): McpToolSpec[] | null;\n set(key: string, specs: McpToolSpec[]): void;\n}\n\n/** Stable cache key for a server config — command/args/cwd + env NAMES (not secret values), or\n * url + header names. Changing any of these invalidates the cached catalog; rotating a secret does not. */\nexport function mcpConfigKey(cfg: McpServerConfig): string {\n const parts = cfg.url\n ? ['http', cfg.url, ...Object.keys(cfg.headers ?? {}).sort()]\n : ['stdio', cfg.command ?? '', ...(cfg.args ?? []), cfg.cwd ?? '', ...Object.keys(cfg.env ?? {}).sort()];\n return createHash('sha256').update(parts.join('\\0')).digest('hex').slice(0, 16);\n}\n\n/** Default in-memory catalog: process-lifetime, hash-keyed, TTL-expiring (so a server that gains\n * tools is picked up after the TTL without a restart). Shared module singleton → cross-turn reuse. */\nexport class MemMcpCatalog implements McpCatalogStore {\n private m = new Map<string, { specs: McpToolSpec[]; exp: number }>();\n constructor(private ttlMs = 5 * 60_000) {}\n get(key: string): McpToolSpec[] | null {\n const e = this.m.get(key);\n if (!e) return null;\n if (Date.now() > e.exp) { this.m.delete(key); return null; }\n return e.specs;\n }\n set(key: string, specs: McpToolSpec[]): void { this.m.set(key, { specs, exp: Date.now() + this.ttlMs }); }\n}\n\n/** Opt-in warm pool: keeps stdio MCP clients connected across turns, reaping each after `ttlMs`\n * idle. Most stdio MCPs are per-turn by design, so this is off by default; HTTP servers are\n * stateless and never pooled. */\nexport class McpPool {\n private warm = new Map<string, { client: McpClient; timer: ReturnType<typeof setTimeout> }>();\n constructor(private ttlMs = 5 * 60_000) {}\n get(key: string): McpClient | null { const e = this.warm.get(key); if (!e) return null; this.arm(key, e); return e.client; }\n put(key: string, client: McpClient): void {\n const prev = this.warm.get(key); // overwrite: cancel the stale timer + close the displaced client\n if (prev) { clearTimeout(prev.timer); if (prev.client !== client) void prev.client.close().catch((err) => log.debug(`warm-pool replace close failed: ${err}`)); }\n const e = { client, timer: undefined as any };\n this.warm.set(key, e); this.arm(key, e);\n }\n private arm(key: string, e: { client: McpClient; timer: any }): void {\n clearTimeout(e.timer);\n e.timer = setTimeout(() => { void this.evict(key); }, this.ttlMs);\n (e.timer as any).unref?.();\n }\n private async evict(key: string): Promise<void> {\n const e = this.warm.get(key); if (!e) return;\n this.warm.delete(key);\n await e.client.close().catch((err) => log.debug(`warm-pool evict close failed: ${err}`));\n }\n async closeAll(): Promise<void> { for (const e of this.warm.values()) { clearTimeout(e.timer); await e.client.close().catch(() => {}); } this.warm.clear(); }\n}\n\nconst defaultCatalog = new MemMcpCatalog();\nconst defaultPool = new McpPool();\n\nexport interface McpCatalogOptions extends McpToolSearchOptions {\n /** Where to read/write discovered specs. Default: a shared process-lifetime `MemMcpCatalog`. */\n catalog?: McpCatalogStore;\n /** Per-server deadline for the connect+list on a cache MISS. A hung server is skipped, not blocking. */\n mountTimeoutMs?: number;\n /** Opt-in: keep stdio clients warm across turns (see `McpPool`). HTTP servers are never pooled. */\n keepWarm?: boolean;\n /** Warm-client pool. Default: a shared process-lifetime `McpPool` (only used when `keepWarm`). */\n pool?: McpPool;\n}\n\n/**\n * Lazy + cached MCP mount. Builds the `ToolSearch`/`McpCall` pair from the CACHED catalog when one\n * exists — connecting NOTHING. On a cache miss it connects once (parallel, deadline-bounded), lists,\n * caches, then disconnects (or keeps warm if `keepWarm`). A server is connected only when one of its\n * tools is actually invoked via `McpCall` (memoized per turn; reused from the warm pool if enabled).\n *\n * Per-turn cost: a turn using NO MCP tool → 0 connections; a turn using one → exactly one. Latency\n * scales with tools-used, not servers-configured. Returns `connect`/`close` for explicit control.\n */\nexport async function mountMcpCatalog(\n servers: Record<string, McpServerConfig> = {},\n opts: McpCatalogOptions = {},\n): Promise<{ tools: AgentTool[]; serverNames: string[]; toolCount: number; connect(name: string): Promise<McpClient>; close(): Promise<void> }> {\n const catalog = opts.catalog ?? defaultCatalog;\n const pool = opts.pool ?? defaultPool;\n\n const discovered = (await Promise.all(validEntries(servers).map(async ([name, cfg]) => {\n const key = mcpConfigKey(cfg);\n const cached = catalog.get(key);\n if (cached) return { name, cfg, key, specs: cached }; // catalog hit → no connection\n const client = new McpClient(buildTransport(cfg));\n try {\n const specs = await withTimeout((async () => { await client.connect(); return client.listTools(); })(), opts.mountTimeoutMs, name);\n catalog.set(key, specs);\n if (opts.keepWarm && !cfg.url) pool.put(key, client); // reuse this connection for the lazy-call phase\n else await client.close().catch(() => {});\n return { name, cfg, key, specs };\n } catch (e: any) {\n await client.close().catch(() => {});\n logMountFailure(name, e);\n return null;\n }\n }))).filter(Boolean) as Array<{ name: string; cfg: McpServerConfig; key: string; specs: McpToolSpec[] }>;\n\n const byName = new Map(discovered.map((d) => [d.name, d]));\n const inflight = new Map<string, Promise<McpClient>>(); // memoize per server → concurrent calls share one connect\n const live: McpClient[] = []; // non-warm clients opened this turn (closed on close())\n\n const connect = (name: string): Promise<McpClient> => {\n let p = inflight.get(name);\n if (p) return p;\n p = (async () => {\n const d = byName.get(name);\n if (!d) throw new Error(`MCP server '${name}' is not in the catalog`);\n const warmable = opts.keepWarm && !d.cfg.url;\n if (warmable) { const w = pool.get(d.key); if (w) return w; }\n const client = new McpClient(buildTransport(d.cfg));\n await client.connect();\n if (warmable) pool.put(d.key, client); else live.push(client);\n return client;\n })();\n inflight.set(name, p);\n return p;\n };\n\n const search = makeLazyMcpToolSearch(\n discovered.map((d) => ({ name: d.name, specs: d.specs })),\n async (server, rawName, args) => (await connect(server)).callTool(rawName, args),\n opts,\n );\n const close = async (): Promise<void> => { for (const c of live) await c.close().catch(() => {}); live.length = 0; inflight.clear(); };\n return { ...search, connect, close };\n}\n","// Import the log module directly from libx.js source: libx.js's main bundle\n// doesn't re-export `log` as a named ESM export, and source-importing keeps\n// libx.js patches live (no rebuild) — matching the `bun link` workflow.\nimport { log } from 'libx.js/src/modules/log';\n\n/** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */\nexport const forComponent = (name: string) => log.forComponent(name);\nexport { log };\n","/**\n * Lexical relevance — no deps, deterministic, edge-safe. Ranks catalog entries (skills,\n * commands, memories, docs) by a task hint so a LARGE catalog doesn't dump every entry into\n * the prompt. TF-IDF weighted: rare terms in the corpus score higher than common ones.\n */\n\nconst STOP = new Set([\n 'the', 'and', 'for', 'with', 'that', 'this', 'from', 'into', 'your', 'you', 'are', 'was', 'will',\n 'use', 'using', 'run', 'add', 'fix', 'make', 'file', 'files', 'code', 'please', 'need', 'want', 'should', 'all',\n]);\n\n/** Lowercased alphanumeric tokens of length ≥ 3, minus a few stopwords. */\nexport function tokenize(s: string): Set<string> {\n const out = new Set<string>();\n for (const w of String(s ?? '').toLowerCase().match(/[a-z0-9]+/g) ?? []) {\n if (w.length >= 3 && !STOP.has(w)) out.add(w);\n }\n return out;\n}\n\n/** Build IDF weights from a corpus of texts. Rare terms get higher weight. */\nexport function idfWeights(corpus: string[]): Map<string, number> {\n const N = corpus.length;\n if (N === 0) return new Map();\n const df = new Map<string, number>();\n for (const doc of corpus) for (const t of tokenize(doc)) df.set(t, (df.get(t) ?? 0) + 1);\n const idf = new Map<string, number>();\n for (const [t, n] of df) idf.set(t, Math.log((N + 1) / (n + 1)) + 1); // smooth IDF\n return idf;\n}\n\n/** TF-IDF weighted relevance score. Without IDF, falls back to flat token overlap (backward-compatible). */\nexport function relevanceScore(text: string, queryTokens: Set<string>, idf?: Map<string, number>): number {\n if (queryTokens.size === 0) return 0;\n const t = tokenize(text);\n let score = 0;\n for (const q of queryTokens) if (t.has(q)) score += idf?.get(q) ?? 1;\n return score;\n}\n\n/**\n * Split `items` into the `k` most relevant to `query` (by TF-IDF overlap with `text(item)`)\n * and the rest, preserving each item's original order within its group. Returns everything in\n * `kept` (empty `rest`) when `items.length <= k` or `query` is blank — so it's a no-op for\n * small lists. When `corpus` is provided, builds IDF weights for better ranking.\n */\nexport function topByRelevance<T>(items: T[], query: string, text: (x: T) => string, k: number, corpus?: string[]): { kept: T[]; rest: T[] } {\n if (!Number.isInteger(k) || k < 1) return { kept: items, rest: [] }; // invalid k → no-op (keep all), never hide\n if (items.length <= k || !query.trim()) return { kept: items, rest: [] };\n const q = tokenize(query);\n if (q.size === 0) return { kept: items.slice(0, k), rest: items.slice(k) };\n const idf = corpus?.length ? idfWeights(corpus) : undefined;\n const scored = items.map((x, i) => ({ i, s: relevanceScore(text(x), q, idf) }));\n scored.sort((a, b) => b.s - a.s || a.i - b.i); // best score first; stable by original index\n const keep = new Set(scored.slice(0, k).map((e) => e.i));\n return { kept: items.filter((_, i) => keep.has(i)), rest: items.filter((_, i) => !keep.has(i)) };\n}\n","import type { AgentTool } from './tools';\nimport { topByRelevance } from './relevance';\n\n/**\n * MCP bridge — adapt a Model Context Protocol tool list into the agent's AgentTool[],\n * so any MCP server's tools become first-class agent tools (edge-safe: you supply the\n * transport via `callTool`; this module has no node/network dependency of its own).\n *\n * Pass the server's advertised tools + a `callTool(name, args)` that performs the call\n * (over stdio/HTTP/whatever you wire up); each becomes an AgentTool the Agent can use.\n */\nexport interface McpToolSpec {\n name: string;\n description?: string;\n /** JSON Schema for the tool's arguments (MCP's `inputSchema`). */\n inputSchema?: object;\n}\n\n/** Perform an MCP tool call; return its textual result. Throw to surface an error to the model. */\nexport type McpCall = (name: string, args: any) => Promise<unknown>;\n\nexport interface McpImage { mimeType: string; data: string }\nexport interface McpToolResult { text: string; images?: McpImage[] }\n\n/** Normalize an MCP call result into text + optional image blocks. */\nfunction toResult(result: unknown): McpToolResult {\n if (result == null) return { text: '' };\n if (typeof result === 'string') return { text: result };\n const content = (result as any).content;\n if (Array.isArray(content)) {\n const texts: string[] = [];\n const images: McpImage[] = [];\n for (const c of content) {\n if (c?.type === 'image' && typeof c.data === 'string' && c.mimeType) {\n images.push({ mimeType: c.mimeType, data: c.data });\n } else if (typeof c?.text === 'string') {\n texts.push(c.text);\n } else {\n texts.push(JSON.stringify(c));\n }\n }\n const text = texts.join('\\n');\n if (text || images.length) return { text, ...(images.length ? { images } : {}) };\n }\n return { text: JSON.stringify(result) };\n}\n\nfunction toText(result: unknown): string { return toResult(result).text; }\n\n/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__'): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n async run(args, _ctx) {\n const r = toResult(await callTool(spec.name, args ?? {}));\n return r.images?.length ? r : r.text;\n },\n };\n}\n\n/** Adapt a whole MCP tool list into AgentTool[] (names prefixed to avoid collisions).\n * Optional `filter` pre-narrows the set at mount time (host allowlist), so a server with\n * hundreds of tools needn't mount them all eagerly. */\nexport function mcpToolsToAgentTools(specs: McpToolSpec[], callTool: McpCall, prefix = 'mcp__', filter?: (spec: McpToolSpec) => boolean): AgentTool[] {\n return (filter ? specs.filter(filter) : specs).map((s) => mcpToolToAgentTool(s, callTool, prefix));\n}\n\nexport interface McpToolSearchOptions {\n /** Prefix stripped from / shown on tool names (cosmetic; mirrors the adapter prefix). Default 'mcp__'. */\n prefix?: string;\n /** Max tools returned per `ToolSearch` query. Default 10. */\n maxResults?: number;\n}\n\n/** Render one spec for the search result: name, description, and its argument schema (so the\n * model knows how to call it via `McpCall`). */\nfunction describeSpec(s: McpToolSpec): string {\n const schema = s.inputSchema ? `\\n args: ${JSON.stringify(s.inputSchema)}` : '';\n return `${s.name} — ${s.description ?? '(no description)'}${schema}`;\n}\n\n/**\n * Deferred-mount mode (ToolSearch-equivalent) for large MCP tool sets. Instead of mounting N\n * tools into the wire schema (cost + latency + model confusion past a few dozen), mount exactly\n * TWO bounded tools regardless of N:\n * - `ToolSearch({ query })` — ranks the catalog by relevance and returns the top matches with\n * their argument schemas, so the model discovers what's available on demand.\n * - `McpCall({ name, args })` — invokes any catalog tool by name through the same transport.\n * Keep `mcpToolsToAgentTools` (eager) as the default for small sets.\n */\nexport function makeMcpToolSearch(specs: McpToolSpec[], callTool: McpCall, options: McpToolSearchOptions = {}): AgentTool[] {\n const maxResults = options.maxResults ?? 10;\n const byName = new Map(specs.map((s) => [s.name, s]));\n const catalogLine = `${specs.length} MCP tool(s) available — search by keyword, then call by exact name.`;\n\n const searchTool: AgentTool = {\n name: 'ToolSearch',\n description: `Search the available MCP tools by keyword (${catalogLine}). Returns matching tool names + their argument schemas; call one with \\`McpCall\\`.`,\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string', description: 'keywords to match against tool name + description' } } },\n async run({ query }) {\n const q = String(query ?? '').trim();\n if (!q) return catalogLine;\n const { kept } = topByRelevance(specs, q, (s) => `${s.name} ${s.description ?? ''}`, maxResults);\n if (!kept.length) return `(no MCP tool matches \"${q}\" — try broader keywords)`;\n return kept.map(describeSpec).join('\\n');\n },\n };\n\n const callMcpTool: AgentTool = {\n name: 'McpCall',\n description: 'Call an MCP tool discovered via `ToolSearch`, by its exact name. Pass its arguments as `args`.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: {\n name: { type: 'string', description: 'exact tool name from ToolSearch' },\n args: { type: 'object', description: 'arguments object for the tool (per its schema)' },\n },\n },\n async run({ name, args }) {\n const n = String(name ?? '');\n if (!byName.has(n)) return `Error: unknown MCP tool '${n}'. Use ToolSearch to find valid names.`;\n const r = toResult(await callTool(n, args ?? {}));\n return r.images?.length ? r : r.text;\n },\n };\n\n return [searchTool, callMcpTool];\n}\n\n/** Minimal shape of a mounted MCP server this module needs — structurally satisfied by\n * `MountedMcp` from `mcp.client.ts`, kept local so `mcp.ts` stays node-free/edge-safe. */\nexport interface MountedMcpLike {\n name: string;\n specs: McpToolSpec[];\n client: { callTool(name: string, args: unknown): Promise<unknown> };\n}\n\n/** A flattened catalog entry's origin: which server owns it + the un-prefixed raw tool name. */\nexport interface McpRoute { server: string; rawName: string }\n\n/** Flatten servers' specs into one `mcp__<server>__<tool>` namespace + a display→origin map.\n * Sanitizing/truncating to provider name rules can MERGE distinct names (`a/b` & `a:b` → `a_b`),\n * so dedupe with a numeric suffix — a silent overwrite would orphan a tool. */\nexport function buildMcpCatalog(servers: { name: string; specs: McpToolSpec[] }[]): { specs: McpToolSpec[]; routes: Map<string, McpRoute> } {\n const specs: McpToolSpec[] = [];\n const routes = new Map<string, McpRoute>();\n for (const m of servers) {\n for (const s of m.specs) {\n const base = `mcp__${m.name}__${s.name}`.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128);\n let display = base;\n for (let i = 2; routes.has(display); i++) display = `${base.slice(0, 128 - String(i).length - 1)}_${i}`;\n specs.push({ name: display, description: s.description, inputSchema: s.inputSchema });\n routes.set(display, { server: m.name, rawName: s.name });\n }\n }\n return { specs, routes };\n}\n\n/** Resolve a routed MCP call to its result. Throw to surface an error to the model. */\nexport type McpRouteResolver = (server: string, rawName: string, args: any) => Promise<unknown>;\n\n/** Shared core: wire the `ToolSearch`/`McpCall` pair over a prebuilt catalog, dispatching each\n * call through `resolve(server, rawName, args)` (eager → a mounted client; lazy → connect-on-call). */\nfunction searchOverCatalog(servers: string[], specs: McpToolSpec[], routes: Map<string, McpRoute>, resolve: McpRouteResolver, options?: McpToolSearchOptions) {\n const tools = specs.length\n ? makeMcpToolSearch(specs, (name, args) => {\n const r = routes.get(name);\n if (!r) throw new Error(`unknown MCP tool '${name}' — use ToolSearch to find valid names`);\n return resolve(r.server, r.rawName, args ?? {});\n }, options)\n : [];\n return { tools, serverNames: servers, toolCount: specs.length };\n}\n\n/**\n * Ergonomic deferred-mount over already-mounted MCP servers: flattens their specs into one\n * `mcp__<server>__<tool>` namespace and wires a single `ToolSearch`/`McpCall` pair that routes\n * each call to the owning server's RAW `callTool` (so result normalization happens exactly once —\n * double-normalizing corrupts image blocks).\n */\nexport function makeMcpToolSearchFromMounted(\n mounted: MountedMcpLike[],\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(mounted);\n const byName = new Map(mounted.map((m) => [m.name, m]));\n return searchOverCatalog(mounted.map((m) => m.name), specs, routes, (server, rawName, args) => byName.get(server)!.client.callTool(rawName, args), options);\n}\n\n/**\n * Lazy variant: same `ToolSearch`/`McpCall` surface, but the server isn't required to be connected.\n * Each `McpCall` resolves the owning server from the catalog and `resolve(server, rawName, args)`\n * connects-on-demand — so a turn that calls no MCP tool opens ZERO connections. Edge-safe: the\n * caller (`mountMcpCatalog` in `mcp.client.ts`) supplies the node-side connect/pool logic.\n */\nexport function makeLazyMcpToolSearch(\n servers: { name: string; specs: McpToolSpec[] }[],\n resolve: McpRouteResolver,\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(servers);\n return searchOverCatalog(servers.map((s) => s.name), specs, routes, resolve, options);\n}\n"],"mappings":"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","names":["log"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp.client.ts","../src/logging.ts","../src/relevance.ts","../src/mcp.ts"],"sourcesContent":["import { spawn, type ChildProcess } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { forComponent } from './logging';\nimport { mcpToolsToAgentTools, makeMcpToolSearchFromMounted, makeLazyMcpToolSearch, type McpToolSpec, type McpToolSearchOptions } from './mcp';\nimport type { AgentTool } from './tools';\n\nconst log = forComponent('mcp');\n\n/**\n * Real MCP (Model Context Protocol) client — node-only, deliberately kept OUT of the edge-safe\n * `src/index.ts` entry. It speaks JSON-RPC 2.0 over a transport (stdio child process or HTTP),\n * performs the `initialize` handshake + `tools/list` discovery, then hands `(specs, callTool)` to\n * the pure `src/mcp.ts` adapter — so the browser/edge build keeps working without importing this.\n */\n\nconst PROTOCOL_VERSION = '2025-06-18';\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/** A JSON-RPC 2.0 transport: request (awaits a result), notify (fire-and-forget), close. */\nexport interface McpTransport {\n start(): Promise<void>;\n request(method: string, params?: unknown): Promise<any>;\n notify(method: string, params?: unknown): Promise<void>;\n close(): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// stdio transport — newline-delimited JSON-RPC over a spawned child's stdin/stdout.\n// ---------------------------------------------------------------------------\nexport interface StdioServerSpec {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n timeoutMs?: number;\n}\n\nexport class StdioTransport implements McpTransport {\n private proc?: ChildProcess;\n private buf = '';\n private nextId = 1;\n private pending = new Map<number, { resolve: (v: any) => void; reject: (e: any) => void; timer: ReturnType<typeof setTimeout> }>();\n\n constructor(private spec: StdioServerSpec) {}\n\n async start(): Promise<void> {\n const { command, args = [], env, cwd } = this.spec;\n const proc = spawn(command, args, { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env, ...env }, cwd });\n this.proc = proc;\n proc.stdout!.setEncoding('utf8');\n proc.stdout!.on('data', (chunk: string) => this.onData(chunk));\n proc.stderr!.setEncoding('utf8');\n proc.stderr!.on('data', (chunk: string) => log.debug(`[${command}] stderr:`, chunk.trimEnd())); // server diagnostics\n proc.on('exit', (code) => this.failAll(new Error(`MCP server \"${command}\" exited (code ${code})`)));\n proc.on('error', (e) => this.failAll(e instanceof Error ? e : new Error(String(e))));\n }\n\n private onData(chunk: string): void {\n this.buf += chunk;\n let nl: number;\n while ((nl = this.buf.indexOf('\\n')) >= 0) {\n const line = this.buf.slice(0, nl).trim();\n this.buf = this.buf.slice(nl + 1);\n if (!line) continue;\n try { this.dispatch(JSON.parse(line)); }\n catch (e) { log.debug('dropping non-JSON line from MCP server:', line, e); } // never throw out of the stream handler\n }\n }\n\n private dispatch(msg: any): void {\n // We're a minimal client: only correlate responses to our requests; ignore server→client calls.\n if (msg?.id == null || !this.pending.has(msg.id)) return;\n const p = this.pending.get(msg.id)!;\n this.pending.delete(msg.id);\n clearTimeout(p.timer);\n if (msg.error) p.reject(new Error(msg.error?.message ?? JSON.stringify(msg.error)));\n else p.resolve(msg.result);\n }\n\n private failAll(e: Error): void {\n for (const p of this.pending.values()) { clearTimeout(p.timer); p.reject(e); }\n this.pending.clear();\n }\n\n private write(msg: unknown): void {\n if (!this.proc?.stdin) throw new Error('MCP stdio transport not started');\n this.proc.stdin.write(JSON.stringify(msg) + '\\n');\n }\n\n request(method: string, params?: unknown): Promise<any> {\n const id = this.nextId++;\n const timeoutMs = this.spec.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n this.pending.delete(id);\n reject(new Error(`MCP request \"${method}\" timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n this.pending.set(id, { resolve, reject, timer });\n try { this.write({ jsonrpc: '2.0', id, method, params }); }\n catch (e) { clearTimeout(timer); this.pending.delete(id); reject(e); }\n });\n }\n\n async notify(method: string, params?: unknown): Promise<void> {\n this.write({ jsonrpc: '2.0', method, params });\n }\n\n async close(): Promise<void> {\n this.failAll(new Error('MCP transport closed'));\n try { this.proc?.stdin?.end(); } catch (e) { log.debug('stdin end failed', e); }\n this.proc?.kill();\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP transport — Streamable HTTP: POST JSON-RPC, parse JSON or an SSE response.\n// ---------------------------------------------------------------------------\nexport interface HttpServerSpec {\n url: string;\n headers?: Record<string, string>;\n /** Sugar over `headers` → `Authorization: Bearer <token>`. The headless-friendly path (no OAuth loopback);\n * inject a static token (from env / VFS secret) per our CLAUDE.md rule preferring API keys for cron/edge. */\n bearerToken?: string;\n timeoutMs?: number;\n}\n\n/** Thrown when an HTTP MCP server rejects auth (401/403). Carries `needsAuth` so callers can surface a hint\n * (\"set bearerToken / headers\") instead of a generic mount failure — without attempting an interactive flow. */\nexport class McpAuthError extends Error {\n needsAuth = true;\n constructor(public status: number, public serverName?: string) {\n super(`MCP server${serverName ? ` \"${serverName}\"` : ''} requires authentication (HTTP ${status}) — set bearerToken or headers`);\n this.name = 'McpAuthError';\n }\n}\n\nexport class HttpTransport implements McpTransport {\n private nextId = 1;\n private sessionId?: string;\n private fetchImpl: typeof fetch;\n\n constructor(private spec: HttpServerSpec, fetchImpl?: typeof fetch) {\n this.fetchImpl = fetchImpl ?? fetch;\n }\n\n async start(): Promise<void> {}\n\n request(method: string, params?: unknown): Promise<any> {\n return this.post({ jsonrpc: '2.0', id: this.nextId++, method, params }, false);\n }\n\n async notify(method: string, params?: unknown): Promise<void> {\n await this.post({ jsonrpc: '2.0', method, params }, true);\n }\n\n private async post(msg: unknown, isNotify: boolean): Promise<any> {\n const headers: Record<string, string> = {\n 'content-type': 'application/json',\n accept: 'application/json, text/event-stream',\n ...(this.spec.bearerToken ? { authorization: `Bearer ${this.spec.bearerToken}` } : {}),\n ...this.spec.headers, // explicit headers win — lets a caller override the bearer sugar if needed\n ...(this.sessionId ? { 'mcp-session-id': this.sessionId } : {}),\n };\n const resp = await this.fetchImpl(this.spec.url, {\n method: 'POST', headers, body: JSON.stringify(msg),\n signal: AbortSignal.timeout(this.spec.timeoutMs ?? DEFAULT_TIMEOUT_MS),\n });\n const sid = resp.headers.get('mcp-session-id');\n if (sid) this.sessionId = sid; // adopt the server-assigned session for subsequent calls\n if (resp.status === 401 || resp.status === 403) throw new McpAuthError(resp.status);\n if (!resp.ok) throw new Error(`MCP HTTP ${resp.status} ${resp.statusText}`);\n if (isNotify) return;\n const ct = resp.headers.get('content-type') ?? '';\n const data = ct.includes('text/event-stream') ? parseSseResponse(await resp.text()) : await resp.json();\n if (data?.error) throw new Error(data.error?.message ?? JSON.stringify(data.error));\n return data?.result;\n }\n\n async close(): Promise<void> {}\n}\n\n/** Pull the JSON-RPC response object out of an SSE body (the first `data:` payload that carries one). */\nfunction parseSseResponse(body: string): any {\n for (const line of body.split('\\n')) {\n const trimmed = line.trimStart();\n if (!trimmed.startsWith('data:')) continue;\n try {\n const obj = JSON.parse(trimmed.slice(5).trim());\n if (obj && (obj.result !== undefined || obj.error !== undefined)) return obj;\n } catch (e) { log.debug('skipping unparseable SSE data line', e); }\n }\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Client — handshake + discovery on top of a transport.\n// ---------------------------------------------------------------------------\nexport class McpClient {\n constructor(public transport: McpTransport, private clientInfo = { name: 'agent.libx.js', version: '0' }) {}\n\n /** `initialize` handshake → `notifications/initialized`. Returns the server's init result. */\n async connect(): Promise<{ serverInfo?: { name?: string; version?: string }; capabilities?: any }> {\n await this.transport.start();\n const result = await this.transport.request('initialize', {\n protocolVersion: PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: this.clientInfo,\n });\n await this.transport.notify('notifications/initialized');\n return result ?? {};\n }\n\n async listTools(): Promise<McpToolSpec[]> {\n const r = await this.transport.request('tools/list');\n return Array.isArray(r?.tools) ? r.tools : [];\n }\n\n async callTool(name: string, args: unknown): Promise<unknown> {\n return this.transport.request('tools/call', { name, arguments: args ?? {} });\n }\n\n async listResources(): Promise<Array<{ uri: string; name?: string; mimeType?: string }>> {\n const r = await this.transport.request('resources/list');\n return Array.isArray(r?.resources) ? r.resources : [];\n }\n\n async readResource(uri: string): Promise<any> {\n return this.transport.request('resources/read', { uri });\n }\n\n async close(): Promise<void> {\n await this.transport.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Config-driven mounting — Claude-style `mcpServers: { name: {...} }`.\n// ---------------------------------------------------------------------------\n/** One server: stdio (`command`+`args`+`env`) OR http (`url`+`headers`). `disabled` skips it. */\nexport interface McpServerConfig {\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n url?: string;\n headers?: Record<string, string>;\n /** `Authorization: Bearer <token>` sugar for http servers (headless-friendly; no OAuth flow). */\n bearerToken?: string;\n /** Auth strategy for http servers. `'oauth'` → the CLI resolves a token via the attended OAuth flow\n * (cli/mcpOAuth.ts) and injects it as `bearerToken` at mount; the core never runs the flow. Default none. */\n auth?: 'oauth' | 'none';\n timeoutMs?: number;\n disabled?: boolean;\n}\n\nexport interface MountedMcp {\n name: string;\n client: McpClient;\n tools: AgentTool[];\n /** Raw tool specs discovered at mount (already fetched internally) — exposed so deferred-mount\n * glue (`makeMcpToolSearchFromMounted`) needn't re-call `tools/list`. */\n specs: McpToolSpec[];\n serverInfo?: { name?: string; version?: string };\n}\n\n/** Build the transport for a server config (http when `url`, else stdio). Shared by every mount path. */\nfunction buildTransport(cfg: McpServerConfig): McpTransport {\n return cfg.url\n ? new HttpTransport({ url: cfg.url, headers: cfg.headers, bearerToken: cfg.bearerToken, timeoutMs: cfg.timeoutMs })\n : new StdioTransport({ command: cfg.command!, args: cfg.args, env: cfg.env, cwd: cfg.cwd, timeoutMs: cfg.timeoutMs });\n}\n\n/** Race `p` against `ms` (a per-server mount deadline). `ms` falsy/≤0 → no deadline. The caller\n * closes the half-open client on rejection so a hung server leaks nothing. */\nfunction withTimeout<T>(p: Promise<T>, ms: number | undefined, label: string): Promise<T> {\n if (!ms || ms <= 0) return p;\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`MCP \"${label}\" mount exceeded ${ms}ms`)), ms);\n (timer as any).unref?.();\n p.then((v) => { clearTimeout(timer); resolve(v); }, (e) => { clearTimeout(timer); reject(e); });\n });\n}\n\n/** Connect + discover + adapt, with optional per-server deadline; closes the client if it fails. */\nasync function mountWithDeadline(name: string, cfg: McpServerConfig, mountTimeoutMs?: number): Promise<MountedMcp> {\n const client = new McpClient(buildTransport(cfg));\n try {\n return await withTimeout((async () => {\n const init = await client.connect();\n const specs = await client.listTools();\n const tools = mcpToolsToAgentTools(specs, (tool, a) => client.callTool(tool, a), `mcp__${name}__`);\n return { name, client, tools, specs, serverInfo: init?.serverInfo } as MountedMcp;\n })(), mountTimeoutMs, name);\n } catch (e) {\n await client.close().catch((err) => log.debug(`close after failed mount of \"${name}\": ${err}`));\n throw e;\n }\n}\n\n/** Connect one server, discover its tools, and adapt them to prefixed AgentTools (`mcp__<name>__`). */\nexport function mountMcpServer(name: string, cfg: McpServerConfig): Promise<MountedMcp> {\n return mountWithDeadline(name, cfg);\n}\n\n/** Drop disabled/incomplete entries, warning on the incomplete ones. */\nfunction validEntries(servers: Record<string, McpServerConfig>): Array<[string, McpServerConfig]> {\n return Object.entries(servers).filter(([name, cfg]) => {\n if (!cfg || cfg.disabled) return false;\n if (!cfg.command && !cfg.url) { log.warn(`MCP server \"${name}\" needs a command (stdio) or url (http) — skipping`); return false; }\n return true;\n });\n}\n\n/** Log a mount failure (auth vs generic) without throwing — one broken server never blocks startup. */\nfunction logMountFailure(name: string, e: any): void {\n if (e instanceof McpAuthError) log.warn(`MCP \"${name}\" needs-auth: HTTP ${e.status} — set bearerToken or headers in its config; skipping`);\n else log.error(`MCP server \"${name}\" failed to mount: ${e?.message ?? e}`); // logged, then skipped\n}\n\n/**\n * Mount every configured server in PARALLEL (one slow/dead server no longer serializes the rest);\n * each may carry a `mountTimeoutMs` deadline. A server that fails is logged and skipped.\n */\nexport async function mountMcpServers(servers: Record<string, McpServerConfig> = {}, opts: { mountTimeoutMs?: number } = {}): Promise<MountedMcp[]> {\n const entries = validEntries(servers);\n const settled = await Promise.allSettled(entries.map(([name, cfg]) => mountWithDeadline(name, cfg, opts.mountTimeoutMs)));\n const out: MountedMcp[] = [];\n settled.forEach((r, i) => {\n const name = entries[i][0];\n if (r.status === 'fulfilled') { out.push(r.value); log.info(`MCP \"${name}\" mounted — ${r.value.tools.length} tool(s)${r.value.serverInfo?.name ? ` from ${r.value.serverInfo.name}` : ''}`); }\n else logMountFailure(name, r.reason);\n });\n return out;\n}\n\n/**\n * One-shot deferred MCP mount: connect every entry (failures dropped, never block startup) and\n * fold the survivors into a single `ToolSearch`/`McpCall` pair via `makeMcpToolSearchFromMounted`.\n * The node-only counterpart to that edge-safe helper — returns `mounted` too so callers can close\n * the clients on shutdown. Eager: it connects all servers up front. For lazy connect + a cached\n * catalog (zero connections on a turn that uses no MCP tool), use `mountMcpCatalog`.\n */\nexport async function mountMcpDeferred(\n servers: Record<string, McpServerConfig> = {},\n options?: McpToolSearchOptions & { mountTimeoutMs?: number },\n): Promise<{ tools: AgentTool[]; serverNames: string[]; toolCount: number; mounted: MountedMcp[] }> {\n const mounted = await mountMcpServers(servers, { mountTimeoutMs: options?.mountTimeoutMs });\n return { ...makeMcpToolSearchFromMounted(mounted, options), mounted };\n}\n\n// ---------------------------------------------------------------------------\n// Lazy connect + catalog cache — defer the CONNECTION, not just the schemas.\n// ---------------------------------------------------------------------------\n/** A persistent tool catalog: lets `mountMcpCatalog` build `ToolSearch` WITHOUT connecting when a\n * fresh entry exists. The lib defines the interface; the consumer supplies the store (RAM/disk).\n * Key = a hash of the server's resolved config (see `mcpConfigKey`). TTL/versioning is the store's. */\nexport interface McpCatalogStore {\n get(key: string): McpToolSpec[] | null;\n set(key: string, specs: McpToolSpec[]): void;\n}\n\n/** Stable cache key for a server config — command/args/cwd + env NAMES (not secret values), or\n * url + header names. Changing any of these invalidates the cached catalog; rotating a secret does not. */\nexport function mcpConfigKey(cfg: McpServerConfig): string {\n const parts = cfg.url\n ? ['http', cfg.url, ...Object.keys(cfg.headers ?? {}).sort()]\n : ['stdio', cfg.command ?? '', ...(cfg.args ?? []), cfg.cwd ?? '', ...Object.keys(cfg.env ?? {}).sort()];\n return createHash('sha256').update(parts.join('\\0')).digest('hex').slice(0, 16);\n}\n\n/** Default in-memory catalog: process-lifetime, hash-keyed, TTL-expiring (so a server that gains\n * tools is picked up after the TTL without a restart). Shared module singleton → cross-turn reuse. */\nexport class MemMcpCatalog implements McpCatalogStore {\n private m = new Map<string, { specs: McpToolSpec[]; exp: number }>();\n constructor(private ttlMs = 5 * 60_000) {}\n get(key: string): McpToolSpec[] | null {\n const e = this.m.get(key);\n if (!e) return null;\n if (Date.now() > e.exp) { this.m.delete(key); return null; }\n return e.specs;\n }\n set(key: string, specs: McpToolSpec[]): void { this.m.set(key, { specs, exp: Date.now() + this.ttlMs }); }\n}\n\n/** Opt-in warm pool: keeps stdio MCP clients connected across turns, reaping each after `ttlMs`\n * idle. Most stdio MCPs are per-turn by design, so this is off by default; HTTP servers are\n * stateless and never pooled. */\nexport class McpPool {\n private warm = new Map<string, { client: McpClient; timer: ReturnType<typeof setTimeout> }>();\n constructor(private ttlMs = 5 * 60_000) {}\n get(key: string): McpClient | null { const e = this.warm.get(key); if (!e) return null; this.arm(key, e); return e.client; }\n put(key: string, client: McpClient): void {\n const prev = this.warm.get(key); // overwrite: cancel the stale timer + close the displaced client\n if (prev) { clearTimeout(prev.timer); if (prev.client !== client) void prev.client.close().catch((err) => log.debug(`warm-pool replace close failed: ${err}`)); }\n const e = { client, timer: undefined as any };\n this.warm.set(key, e); this.arm(key, e);\n }\n private arm(key: string, e: { client: McpClient; timer: any }): void {\n clearTimeout(e.timer);\n e.timer = setTimeout(() => { void this.evict(key); }, this.ttlMs);\n (e.timer as any).unref?.();\n }\n private async evict(key: string): Promise<void> {\n const e = this.warm.get(key); if (!e) return;\n this.warm.delete(key);\n await e.client.close().catch((err) => log.debug(`warm-pool evict close failed: ${err}`));\n }\n async closeAll(): Promise<void> { for (const e of this.warm.values()) { clearTimeout(e.timer); await e.client.close().catch(() => {}); } this.warm.clear(); }\n}\n\nconst defaultCatalog = new MemMcpCatalog();\nconst defaultPool = new McpPool();\nconst defaultFailures = new Map<string, number>(); // configKey → cooldown-until epoch ms (negative cache)\nconst bgInflight = new Set<string>(); // configKey → background discovery in flight (dedupe)\nconst DEFAULT_FAILURE_COOLDOWN_MS = 60_000;\n\nexport interface McpCatalogOptions extends McpToolSearchOptions {\n /** Where to read/write discovered specs. Default: a shared process-lifetime `MemMcpCatalog`. */\n catalog?: McpCatalogStore;\n /** Per-server deadline for the connect+list on a cache MISS. A hung server is skipped, not blocking. */\n mountTimeoutMs?: number;\n /** Opt-in: keep stdio clients warm across turns (see `McpPool`). HTTP servers are never pooled. */\n keepWarm?: boolean;\n /** Warm-client pool. Default: a shared process-lifetime `McpPool` (only used when `keepWarm`). */\n pool?: McpPool;\n /** Negative cache: after a server fails/times out discovery, skip it for this long so it never\n * re-floors a turn at the deadline. Default 60s; the server is re-probed once the cooldown lapses. */\n failureCooldownMs?: number;\n /** Shared failure-cooldown map (configKey → until-epoch-ms). Default: a process-lifetime singleton. */\n failures?: Map<string, number>;\n /** Discovery policy on a cache MISS:\n * - `'connect'` (default): synchronously connect+list (deadline-bounded) — blocks until ready.\n * - `'cache-only'`: NEVER block the turn — serve only cached servers, and kick uncached discovery\n * to the background (so it's warm next turn). Pair with a boot/timer `warmMcpCatalog` so the\n * first turn is already a cache hit. */\n discover?: 'connect' | 'cache-only';\n}\n\ninterface Discovered { name: string; cfg: McpServerConfig; key: string; specs: McpToolSpec[] }\n\n/** Connect+list one server (deadline-bounded), populate the catalog on success / negative-cache on\n * failure. Closes the client unless `keepWarm` keeps it for the lazy-call phase. */\nasync function connectAndList(name: string, cfg: McpServerConfig, key: string, opts: McpCatalogOptions): Promise<Discovered | null> {\n const catalog = opts.catalog ?? defaultCatalog;\n const pool = opts.pool ?? defaultPool;\n const failures = opts.failures ?? defaultFailures;\n const client = new McpClient(buildTransport(cfg));\n try {\n const specs = await withTimeout((async () => { await client.connect(); return client.listTools(); })(), opts.mountTimeoutMs, name);\n catalog.set(key, specs);\n failures.delete(key); // recovered\n if (opts.keepWarm && !cfg.url) pool.put(key, client); // reuse this connection for the lazy-call phase\n else await client.close().catch(() => {});\n return { name, cfg, key, specs };\n } catch (e: any) {\n await client.close().catch(() => {});\n failures.set(key, Date.now() + (opts.failureCooldownMs ?? DEFAULT_FAILURE_COOLDOWN_MS));\n logMountFailure(name, e);\n return null;\n }\n}\n\n/** Resolve one server to its specs: cache hit → no connection; in failure-cooldown → skip;\n * otherwise connect (or, in `cache-only` mode, kick background discovery and skip for now). */\nasync function discoverOne(name: string, cfg: McpServerConfig, opts: McpCatalogOptions): Promise<Discovered | null> {\n const catalog = opts.catalog ?? defaultCatalog;\n const failures = opts.failures ?? defaultFailures;\n const key = mcpConfigKey(cfg);\n const cached = catalog.get(key);\n if (cached) return { name, cfg, key, specs: cached };\n const until = failures.get(key);\n if (until && until > Date.now()) return null; // negative cache → known-down, skip\n if (opts.discover === 'cache-only') {\n if (!bgInflight.has(key)) { bgInflight.add(key); void connectAndList(name, cfg, key, opts).finally(() => bgInflight.delete(key)); }\n return null; // not available THIS turn; warms for the next one\n }\n return connectAndList(name, cfg, key, opts);\n}\n\n/**\n * Lazy + cached MCP mount. Builds the `ToolSearch`/`McpCall` pair from the CACHED catalog when one\n * exists — connecting NOTHING. On a cache miss it (by default) connects once (parallel, deadline-\n * bounded), lists, caches, then disconnects (or keeps warm if `keepWarm`). A server is connected only\n * when one of its tools is actually invoked via `McpCall` (memoized per turn; reused from the warm\n * pool if enabled). A server that fails/times out is negative-cached (`failureCooldownMs`) so it\n * never re-floors a later turn.\n *\n * For zero turn-path latency even on a cold process, set `discover: 'cache-only'` and call\n * `warmMcpCatalog` at boot + on a timer: the turn then NEVER synchronously connects — it serves\n * cached servers and warms the rest in the background.\n *\n * Per-turn cost: a turn using NO MCP tool → 0 connections; a turn using one → exactly one.\n */\nexport async function mountMcpCatalog(\n servers: Record<string, McpServerConfig> = {},\n opts: McpCatalogOptions = {},\n): Promise<{ tools: AgentTool[]; serverNames: string[]; toolCount: number; connect(name: string): Promise<McpClient>; close(): Promise<void> }> {\n const pool = opts.pool ?? defaultPool;\n const discovered = (await Promise.all(validEntries(servers).map(([name, cfg]) => discoverOne(name, cfg, opts)))).filter(Boolean) as Discovered[];\n\n const byName = new Map(discovered.map((d) => [d.name, d]));\n const inflight = new Map<string, Promise<McpClient>>(); // memoize per server → concurrent calls share one connect\n const live: McpClient[] = []; // non-warm clients opened this turn (closed on close())\n\n const connect = (name: string): Promise<McpClient> => {\n let p = inflight.get(name);\n if (p) return p;\n p = (async () => {\n const d = byName.get(name);\n if (!d) throw new Error(`MCP server '${name}' is not in the catalog`);\n const warmable = opts.keepWarm && !d.cfg.url;\n if (warmable) { const w = pool.get(d.key); if (w) return w; }\n const client = new McpClient(buildTransport(d.cfg));\n await client.connect();\n if (warmable) pool.put(d.key, client); else live.push(client);\n return client;\n })();\n inflight.set(name, p);\n return p;\n };\n\n const search = makeLazyMcpToolSearch(\n discovered.map((d) => ({ name: d.name, specs: d.specs })),\n async (server, rawName, args) => (await connect(server)).callTool(rawName, args),\n opts,\n );\n const close = async (): Promise<void> => { for (const c of live) await c.close().catch(() => {}); live.length = 0; inflight.clear(); };\n return { ...search, connect, close };\n}\n\n/**\n * Off-turn catalog warm-up: do the one cold discovery pass (connect + list, parallel, deadline-\n * bounded) so a later `mountMcpCatalog(..., { discover: 'cache-only' })` is a cache HIT. Call at\n * server boot and on a timer (cadence < the catalog TTL). Cache hits cost nothing; down servers are\n * negative-cached so turns never touch them. Returns which servers warmed vs failed.\n */\nexport async function warmMcpCatalog(\n servers: Record<string, McpServerConfig> = {},\n opts: McpCatalogOptions = {},\n): Promise<{ warmed: string[]; failed: string[]; toolCount: number }> {\n const entries = validEntries(servers);\n const discovered = (await Promise.all(entries.map(([name, cfg]) => discoverOne(name, cfg, { ...opts, discover: 'connect' })))).filter(Boolean) as Discovered[];\n const warmedNames = new Set(discovered.map((d) => d.name));\n return {\n warmed: discovered.map((d) => d.name),\n failed: entries.map(([n]) => n).filter((n) => !warmedNames.has(n)),\n toolCount: discovered.reduce((s, d) => s + d.specs.length, 0),\n };\n}\n","// Import the log module directly from libx.js source: libx.js's main bundle\n// doesn't re-export `log` as a named ESM export, and source-importing keeps\n// libx.js patches live (no rebuild) — matching the `bun link` workflow.\nimport { log } from 'libx.js/src/modules/log';\n\n/** Component-scoped logger (libx.js). debug/verbose gated via DEBUG env/localStorage. */\nexport const forComponent = (name: string) => log.forComponent(name);\nexport { log };\n","/**\n * Lexical relevance — no deps, deterministic, edge-safe. Ranks catalog entries (skills,\n * commands, memories, docs) by a task hint so a LARGE catalog doesn't dump every entry into\n * the prompt. TF-IDF weighted: rare terms in the corpus score higher than common ones.\n */\n\nconst STOP = new Set([\n 'the', 'and', 'for', 'with', 'that', 'this', 'from', 'into', 'your', 'you', 'are', 'was', 'will',\n 'use', 'using', 'run', 'add', 'fix', 'make', 'file', 'files', 'code', 'please', 'need', 'want', 'should', 'all',\n]);\n\n/** Lowercased alphanumeric tokens of length ≥ 3, minus a few stopwords. */\nexport function tokenize(s: string): Set<string> {\n const out = new Set<string>();\n for (const w of String(s ?? '').toLowerCase().match(/[a-z0-9]+/g) ?? []) {\n if (w.length >= 3 && !STOP.has(w)) out.add(w);\n }\n return out;\n}\n\n/** Build IDF weights from a corpus of texts. Rare terms get higher weight. */\nexport function idfWeights(corpus: string[]): Map<string, number> {\n const N = corpus.length;\n if (N === 0) return new Map();\n const df = new Map<string, number>();\n for (const doc of corpus) for (const t of tokenize(doc)) df.set(t, (df.get(t) ?? 0) + 1);\n const idf = new Map<string, number>();\n for (const [t, n] of df) idf.set(t, Math.log((N + 1) / (n + 1)) + 1); // smooth IDF\n return idf;\n}\n\n/** TF-IDF weighted relevance score. Without IDF, falls back to flat token overlap (backward-compatible). */\nexport function relevanceScore(text: string, queryTokens: Set<string>, idf?: Map<string, number>): number {\n if (queryTokens.size === 0) return 0;\n const t = tokenize(text);\n let score = 0;\n for (const q of queryTokens) if (t.has(q)) score += idf?.get(q) ?? 1;\n return score;\n}\n\n/**\n * Split `items` into the `k` most relevant to `query` (by TF-IDF overlap with `text(item)`)\n * and the rest, preserving each item's original order within its group. Returns everything in\n * `kept` (empty `rest`) when `items.length <= k` or `query` is blank — so it's a no-op for\n * small lists. When `corpus` is provided, builds IDF weights for better ranking.\n */\nexport function topByRelevance<T>(items: T[], query: string, text: (x: T) => string, k: number, corpus?: string[]): { kept: T[]; rest: T[] } {\n if (!Number.isInteger(k) || k < 1) return { kept: items, rest: [] }; // invalid k → no-op (keep all), never hide\n if (items.length <= k || !query.trim()) return { kept: items, rest: [] };\n const q = tokenize(query);\n if (q.size === 0) return { kept: items.slice(0, k), rest: items.slice(k) };\n const idf = corpus?.length ? idfWeights(corpus) : undefined;\n const scored = items.map((x, i) => ({ i, s: relevanceScore(text(x), q, idf) }));\n scored.sort((a, b) => b.s - a.s || a.i - b.i); // best score first; stable by original index\n const keep = new Set(scored.slice(0, k).map((e) => e.i));\n return { kept: items.filter((_, i) => keep.has(i)), rest: items.filter((_, i) => !keep.has(i)) };\n}\n","import type { AgentTool } from './tools';\nimport { topByRelevance } from './relevance';\n\n/**\n * MCP bridge — adapt a Model Context Protocol tool list into the agent's AgentTool[],\n * so any MCP server's tools become first-class agent tools (edge-safe: you supply the\n * transport via `callTool`; this module has no node/network dependency of its own).\n *\n * Pass the server's advertised tools + a `callTool(name, args)` that performs the call\n * (over stdio/HTTP/whatever you wire up); each becomes an AgentTool the Agent can use.\n */\nexport interface McpToolSpec {\n name: string;\n description?: string;\n /** JSON Schema for the tool's arguments (MCP's `inputSchema`). */\n inputSchema?: object;\n}\n\n/** Perform an MCP tool call; return its textual result. Throw to surface an error to the model. */\nexport type McpCall = (name: string, args: any) => Promise<unknown>;\n\nexport interface McpImage { mimeType: string; data: string }\nexport interface McpToolResult { text: string; images?: McpImage[] }\n\n/** Normalize an MCP call result into text + optional image blocks. */\nfunction toResult(result: unknown): McpToolResult {\n if (result == null) return { text: '' };\n if (typeof result === 'string') return { text: result };\n const content = (result as any).content;\n if (Array.isArray(content)) {\n const texts: string[] = [];\n const images: McpImage[] = [];\n for (const c of content) {\n if (c?.type === 'image' && typeof c.data === 'string' && c.mimeType) {\n images.push({ mimeType: c.mimeType, data: c.data });\n } else if (typeof c?.text === 'string') {\n texts.push(c.text);\n } else {\n texts.push(JSON.stringify(c));\n }\n }\n const text = texts.join('\\n');\n if (text || images.length) return { text, ...(images.length ? { images } : {}) };\n }\n return { text: JSON.stringify(result) };\n}\n\nfunction toText(result: unknown): string { return toResult(result).text; }\n\n/** Adapt one MCP tool spec into an AgentTool backed by `callTool`. */\nexport function mcpToolToAgentTool(spec: McpToolSpec, callTool: McpCall, prefix = 'mcp__'): AgentTool {\n return {\n name: `${prefix}${spec.name}`,\n description: spec.description ?? `MCP tool ${spec.name}`,\n parameters: spec.inputSchema ?? { type: 'object', properties: {} },\n async run(args, _ctx) {\n const r = toResult(await callTool(spec.name, args ?? {}));\n return r.images?.length ? r : r.text;\n },\n };\n}\n\n/** Adapt a whole MCP tool list into AgentTool[] (names prefixed to avoid collisions).\n * Optional `filter` pre-narrows the set at mount time (host allowlist), so a server with\n * hundreds of tools needn't mount them all eagerly. */\nexport function mcpToolsToAgentTools(specs: McpToolSpec[], callTool: McpCall, prefix = 'mcp__', filter?: (spec: McpToolSpec) => boolean): AgentTool[] {\n return (filter ? specs.filter(filter) : specs).map((s) => mcpToolToAgentTool(s, callTool, prefix));\n}\n\nexport interface McpToolSearchOptions {\n /** Prefix stripped from / shown on tool names (cosmetic; mirrors the adapter prefix). Default 'mcp__'. */\n prefix?: string;\n /** Max tools returned per `ToolSearch` query. Default 10. */\n maxResults?: number;\n}\n\n/** Render one spec for the search result: name, description, and its argument schema (so the\n * model knows how to call it via `McpCall`). */\nfunction describeSpec(s: McpToolSpec): string {\n const schema = s.inputSchema ? `\\n args: ${JSON.stringify(s.inputSchema)}` : '';\n return `${s.name} — ${s.description ?? '(no description)'}${schema}`;\n}\n\n/**\n * Deferred-mount mode (ToolSearch-equivalent) for large MCP tool sets. Instead of mounting N\n * tools into the wire schema (cost + latency + model confusion past a few dozen), mount exactly\n * TWO bounded tools regardless of N:\n * - `ToolSearch({ query })` — ranks the catalog by relevance and returns the top matches with\n * their argument schemas, so the model discovers what's available on demand.\n * - `McpCall({ name, args })` — invokes any catalog tool by name through the same transport.\n * Keep `mcpToolsToAgentTools` (eager) as the default for small sets.\n */\nexport function makeMcpToolSearch(specs: McpToolSpec[], callTool: McpCall, options: McpToolSearchOptions = {}): AgentTool[] {\n const maxResults = options.maxResults ?? 10;\n const byName = new Map(specs.map((s) => [s.name, s]));\n const catalogLine = `${specs.length} MCP tool(s) available — search by keyword, then call by exact name.`;\n\n const searchTool: AgentTool = {\n name: 'ToolSearch',\n description: `Search the available MCP tools by keyword (${catalogLine}). Returns matching tool names + their argument schemas; call one with \\`McpCall\\`.`,\n parameters: { type: 'object', required: ['query'], properties: { query: { type: 'string', description: 'keywords to match against tool name + description' } } },\n async run({ query }) {\n const q = String(query ?? '').trim();\n if (!q) return catalogLine;\n const { kept } = topByRelevance(specs, q, (s) => `${s.name} ${s.description ?? ''}`, maxResults);\n if (!kept.length) return `(no MCP tool matches \"${q}\" — try broader keywords)`;\n return kept.map(describeSpec).join('\\n');\n },\n };\n\n const callMcpTool: AgentTool = {\n name: 'McpCall',\n description: 'Call an MCP tool discovered via `ToolSearch`, by its exact name. Pass its arguments as `args`.',\n parameters: {\n type: 'object',\n required: ['name'],\n properties: {\n name: { type: 'string', description: 'exact tool name from ToolSearch' },\n args: { type: 'object', description: 'arguments object for the tool (per its schema)' },\n },\n },\n async run({ name, args }) {\n const n = String(name ?? '');\n if (!byName.has(n)) return `Error: unknown MCP tool '${n}'. Use ToolSearch to find valid names.`;\n const r = toResult(await callTool(n, args ?? {}));\n return r.images?.length ? r : r.text;\n },\n };\n\n return [searchTool, callMcpTool];\n}\n\n/** Minimal shape of a mounted MCP server this module needs — structurally satisfied by\n * `MountedMcp` from `mcp.client.ts`, kept local so `mcp.ts` stays node-free/edge-safe. */\nexport interface MountedMcpLike {\n name: string;\n specs: McpToolSpec[];\n client: { callTool(name: string, args: unknown): Promise<unknown> };\n}\n\n/** A flattened catalog entry's origin: which server owns it + the un-prefixed raw tool name. */\nexport interface McpRoute { server: string; rawName: string }\n\n/** Flatten servers' specs into one `mcp__<server>__<tool>` namespace + a display→origin map.\n * Sanitizing/truncating to provider name rules can MERGE distinct names (`a/b` & `a:b` → `a_b`),\n * so dedupe with a numeric suffix — a silent overwrite would orphan a tool. */\nexport function buildMcpCatalog(servers: { name: string; specs: McpToolSpec[] }[]): { specs: McpToolSpec[]; routes: Map<string, McpRoute> } {\n const specs: McpToolSpec[] = [];\n const routes = new Map<string, McpRoute>();\n for (const m of servers) {\n for (const s of m.specs) {\n const base = `mcp__${m.name}__${s.name}`.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 128);\n let display = base;\n for (let i = 2; routes.has(display); i++) display = `${base.slice(0, 128 - String(i).length - 1)}_${i}`;\n specs.push({ name: display, description: s.description, inputSchema: s.inputSchema });\n routes.set(display, { server: m.name, rawName: s.name });\n }\n }\n return { specs, routes };\n}\n\n/** Resolve a routed MCP call to its result. Throw to surface an error to the model. */\nexport type McpRouteResolver = (server: string, rawName: string, args: any) => Promise<unknown>;\n\n/** Shared core: wire the `ToolSearch`/`McpCall` pair over a prebuilt catalog, dispatching each\n * call through `resolve(server, rawName, args)` (eager → a mounted client; lazy → connect-on-call). */\nfunction searchOverCatalog(servers: string[], specs: McpToolSpec[], routes: Map<string, McpRoute>, resolve: McpRouteResolver, options?: McpToolSearchOptions) {\n const tools = specs.length\n ? makeMcpToolSearch(specs, (name, args) => {\n const r = routes.get(name);\n if (!r) throw new Error(`unknown MCP tool '${name}' — use ToolSearch to find valid names`);\n return resolve(r.server, r.rawName, args ?? {});\n }, options)\n : [];\n return { tools, serverNames: servers, toolCount: specs.length };\n}\n\n/**\n * Ergonomic deferred-mount over already-mounted MCP servers: flattens their specs into one\n * `mcp__<server>__<tool>` namespace and wires a single `ToolSearch`/`McpCall` pair that routes\n * each call to the owning server's RAW `callTool` (so result normalization happens exactly once —\n * double-normalizing corrupts image blocks).\n */\nexport function makeMcpToolSearchFromMounted(\n mounted: MountedMcpLike[],\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(mounted);\n const byName = new Map(mounted.map((m) => [m.name, m]));\n return searchOverCatalog(mounted.map((m) => m.name), specs, routes, (server, rawName, args) => byName.get(server)!.client.callTool(rawName, args), options);\n}\n\n/**\n * Lazy variant: same `ToolSearch`/`McpCall` surface, but the server isn't required to be connected.\n * Each `McpCall` resolves the owning server from the catalog and `resolve(server, rawName, args)`\n * connects-on-demand — so a turn that calls no MCP tool opens ZERO connections. Edge-safe: the\n * caller (`mountMcpCatalog` in `mcp.client.ts`) supplies the node-side connect/pool logic.\n */\nexport function makeLazyMcpToolSearch(\n servers: { name: string; specs: McpToolSpec[] }[],\n resolve: McpRouteResolver,\n options?: McpToolSearchOptions,\n): { tools: AgentTool[]; serverNames: string[]; toolCount: number } {\n const { specs, routes } = buildMcpCatalog(servers);\n return searchOverCatalog(servers.map((s) => s.name), specs, routes, resolve, options);\n}\n"],"mappings":"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","names":["log"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent.libx.js",
|
|
3
|
-
"version": "0.93.
|
|
3
|
+
"version": "0.93.23",
|
|
4
4
|
"description": "Edge-native AI agent runtime — drives a virtual filesystem via any LLM (ai.libx.js). Same bytes run in node, browser, or edge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|