/** * Tool dispatch — wraps each registered handler with: * * 1. Concurrency via an in-house read/write lock. The stdio transport * receives requests one-at-a-time, but the SDK does not serialize * tool calls on its own. Multiple read tools (`*_inspect`, * `environment_status`, …) run concurrently; writes are exclusive * against everything. Writer preference keeps a queued * `recipe_push` from starving behind a stream of reads. * * v1 used a single Promise-chain mutex that serialized every tool * call. The rwlock keeps the write-time correctness guarantee * (mutations don't observe each other's half-applied state) while * letting read fan-out cost what it should. * * 2. The per-call `allowWrite` gate. Write-typed tools that receive * `allowWrite !== true` short-circuit to an INPUT_INVALID envelope * before the handler runs — no side effects, no library import. * * 3. The cancellation gate. The SDK's `RequestHandlerExtra.signal` * fires `aborted` when the client sends `notifications/cancelled`. * We thread that signal through to the handler (and the handler * plumbs it into the library). When the handler returns AND * `signal.aborted` is true, we convert the result to a `CANCELLED` * envelope so the client sees consistent typed-error shape rather * than a half-applied success. * * 4. Error envelope conversion. Anything the handler throws (or any * ScaiError it returns by raising) lands in `toolResultFromError` * and crosses the wire as `{ isError: true, content, structuredContent }`. */ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import type { McpContext } from "./auth.js"; import type { ToolDescriptor, ToolExtra } from "./registry.js"; export interface DispatchOptions { context: McpContext; extra: ToolExtra; } export declare const dispatchTool: (descriptor: ToolDescriptor, input: Record, options: DispatchOptions) => Promise; /** * Test-only helper to reset the dispatch lock between tests so the * rwlock's pending-queue state doesn't carry across `describe` blocks. */ export declare const __resetDispatchLockForTests: () => void;