/**
 * @fileoverview Tool definition types and `tool()` builder function.
 * Provides the canonical `ToolDefinition` interface and `ToolAnnotations` type
 * used by all tool definitions and the handler factory.
 *
 * Also re-exports `disabledTool()` and `DisabledMetadata` so consumers can
 * import the wrapper from the same `/tools` subpath as the builder.
 * @module src/mcp-server/tools/utils/toolDefinition
 */
import type { ContentBlock } from '@modelcontextprotocol/sdk/types.js';
import type { ZodObject, ZodRawShape, z } from 'zod';
import type { HandlerContext, ReasonOf } from '../../../core/context.js';
import type { ErrorContract } from '../../../types-global/errors.js';
export { type DisabledMetadata, disabledTool } from './disabled-tool.js';
/**
 * Defines the annotations that provide hints about a tool's behavior.
 * These are not guarantees but are useful for client-side rendering and decision-making.
 * The index signature `[key: string]: unknown;` ensures compatibility with the MCP SDK.
 */
export interface ToolAnnotations {
    /**
     * A hint indicating that the tool may destroy or modify data in a way that cannot
     * be undone. Only meaningful when `readOnlyHint` is false (the default).
     * Defaults to `true` when unset.
     */
    destructiveHint?: boolean;
    /**
     * A hint indicating that repeated calls with the same arguments have no additional
     * effect beyond the first call. Only meaningful when `readOnlyHint` is false.
     * Defaults to `false` when unset.
     */
    idempotentHint?: boolean;
    /**
     * A hint indicating that the tool may interact with external, unpredictable,
     * or dynamic systems (e.g., fetching from a live API, web search).
     */
    openWorldHint?: boolean;
    /**
     * A hint indicating that the tool does not modify any state.
     * For example, a "read" operation.
     */
    readOnlyHint?: boolean;
    /**
     * An optional human-readable name for the tool, optimized for UI display.
     * If provided, it may be used by clients instead of the programmatic `name`.
     */
    title?: string;
    [key: string]: unknown;
}
/**
 * Per-field rendering config for the `enrichment` block's `content[]` trailer,
 * keyed to the declared enrichment field names. The success-path analogue of how
 * `format()` controls `output` rendering: `enrichment` is the data contract,
 * `enrichmentTrailer` is its presentation.
 *
 * Scope: this shapes the `content[]` trailer text ONLY. It never affects
 * `structuredContent`, which always carries the raw validated enrichment value
 * (the object/array/scalar exactly as declared) — never the rendered markdown.
 *
 * Each entry is optional and may set:
 *   - `render` — maps the field's validated value to trailer markdown. Wins over
 *     the kind-tag and the generic `**key:** value` fallback. Use it to stop a
 *     structured (object/array) field from collapsing to a JSON blob in
 *     `content[]`; `structuredContent` always keeps the full structured value.
 *   - `label` — overrides the field-name shown in the generic / `delta` rendering
 *     (e.g. `Total Found` for a `totalFound` field, instead of the raw key).
 *
 * Resolves to `never` when no `enrichment` block is declared — `enrichmentTrailer`
 * requires one.
 */
export type EnrichmentTrailerConfig<TEnrich extends ZodRawShape | undefined> = TEnrich extends ZodRawShape ? {
    [K in keyof TEnrich]?: {
        label?: string;
        /**
         * Declared with method syntax (not an arrow property) for the same
         * reason as `format` / `handler`: method parameters are checked
         * bivariantly, so a concrete tool's narrow `render` value stays
         * assignable to the type-erased `AnyToolDefinition` (whose param
         * widens to `unknown`). An arrow property would be variance-strict
         * and break `createApp({ tools: [...] })` for every enrichment tool.
         */
        render?(value: z.infer<TEnrich[K]>): string;
    };
} : never;
/**
 * Represents the complete, self-contained definition of an MCP tool.
 *
 * `TErrors` is the const tuple of `ErrorContract` entries declared on the
 * definition (or `undefined` when none are declared). The reason union extracted
 * from `TErrors` flows into the handler's `ctx.fail` for compile-time-checked
 * error throws.
 *
 * `TEnrich` is the `ZodRawShape` of the `enrichment` block (or `undefined` when
 * none is declared). Its inferred fields type `ctx.enrich(...)` and are advertised
 * to clients as part of `outputSchema`.
 */
