import type { InputSchema, ToolResponse } from './common.js'; import type { JsonSchemaForInference } from './json-schema.js'; import type { ToolDescriptor, ToolDescriptorFromSchema, ToolListItem, ToolRawResult, } from './tool.js'; // ============================================================================ // Model Context Testing // ============================================================================ /** * Tool info returned by ModelContextTesting.listTools(). */ export interface ModelContextTestingToolInfo { name: string; description: string; inputSchema?: string; } /** * Tool info returned by Chromium's producer-facing ModelContext.getTools(). */ export interface ModelContextToolInfo extends ModelContextTestingToolInfo { title: string; origin: string; window: Window; } /** * Options supported by ModelContextTesting.executeTool(). */ export interface ModelContextTestingExecuteToolOptions { signal?: AbortSignal; } /** * Chromium testing API on navigator.modelContextTesting. * * The native runtime extends EventTarget and fires `toolchange` events. */ export interface ModelContextTesting extends EventTarget { listTools(): ModelContextTestingToolInfo[]; executeTool( toolName: string, inputArgsJson: string, options?: ModelContextTestingExecuteToolOptions ): Promise; getCrossDocumentScriptToolResult(): Promise; ontoolchange: ((this: ModelContextTesting, ev: Event) => unknown) | null; /** * @deprecated Use `addEventListener('toolchange', ...)` instead. */ registerToolsChangedCallback?(callback: () => void): void; } /** * Polyfill-only testing extensions layered on top of ModelContextTesting. */ export interface ModelContextTestingPolyfillExtensions { /** * Registers a callback invoked when the tool list changes. * @deprecated Use `addEventListener('toolchange', ...)` on native runtimes. * Kept for polyfill backward compatibility. */ registerToolsChangedCallback(callback: () => void): void; getToolCalls(): Array<{ toolName: string; arguments: Record; timestamp: number; }>; clearToolCalls(): void; setMockToolResponse(toolName: string, response: ToolResponse): void; clearMockToolResponse(toolName: string): void; clearAllMockToolResponses(): void; getRegisteredTools(): ReturnType; reset(): void; } // ============================================================================ // Type Inference Helpers // ============================================================================ /** * Any supported tool descriptor. * * Uses `never` for args so descriptors with stricter argument objects remain assignable. */ export type AnyToolDescriptor = ToolDescriptor; /** * Infers argument shape from a tool descriptor. */ export type InferToolArgs = TTool extends ToolDescriptor ? TArgs : never; /** * Infers result shape from a tool descriptor. */ export type InferToolResult = TTool extends ToolDescriptor ? TResult : never; /** * Union of tool names from a tuple/array of descriptors. */ export type ToolName = TTools[number]['name']; /** * Extracts a tool descriptor by name from a tuple/array. */ export type ToolByName< TTools extends readonly { name: string }[], TName extends ToolName, > = Extract; /** * Tool argument type by tool name from a tuple/array. */ export type ToolArgsByName< TTools extends readonly { name: string }[], TName extends ToolName, > = InferToolArgs>; /** * Tool result type by tool name from a tuple/array. */ export type ToolResultByName< TTools extends readonly { name: string }[], TName extends ToolName, > = InferToolResult>; /** * Typed parameters for `callTool`. * * When a tool has no args (`Record`), `arguments` becomes optional. */ export type ToolCallParams< TName extends string = string, TArgs extends Record = Record, > = { name: TName } & (TArgs extends Record ? { arguments?: TArgs } : { arguments: TArgs }); // ============================================================================ // Tool Call Event // ============================================================================ /** * Event dispatched when a tool is called. */ export interface ToolCallEvent extends Event { /** * Tool name being invoked. */ name: string; /** * Tool arguments supplied by the caller. */ arguments: Record; /** * Intercepts execution with a custom tool response. */ respondWith: (response: ToolResponse) => void; } /** * Tool identity accepted by compatibility unregister flows. * * Current Chromium exposes string-name unregistration. * MCP-B compatibility runtimes may also accept the originally registered tool object. */ export interface ModelContextToolReference { name: string; } /** * Non-standard compatibility handle returned by some runtimes after registerTool(). * * @deprecated Use `options.signal` on `registerTool(tool, options)`. Will be removed in the next major. */ export interface ModelContextToolRegistrationHandle { unregister(): void; } /** * @see {@link https://webmachinelearning.github.io/webmcp/#dictdef-modelcontextregistertooloptions} */ export interface ModelContextRegisterToolOptions { /** * An `AbortSignal` whose abortion unregisters the tool. A pre-aborted signal short-circuits registration. */ signal?: AbortSignal; /** * Origins that can observe this tool from other documents in the same tree. */ exposedTo?: string[]; } // ============================================================================ // Model Context // ============================================================================ /** * Strict WebMCP core interface on document.modelContext. */ export interface ModelContextCore { // ==================== TOOLS ==================== /** * Registers a dynamic tool with JSON Schema-driven inference. * * `execute(args)` is inferred from `inputSchema`, and when a literal object * `outputSchema` is provided, `execute(...).structuredContent` is inferred too. */ registerTool< TInputSchema extends JsonSchemaForInference, TOutputSchema extends JsonSchemaForInference | undefined = undefined, TName extends string = string, >( tool: ToolDescriptorFromSchema, options?: ModelContextRegisterToolOptions ): void; /** * Registers a dynamic tool with explicitly typed args/result. */ registerTool< TInputSchema extends InputSchema, TArgs extends Record = Record, TName extends string = string, >( tool: ToolDescriptor & { inputSchema: TInputSchema; } & (TInputSchema extends InputSchema ? string extends TInputSchema['type'] ? unknown : never : unknown), options?: ModelContextRegisterToolOptions ): void; /** * Registers a dynamic tool without an explicit inputSchema. * Runtime defaults this to an empty object schema. */ registerTool< TArgs extends Record = Record, TName extends string = string, >( tool: Omit, 'inputSchema'> & { inputSchema?: undefined; }, options?: ModelContextRegisterToolOptions ): void; /** * Lists currently registered producer tools using the native Chromium preview * shape. Current Chromium returns JSON-stringified schemas here, matching * ModelContextTesting.listTools(). */ getTools(): Promise; /** * Executes a registered tool object returned from getTools(). * * This mirrors Chromium's current producer-facing preview API. The testing API * still executes by `(toolName, inputArgsJson)`. */ executeTool( tool: ModelContextToolInfo, inputArgsJson: string, options?: ModelContextTestingExecuteToolOptions ): Promise; /** * Handler invoked when the producer tool list changes. */ ontoolchange: ((this: ModelContextCore, ev: Event) => unknown) | null; addEventListener( type: 'toolchange', listener: () => void, options?: boolean | AddEventListenerOptions ): void; removeEventListener( type: 'toolchange', listener: () => void, options?: boolean | EventListenerOptions ): void; dispatchEvent(event: Event): boolean; } /** * MCPB extension surface layered on top of strict WebMCP core. * These members are intentionally non-standard. */ export interface ModelContextExtensions { /** * Unregisters a dynamic tool by name or tool reference. * * @deprecated Removed from the WebMCP spec on April 23, 2026. Use `registerTool(tool, { signal })`. Will be removed in the next major. */ unregisterTool(nameOrTool: string | ModelContextToolReference): void; /** * Lists currently registered tools. */ listTools(): ToolListItem[]; /** * Executes a registered tool. */ callTool< TName extends string = string, TArgs extends Record = Record, >(params: { name: TName; arguments?: TArgs; }): Promise; // ==================== EVENTS ==================== /** * Adds a listener for tool invocation events. */ addEventListener( type: 'toolcall', listener: (event: ToolCallEvent) => void | Promise, options?: boolean | AddEventListenerOptions ): void; /** * Adds a listener for tool list changes. */ addEventListener( type: 'toolchange', listener: () => void, options?: boolean | AddEventListenerOptions ): void; /** * @deprecated Use `'toolchange'` instead. Will be removed in the next major. */ addEventListener( type: 'toolschanged', listener: () => void, options?: boolean | AddEventListenerOptions ): void; /** * Removes a listener for tool invocation events. */ removeEventListener( type: 'toolcall', listener: (event: ToolCallEvent) => void | Promise, options?: boolean | EventListenerOptions ): void; /** * Removes a listener for tool list changes. */ removeEventListener( type: 'toolchange', listener: () => void, options?: boolean | EventListenerOptions ): void; /** * @deprecated Use `'toolchange'` instead. Will be removed in the next major. */ removeEventListener( type: 'toolschanged', listener: () => void, options?: boolean | EventListenerOptions ): void; /** * Dispatches an event. */ dispatchEvent(event: Event): boolean; } /** * Public document.modelContext type (strict core only). */ export type ModelContext = ModelContextCore; /** * Full runtime shape including MCPB extensions. */ export type ModelContextWithExtensions = ModelContextCore & ModelContextExtensions; // ============================================================================ // Typed Model Context // ============================================================================ /** * Strongly-typed `ModelContext` view derived from known tool descriptors. * * This is useful when your project has a static tool registry and you want * name-aware inference for `callTool`. */ export type TypedModelContext< TTools extends readonly { name: string }[] = readonly ToolDescriptor[], > = ModelContextWithExtensions & { /** * Executes a known tool with name-aware argument and response inference. */ callTool>( params: ToolCallParams> ): Promise>; /** * Fallback call signature for unknown or dynamically-discovered tools. */ callTool(params: { name: string; arguments?: Record }): Promise; /** * Lists tools with a narrowed name union. */ listTools(): Array>>; };