import { z } from 'zod'; import type { ToolContext } from './context.js'; export interface ToolAnnotations { /** Advertised MCP hint: does not modify state. */ readOnlyHint?: boolean; /** Advertised MCP hint: may perform destructive updates. */ destructiveHint?: boolean; /** Advertised MCP hint: repeated identical calls are safe. */ idempotentHint?: boolean; /** Advertised MCP hint: interacts with external systems. */ openWorldHint?: boolean; } export interface ToolDef { name: string; description: string; inputSchema: z.ZodType; handler: (input: I, ctx: ToolContext) => Promise; annotations?: ToolAnnotations; } /** Identity helper that preserves the input/output generics for handler type-safety. */ export declare function defineTool(def: ToolDef): ToolDef; export interface ListedTool { name: string; description: string; inputSchema: Record; annotations?: ToolAnnotations; } /** * A short content fingerprint over a tool's description + input schema. * * ⛔ WHY THIS IS EMBEDDED IN THE DESCRIPTION RATHER THAN REPORTED ALONE (#173). * The client comparing these is a language model reading text, not a program * computing digests. It cannot hash its own cached schemas to compare against * ours — that would need identical JSON Schema canonicalisation in every client * AND the ability to execute a hash. So the marker has to travel INSIDE the * artifact being versioned: a stale copy then carries a stale marker by * construction, and the agent compares two short strings it can literally see. * * ⚠️ Per-tool, deliberately, NOT one global server version. A global stamp would * change every description on every release, which resets per-tool "always * allow" grants across the whole surface each time and degrades exactly the * unattended runs this protects. A content-derived fingerprint changes only for * tools that actually changed — which is precisely the set that should * re-prompt. * * Computed from the RAW description, before the marker is appended, so it stays * stable rather than folding in its own output. */ export declare function toolFingerprint(def: Pick): string; /** How the marker is rendered into a served description and the self-report. */ export declare function fingerprintMarker(fingerprint: string): string; export declare class ToolRegistry { private readonly tools; register(def: ToolDef): void; registerAll(defs: ToolDef[]): void; has(name: string): boolean; size(): number; names(): string[]; list(): ListedTool[]; /** `name [#abcdef]` per tool, for the connector self-report to publish. */ fingerprints(): string[]; /** Validate arguments against the tool's zod schema, then run the handler. Throws AhError * on unknown tool / invalid input; the server wraps all throws into the error contract. */ dispatch(name: string, args: unknown, ctx: ToolContext): Promise; }