/** * MCP tool annotations. * * The MCP spec lets a server describe each tool's behaviour so that clients can * decide what needs a confirmation prompt, what is safe to retry, and what * reaches the open internet. Both the Anthropic Connectors directory and the * OpenAI plugins directory make these a hard listing requirement. * * Shape (fetched from the current spec, not from memory — * , `ToolAnnotations`): * * interface ToolAnnotations { * title?: string; * readOnlyHint?: boolean; // tool does not modify its environment. Default false * destructiveHint?: boolean; // may perform destructive updates. Default true * // (meaningful only when readOnlyHint == false) * idempotentHint?: boolean; // repeat calls w/ same args add no effect. Default false * openWorldHint?: boolean; // interacts with an open, external world. Default true * } * * `Tool.title` is a separate top-level field on the tool itself; we emit both so * that clients reading either location get a human-readable name. * * --------------------------------------------------------------------------- * Classification rules used below (applied by reading each implementation, not * by guessing from the tool's name): * * readOnlyHint true only if the call cannot change the browser, the page, * or anything the page can reach. Reading is fine; *anything* * that clicks, types, navigates, resizes, closes, or executes * page JavaScript is not read-only. * destructiveHint true if a single call can irreversibly lose state — a closed * tab, a submitted form, an arbitrary script, a drag that * reorders or deletes. Additive-only edits are false. * idempotentHint true if calling twice with identical arguments leaves the * same end state. Relative operations (scroll by N, type more * text, navigate through a flow) are false. * openWorldHint true if the call can reach a URL/host the caller chooses — * navigation, fetching, arbitrary JS (it can `fetch()`), or * clicking a link. * * Two entries are deliberately counter-intuitive; both were resolved by reading * the extension source rather than the tool name: * * wait_for_condition reads like an observer, but evaluates a caller-supplied * JavaScript expression through `new Function()` in the * page. That is arbitrary code execution, so it is NOT * read-only. (vibe: lib/extension/tools/InteractionTools.js) * secrets_manager reads like a mutator, but only supports `list` and * `read` of credential *metadata*, never writes and never * returns plaintext. It IS read-only. * (vibe: lib/extension/tools/CredentialManagerTool.js) */ import type { ToolDefinition } from './types.js'; /** The four behavioural hints plus a display title, all required internally. */ export interface McpToolAnnotations { title: string; readOnlyHint: boolean; destructiveHint: boolean; idempotentHint: boolean; openWorldHint: boolean; } /** A tool definition enriched with its title and annotations, ready for `tools/list`. */ export interface AnnotatedToolDefinition extends ToolDefinition { title: string; annotations: McpToolAnnotations; } /** * Normalize a tool name for registry lookup. * * Backends spell the same tool differently (`press_key` vs `keyboard-shortcut` * vs `Press Key`), so match on a canonical lower-snake form. */ export declare function normalizeAnnotationKey(value: string): string; /** * Annotations applied when a backend advertises a tool we have never classified. * * Deliberately the most cautious combination the spec allows — assume it writes, * assume it can destroy, assume it is unsafe to retry, assume it touches the * internet. A client will then prompt the user, which is the correct failure * mode for an unknown capability. `assertAnnotationCoverage` exists so that this * fallback never silently becomes the answer for a tool we actually ship. */ export declare const FALLBACK_TOOL_ANNOTATIONS: Omit; /** * The classification table. * * readOnly destructive idempotent openWorld */ export declare const TOOL_ANNOTATIONS: Record; /** * Look up a tool's annotations, or `undefined` when it is not classified. * * Callers that need a value regardless should use {@link annotateTool}, which * falls back to the cautious defaults. */ export declare function getToolAnnotations(name: string): McpToolAnnotations | undefined; /** Attach `title` + `annotations` to a tool definition for the `tools/list` reply. */ export declare function annotateTool(tool: ToolDefinition): AnnotatedToolDefinition; /** * Every tool name this server can expose, across all backends. * * Kept explicit (rather than derived at runtime) so the coverage test can run * without a browser: it is the contract that each of these has a hand-written * classification. Adding a tool to a backend without adding it here — or here * without adding it to {@link TOOL_ANNOTATIONS} — fails the test. */ export declare const EXTENSION_CORE_TOOL_NAMES: readonly string[]; /** * Assert that every supplied tool name has a hand-written classification. * * Throws listing the offenders, so the failure names the tool that needs * classifying rather than just going red. */ export declare function assertAnnotationCoverage(names: readonly string[]): void; //# sourceMappingURL=tool-annotations.d.ts.map