/** * SDK-side MCP tool projection. * * `projectMcpTools` resolves a consumer's `mcpTools` selector against the * live {@link McpClientPool} catalog and produces the concrete * `FunctionToolDef[]` shipped to QAR via `AgentSpec.tools`. The function is * the SDK's single point of responsibility for the MCP-projection contract: * * - **Shape A** (`readonly string[]`) — entries are either MCP names * (whole-server inclusion) or `.` dotted references * (specific tool). * - **Shape B** (`{ allowlist?, blocklist? }`) — set difference, * same dotted-name resolution as Shape A. * - **Shape C** (`(tool: DiscoveredMcpTool) => boolean`) — dynamic * filter receiving every discovered tool across every registered MCP. * * Each match becomes a `FunctionToolDef` carrying the upstream MCP's * `inputSchema` + `description` + (new) `annotations`. Tool names are * auto-prefixed `.` when the per-MCP `prefixToolNames` policy * is on (default); off when the consumer explicitly opted out at * `registerMcp` time. Consumer-shipped `tools[]` entries are merged on * top — consumer-shipped wins on name collision; consumer-shipped tools * escape prefixing because the consumer wrote the name. * * Diagnostics surface drift between consumer code and the live MCP * surface as three buckets: * * - `unknownMcps` — allowlist entries naming an MCP not in the pool. * - `unknownMcpTools` — dotted-name allowlist / override entries whose * suffix doesn't match a discovered tool. * - `unreachableMcps` — registered MCPs that the selector explicitly * *referenced* AND whose catalog is absent (cold start hasn't * populated). Note the **referenced** scope: an unreachable MCP that * this agent doesn't depend on is silently omitted, NOT flagged. * Reference scope: * - Shape A (string[]) — bare names + the MCP part of dotted entries. * - Shape B allowlist — bare names + dotted MCP parts. Blocklist * entries do NOT add references (the consumer is trying to * exclude something; if it's already absent, intent is fulfilled). * - Shape B blocklist-only (no allowlist) — no references; full * reachable surface minus blocks. * - Shape C callback — no references; the consumer accepts whatever * the live catalog provides. * The caller chooses what to do with each diagnostic per the * registered `unavailability` policy. * * Ordering for prompt-cache stability (D17-9): consumer-shipped first * (in original insertion order), then projected tools sorted * lexicographically by `.`. Stable across runs so Anthropic's * prompt-cache prefix matching keeps hitting. * * The function is pure — same inputs, same outputs — so tests can drive * it directly without a live pool. Callers await * `pool.waitForCatalogsToSettle()` BEFORE invoking projection so a * still-loading MCP doesn't read as unreachable. */ import type { FunctionToolDef, McpToolOverrides, McpToolsSelector } from '../../qar/specs.js'; import type { McpClientPool } from './McpClientPool.js'; /** * Input to {@link projectMcpTools}. Consumer-facing fields lifted off the * `InlineAgentSpec` at the wire boundary. */ export interface ProjectionInput { /** The `mcpTools` selector — Shape A / B / C, or `undefined` to skip discovery. */ readonly mcpTools?: McpToolsSelector; /** Consumer-shipped `tools[]` — preserved verbatim (consumer wins on name match). */ readonly consumerTools?: readonly FunctionToolDef[] | null; /** Per-tool description overlay — applied AFTER projection. */ readonly mcpToolOverrides?: McpToolOverrides; } /** * Result of {@link projectMcpTools}. `tools` is the merged + ordered * surface (consumer-shipped first, projected sorted lex); `diagnostics` * captures drift the caller may want to raise as typed errors. */ export interface ProjectionResult { readonly tools: readonly FunctionToolDef[]; readonly diagnostics: { readonly unknownMcps: readonly string[]; readonly unknownMcpTools: readonly string[]; readonly unreachableMcps: readonly string[]; }; } /** * Resolve the MCP selector against the pool and produce the concrete * `FunctionToolDef[]` for the wire envelope. See module docblock for the * contract. * * @param input Consumer-side selector + tools[] + overrides. * @param pool Live `McpClientPool` (sync-snapshot accessor; the * caller is responsible for awaiting * `waitForCatalogsToSettle()` first). * @param prefixPolicy Per-MCP prefix-on policy. Default `true` when the * map is missing an entry — the wire fallback for * an MCP registered before the projection ergonomics * existed. * @param extraKnownMcps Additional MCP names known to the registry but * NOT present in the pool. The canonical use case * is `transport: 'sdk'` in-process MCPs whose * dispatch path bypasses the pool — they have no * `tools/list` contract, so the projection layer * doesn't auto-project tools for them; but * referencing one in `mcpTools` should NOT raise * `QodoUnknownMcpError`. Tools for those MCPs ship * via consumer `tools[]` instead. Optional; * defaults empty. */ export declare function projectMcpTools(input: ProjectionInput, pool: McpClientPool, prefixPolicy: ReadonlyMap, extraKnownMcps?: ReadonlySet): ProjectionResult; //# sourceMappingURL=projection.d.ts.map