export interface ToolDefinition<TInput extends ZodObject<ZodRawShape> = ZodObject<ZodRawShape>, TOutput extends ZodObject<ZodRawShape> = ZodObject<ZodRawShape>, TErrors extends readonly ErrorContract[] | undefined = undefined, TEnrich extends ZodRawShape | undefined = undefined> {
    /** Protocol-level metadata (e.g., MCP Apps extension). */
    _meta?: Record<string, unknown>;
    /** UI/behavior hints for clients. */
    annotations?: ToolAnnotations;
    /** Required auth scopes. Checked by handler factory before calling handler. */
    auth?: string[];
    /** LLM-facing description. */
    description: string;
    /**
     * Declarative contract for agent-facing context on the success path — the
     * counterpart to `errors[]`. A `ZodRawShape` (`{ <name>: <ZodType> }`) of
     * fields the handler populates via `ctx.enrich(...)`: empty-result notices,
     * the query/filter as the server parsed it, pagination totals.
     *
     * **Reaches both client surfaces.** Enrichment is merged into the validated
     * output (→ `structuredContent`) and mirrored into `content[]` as a trailer —
     * so `structuredContent`-only clients (e.g. Claude Code) and `content[]`-only
     * clients (e.g. Claude Desktop) both see it, even when the tool defines no
     * `format()`. The extended schema (`output.extend(enrichment)`) is advertised
     * as the tool's `outputSchema` in `tools/list`.
     *
     * **Type-driven.** When declared, `ctx.enrich(...)` is typed to a `Partial` of
     * these fields. Enrichment is not part of `output`, so `format-parity` never
     * touches it. A *required* enrichment field that is never populated fails the
     * effective-output parse — surfacing the bug rather than dropping it silently.
     * Keys must be disjoint from `output` keys (lint-enforced; `.extend` would
     * otherwise silently override).
     */
    enrichment?: TEnrich;
    /**
     * Per-field `content[]` trailer rendering for the `enrichment` block — the
     * presentation layer to `enrichment`'s data contract (mirrors `output` /
     * `format`).
     *
     * Supply a `render` to stop a structured (object/array) enrichment field from
     * collapsing to a JSON blob in `content[]` (it renders as bulleted markdown
     * instead; `structuredContent` is unaffected), or a `label` to show a
     * human-readable field name. Keyed to the declared `enrichment` fields and
     * type-checked against them. The `enrichment-trailer-render` lint rule requires
     * a `render` for any non-scalar enrichment field that isn't a `delta` shape.
     */
    enrichmentTrailer?: EnrichmentTrailerConfig<TEnrich>;
    /**
     * Declarative contract describing the failure modes this tool can surface.
     *
     * Each entry pairs a `JsonRpcErrorCode` with a stable `reason` string and a
     * `when` description.
     *
     * **Type-driven.** When declared, the handler receives `ctx.fail(reason, …)`
     * typed against the union of `reason` strings — TypeScript enforces that you
     * can only `fail()` with a declared reason, and the runtime auto-populates
     * `data.reason` on the thrown `McpError`.
     *
     * Optional. Without it, handlers still throw `McpError` directly and the
     * framework's auto-classifier produces correct codes at runtime — the
     * contract just adds compile-time enforcement.
     *
     * The definition linter (`bun run lint:mcp`, gated in `devcheck`) validates each
     * entry's `code` is a real `JsonRpcErrorCode` and that `reason` strings are
     * unique within the contract.
     */
    errors?: TErrors;
    /**
     * Optional formatter mapping output to MCP `content[]`. Different MCP clients
     * forward different surfaces to the model: some (e.g., Claude Code) read
     * `structuredContent` from `output`, others (e.g., Claude Desktop) read
     * `content[]` from `format()`. **Both must be content-complete** — `format()`
     * is the markdown-rendered twin of `structuredContent`, not a separate payload.
     *
     * **Make `format()` content-complete.** A thin one-liner (e.g., a count or
     * title) leaves `content[]`-only clients blind to data that `structuredContent`
     * clients can see. The `format-parity` lint rule enforces this at build time.
     *
     * If omitted, the handler factory JSON-stringifies the output as a fallback.
     *
     * Declared as a method (not an arrow property) for the same reason as `handler`:
     * method parameters are checked bivariantly, so a concrete tool's narrow `format`
     * stays assignable to the type-erased `AnyToolDefinition` (whose `format` param is
     * the widened `Record<string, unknown>`).
     */
    format?(result: z.infer<TOutput>): ContentBlock[];
    /**
     * The core handler function. Receives validated input and unified Context.
     * Throw on failure — no try/catch needed.
     *
     * When `errors[]` is declared, `ctx` carries a typed `fail(reason, message?, data?)`
     * helper keyed by the declared reason union — `ctx.fail('typo')` is a TS error.
     * Without `errors[]`, `ctx` is plain `Context` and you throw `McpError` directly.
     *
     * When `enrichment` is declared, `ctx.enrich(...)` is typed to a `Partial` of
     * the declared fields; without it, the loose base `enrich` is available (a
     * no-op merge, since nothing reads it).
     *
     * Declared as a method (not an arrow property) so TypeScript checks the
     * signature bivariantly — concrete tools with narrow `ctx.fail` / `ctx.enrich`
     * types remain assignable to the type-erased `AnyToolDefinition` array.
     */
    handler(input: z.infer<TInput>, ctx: HandlerContext<ReasonOf<TErrors>, TEnrich>): Promise<z.infer<TOutput>> | z.infer<TOutput>;
    /** Zod schema for input validation. All fields need `.describe()`. */
    input: TInput;
    /** Programmatic unique name (snake_case). */
    name: string;
    /** Zod schema for output validation. All fields need `.describe()`. */
    output: TOutput;
    /**
     * View-source URL override for the landing page. Bypasses the
     * `landing.repoRoot`-based auto-derivation, which assumes the file lives at
     * `<repoRoot>/blob/main/src/mcp-server/tools/definitions/<kebab-name>.tool.ts`.
     * Set this when the file path diverges from that convention (e.g.,
     * domain-namespaced subdirectories or a filename that doesn't mirror `name`).
     */
    sourceUrl?: string;
    /** When true, the framework manages task lifecycle automatically. */
    task?: boolean;
    /** Human-readable title for UI display. */
    title?: string;
}
/** Type-erased union for mixed arrays passed to createApp(). */
export type AnyToolDefinition = ToolDefinition<ZodObject<ZodRawShape>, ZodObject<ZodRawShape>, readonly ErrorContract[] | undefined, ZodRawShape | undefined>;
/**
 * Creates a tool definition with full type inference from Zod schemas.
 *
 * The `const` modifier on `TErrors` preserves literal types in the `errors[]`
 * array without requiring `as const` at the call site, so the reason union
 * flows into `ctx.fail` automatically.
 *
 * @example Without an error contract — throw `McpError` directly:
 * ```ts
 * const myTool = tool('my_tool', {
 *   description: 'Does something useful.',
 *   input: z.object({ query: z.string().describe('Search query') }),
 *   output: z.object({
 *     items: z.array(z.object({
 *       id: z.string().describe('Item ID'),
 *       name: z.string().describe('Item name'),
 *     })).describe('Matching items'),
 *   }),
 *   async handler(input, ctx) {
 *     if (!input.query) throw notFound('Empty query');
 *     return { items: await search(input.query) };
 *   },
 * });
 * ```
 *
 * @example With a typed error contract — `ctx.fail(reason, …)`:
 * ```ts
 * const myTool = tool('my_tool', {
 *   errors: [
 *     { reason: 'no_match', code: JsonRpcErrorCode.NotFound,
 *       when: 'No items match the query',
 *       recovery: 'Broaden the query or check the spelling and try again.' },
 *     { reason: 'rate_limited', code: JsonRpcErrorCode.RateLimited,
 *       when: 'Upstream rate limit hit', retryable: true,
 *       recovery: 'Wait a few seconds before retrying or reduce request frequency.' },
 *   ],
 *   input: z.object({ query: z.string().describe('Search query') }),
 *   output: z.object({ items: z.array(z.string()).describe('Matched items') }),
 *   async handler(input, ctx) {
 *     const items = await search(input.query);
 *     if (items.length === 0) throw ctx.fail('no_match', `No matches for "${input.query}"`);
 *     // ctx.fail('typo')  ← TypeScript error: 'typo' isn't in the contract
 *     return { items };
 *   },
 * });
 * ```
 */
export declare function tool<TInput extends ZodObject<ZodRawShape>, TOutput extends ZodObject<ZodRawShape>, const TErrors extends readonly ErrorContract[] | undefined = undefined, const TEnrich extends ZodRawShape | undefined = undefined>(name: string, options: Omit<ToolDefinition<TInput, TOutput, TErrors, TEnrich>, 'name'>): ToolDefinition<TInput, TOutput, TErrors, TEnrich>;
//# sourceMappingURL=toolDefinition.d.ts.map