import { EventEmitter } from "node:events"; import { CallToolRequestParamsSchema, CallToolResultSchema, ToolAnnotationsSchema, ToolSchema } from "@modelcontextprotocol/core"; import { z } from "zod/v4"; import { CallToolResult, Tool, ToolAnnotations, Transport } from "@modelcontextprotocol/server"; //#region src/protocol.d.ts /** * SDK-derived canonical tool schema used internally by the relay. */ declare const NormalizedToolSchema: z.ZodObject<{ description: z.ZodOptional; inputSchema: z.ZodObject<{ type: z.ZodLiteral<"object">; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; }, z.core.$strip>; /** * SDK-derived argument schema for tool invocation payloads. */ declare const RelayInvokeArgsSchema: z.ZodOptional>; /** * Default input schema applied when inbound payload omits or provides * a non-object input schema. */ declare const DEFAULT_TOOL_INPUT_SCHEMA: Tool['inputSchema']; /** SDK tool schema with a browser-compatible default input schema. */ declare const InboundToolSchema: z.ZodObject<{ description: z.ZodOptional; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; inputSchema: z.ZodOptional; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>>; }, z.core.$strip>; /** * Canonical normalized relay tool shape. */ type RelayTool = z.infer; /** * Canonical relay tool annotations shape. */ type RelayToolAnnotations = ToolAnnotations; /** * Canonical relay call result shape. */ type RelayCallToolResult = CallToolResult; /** * Invocation argument object shape derived from MCP SDK request params. */ type RelayInvokeArgs = Exclude, undefined>; /** * Applies the browser default input schema and validates the complete SDK tool. */ declare function normalizeInboundTool(inbound: z.infer): RelayTool; //#endregion //#region src/schemas.d.ts declare const BrowserHelloMessageSchema: z.ZodObject<{ type: z.ZodLiteral<"hello">; tabId: z.ZodString; origin: z.ZodOptional; url: z.ZodOptional; title: z.ZodOptional; iconUrl: z.ZodOptional; }, z.core.$strip>; /** * Union schema for all browser-to-relay protocol messages. */ declare const BrowserToRelayMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ type: z.ZodLiteral<"hello">; tabId: z.ZodString; origin: z.ZodOptional; url: z.ZodOptional; title: z.ZodOptional; iconUrl: z.ZodOptional; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"tools/list">; tools: z.ZodPipe; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; inputSchema: z.ZodOptional; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>>; }, z.core.$strip>>, z.ZodTransform<{ inputSchema: { [x: string]: unknown; type: "object"; properties?: Record | undefined; required?: string[] | undefined; }; name: string; description?: string | undefined; outputSchema?: { [x: string]: unknown; $schema?: string | undefined; } | undefined; annotations?: { title?: string | undefined; readOnlyHint?: boolean | undefined; destructiveHint?: boolean | undefined; idempotentHint?: boolean | undefined; openWorldHint?: boolean | undefined; } | undefined; execution?: { taskSupport?: "optional" | "required" | "forbidden" | undefined; } | undefined; _meta?: Record | undefined; icons?: { src: string; mimeType?: string | undefined; sizes?: string[] | undefined; theme?: "light" | "dark" | undefined; }[] | undefined; title?: string | undefined; }[], { name: string; description?: string | undefined; outputSchema?: { [x: string]: unknown; $schema?: string | undefined; } | undefined; annotations?: { title?: string | undefined; readOnlyHint?: boolean | undefined; destructiveHint?: boolean | undefined; idempotentHint?: boolean | undefined; openWorldHint?: boolean | undefined; } | undefined; execution?: { taskSupport?: "optional" | "required" | "forbidden" | undefined; } | undefined; _meta?: Record | undefined; icons?: { src: string; mimeType?: string | undefined; sizes?: string[] | undefined; theme?: "light" | "dark" | undefined; }[] | undefined; title?: string | undefined; inputSchema?: { [x: string]: unknown; type: "object"; properties?: Record | undefined; required?: string[] | undefined; } | undefined; }[]>>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"tools/changed">; tools: z.ZodPipe; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; inputSchema: z.ZodOptional; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>>; }, z.core.$strip>>, z.ZodTransform<{ inputSchema: { [x: string]: unknown; type: "object"; properties?: Record | undefined; required?: string[] | undefined; }; name: string; description?: string | undefined; outputSchema?: { [x: string]: unknown; $schema?: string | undefined; } | undefined; annotations?: { title?: string | undefined; readOnlyHint?: boolean | undefined; destructiveHint?: boolean | undefined; idempotentHint?: boolean | undefined; openWorldHint?: boolean | undefined; } | undefined; execution?: { taskSupport?: "optional" | "required" | "forbidden" | undefined; } | undefined; _meta?: Record | undefined; icons?: { src: string; mimeType?: string | undefined; sizes?: string[] | undefined; theme?: "light" | "dark" | undefined; }[] | undefined; title?: string | undefined; }[], { name: string; description?: string | undefined; outputSchema?: { [x: string]: unknown; $schema?: string | undefined; } | undefined; annotations?: { title?: string | undefined; readOnlyHint?: boolean | undefined; destructiveHint?: boolean | undefined; idempotentHint?: boolean | undefined; openWorldHint?: boolean | undefined; } | undefined; execution?: { taskSupport?: "optional" | "required" | "forbidden" | undefined; } | undefined; _meta?: Record | undefined; icons?: { src: string; mimeType?: string | undefined; sizes?: string[] | undefined; theme?: "light" | "dark" | undefined; }[] | undefined; title?: string | undefined; inputSchema?: { [x: string]: unknown; type: "object"; properties?: Record | undefined; required?: string[] | undefined; } | undefined; }[]>>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"result">; callId: z.ZodString; result: z.ZodUnknown; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"pong">; }, z.core.$strip>], "type">; /** * Browser-to-relay message payload. */ type BrowserToRelayMessage = z.infer; /** * Browser source bootstrap message. */ type BrowserHelloMessage = z.infer; /** * Shared relay identity used for discovery and attach verification. */ declare const RelayDescriptorSchema: z.ZodObject<{ host: z.ZodString; instanceId: z.ZodString; label: z.ZodOptional; port: z.ZodNumber; relayId: z.ZodOptional; workspace: z.ZodOptional; }, z.core.$strip>; /** * Relay identity used for discovery and attach verification. */ type RelayDescriptor = z.infer; /** * Schema for server hello messages sent immediately after WebSocket connect. */ declare const ServerHelloMessageSchema: z.ZodObject<{ host: z.ZodString; instanceId: z.ZodString; label: z.ZodOptional; port: z.ZodNumber; relayId: z.ZodOptional; workspace: z.ZodOptional; type: z.ZodLiteral<"server-hello">; service: z.ZodLiteral<"webmcp-local-relay">; version: z.ZodLiteral<1>; }, z.core.$strip>; /** * Server hello payload. */ type ServerHelloMessage = z.infer; /** * Schema for acceptance of a browser source hello message. */ declare const RelayHelloAcceptedMessageSchema: z.ZodObject<{ type: z.ZodLiteral<"hello/accepted">; }, z.core.$strip>; /** * Acceptance payload for a browser source hello message. */ type RelayHelloAcceptedMessage = z.infer; /** * Schema for rejection of a browser source hello message. */ declare const RelayHelloRejectedMessageSchema: z.ZodObject<{ type: z.ZodLiteral<"hello/rejected">; reason: z.ZodString; message: z.ZodString; }, z.core.$strip>; /** * Rejection payload for a browser source hello message. */ type RelayHelloRejectedMessage = z.infer; /** * Union schema for all relay-to-browser protocol messages. */ declare const RelayToBrowserMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ host: z.ZodString; instanceId: z.ZodString; label: z.ZodOptional; port: z.ZodNumber; relayId: z.ZodOptional; workspace: z.ZodOptional; type: z.ZodLiteral<"server-hello">; service: z.ZodLiteral<"webmcp-local-relay">; version: z.ZodLiteral<1>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"hello/accepted">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"hello/rejected">; reason: z.ZodString; message: z.ZodString; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"invoke">; callId: z.ZodString; toolName: z.ZodString; args: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"ping">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"reload">; }, z.core.$strip>], "type">; /** * Relay-to-browser message payload. */ type RelayToBrowserMessage = z.infer; /** * Schema for source metadata transmitted in relay-to-relay messages. */ declare const RelaySourceInfoSchema: z.ZodObject<{ sourceId: z.ZodString; tabId: z.ZodString; origin: z.ZodOptional; url: z.ZodOptional; title: z.ZodOptional; iconUrl: z.ZodOptional; connectedAt: z.ZodNumber; lastSeenAt: z.ZodNumber; toolCount: z.ZodNumber; }, z.core.$strip>; /** * Source metadata transmitted in relay-to-relay messages. */ type RelaySourceInfo = z.infer; /** * Union schema for all relay-client-to-server messages. */ declare const RelayClientToServerMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ type: z.ZodLiteral<"relay/hello">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"relay/list-tools">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"relay/invoke">; callId: z.ZodString; toolName: z.ZodString; args: z.ZodOptional>; }, z.core.$strip>], "type">; /** * Relay client to server message payload. */ type RelayClientToServerMessage = z.infer; /** * Union schema for all relay-server-to-client messages. */ declare const RelayServerToClientMessageSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ host: z.ZodString; instanceId: z.ZodString; label: z.ZodOptional; port: z.ZodNumber; relayId: z.ZodOptional; workspace: z.ZodOptional; type: z.ZodLiteral<"server-hello">; service: z.ZodLiteral<"webmcp-local-relay">; version: z.ZodLiteral<1>; }, z.core.$strip>, z.ZodObject<{ tools: z.ZodArray; inputSchema: z.ZodObject<{ type: z.ZodLiteral<"object">; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; }, z.core.$strip>>; sources: z.ZodArray; url: z.ZodOptional; title: z.ZodOptional; iconUrl: z.ZodOptional; connectedAt: z.ZodNumber; lastSeenAt: z.ZodNumber; toolCount: z.ZodNumber; }, z.core.$strip>>; toolSourceMap: z.ZodRecord>; type: z.ZodLiteral<"relay/tools">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"relay/result">; callId: z.ZodString; result: z.ZodObject<{ _meta: z.ZodOptional; description: z.ZodOptional; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; name: z.ZodString; title: z.ZodOptional; }, z.core.$strip>>>; }, z.core.$loose>>; content: z.ZodDefault; text: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"image">; data: z.ZodString; mimeType: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"audio">; data: z.ZodString; mimeType: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ uri: z.ZodString; description: z.ZodOptional; mimeType: z.ZodOptional; size: z.ZodOptional; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; name: z.ZodString; title: z.ZodOptional; type: z.ZodLiteral<"resource_link">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"resource">; resource: z.ZodUnion; _meta: z.ZodOptional>; text: z.ZodString; }, z.core.$strip>, z.ZodObject<{ uri: z.ZodString; mimeType: z.ZodOptional; _meta: z.ZodOptional>; blob: z.ZodString; }, z.core.$strip>]>; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>]>>>; structuredContent: z.ZodOptional; isError: z.ZodOptional; }, z.core.$loose>; }, z.core.$strip>, z.ZodObject<{ tools: z.ZodArray; inputSchema: z.ZodObject<{ type: z.ZodLiteral<"object">; properties: z.ZodOptional>>>; required: z.ZodOptional>; }, z.core.$catchall>; outputSchema: z.ZodOptional; }, z.core.$loose>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; title: z.ZodOptional; name: z.ZodString; }, z.core.$strip>>; sources: z.ZodArray; url: z.ZodOptional; title: z.ZodOptional; iconUrl: z.ZodOptional; connectedAt: z.ZodNumber; lastSeenAt: z.ZodNumber; toolCount: z.ZodNumber; }, z.core.$strip>>; toolSourceMap: z.ZodRecord>; type: z.ZodLiteral<"relay/tools-changed">; }, z.core.$strip>], "type">; /** * Relay server to client message payload. */ type RelayServerToClientMessage = z.infer; //#endregion //#region src/registry.d.ts /** * Internal metadata tracked for each active browser source. */ interface SourceMetadata { sourceId: string; tabId: string; origin?: string | undefined; url?: string | undefined; title?: string | undefined; iconUrl?: string | undefined; connectedAt: number; lastSeenAt: number; } /** * Public source metadata exposed by registry APIs. */ interface SourceInfo extends SourceMetadata { toolCount: number; } /** * Aggregated relayed tool metadata across one or more sources. * * Extends {@link RelayTool} with relay-specific fields so new SDK tool * properties are automatically inherited without manual duplication. */ interface AggregatedTool extends RelayTool { originalName: string; sources: SourceInfo[]; } /** * Invocation target selected by the registry. */ interface ResolvedInvocation { connectionId: string; tool: RelayTool; publicToolName: string; } /** * Error thrown when a source attempts to register tools before `hello`. */ declare class HelloRequiredError extends Error { readonly connectionId: string; constructor(connectionId: string); } /** * In-memory source and tool registry used by the relay bridge. */ declare class RelayRegistry { private readonly now; private readonly sourceByConnectionId; private readonly toolsByConnectionId; private readonly providersByPublicToolName; /** * @param now Time provider used for recency ordering. */ constructor(now?: () => number); /** * Upserts source metadata from a browser `hello` message. * * `sourceId` currently matches `connectionId`, but remains conceptually distinct * so stable source identity can be introduced in the future. */ upsertSource(connectionId: string, hello: BrowserHelloMessage): void; /** * Replaces the full tool set for a source connection. */ registerTools(connectionId: string, tools: RelayTool[]): void; /** * Removes a source and all of its tool registrations. */ removeConnection(connectionId: string): void; /** * Marks a source as recently seen without mutating identity metadata. */ touchConnection(connectionId: string): void; /** * Lists active sources that currently publish at least one tool. */ listSources(): SourceInfo[]; /** * Lists aggregated tools ordered by public tool name. */ listTools(): AggregatedTool[]; /** * Resolves a tool invocation to a concrete source provider. * * Resolution order: * 1. `sourceId`: exact source id, then fallback to tab id. * 2. `requestTabId`: strict tab id match with no fallback. * 3. Default: most recently seen provider. */ resolveInvocation(options: { toolName: string; sourceId?: string; requestTabId?: string; }): ResolvedInvocation | null; /** * Converts internal source metadata to public source info. */ private toSourceInfo; /** * Rebuilds public tool names after source set changes. * * When the same original tool name appears in multiple tabs, names are * disambiguated with a short tab suffix. */ private rebuildPublicNames; /** * Returns providers sorted by source recency. */ private sortProvidersByRecency; /** * Compares two source recency tuples and stabilizes order by source id. */ private compareRecency; } //#endregion //#region src/bridgeServer.d.ts /** * Runtime options for {@link RelayBridgeServer}. */ interface RelayBridgeServerOptions { /** * Network interface used by the local WebSocket server. * @defaultValue `"127.0.0.1"` */ host?: string; /** * Preferred WebSocket port for browser widget connections. * @defaultValue `9333` */ port?: number; /** * Whether the preferred port came from an explicit CLI/API override. * Explicit ports fail if occupied by a non-relay process. * @defaultValue `false` */ portExplicitlySet?: boolean; /** * Inclusive upper bound for automatic port discovery. * @defaultValue `9348` */ portRangeEnd?: number; /** * File path used to cache the last successful relay port. * @defaultValue `~/.webmcp/relay-port.json` */ persistPath?: string; /** * Allowed host page origins verified from browser WebSocket requests. * Use `["*"]` to allow all origins. * * Permissive by default for zero-config developer experience: any browser * page can connect and register tools without additional setup. For production * or shared machines, restrict to trusted host origins via the * `--widget-origin` CLI flag or by passing explicit origins here. * * @defaultValue `["*"]` */ allowedOrigins?: string[]; /** * Maximum WebSocket payload size in bytes. * @defaultValue `10000000` */ maxPayloadBytes?: number; /** * Timeout used for browser tool invocations. * @defaultValue `65000` */ invokeTimeoutMs?: number; /** * Human-readable relay label reported in discovery handshakes. */ label?: string; /** * Optional workspace name reported in discovery handshakes. */ workspace?: string; /** * Stable relay identifier used to select between multiple relays. */ relayId?: string; } /** * WebSocket relay between browser widget frames and MCP server calls. * * Operates in two modes: * - **server** (default): Runs a WebSocket server, accepts browser and relay * client connections. * - **client** (fallback on EADDRINUSE): Connects as a WebSocket client to an * existing server relay and proxies tool operations through it. */ declare class RelayBridgeServer extends EventEmitter { /** * Registry for connected sources and aggregated tool definitions. * Only actively used in server mode; remains empty when operating as a client. */ readonly registry: RelayRegistry; private readonly host; private readonly preferredPort; private desiredPort; private readonly portExplicitlySet; private readonly portRangeEnd; private readonly persistPath; private readonly allowedOrigins; private readonly maxPayloadBytes; private readonly invokeTimeoutMs; private readonly label; private readonly workspace; private readonly relayId; private readonly instanceId; private wss; private readonly socketByConnectionId; private readonly requestOriginByConnectionId; private readonly pendingInvocations; private readonly browserClientConnectionIds; private readonly relayClientConnectionIds; private readonly heartbeatIntervalByConnectionId; private readonly lastPongByConnectionId; private readonly onStateChangedPushRelay; private _mode; private clientSocket; private clientReconnectTimer; private clientReconnectDelay; /** * Maximum delay for relay-to-relay reconnection backoff in client mode. */ private readonly clientMaxReconnectDelay; private readonly clientMaxReconnectAttempts; private clientReconnectAttempts; private readonly clientPendingInvocations; private clientTools; private clientSources; private clientToolSourceMap; private stopping; /** * Creates a relay bridge server instance. */ constructor(options?: RelayBridgeServerOptions, registry?: RelayRegistry); /** * Current operating mode. */ get mode(): 'server' | 'client'; /** * Resolved listening port. In client mode this is the port of the server * relay being proxied through. */ get port(): number; /** * Tools received from the server relay (client mode only). * Returns an empty array in server mode. */ listToolsFromRelay(): RelayTool[]; /** * Source metadata received from the server relay (client mode only). * Returns an empty array in server mode. */ listSourcesFromRelay(): RelaySourceInfo[]; /** * Tool-to-source mapping received from the server relay (client mode only). * Maps public tool names to arrays of source IDs. * Returns an empty record in server mode. */ getToolSourceMapFromRelay(): Record; /** * Starts the bridge. Attempts to bind a WebSocket server (server mode). * If a compatible relay already owns a candidate port, joins it in client mode. * If a non-relay process owns the port, continues searching the reserved range. */ start(): Promise; private startUsingPortStrategy; private isAddressInUseError; private persistSelectedPort; private tryAttachToExistingRelay; /** * Stops all relay resources and rejects any pending invocations. */ stop(): Promise; /** * Sends a reload message to a connected browser source. * Only supported in server mode. */ reloadSource(connectionId: string): void; /** * Invokes a tool either locally (server mode) or through the upstream relay * (client mode). */ invokeTool(toolName: string, args: RelayInvokeArgs, options?: { sourceId?: string; requestTabId?: string; }): Promise; private startAsServer; private buildServerHello; /** * `async` is load-bearing: {@link onRelayClientMessage} consumes this through * `.then(onResult, onError)`, so a synchronous throw would escape the socket * message handler as an uncaught exception and leave the relay client waiting * for a `relay/result` that never arrives. */ private invokeToolLocally; /** Handles a raw message according to the negotiated WebSocket protocol. */ private onSocketMessage; private onBrowserClientMessage; /** * Handles relay-protocol messages from relay client connections. */ private onRelayClientMessage; private sendRelayResult; /** * Pushes current tool state to all connected relay clients. */ private pushToolsToRelayClients; /** * Handles source disconnection and rejects in-flight calls owned by that source. * * Guarded against double-call: both 'error' and 'close' events fire on * socket failure, but cleanup (and the stateChanged emission) runs only once. */ private onSocketClose; private startHeartbeat; private stopHeartbeat; private startAsClient; private connectToRelayServer; private setupClientHandlers; private sendRelayClientHandshake; private parseRelayServerMessage; private processRelayServerMessage; private scheduleReconnect; /** * Attempts to promote from client to server mode when reconnecting. * Re-runs the same attach-or-bind strategy used during startup. */ private reconnectWithModePromotion; private invokeToolViaRelay; /** * Builds the complete relay response payload including tools and source metadata. */ private buildRelayToolsPayload; private isHostOriginAllowed; private sendHelloAccepted; private sendHelloRejected; /** * Validates browser tool results against CallToolResultSchema. * Non-conforming payloads are wrapped as error results with diagnostic text. */ private normalizeCallToolResult; /** * Converts WebSocket raw data variants to a UTF-8 string payload. */ private rawDataToUtf8; } //#endregion //#region src/cli-utils.d.ts /** * Parsed CLI options for relay startup. */ interface CliOptions { help: boolean; host: string; port: number; portExplicitlySet: boolean; allowedOrigins: string[]; label?: string; workspace?: string; relayId?: string; maxPayloadBytes?: number; invokeTimeoutMs?: number; } /** * Parses supported CLI flags for relay startup. */ declare function parseCliOptions(argv: string[]): CliOptions; /** * Prints CLI usage to stderr. */ declare function printHelp(): void; //#endregion //#region src/mcpRelayServer.d.ts /** * Base options shared by all {@link LocalRelayMcpServer} configurations. */ interface LocalRelayMcpServerBaseOptions { /** * MCP server name reported during initialization. */ serverName?: string; /** * MCP server version reported during initialization. */ serverVersion?: string; } /** * Construction options for {@link LocalRelayMcpServer}. * * Provide either an existing `bridge` instance OR `bridgeOptions` to create * one internally — not both. */ type LocalRelayMcpServerOptions = LocalRelayMcpServerBaseOptions & ({ bridge: RelayBridgeServer; bridgeOptions?: never; } | { bridge?: never; bridgeOptions?: RelayBridgeServerOptions; }); /** * MCP server facade that exposes browser-relayed tools over MCP transport. */ declare class LocalRelayMcpServer { /** * Underlying WebSocket bridge used for browser communication. */ readonly bridge: RelayBridgeServer; private readonly mcpServer; private readonly dynamicTools; private syncDebounceTimer; private connected; /** * Creates a local relay MCP server with static and dynamic tool registration. */ constructor(options?: LocalRelayMcpServerOptions); /** * Starts the browser bridge and synchronizes dynamic MCP tools. */ start(): Promise; /** * Connects the MCP server to a transport. * * This may be called exactly once per instance lifecycle. */ connect(transport: Transport): Promise; /** * Convenience helper that connects the server over stdio transport. */ startStdio(): Promise; /** * Stops MCP transport and bridge resources. */ stop(): Promise; /** * Returns dynamic tool names currently registered in MCP. */ listDynamicToolNames(): string[]; /** * Registers built-in management tools exposed by the relay. */ private registerStaticTools; /** * Opens a URL in the user's default browser using the platform open command. * * Passes the re-serialized `URL.href` directly to the platform launcher. * No shell or command-language string is involved. */ private openInBrowser; /** * Debounces rapid stateChanged events into a single sync pass. * * Browser reconnections emit multiple stateChanged events in quick * succession (hello, tools/list). Without debouncing, each triggers a * full sync that removes and re-registers tools — sending per-operation * notifications through the stdio transport and overwhelming the agent. */ private debouncedSyncDynamicTools; /** * Returns the current aggregated tool list, dispatching based on bridge mode. */ private listAggregatedTools; /** * Converts relay client tool descriptors to aggregated tool shape. * Populates per-tool source metadata from the relay's tool-source mapping. */ private buildAggregatedToolsFromRelay; /** * Applies current aggregated tool state to MCP dynamic registrations. */ private syncDynamicTools; /** * Registers a single dynamic tool and returns a removal handle. */ private registerDynamicTool; /** * Builds a display description for relayed tools including source context. * In client mode, source metadata is unavailable, so tools are labeled `[WebMCP relay]`. */ private dynamicToolDescription; /** * Produces a stable signature for change detection of dynamic tool metadata. * * Deliberately excludes `sourceId` (which is a per-connection UUID that * changes on every browser reconnect) so that a reconnecting tab with the * same tools does not trigger a needless remove+re-register cycle. */ private toolSignature; } //#endregion //#region src/naming.d.ts /** * Converts arbitrary text into MCP-safe identifier characters. */ declare function sanitizeName(value: string): string; /** * Extracts and sanitizes a domain label from an origin or URL. */ declare function extractSanitizedDomain(originOrUrl?: string): string; /** * Builds a public tool name for MCP registration. * * Names can include a short tab-id suffix when multiple tabs publish the same * original tool name. */ declare function buildPublicToolName(options: { originalToolName: string; tabId?: string; disambiguate?: boolean; }): string; //#endregion export { type AggregatedTool, type BrowserToRelayMessage, BrowserToRelayMessageSchema, CallToolRequestParamsSchema, CallToolResultSchema, type CliOptions, DEFAULT_TOOL_INPUT_SCHEMA, HelloRequiredError, InboundToolSchema, LocalRelayMcpServer, type LocalRelayMcpServerOptions, NormalizedToolSchema, RelayBridgeServer, type RelayBridgeServerOptions, type RelayCallToolResult, type RelayClientToServerMessage, RelayClientToServerMessageSchema, type RelayDescriptor, RelayDescriptorSchema, type RelayHelloAcceptedMessage, RelayHelloAcceptedMessageSchema, type RelayHelloRejectedMessage, RelayHelloRejectedMessageSchema, type RelayInvokeArgs, RelayInvokeArgsSchema, RelayRegistry, type RelayServerToClientMessage, RelayServerToClientMessageSchema, type RelaySourceInfo, RelaySourceInfoSchema, type RelayToBrowserMessage, RelayToBrowserMessageSchema, type RelayTool, type RelayToolAnnotations, type ResolvedInvocation, type ServerHelloMessage, ServerHelloMessageSchema, type SourceInfo, ToolAnnotationsSchema, ToolSchema, buildPublicToolName, extractSanitizedDomain, normalizeInboundTool, parseCliOptions, printHelp, sanitizeName }; //# sourceMappingURL=index.d.mts.map