/** * LLM-tolerant input coercion at the registration layer. * * Why this exists: Claude Code, Cursor, ChatGPT, and Gemini frequently emit * arguments that are *structurally* valid but *type-loose*. The most common * cases on the wire are: * * - `"limit": "5"` instead of `"limit": 5` (string-quoted number) * - `"top_n": "20"` instead of `"top_n": 20` (same) * - `"events": "the only event"` instead of `"events": ["the only event"]` * (single string for a string-array field) * * Strict Zod (which we use at registration) rejects all three with a * 4xx-shaped Zod error. From the agent's point of view that looks like a * tool that randomly fails on trivial input. Grafana's mcp-grafana solved * this in Go via `unmarshalWithIntConversion` at `tools.go:81-128`: before * the strict schema runs, walk the schema descriptor and coerce * string-quoted numerics into numbers, and single string values into * single-element string arrays. * * This file is the TypeScript equivalent. We do it at the registration * boundary, BEFORE the SDK's Zod validator runs, by reaching into the raw * `arguments` object and rewriting fields whose declared Zod type is * `number` / `integer` / `array of string`. The inner handler still gets * a fully-validated, strictly-typed args object — coercion only happens * on the outer surface. * * Limitations: * - We only coerce at the TOP level of the args object. Nested objects * (e.g. `args.metadata.analyzer_cost`) keep Zod's strict behavior. * This matches Grafana's scope; their unmarshaler is also one-level. * - We don't coerce booleans (`"true"` → `true`) because the failure * mode is rare and the cost-of-being-wrong is higher. * - We don't coerce numbers from objects with `.value` keys etc. — the * coercion is intentionally narrow: only the two specific cases the * LLM-host telemetry shows as the bulk of complaints. */ import { type ZodRawShape } from 'zod'; /** * Build a coercive copy of a Zod shape. Used at tool registration: * `applyToolRegistrations()` rewrites every tool's `inputSchema` through * this so the SDK's strict Zod validation sees coerced values. */ export declare function makeShapeCoercive(shape: ZodRawShape): ZodRawShape;