@mcp-b/webmcp-ts-sdk 5.1.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -18
- package/dist/common-CRzM40Z0.d.ts +22 -0
- package/dist/index.d.ts +127 -18
- package/dist/index.js +207 -228
- package/dist/index.js.map +1 -1
- package/dist/schema-FbP7xLdQ.js +187 -0
- package/dist/schema-FbP7xLdQ.js.map +1 -0
- package/dist/schema.d.ts +18 -0
- package/dist/schema.js +3 -0
- package/package.json +12 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/browser-server.ts"],"sourcesContent":["import {\n coerceWebMcpToolDescriptor,\n createInvalidStateError,\n createToolInvocationFailedError,\n createUnknownError,\n isPlainObject,\n normalizeToolResponse,\n normalizeInputSchema,\n parseChromeToolInput,\n serializeChromeToolResult,\n toWebMcpAnnotations,\n validateExecutableOrigin,\n validatePotentiallyTrustworthyOrigins,\n validateWebMcpAccess,\n validateWebMcpToolDescriptor,\n withAbortSignal,\n} from '@mcp-b/webmcp-polyfill/schema';\nimport type { NormalizedInputSchema } from '@mcp-b/webmcp-polyfill/schema';\nimport type {\n ChromeModelContextExecuteToolOptions,\n ChromeModelContextExtensions,\n InputSchema,\n ModelContext,\n ModelContextGetToolOptions,\n ModelContextRegisterToolOptions,\n ModelContextTool,\n ModelContextWithExtensions,\n RegistrationHandle,\n RegisteredTool,\n ToolAnnotations,\n ToolDescriptor,\n ToolListItem,\n WebMcpToolInput,\n} from '@mcp-b/webmcp-types';\nimport {\n fromJsonSchema,\n isInputRequiredResult,\n McpServer,\n mergeCapabilities,\n ResourceTemplate,\n type GetPromptResult,\n type Implementation,\n type ReadResourceResult,\n type RegisteredPrompt as McpRegisteredPrompt,\n type RegisteredResource as McpRegisteredResource,\n type RegisteredResourceTemplate as McpRegisteredResourceTemplate,\n type RegisteredTool as McpRegisteredTool,\n type ServerOptions,\n type StandardSchemaWithJSON,\n type ToolAnnotations as McpToolAnnotations,\n type Transport,\n type Variables,\n} from '@modelcontextprotocol/server';\n\nconst DEFAULT_INPUT_SCHEMA = normalizeInputSchema(undefined).inputSchema;\nconst SERVER_MARKER_PROPERTY = '__isBrowserMcpServer' as const;\n\nexport function isBrowserMcpServer(context: unknown): context is BrowserMcpServer {\n return (\n typeof context === 'object' &&\n context !== null &&\n SERVER_MARKER_PROPERTY in context &&\n context[SERVER_MARKER_PROPERTY] === true\n );\n}\n\ninterface RegisteredWebMcpTool {\n item: ToolListItem;\n registeredInputSchema?: string;\n execute: (args: WebMcpToolInput, signal?: AbortSignal) => Promise<unknown>;\n mcpHandle: McpRegisteredTool | undefined;\n exposedTo?: readonly string[];\n abortSignal?: AbortSignal;\n abortListener?: () => void;\n}\n\ntype McpRegistration = McpRegisteredPrompt | McpRegisteredResource | McpRegisteredResourceTemplate;\n\nexport interface BrowserMcpServerOptions extends ServerOptions {\n native?: ModelContext;\n}\n\ntype NativeStandardToolsApi = ModelContext & {\n executeTool: NonNullable<ChromeModelContextExtensions['executeTool']>;\n};\ntype NativeRegisterToolFn = (\n tool: ModelContextTool<WebMcpToolInput>,\n options?: ModelContextRegisterToolOptions\n) => Promise<void>;\n\ninterface NativeBackfilledTool {\n source: RegisteredTool;\n item: ToolListItem;\n fingerprint: string;\n}\n\nfunction parseNativeToolResult(serialized: string | null): unknown {\n if (serialized === null) {\n return {\n content: [{ type: 'text', text: 'Tool execution interrupted by navigation' }],\n isError: true,\n };\n }\n\n let result: unknown;\n try {\n result = JSON.parse(serialized);\n } catch {\n return normalizeToolResponse(serialized);\n }\n return isInputRequiredResult(result) ? result : normalizeToolResponse(result);\n}\n\nfunction toMcpInputSchema(\n normalized: NormalizedInputSchema\n): StandardSchemaWithJSON<Record<string, unknown>> {\n // normalizeInputSchema() attaches a non-enumerable `~standard` when the caller supplied a\n // Standard Schema validator, so reuse it instead of recompiling the JSON Schema projection.\n const standardSchema = Object.getOwnPropertyDescriptor(normalized.inputSchema, '~standard');\n return standardSchema && !standardSchema.enumerable\n ? (normalized.inputSchema as unknown as StandardSchemaWithJSON<Record<string, unknown>>)\n : fromJsonSchema<Record<string, unknown>>(\n normalized.inputSchema as Parameters<typeof fromJsonSchema>[0]\n );\n}\n\nfunction toMcpAnnotations(\n annotations: ToolAnnotations | undefined\n): McpToolAnnotations | undefined {\n if (!annotations) return undefined;\n const { untrustedContentHint: _untrustedContentHint, ...mcpAnnotations } = annotations;\n return mcpAnnotations;\n}\n\nfunction toNativeTool(\n tool: ToolDescriptor<WebMcpToolInput>,\n inputSchema: InputSchema | undefined,\n execute: ModelContextTool<WebMcpToolInput>['execute']\n): ModelContextTool<WebMcpToolInput> {\n const annotations = tool.annotations ? toWebMcpAnnotations(tool.annotations) : undefined;\n return {\n name: tool.name,\n ...(tool.title !== undefined ? { title: tool.title } : {}),\n description: tool.description,\n ...(inputSchema !== undefined ? { inputSchema } : {}),\n ...(annotations ? { annotations } : {}),\n execute,\n };\n}\n\n/**\n * Thin WebMCP-to-MCP v2 adapter.\n *\n * The official v2 `McpServer` owns MCP registration, validation, and transport\n * behavior. This class only adds the document-facing WebMCP contract and native\n * Chrome mirroring.\n */\nexport class BrowserMcpServer extends EventTarget implements ModelContextWithExtensions {\n readonly [SERVER_MARKER_PROPERTY] = true as const;\n readonly mcpServer: McpServer;\n\n private readonly native: ModelContext | undefined;\n private readonly ownerDocument: Document | null;\n private readonly tools = new Map<string, RegisteredWebMcpTool>();\n private peerOrigin: string | undefined;\n private stopObservingPeerOrigin: (() => void) | undefined;\n private readonly registrations = new Set<McpRegistration>();\n private readonly nativeToolAbortControllers = new Map<string, AbortController>();\n private readonly nativeBackfilledTools = new Map<string, NativeBackfilledTool>();\n private readonly pendingTools = new Map<string, AbortController>();\n private readonly removingNativeTools = new Set<string>();\n private nativeSyncQueue: Promise<void> = Promise.resolve();\n private nativeToolChangeQueue: Promise<void> = Promise.resolve();\n private nativeToolChangeListener: EventListener | undefined;\n private closed = false;\n private closePromise: Promise<void> | undefined;\n private ontoolchangeHandler: ((this: ModelContext, event: Event) => unknown) | null = null;\n private readonly ontoolchangeListener: EventListener = (event) => {\n this.ontoolchangeHandler?.call(this, event);\n };\n\n constructor(serverInfo: Implementation, options: BrowserMcpServerOptions = {}) {\n super();\n const { native, ...serverOptions } = options;\n this.mcpServer = new McpServer(serverInfo, {\n ...serverOptions,\n capabilities: mergeCapabilities(serverOptions.capabilities ?? {}, {\n tools: { listChanged: true },\n resources: { listChanged: true },\n prompts: { listChanged: true },\n }),\n });\n this.native = native;\n this.ownerDocument = globalThis.document ?? null;\n if (\n native &&\n typeof native.addEventListener === 'function' &&\n typeof native.removeEventListener === 'function'\n ) {\n this.nativeToolChangeListener = () => {\n if (this.closed) return;\n this.nativeToolChangeQueue = this.nativeToolChangeQueue.then(async () => {\n try {\n await this.syncNativeTools();\n } catch (error) {\n console.warn('[BrowserMcpServer] Native WebMCP tool reconciliation failed:', error);\n }\n await this.notifyProducerToolsChanged();\n });\n };\n native.addEventListener('toolchange', this.nativeToolChangeListener);\n }\n }\n\n get ontoolchange(): ((this: ModelContext, event: Event) => unknown) | null {\n return this.ontoolchangeHandler;\n }\n\n set ontoolchange(handler: ((this: ModelContext, event: Event) => unknown) | null) {\n const listener = typeof handler === 'function' ? handler : null;\n if (listener === null) {\n this.ontoolchangeHandler = null;\n super.removeEventListener('toolchange', this.ontoolchangeListener);\n return;\n }\n\n if (this.ontoolchangeHandler === null) {\n super.addEventListener('toolchange', this.ontoolchangeListener);\n }\n this.ontoolchangeHandler = listener;\n }\n\n private async notifyProducerToolsChanged(): Promise<void> {\n if (this.closed) return;\n // Preserve task ordering because WebMCP does not expose its platform task source.\n await new Promise((resolve) => setTimeout(resolve, 0));\n if (!this.closed) this.dispatchEvent(new Event('toolchange'));\n }\n\n private getNativeStandardToolsApi(): NativeStandardToolsApi | undefined {\n const candidate: (ModelContext & Partial<ChromeModelContextExtensions>) | undefined =\n this.native;\n return candidate && typeof candidate.executeTool === 'function'\n ? (candidate as NativeStandardToolsApi)\n : undefined;\n }\n\n private async registerNativeToolMirror(\n tool: ToolDescriptor<WebMcpToolInput>,\n normalized: NormalizedInputSchema,\n options: ModelContextRegisterToolOptions,\n execute: RegisteredWebMcpTool['execute'],\n controller: AbortController\n ): Promise<void> {\n if (!this.native) return;\n\n // The overload set keys on a statically known inputSchema; mirrored tools carry a dynamic one.\n const nativeRegister = this.native.registerTool as unknown as NativeRegisterToolFn;\n const signal = options.signal\n ? AbortSignal.any([options.signal, controller.signal])\n : controller.signal;\n\n const nativeInputSchema =\n normalized.registeredInputSchema === undefined\n ? undefined\n : (JSON.parse(normalized.registeredInputSchema) as InputSchema);\n this.nativeToolAbortControllers.set(tool.name, controller);\n try {\n await nativeRegister.call(\n this.native,\n toNativeTool(tool, nativeInputSchema, (input) => execute(input)),\n { ...options, signal }\n );\n } catch (error) {\n controller.abort();\n if (this.nativeToolAbortControllers.get(tool.name) === controller) {\n this.nativeToolAbortControllers.delete(tool.name);\n }\n throw error;\n }\n if (this.nativeToolAbortControllers.get(tool.name) === controller) {\n this.removingNativeTools.delete(tool.name);\n }\n }\n\n private abortNativeToolMirror(\n name: string,\n controller = this.nativeToolAbortControllers.get(name)\n ): void {\n if (!controller || this.nativeToolAbortControllers.get(name) !== controller) return;\n this.removingNativeTools.add(name);\n controller.abort();\n this.nativeToolAbortControllers.delete(name);\n }\n\n private validateToolDescriptor(tool: ToolDescriptor<WebMcpToolInput>): NormalizedInputSchema {\n validateWebMcpToolDescriptor(tool);\n if (this.tools.has(tool.name) || this.pendingTools.has(tool.name)) {\n throw createInvalidStateError(`Tool already registered: ${tool.name}`);\n }\n return normalizeInputSchema(tool.inputSchema);\n }\n\n private registerToolInMcp(\n tool: ToolDescriptor<WebMcpToolInput>,\n normalized: NormalizedInputSchema,\n executeTool: RegisteredWebMcpTool['execute'],\n exposedTo: readonly string[] | undefined\n ): RegisteredWebMcpTool {\n const outputSchema =\n tool.outputSchema === undefined ? undefined : structuredClone(tool.outputSchema);\n const mcpOutputSchema =\n outputSchema === undefined\n ? undefined\n : fromJsonSchema(outputSchema as Parameters<typeof fromJsonSchema>[0]);\n const mcpAnnotations = toMcpAnnotations(tool.annotations);\n const mcpCompatibleInput =\n normalized.inputSchema.type === undefined || normalized.inputSchema.type === 'object';\n const mcpHandle = mcpCompatibleInput\n ? this.mcpServer.registerTool(\n tool.name,\n {\n ...(tool.title !== undefined ? { title: tool.title } : {}),\n description: tool.description,\n inputSchema: toMcpInputSchema(normalized),\n ...(mcpOutputSchema ? { outputSchema: mcpOutputSchema } : {}),\n ...(mcpAnnotations ? { annotations: mcpAnnotations } : {}),\n },\n async (args, context) => {\n const result = await executeTool(args, context.mcpReq.signal);\n if (isInputRequiredResult(result)) {\n throw new Error(\n `WebMCP tool \"${tool.name}\" returned input_required. Multi-round tool flows require BrowserMcpServer.mcpServer.registerTool().`\n );\n }\n return normalizeToolResponse(result);\n }\n )\n : undefined;\n // A restricted tool is never observable on the wire before its audience is\n // checked: the handle is disabled here, in the same synchronous step that created\n // it, and only applyToolExposure re-enables it.\n if (exposedTo?.length) mcpHandle?.disable();\n\n if (!mcpCompatibleInput) {\n console.warn(\n `[BrowserMcpServer] Tool \"${tool.name}\" remains available through WebMCP but cannot be exposed over MCP because MCP input schemas require an object root.`\n );\n }\n\n const item: ToolListItem = {\n name: tool.name,\n ...(tool.title !== undefined ? { title: tool.title } : {}),\n description: tool.description,\n inputSchema: normalized.inputSchema,\n ...(outputSchema === undefined ? {} : { outputSchema }),\n ...(tool.annotations ? { annotations: tool.annotations } : {}),\n };\n return {\n item,\n ...(normalized.registeredInputSchema !== undefined\n ? { registeredInputSchema: normalized.registeredInputSchema }\n : {}),\n execute: executeTool,\n mcpHandle,\n ...(exposedTo?.length ? { exposedTo } : {}),\n };\n }\n\n readonly registerTool: ModelContextWithExtensions['registerTool'] = async (\n toolValue: unknown,\n optionsValue: ModelContextRegisterToolOptions | null = {}\n ): Promise<void> => {\n const { signal, exposedTo } = optionsValue ?? {};\n const options = {\n ...(signal ? { signal } : {}),\n ...(exposedTo ? { exposedTo: [...exposedTo] } : {}),\n };\n validateWebMcpAccess(this.ownerDocument);\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (!isPlainObject(toolValue)) {\n throw new TypeError('registerTool(tool) requires a tool object');\n }\n const tool = coerceWebMcpToolDescriptor(toolValue);\n const normalized = this.validateToolDescriptor(tool);\n options.signal?.throwIfAborted();\n validatePotentiallyTrustworthyOrigins(options.exposedTo);\n options.signal?.throwIfAborted();\n const execute: RegisteredWebMcpTool['execute'] = async (args, signal) => {\n signal?.throwIfAborted();\n return withAbortSignal(\n Promise.resolve().then(() => Reflect.apply(tool.execute, undefined, [args])),\n signal\n );\n };\n const controller = new AbortController();\n let registered: RegisteredWebMcpTool | undefined;\n const abort = () => {\n if (this.pendingTools.get(tool.name) === controller) {\n this.pendingTools.delete(tool.name);\n }\n if (registered && this.tools.get(tool.name) === registered) {\n this.removeTool(tool.name);\n } else {\n this.abortNativeToolMirror(tool.name, controller);\n }\n };\n options.signal?.addEventListener('abort', abort, { once: true });\n this.pendingTools.set(tool.name, controller);\n try {\n await this.registerNativeToolMirror(tool, normalized, options, execute, controller);\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n options.signal?.throwIfAborted();\n registered = this.registerToolInMcp(\n tool,\n normalized,\n execute,\n options.exposedTo?.map((origin) => {\n const parsedOrigin = new URL(origin).origin;\n // Keep exact extension identifiers when this browser cannot parse their origin.\n return parsedOrigin === 'null' ? origin : parsedOrigin;\n })\n );\n this.tools.set(tool.name, registered);\n this.applyToolExposure();\n if (options.signal?.aborted) {\n abort();\n options.signal.throwIfAborted();\n }\n } catch (error) {\n this.abortNativeToolMirror(tool.name, controller);\n options.signal?.removeEventListener('abort', abort);\n options.signal?.throwIfAborted();\n throw error;\n } finally {\n if (this.pendingTools.get(tool.name) === controller) {\n this.pendingTools.delete(tool.name);\n }\n }\n if (options.signal) {\n registered.abortSignal = options.signal;\n registered.abortListener = abort;\n }\n if (this.tools.get(tool.name) === registered) {\n if (this.native) await this.nativeToolChangeQueue;\n else await this.notifyProducerToolsChanged();\n }\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n options.signal?.throwIfAborted();\n };\n\n private removeTool(name: string, options?: { skipNative?: boolean; notify?: boolean }): void {\n const registered = this.tools.get(name);\n if (registered) {\n if (registered.abortSignal && registered.abortListener) {\n registered.abortSignal.removeEventListener('abort', registered.abortListener);\n }\n this.tools.delete(name);\n this.nativeBackfilledTools.delete(name);\n registered.mcpHandle?.remove();\n if ((options?.notify ?? true) && !this.native) {\n void this.notifyProducerToolsChanged();\n }\n }\n if (!options?.skipNative) this.abortNativeToolMirror(name);\n }\n\n syncNativeTools(): Promise<void> {\n const sync = this.nativeSyncQueue.then(async () => {\n if (this.closed) return;\n const native = this.getNativeStandardToolsApi();\n if (native) await this.backfillNativeStandardTools(native);\n });\n this.nativeSyncQueue = sync.then(\n () => undefined,\n () => undefined\n );\n return sync;\n }\n\n private async backfillNativeStandardTools(native: NativeStandardToolsApi): Promise<void> {\n const tools = await native.getTools();\n if (this.closed) return;\n const nextTools = new Map<string, NativeBackfilledTool>();\n const nativeNames = new Set(tools.map(({ name }) => name));\n for (const name of this.removingNativeTools) {\n if (!nativeNames.has(name)) this.removingNativeTools.delete(name);\n }\n for (const tool of tools) {\n // ponytail: MCP tool names are global, so keep the first valid visible tool.\n // Add origin-qualified aliases if MCP gains scoped tool identity.\n if (\n nextTools.has(tool.name) ||\n this.pendingTools.has(tool.name) ||\n this.removingNativeTools.has(tool.name)\n ) {\n continue;\n }\n let inputSchema: InputSchema | undefined = DEFAULT_INPUT_SCHEMA;\n if (tool.inputSchema !== undefined) {\n try {\n // An object since webmcp#241; a serialized string from older Chrome. The\n // round-trip detaches the object from the page's graph and rejects non-JSON.\n const serialized =\n typeof tool.inputSchema === 'string'\n ? tool.inputSchema\n : JSON.stringify(tool.inputSchema);\n const parsed: unknown = JSON.parse(serialized);\n inputSchema = isPlainObject(parsed) ? (parsed as InputSchema) : undefined;\n } catch {\n inputSchema = undefined;\n }\n }\n if (!inputSchema) {\n console.warn(\n `[BrowserMcpServer] Native tool \"${tool.name}\" was not exposed over MCP because its input schema is malformed.`\n );\n continue;\n }\n const item: ToolListItem = {\n name: tool.name,\n ...(tool.title !== undefined ? { title: tool.title } : {}),\n description: tool.description,\n inputSchema,\n ...(tool.annotations ? { annotations: tool.annotations } : {}),\n };\n nextTools.set(tool.name, {\n source: tool,\n item,\n fingerprint: JSON.stringify(item),\n });\n }\n\n for (const [name, current] of this.nativeBackfilledTools) {\n const next = nextTools.get(name);\n if (!next || next.fingerprint !== current.fingerprint) {\n this.removeTool(name, { skipNative: true, notify: false });\n continue;\n }\n this.nativeBackfilledTools.set(name, next);\n }\n\n for (const [name, next] of nextTools) {\n if (this.tools.has(name)) continue;\n const execute = async (args: WebMcpToolInput, signal?: AbortSignal) => {\n const currentTool = this.nativeBackfilledTools.get(name)?.source;\n if (!currentTool) throw new Error(`Native tool not found: ${name}`);\n const input = JSON.stringify(args);\n return parseNativeToolResult(\n signal\n ? await native.executeTool.call(this.native, currentTool, input, { signal })\n : await native.executeTool.call(this.native, currentTool, input)\n );\n };\n const tool: ToolDescriptor<WebMcpToolInput> = {\n name,\n ...(next.item.title !== undefined ? { title: next.item.title } : {}),\n description: next.item.description,\n inputSchema: next.item.inputSchema,\n ...(next.item.annotations ? { annotations: next.item.annotations } : {}),\n execute: (args) => execute(args),\n };\n try {\n const normalized = this.validateToolDescriptor(tool);\n // Native getTools() does not report the allowlist a tool registered with, so a\n // backfilled mirror carries none and stays as widely exposed as it is today.\n this.tools.set(tool.name, this.registerToolInMcp(tool, normalized, execute, undefined));\n this.nativeBackfilledTools.set(name, next);\n } catch (error) {\n console.warn(\n `[BrowserMcpServer] Native tool \"${name}\" was not exposed over MCP because its schema could not be compiled:`,\n error\n );\n }\n }\n }\n\n registerResource(descriptor: ResourceDescriptor): RegistrationHandle {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n const registeredDescriptor = { ...descriptor };\n const config = {\n ...(registeredDescriptor.description !== undefined\n ? { description: registeredDescriptor.description }\n : {}),\n ...(registeredDescriptor.mimeType !== undefined\n ? { mimeType: registeredDescriptor.mimeType }\n : {}),\n };\n const template = registeredDescriptor.uri.includes('{')\n ? new ResourceTemplate(registeredDescriptor.uri, { list: undefined })\n : undefined;\n const mcpHandle = template\n ? this.mcpServer.registerResource(\n registeredDescriptor.name,\n template,\n config,\n async (uri, variables) => registeredDescriptor.read(uri, variables)\n )\n : this.mcpServer.registerResource(\n registeredDescriptor.name,\n registeredDescriptor.uri,\n config,\n async (uri) => registeredDescriptor.read(uri)\n );\n this.registrations.add(mcpHandle);\n return {\n unregister: () => {\n if (this.registrations.delete(mcpHandle)) mcpHandle.remove();\n },\n };\n }\n\n registerPrompt(descriptor: PromptDescriptor): RegistrationHandle {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n const registeredDescriptor = {\n ...descriptor,\n ...(descriptor.argsSchema === undefined\n ? {}\n : { argsSchema: structuredClone(descriptor.argsSchema) }),\n };\n const argsSchema =\n registeredDescriptor.argsSchema === undefined\n ? undefined\n : fromJsonSchema<Record<string, string>>(\n registeredDescriptor.argsSchema as Parameters<typeof fromJsonSchema>[0]\n );\n const mcpHandle = this.mcpServer.registerPrompt(\n registeredDescriptor.name,\n {\n ...(registeredDescriptor.description !== undefined\n ? { description: registeredDescriptor.description }\n : {}),\n ...(argsSchema ? { argsSchema } : {}),\n },\n async (args) => registeredDescriptor.get(args ?? {})\n );\n this.registrations.add(mcpHandle);\n return {\n unregister: () => {\n if (this.registrations.delete(mcpHandle)) mcpHandle.remove();\n },\n };\n }\n\n listTools(): ToolListItem[] {\n return structuredClone([...this.tools.values()].map(({ item }) => item));\n }\n\n async getTools(options?: ModelContextGetToolOptions): Promise<RegisteredTool[]> {\n validateWebMcpAccess(this.ownerDocument);\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (this.native) {\n return this.native.getTools(options);\n }\n validatePotentiallyTrustworthyOrigins(options?.fromOrigins);\n if (options?.fromOrigins?.length) {\n throw new DOMException(\n 'Cross-document tool discovery requires native WebMCP',\n 'NotSupportedError'\n );\n }\n\n const origin = globalThis.location?.origin ?? '';\n const currentWindow = globalThis.window;\n\n const tools = [...this.tools.values()]\n .map(({ item, registeredInputSchema }) => {\n // A fresh object per call, aligned with the polyfill's post-webmcp#241\n // shape. A custom toJSON can serialize to non-object JSON; omit those\n // rather than emit a value consumers would mistake for a pre-154\n // serialized string.\n const parsed: unknown =\n registeredInputSchema === undefined ? undefined : JSON.parse(registeredInputSchema);\n return {\n name: item.name,\n title: item.title ?? '',\n description: item.description,\n ...(isPlainObject(parsed) ? { inputSchema: parsed } : {}),\n origin,\n window: currentWindow,\n ...(item.annotations ? { annotations: toWebMcpAnnotations(item.annotations) } : {}),\n };\n })\n .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));\n await new Promise((resolve) => setTimeout(resolve, 0));\n return tools;\n }\n\n async executeTool(\n tool: RegisteredTool,\n inputArgsJson: string,\n options?: ChromeModelContextExecuteToolOptions\n ): Promise<string | null> {\n validateWebMcpAccess(this.ownerDocument);\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n const native = this.getNativeStandardToolsApi();\n if (native) {\n return native.executeTool.call(this.native, tool, inputArgsJson, options);\n }\n\n if (tool === null || typeof tool !== 'object') {\n throw new TypeError('RegisteredTool must be an object');\n }\n for (const required of ['name', 'description', 'window', 'origin'] as const) {\n if (!(required in tool)) {\n throw new TypeError(`RegisteredTool.${required} is required`);\n }\n }\n validateExecutableOrigin(tool.origin);\n const origin = globalThis.location?.origin ?? '';\n const currentWindow = globalThis.window;\n if (tool.origin !== origin || tool.window !== currentWindow) {\n throw createUnknownError(`Native tool not found: ${tool.name}`);\n }\n options?.signal?.throwIfAborted();\n const registered = this.tools.get(tool.name);\n if (!registered) throw createUnknownError(`Tool not found: ${tool.name}`);\n const args = parseChromeToolInput(inputArgsJson);\n try {\n const result = await withAbortSignal(\n registered.execute(args, options?.signal),\n registered.abortSignal,\n () => createUnknownError('Tool unregistered')\n );\n return serializeChromeToolResult(result);\n } catch (error) {\n if (options?.signal?.aborted && error === options.signal.reason) throw error;\n if (registered.abortSignal?.aborted) throw error;\n throw createToolInvocationFailedError(error);\n }\n }\n\n /**\n * Re-evaluate which registered tools may appear on the wire.\n *\n * `exposedTo` narrows a tool to named embedder origins. The peer origin is only known\n * once a transport that reports one has heard from its peer, so a restricted tool stays\n * disabled until then — and stays disabled forever on transports that cannot name a peer\n * at all. Failing closed keeps a tool that asked for a narrow audience from reaching a\n * wider one; unrestricted tools are untouched and behave exactly as before.\n */\n private applyToolExposure(): void {\n for (const { exposedTo, mcpHandle } of this.tools.values()) {\n if (!exposedTo?.length || !mcpHandle) continue;\n // Opaque origins serialize identically and cannot identify an allowed peer.\n const visible =\n this.peerOrigin !== undefined &&\n this.peerOrigin !== 'null' &&\n exposedTo.includes(this.peerOrigin);\n if (visible === mcpHandle.enabled) continue;\n if (visible) mcpHandle.enable();\n else mcpHandle.disable();\n }\n }\n\n /**\n * Follow the peer origin of transports that report one, so `exposedTo` can be scoped to\n * the embedder actually connected. Duck-typed rather than imported: the SDK must not take\n * a build dependency on `@mcp-b/transports`, and transports that never name a peer simply\n * leave every restricted tool disabled.\n */\n private observePeerOrigin(transport: Transport): void {\n this.stopObservingPeerOrigin?.();\n this.stopObservingPeerOrigin = undefined;\n this.peerOrigin = undefined;\n this.applyToolExposure();\n if (!('clientOrigin' in transport)) return;\n const peered = transport as Transport & {\n clientOrigin?: string;\n onclientorigin?: ((origin: string) => void) | undefined;\n };\n this.peerOrigin = peered.clientOrigin;\n this.applyToolExposure();\n const previous = peered.onclientorigin;\n let observing = true;\n const onclientorigin = (origin: string) => {\n previous?.(origin);\n if (!observing) return;\n this.peerOrigin = origin;\n this.applyToolExposure();\n };\n peered.onclientorigin = onclientorigin;\n this.stopObservingPeerOrigin = () => {\n observing = false;\n if (peered.onclientorigin === onclientorigin) peered.onclientorigin = previous;\n };\n }\n\n async connect(transport: Transport): Promise<void> {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (this.mcpServer.server.transport) {\n throw createInvalidStateError('BrowserMcpServer is already connected');\n }\n this.observePeerOrigin(transport);\n const stopObserving = this.stopObservingPeerOrigin;\n try {\n await this.mcpServer.connect(transport);\n } catch (error) {\n if (this.stopObservingPeerOrigin === stopObserving) {\n stopObserving?.();\n this.stopObservingPeerOrigin = undefined;\n this.peerOrigin = undefined;\n this.applyToolExposure();\n }\n if (this.mcpServer.server.transport === transport) await this.mcpServer.close();\n throw error;\n }\n }\n\n close(): Promise<void> {\n if (this.closePromise) return this.closePromise;\n this.closed = true;\n this.stopObservingPeerOrigin?.();\n this.stopObservingPeerOrigin = undefined;\n this.closePromise = (async () => {\n if (this.native && this.nativeToolChangeListener) {\n this.native.removeEventListener('toolchange', this.nativeToolChangeListener);\n this.nativeToolChangeListener = undefined;\n }\n for (const name of this.nativeToolAbortControllers.keys()) {\n this.abortNativeToolMirror(name);\n }\n for (const name of this.tools.keys()) {\n this.removeTool(name, { notify: false });\n }\n for (const handle of this.registrations) handle.remove();\n this.registrations.clear();\n this.nativeBackfilledTools.clear();\n this.removingNativeTools.clear();\n await this.mcpServer.close();\n })();\n return this.closePromise;\n }\n}\n\nexport interface ResourceDescriptor {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n read: (uri: URL, params?: Variables) => Promise<ReadResourceResult>;\n}\n\nexport interface PromptDescriptor {\n name: string;\n description?: string;\n argsSchema?: InputSchema;\n get: (args: Record<string, string>) => Promise<GetPromptResult>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/browser-server.ts"],"sourcesContent":["import type { WebMCP } from 'webmcp-types';\nimport { installWebMCP } from '@mcp-b/webmcp-polyfill';\nimport {\n coerceWebMcpToolDescriptor,\n createInvalidStateError,\n isPlainObject,\n serializeInputSchema,\n type ToolRegistrationDictionary,\n} from './normalize.js';\nimport {\n isMcpStandardSchema,\n normalizeInputSchema,\n normalizeToolResponse,\n type NormalizedInputSchema,\n} from './schema.js';\nimport type {\n ModelContext,\n ModelContextGetToolOptions,\n ModelContextRegisterToolOptions,\n ModelContextWithExtensions,\n RegisteredTool,\n} from './model-context.js';\nimport type {\n CallToolResult,\n InputSchema,\n RegistrationHandle,\n WebMcpToolInput,\n WebMcpToolObjectInput,\n} from './common.js';\nimport type { ModelContextTool, ToolDescriptor, ToolListItem } from './tool.js';\nimport {\n fromJsonSchema,\n isInputRequiredResult,\n McpServer,\n mergeCapabilities,\n ResourceTemplate,\n type GetPromptResult,\n type Implementation,\n type ReadResourceResult,\n type ResourceMetadata,\n type RegisteredPrompt as McpRegisteredPrompt,\n type RegisteredResource as McpRegisteredResource,\n type RegisteredResourceTemplate as McpRegisteredResourceTemplate,\n type RegisteredTool as McpRegisteredTool,\n type ServerOptions,\n type StandardSchemaWithJSON,\n type Transport,\n type Variables,\n} from '@modelcontextprotocol/server';\n\nconst DEFAULT_INPUT_SCHEMA = normalizeInputSchema(undefined).inputSchema;\nconst SERVER_MARKER_PROPERTY = '__isBrowserMcpServer' as const;\n\nexport function isBrowserMcpServer(context: unknown): context is BrowserMcpServer {\n return (\n typeof context === 'object' &&\n context !== null &&\n SERVER_MARKER_PROPERTY in context &&\n context[SERVER_MARKER_PROPERTY] === true\n );\n}\n\nexport interface PeerOriginTransport extends Transport {\n clientOrigin?: string | undefined;\n onclientorigin?: ((origin: string) => void) | undefined;\n}\n\nfunction isPeerOriginTransport(transport: Transport): transport is PeerOriginTransport {\n return (\n 'clientOrigin' in transport &&\n (transport.clientOrigin === undefined || typeof transport.clientOrigin === 'string') &&\n (!('onclientorigin' in transport) ||\n transport.onclientorigin === undefined ||\n typeof transport.onclientorigin === 'function')\n );\n}\n\ninterface RegisteredWebMcpTool {\n item: ToolListItem;\n mcpHandle: McpRegisteredTool | undefined;\n exposedTo?: readonly string[];\n abortSignal?: AbortSignal;\n abortListener?: () => void;\n}\n\ntype McpRegistration = McpRegisteredPrompt | McpRegisteredResource | McpRegisteredResourceTemplate;\ntype ModelContextEventHandler = ModelContext['ontoolchange'];\n\nexport interface BrowserMcpServerOptions extends ServerOptions {\n /** Underlying context. Defaults to document.modelContext, installing upstream if needed. */\n native?: ModelContext;\n}\n\ninterface NativeBackfilledTool {\n source: RegisteredTool;\n item: ToolListItem;\n fingerprint: string;\n}\n\nfunction parseNativeToolResult(serialized: string): CallToolResult | WebMcpToolObjectInput {\n let result: unknown;\n try {\n result = JSON.parse(serialized);\n } catch {\n // Native declarative tools return plain text for string responses.\n result = serialized;\n }\n if (isPlainObject(result)) return result;\n // Strings cross as their content; every other value keeps its original text.\n return { content: [{ type: 'text', text: typeof result === 'string' ? result : serialized }] };\n}\n\n/** Runs `operation` in a microtask; rejects with the reason as soon as `signal` aborts. */\nfunction withAbortSignal<T>(operation: () => T | PromiseLike<T>, signal: AbortSignal): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n signal.throwIfAborted();\n const onAbort = () => reject(signal.reason);\n signal.addEventListener('abort', onAbort, { once: true });\n Promise.resolve()\n .then(operation)\n .then(resolve, reject)\n .finally(() => signal.removeEventListener('abort', onAbort));\n });\n}\n\nfunction toMcpInputSchema(\n normalized: NormalizedInputSchema\n): StandardSchemaWithJSON<WebMcpToolObjectInput> {\n // normalizeInputSchema() keeps the caller's Standard Schema validator on the converted\n // schema, so reuse it instead of recompiling the JSON Schema projection.\n if (isMcpStandardSchema(normalized.inputSchema)) return normalized.inputSchema;\n // SAFETY: normalizeInputSchema returns a plain JSON object whose keywords may exceed the SDK's\n // declared JSON Schema type; fromJsonSchema compiles it and validates its dialect at runtime.\n return fromJsonSchema<WebMcpToolObjectInput>(\n normalized.inputSchema as Parameters<typeof fromJsonSchema>[0]\n );\n}\n\n/**\n * Thin WebMCP-to-MCP v2 adapter.\n *\n * The official v2 `McpServer` owns MCP registration, validation, and transport\n * behavior. This class extends the upstream WebMCP context with MCP capabilities.\n */\nexport class BrowserMcpServer extends EventTarget implements ModelContextWithExtensions {\n readonly [SERVER_MARKER_PROPERTY] = true as const;\n readonly mcpServer: McpServer;\n\n private readonly native: ModelContext | undefined;\n private readonly ownerDocument: Document | null;\n private readonly tools = new Map<string, RegisteredWebMcpTool>();\n private peerOrigin: string | undefined;\n private stopObservingPeerOrigin: (() => void) | undefined;\n private readonly registrations = new Set<McpRegistration>();\n private readonly nativeToolAbortControllers = new Map<string, AbortController>();\n private readonly nativeBackfilledTools = new Map<string, NativeBackfilledTool>();\n private readonly pendingTools = new Map<string, AbortController>();\n private readonly removingNativeTools = new Set<string>();\n private nativeSyncQueue: Promise<void> = Promise.resolve();\n private nativeToolChangeQueue: Promise<void> = Promise.resolve();\n private readonly nativeToolChangeListener: () => void;\n private closed = false;\n private closePromise: Promise<void> | undefined;\n private readonly eventHandlers = new Map<string, NonNullable<ModelContextEventHandler>>();\n private readonly eventHandlerListener: EventListener = (event) => {\n this.eventHandlers.get(event.type)?.call(this, event);\n };\n // Lifecycle events fire at the underlying context; listeners on the extended\n // document context see them through this target.\n private readonly nativeLifecycleListener: EventListener = (event) => {\n if (this.closed) return;\n const mirrored = new Event(event.type);\n if ('toolName' in event) {\n Object.defineProperty(mirrored, 'toolName', { enumerable: true, value: event.toolName });\n }\n this.dispatchEvent(mirrored);\n };\n\n constructor(serverInfo: Implementation, options: BrowserMcpServerOptions = {}) {\n super();\n const { native: suppliedContext, ...serverOptions } = options;\n if (!suppliedContext && !globalThis.document?.modelContext) installWebMCP();\n this.mcpServer = new McpServer(serverInfo, {\n ...serverOptions,\n capabilities: mergeCapabilities(serverOptions.capabilities ?? {}, {\n tools: { listChanged: true },\n resources: { listChanged: true },\n prompts: { listChanged: true },\n }),\n });\n // Outside a secure document no context exists; the server then serves MCP only.\n this.native = suppliedContext ?? globalThis.document?.modelContext;\n this.ownerDocument = globalThis.document ?? null;\n this.nativeToolChangeListener = () => {\n if (this.closed) return;\n this.nativeToolChangeQueue = this.nativeToolChangeQueue.then(async () => {\n try {\n await this.syncNativeTools();\n } catch (error) {\n console.warn('[BrowserMcpServer] Native WebMCP tool reconciliation failed:', error);\n }\n await this.notifyProducerToolsChanged();\n });\n };\n this.native?.addEventListener('toolchange', this.nativeToolChangeListener);\n this.native?.addEventListener('toolactivated', this.nativeLifecycleListener);\n this.native?.addEventListener('toolcancel', this.nativeLifecycleListener);\n }\n\n private getEventHandler(type: string): ModelContextEventHandler {\n return this.eventHandlers.get(type) ?? null;\n }\n\n private setEventHandler(type: string, handler: ModelContextEventHandler): void {\n if (typeof handler === 'function') {\n if (!this.eventHandlers.has(type)) super.addEventListener(type, this.eventHandlerListener);\n this.eventHandlers.set(type, handler);\n } else if (this.eventHandlers.delete(type)) {\n super.removeEventListener(type, this.eventHandlerListener);\n }\n }\n\n get ontoolchange(): ModelContextEventHandler {\n return this.getEventHandler('toolchange');\n }\n\n set ontoolchange(handler: ModelContextEventHandler) {\n this.setEventHandler('toolchange', handler);\n }\n\n get ontoolactivated(): ModelContextEventHandler {\n return this.getEventHandler('toolactivated');\n }\n\n set ontoolactivated(handler: ModelContextEventHandler) {\n this.setEventHandler('toolactivated', handler);\n }\n\n get ontoolcancel(): ModelContextEventHandler {\n return this.getEventHandler('toolcancel');\n }\n\n set ontoolcancel(handler: ModelContextEventHandler) {\n this.setEventHandler('toolcancel', handler);\n }\n\n private async notifyProducerToolsChanged(): Promise<void> {\n if (this.closed) return;\n // Preserve task ordering because WebMCP does not expose its platform task source.\n await new Promise((resolve) => setTimeout(resolve, 0));\n if (!this.closed) this.dispatchEvent(new Event('toolchange'));\n }\n\n private async registerNativeToolMirror(\n tool: ToolDescriptor<WebMcpToolInput>,\n normalized: NormalizedInputSchema,\n options: ModelContextRegisterToolOptions,\n execute: ModelContextTool<WebMcpToolInput>['execute'],\n controller: AbortController\n ): Promise<void> {\n const native = this.native;\n if (!native) return;\n const signal = options.signal\n ? AbortSignal.any([options.signal, controller.signal])\n : controller.signal;\n const nativeTool: WebMCP.ModelContextTool = {\n name: tool.name,\n description: tool.description,\n execute,\n };\n if (tool.title !== undefined) nativeTool.title = tool.title;\n if (normalized.registeredInputSchema !== undefined) {\n const inputSchema: unknown = JSON.parse(normalized.registeredInputSchema);\n if (!isPlainObject(inputSchema)) throw new TypeError('inputSchema must be an object');\n nativeTool.inputSchema = inputSchema;\n }\n if (tool.annotations) nativeTool.annotations = tool.annotations;\n\n this.nativeToolAbortControllers.set(tool.name, controller);\n try {\n await native.registerTool(nativeTool, { ...options, signal });\n } catch (error) {\n controller.abort();\n if (this.nativeToolAbortControllers.get(tool.name) === controller) {\n this.nativeToolAbortControllers.delete(tool.name);\n }\n // A frame without allow=\"tools\" can still serve the tool over MCP, as in 5.x.\n if (error instanceof DOMException && error.name === 'NotAllowedError') {\n console.warn(\n `[BrowserMcpServer] Tool \"${tool.name}\" is available over MCP only: ${error.message}. Grant allow=\"tools\" on the iframe to expose it to WebMCP.`\n );\n return;\n }\n throw error;\n }\n if (this.nativeToolAbortControllers.get(tool.name) === controller) {\n this.removingNativeTools.delete(tool.name);\n }\n }\n\n private abortNativeToolMirror(\n name: string,\n controller = this.nativeToolAbortControllers.get(name)\n ): void {\n if (!controller || this.nativeToolAbortControllers.get(name) !== controller) return;\n this.removingNativeTools.add(name);\n controller.abort();\n this.nativeToolAbortControllers.delete(name);\n }\n\n private registerToolInMcp(\n tool: ToolDescriptor<WebMcpToolInput>,\n normalized: NormalizedInputSchema,\n executeTool: ModelContextTool<WebMcpToolInput>['execute'],\n exposedTo?: readonly string[]\n ): RegisteredWebMcpTool {\n const item: ToolListItem = {\n name: tool.name,\n description: tool.description,\n inputSchema: normalized.inputSchema,\n };\n if (tool.title !== undefined) item.title = tool.title;\n if (tool.outputSchema !== undefined) item.outputSchema = structuredClone(tool.outputSchema);\n if (tool.annotations) item.annotations = tool.annotations;\n\n const config: Omit<Parameters<McpServer['registerTool']>[1], 'inputSchema' | 'outputSchema'> & {\n inputSchema?: ReturnType<typeof toMcpInputSchema>;\n outputSchema?: ReturnType<typeof fromJsonSchema>;\n } = {\n description: tool.description,\n };\n if (item.outputSchema !== undefined) config.outputSchema = fromJsonSchema(item.outputSchema);\n if (tool.title !== undefined) config.title = tool.title;\n if (tool.annotations) {\n const { untrustedContentHint: _untrustedContentHint, ...annotations } = tool.annotations;\n config.annotations = annotations;\n }\n let mcpHandle: McpRegisteredTool | undefined;\n if (normalized.inputSchema.type === undefined || normalized.inputSchema.type === 'object') {\n config.inputSchema = toMcpInputSchema(normalized);\n mcpHandle = this.mcpServer.registerTool(tool.name, config, async (args, context) => {\n const result = await executeTool(args, { signal: context.mcpReq.signal });\n if (isInputRequiredResult(result)) {\n throw new Error(\n `WebMCP tool \"${tool.name}\" returned input_required. Multi-round tool flows require BrowserMcpServer.mcpServer.registerTool().`\n );\n }\n return normalizeToolResponse(result);\n });\n // A tool is never observable on the wire before it is published: the handle is\n // disabled here, in the same synchronous step that created it, and only\n // applyToolExposure enables it.\n mcpHandle.disable();\n } else {\n console.warn(\n `[BrowserMcpServer] Tool \"${tool.name}\" remains available through WebMCP but cannot be exposed over MCP because MCP input schemas require an object root.`\n );\n }\n\n const registered: RegisteredWebMcpTool = { item, mcpHandle };\n if (exposedTo?.length) registered.exposedTo = exposedTo;\n return registered;\n }\n\n readonly registerTool: ModelContextWithExtensions['registerTool'] = async (\n toolValue: ToolRegistrationDictionary,\n optionsValue: ModelContextRegisterToolOptions | null = {}\n ): Promise<void> => {\n const { signal, exposedTo } = optionsValue ?? {};\n const options: ModelContextRegisterToolOptions = {};\n if (signal) options.signal = signal;\n if (exposedTo) options.exposedTo = [...exposedTo];\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (!isPlainObject(toolValue)) {\n throw new TypeError('registerTool(tool) requires a tool object');\n }\n const tool = coerceWebMcpToolDescriptor(toolValue);\n // Upstream keys names per document, so only local and pending registrations\n // collide; a mirror of another document's tool yields once native accepts.\n if (\n (this.tools.has(tool.name) && !this.nativeBackfilledTools.has(tool.name)) ||\n this.pendingTools.has(tool.name)\n ) {\n throw createInvalidStateError(`Tool already registered: ${tool.name}`);\n }\n const normalized = normalizeInputSchema(tool.inputSchema);\n options.signal?.throwIfAborted();\n const callback = tool.execute;\n const execute: ModelContextTool<WebMcpToolInput>['execute'] = (args, options) =>\n withAbortSignal(() => callback(args, options), options.signal);\n const controller = new AbortController();\n // An unparsable entry reaches the context, which rejects it with its own error.\n const exposedOrigins = options.exposedTo?.map((origin) => URL.parse(origin)?.origin ?? origin);\n // `registered` owns the MCP handle until the tool is published or the handle is released.\n let registered: RegisteredWebMcpTool | undefined;\n const abort = () => {\n if (this.pendingTools.get(tool.name) === controller) {\n this.pendingTools.delete(tool.name);\n }\n if (registered && this.tools.get(tool.name) === registered) {\n this.removeTool(tool.name);\n } else {\n registered?.mcpHandle?.remove();\n this.abortNativeToolMirror(tool.name, controller);\n }\n registered = undefined;\n };\n options.signal?.addEventListener('abort', abort, { once: true });\n this.pendingTools.set(tool.name, controller);\n try {\n // The MCP side compiles before other frames can see the tool. A mirror of\n // another document's tool keeps the MCP name until native accepts this one.\n if (!this.nativeBackfilledTools.has(tool.name)) {\n registered = this.registerToolInMcp(tool, normalized, execute, exposedOrigins);\n }\n options.signal?.throwIfAborted();\n await this.registerNativeToolMirror(tool, normalized, options, execute, controller);\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n options.signal?.throwIfAborted();\n this.removeTool(tool.name, { skipNative: true });\n registered ??= this.registerToolInMcp(tool, normalized, execute, exposedOrigins);\n this.tools.set(tool.name, registered);\n this.applyToolExposure();\n if (options.signal?.aborted) {\n abort();\n options.signal.throwIfAborted();\n }\n } catch (error) {\n registered?.mcpHandle?.remove();\n this.abortNativeToolMirror(tool.name, controller);\n options.signal?.removeEventListener('abort', abort);\n options.signal?.throwIfAborted();\n throw error;\n } finally {\n if (this.pendingTools.get(tool.name) === controller) {\n this.pendingTools.delete(tool.name);\n }\n }\n if (options.signal) {\n registered.abortSignal = options.signal;\n registered.abortListener = abort;\n }\n if (this.tools.get(tool.name) === registered) {\n await this.nativeToolChangeQueue;\n }\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n options.signal?.throwIfAborted();\n };\n\n private removeTool(name: string, options?: { skipNative?: boolean }): void {\n const registered = this.tools.get(name);\n if (registered) {\n if (registered.abortSignal && registered.abortListener) {\n registered.abortSignal.removeEventListener('abort', registered.abortListener);\n }\n this.tools.delete(name);\n this.nativeBackfilledTools.delete(name);\n registered.mcpHandle?.remove();\n }\n if (!options?.skipNative) this.abortNativeToolMirror(name);\n }\n\n syncNativeTools(): Promise<void> {\n const native = this.native;\n const sync = this.nativeSyncQueue.then(async () => {\n if (this.closed || !native) return;\n await this.backfillNativeStandardTools(native);\n });\n this.nativeSyncQueue = sync.then(\n () => undefined,\n () => undefined\n );\n return sync;\n }\n\n private async backfillNativeStandardTools(native: ModelContext): Promise<void> {\n // A top-level server serves its subtree; a framed one serves only its own\n // document, so an embedder cannot reach same-origin children through the\n // framed page, and ancestor or sibling tools never feed iframe bridges back\n // into their source.\n const ownerWindow = this.ownerDocument?.defaultView;\n const tools = (await native.getTools()).filter((tool) => {\n if (tool.window === ownerWindow) return true;\n if (ownerWindow?.parent !== ownerWindow) return false;\n let frame = tool.window;\n while (frame) {\n if (frame === ownerWindow) return true;\n const parent = frame.parent;\n if (parent === frame) break;\n frame = parent;\n }\n return false;\n });\n if (this.closed) return;\n // A removal completes once this document no longer registers the name; a\n // descendant's same-named tool is mirrored afterwards.\n for (const name of this.removingNativeTools) {\n if (!tools.some((tool) => tool.name === name && tool.window === ownerWindow)) {\n this.removingNativeTools.delete(name);\n }\n }\n const nextTools = new Map<string, NativeBackfilledTool>();\n for (const tool of tools) {\n // MCP tool names are global, so the first visible tool with a name wins.\n if (\n nextTools.has(tool.name) ||\n this.pendingTools.has(tool.name) ||\n this.removingNativeTools.has(tool.name)\n ) {\n continue;\n }\n // Detach the schema from the page; a value that cannot cross JSON stays undefined.\n let inputSchema: unknown;\n try {\n inputSchema = JSON.parse(serializeInputSchema(tool.inputSchema ?? DEFAULT_INPUT_SCHEMA));\n } catch {}\n if (!isPlainObject(inputSchema)) {\n console.warn(\n `[BrowserMcpServer] Native tool \"${tool.name}\" was not exposed over MCP because its input schema is malformed.`\n );\n continue;\n }\n const item: ToolListItem = { name: tool.name, description: tool.description, inputSchema };\n if (tool.title !== undefined) item.title = tool.title;\n if (tool.annotations) item.annotations = tool.annotations;\n nextTools.set(tool.name, { source: tool, item, fingerprint: JSON.stringify(item) });\n }\n\n for (const [name, current] of this.nativeBackfilledTools) {\n const next = nextTools.get(name);\n if (next?.fingerprint === current.fingerprint) this.nativeBackfilledTools.set(name, next);\n else this.removeTool(name, { skipNative: true });\n }\n\n for (const [name, next] of nextTools) {\n if (this.tools.has(name)) continue;\n const execute: ModelContextTool<WebMcpToolInput>['execute'] = async (args, options) => {\n const currentTool = this.nativeBackfilledTools.get(name)?.source;\n if (!currentTool) throw new Error(`Native tool not found: ${name}`);\n try {\n return parseNativeToolResult(await native.executeTool(currentTool, args, options));\n } catch (error) {\n // Upstream fires no toolchange when a frame is removed, so a failed call\n // into a closed window is the first signal to drop its mirrors.\n if (currentTool.window.closed) this.nativeToolChangeListener();\n throw error;\n }\n };\n const tool = { ...next.item, execute };\n try {\n // Native getTools() does not report a tool's exposedTo allowlist, so a\n // backfilled mirror is exposed to every MCP peer.\n const normalized = normalizeInputSchema(tool.inputSchema);\n this.tools.set(name, this.registerToolInMcp(tool, normalized, execute));\n this.nativeBackfilledTools.set(name, next);\n } catch (error) {\n console.warn(\n `[BrowserMcpServer] Native tool \"${name}\" was not exposed over MCP because its schema could not be compiled:`,\n error\n );\n }\n }\n this.applyToolExposure();\n }\n\n registerResource(descriptor: ResourceDescriptor): RegistrationHandle {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n const registeredDescriptor = { ...descriptor };\n const config: ResourceMetadata = {};\n if (registeredDescriptor.description !== undefined) {\n config.description = registeredDescriptor.description;\n }\n if (registeredDescriptor.mimeType !== undefined)\n config.mimeType = registeredDescriptor.mimeType;\n const template = registeredDescriptor.uri.includes('{')\n ? new ResourceTemplate(registeredDescriptor.uri, { list: undefined })\n : undefined;\n const mcpHandle = template\n ? this.mcpServer.registerResource(\n registeredDescriptor.name,\n template,\n config,\n async (uri, variables) => registeredDescriptor.read(uri, variables)\n )\n : this.mcpServer.registerResource(\n registeredDescriptor.name,\n registeredDescriptor.uri,\n config,\n async (uri) => registeredDescriptor.read(uri)\n );\n this.registrations.add(mcpHandle);\n return {\n unregister: () => {\n if (this.registrations.delete(mcpHandle)) mcpHandle.remove();\n },\n };\n }\n\n registerPrompt(descriptor: PromptDescriptor): RegistrationHandle {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n const registeredDescriptor = { ...descriptor };\n if (descriptor.argsSchema !== undefined) {\n registeredDescriptor.argsSchema = structuredClone(descriptor.argsSchema);\n }\n const argsSchema =\n registeredDescriptor.argsSchema === undefined\n ? undefined\n : fromJsonSchema<Record<string, string>>(\n // SAFETY: PromptDescriptor accepts WebMCP's JSON schema shape; the MCP schema\n // compiler validates supported keywords and values at this boundary.\n registeredDescriptor.argsSchema as Parameters<typeof fromJsonSchema>[0]\n );\n const config: Omit<Parameters<McpServer['registerPrompt']>[1], 'argsSchema'> & {\n argsSchema?: NonNullable<typeof argsSchema>;\n } = {};\n if (registeredDescriptor.description !== undefined) {\n config.description = registeredDescriptor.description;\n }\n if (argsSchema) config.argsSchema = argsSchema;\n const mcpHandle = this.mcpServer.registerPrompt(\n registeredDescriptor.name,\n config,\n async (args) => registeredDescriptor.get(args ?? {})\n );\n this.registrations.add(mcpHandle);\n return {\n unregister: () => {\n if (this.registrations.delete(mcpHandle)) mcpHandle.remove();\n },\n };\n }\n\n listTools(): ToolListItem[] {\n return structuredClone([...this.tools.values()].map(({ item }) => item));\n }\n\n async getTools(options?: ModelContextGetToolOptions): Promise<RegisteredTool[]> {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (!this.native) throw createInvalidStateError('BrowserMcpServer has no WebMCP context');\n return this.native.getTools(options);\n }\n\n async executeTool(...args: Parameters<ModelContext['executeTool']>): Promise<string> {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (!this.native) throw createInvalidStateError('BrowserMcpServer has no WebMCP context');\n return this.native.executeTool(...args);\n }\n\n /**\n * Re-evaluate which registered tools may appear on the wire.\n *\n * A published tool without `exposedTo` is enabled. `exposedTo` narrows a tool to named\n * embedder origins. The peer origin is only known once a transport that reports one has\n * heard from its peer, so a restricted tool stays disabled until then — and stays\n * disabled forever on transports that cannot name a peer at all. Failing closed keeps a\n * tool that asked for a narrow audience from reaching a wider one.\n */\n private applyToolExposure(): void {\n for (const { exposedTo, mcpHandle } of this.tools.values()) {\n if (!mcpHandle) continue;\n // Opaque origins serialize identically and cannot identify an allowed peer.\n const visible =\n !exposedTo?.length ||\n (this.peerOrigin !== undefined &&\n this.peerOrigin !== 'null' &&\n exposedTo.includes(this.peerOrigin));\n if (visible === mcpHandle.enabled) continue;\n if (visible) mcpHandle.enable();\n else mcpHandle.disable();\n }\n }\n\n /**\n * Follow the peer origin of transports that report one, so `exposedTo` can be scoped to\n * the embedder actually connected. Duck-typed rather than imported: the SDK must not take\n * a build dependency on `@mcp-b/transports`, and transports that never name a peer simply\n * leave every restricted tool disabled.\n */\n private observePeerOrigin(transport: Transport): void {\n this.stopObservingPeerOrigin?.();\n this.stopObservingPeerOrigin = undefined;\n this.peerOrigin = undefined;\n this.applyToolExposure();\n if (!isPeerOriginTransport(transport)) return;\n const peered = transport;\n this.peerOrigin = peered.clientOrigin;\n this.applyToolExposure();\n const previous = peered.onclientorigin;\n let observing = true;\n const onclientorigin = (origin: string) => {\n previous?.(origin);\n if (!observing) return;\n this.peerOrigin = origin;\n this.applyToolExposure();\n };\n peered.onclientorigin = onclientorigin;\n this.stopObservingPeerOrigin = () => {\n observing = false;\n if (peered.onclientorigin === onclientorigin) peered.onclientorigin = previous;\n };\n }\n\n async connect(transport: Transport): Promise<void> {\n if (this.closed) throw createInvalidStateError('BrowserMcpServer is closed');\n if (this.mcpServer.server.transport) {\n throw createInvalidStateError('BrowserMcpServer is already connected');\n }\n this.observePeerOrigin(transport);\n const stopObserving = this.stopObservingPeerOrigin;\n try {\n await this.mcpServer.connect(transport);\n } catch (error) {\n if (this.stopObservingPeerOrigin === stopObserving) {\n stopObserving?.();\n this.stopObservingPeerOrigin = undefined;\n this.peerOrigin = undefined;\n this.applyToolExposure();\n }\n if (this.mcpServer.server.transport === transport) await this.mcpServer.close();\n throw error;\n }\n }\n\n close(): Promise<void> {\n if (this.closePromise) return this.closePromise;\n this.closed = true;\n this.stopObservingPeerOrigin?.();\n this.stopObservingPeerOrigin = undefined;\n this.closePromise = (async () => {\n this.native?.removeEventListener('toolchange', this.nativeToolChangeListener);\n this.native?.removeEventListener('toolactivated', this.nativeLifecycleListener);\n this.native?.removeEventListener('toolcancel', this.nativeLifecycleListener);\n for (const name of this.nativeToolAbortControllers.keys()) {\n this.abortNativeToolMirror(name);\n }\n for (const name of this.tools.keys()) {\n this.removeTool(name);\n }\n for (const handle of this.registrations) handle.remove();\n this.registrations.clear();\n this.nativeBackfilledTools.clear();\n this.removingNativeTools.clear();\n await this.mcpServer.close();\n })();\n return this.closePromise;\n }\n}\n\nexport interface ResourceDescriptor {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n read: (uri: URL, params?: Variables) => Promise<ReadResourceResult>;\n}\n\nexport interface PromptDescriptor {\n name: string;\n description?: string;\n argsSchema?: InputSchema;\n get: (args: Record<string, string>) => Promise<GetPromptResult>;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
//#region src/normalize.ts
|
|
2
|
+
const VALID_TOOL_NAME_RE = /^[A-Za-z0-9_.-]{1,128}$/u;
|
|
3
|
+
/** Narrows a non-null, non-array object to WebMCP's tool callback input. */
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function isWebIdlObject(value) {
|
|
8
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
9
|
+
}
|
|
10
|
+
function toDomString(value) {
|
|
11
|
+
if (typeof value === "symbol") throw new TypeError("Symbol values cannot be converted to a DOMString");
|
|
12
|
+
return String(value);
|
|
13
|
+
}
|
|
14
|
+
function coerceWebMcpToolDescriptor(tool) {
|
|
15
|
+
const { name, description, title } = tool;
|
|
16
|
+
if (name === void 0) throw new TypeError("Tool \"name\" is required");
|
|
17
|
+
if (description === void 0) throw new TypeError("Tool \"description\" is required");
|
|
18
|
+
const { annotations, inputSchema, outputSchema, execute } = tool;
|
|
19
|
+
const coercedName = toDomString(name);
|
|
20
|
+
const coercedTitle = title === void 0 ? void 0 : toDomString(title).toWellFormed();
|
|
21
|
+
const descriptor = {
|
|
22
|
+
name: coercedName,
|
|
23
|
+
description: toDomString(description),
|
|
24
|
+
execute
|
|
25
|
+
};
|
|
26
|
+
if (coercedTitle !== void 0) descriptor.title = coercedTitle;
|
|
27
|
+
if (inputSchema !== void 0) descriptor.inputSchema = inputSchema;
|
|
28
|
+
if (outputSchema !== void 0) descriptor.outputSchema = outputSchema;
|
|
29
|
+
if (annotations !== void 0) {
|
|
30
|
+
const members = isPlainObject(annotations) ? annotations : {};
|
|
31
|
+
const normalized = {
|
|
32
|
+
readOnlyHint: Boolean(members.readOnlyHint),
|
|
33
|
+
untrustedContentHint: Boolean(members.untrustedContentHint)
|
|
34
|
+
};
|
|
35
|
+
if (members.title !== void 0) normalized.title = toDomString(members.title).toWellFormed();
|
|
36
|
+
for (const hint of [
|
|
37
|
+
"destructiveHint",
|
|
38
|
+
"idempotentHint",
|
|
39
|
+
"openWorldHint",
|
|
40
|
+
"consequentialHint",
|
|
41
|
+
"debugging"
|
|
42
|
+
]) {
|
|
43
|
+
const value = members[hint];
|
|
44
|
+
if (value !== void 0) normalized[hint] = Boolean(value);
|
|
45
|
+
}
|
|
46
|
+
descriptor.annotations = normalized;
|
|
47
|
+
}
|
|
48
|
+
validateWebMcpToolDescriptor(descriptor);
|
|
49
|
+
return descriptor;
|
|
50
|
+
}
|
|
51
|
+
function createInvalidStateError(message) {
|
|
52
|
+
return new DOMException(message, "InvalidStateError");
|
|
53
|
+
}
|
|
54
|
+
function validateWebMcpToolDescriptor(tool) {
|
|
55
|
+
if (tool.name === "") throw createInvalidStateError("Tool \"name\" must be a non-empty string");
|
|
56
|
+
if (!VALID_TOOL_NAME_RE.test(tool.name)) throw createInvalidStateError("Tool \"name\" must be 1–128 characters and contain only ASCII alphanumeric, underscore, hyphen, or period");
|
|
57
|
+
if (tool.description.length === 0) throw createInvalidStateError("Tool \"description\" must be a non-empty string");
|
|
58
|
+
if (typeof tool.execute !== "function") throw new TypeError("Tool \"execute\" must be a function");
|
|
59
|
+
}
|
|
60
|
+
function serializeInputSchema(schema) {
|
|
61
|
+
if (!isWebIdlObject(schema)) throw new TypeError("inputSchema must be an object");
|
|
62
|
+
const serialized = JSON.stringify(schema);
|
|
63
|
+
if (serialized === void 0) throw new TypeError("inputSchema must be JSON-serializable");
|
|
64
|
+
return serialized;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/schema.ts
|
|
69
|
+
const DEFAULT_INPUT_SCHEMA = {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {}
|
|
72
|
+
};
|
|
73
|
+
const STANDARD_JSON_SCHEMA_TARGETS = ["draft-2020-12", "draft-07"];
|
|
74
|
+
function isJsonObjectRecord(value) {
|
|
75
|
+
if (!isPlainObject(value)) return false;
|
|
76
|
+
const prototype = Object.getPrototypeOf(value);
|
|
77
|
+
return prototype === Object.prototype || prototype === null;
|
|
78
|
+
}
|
|
79
|
+
function isJsonValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
80
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
|
|
81
|
+
if (typeof value === "number") return Number.isFinite(value);
|
|
82
|
+
if (typeof value !== "object") return false;
|
|
83
|
+
if (seen.has(value)) return false;
|
|
84
|
+
seen.add(value);
|
|
85
|
+
try {
|
|
86
|
+
return (Array.isArray(value) ? value : isJsonObjectRecord(value) ? Object.values(value) : null)?.every((entry) => isJsonValue(entry, seen)) ?? false;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
} finally {
|
|
90
|
+
seen.delete(value);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function isContentBlock(value) {
|
|
94
|
+
if (!isPlainObject(value)) return false;
|
|
95
|
+
switch (value.type) {
|
|
96
|
+
case "text": return typeof value.text === "string";
|
|
97
|
+
case "image":
|
|
98
|
+
case "audio": return typeof value.data === "string" && typeof value.mimeType === "string";
|
|
99
|
+
case "resource_link": return typeof value.uri === "string" && typeof value.name === "string";
|
|
100
|
+
case "resource": {
|
|
101
|
+
const resource = value.resource;
|
|
102
|
+
return isPlainObject(resource) && typeof resource.uri === "string" && (typeof resource.text === "string" || typeof resource.blob === "string");
|
|
103
|
+
}
|
|
104
|
+
default: return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function isProtocolToolResponse(value) {
|
|
108
|
+
return isPlainObject(value) && isJsonValue(value) && Array.isArray(value.content) && value.content.every(isContentBlock) && (value.isError === void 0 || typeof value.isError === "boolean") && (value._meta === void 0 || isPlainObject(value._meta));
|
|
109
|
+
}
|
|
110
|
+
function serializeTextContent(value) {
|
|
111
|
+
if (typeof value === "string") return value;
|
|
112
|
+
try {
|
|
113
|
+
return JSON.stringify(value) ?? String(value);
|
|
114
|
+
} catch {
|
|
115
|
+
return String(value);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function normalizeToolResponse(value) {
|
|
119
|
+
if (isProtocolToolResponse(value)) return value;
|
|
120
|
+
const result = {
|
|
121
|
+
content: [{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: serializeTextContent(value)
|
|
124
|
+
}],
|
|
125
|
+
isError: false
|
|
126
|
+
};
|
|
127
|
+
if (isJsonValue(value)) result.structuredContent = value;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function readStandardProperties(value) {
|
|
131
|
+
if (!isPlainObject(value)) return null;
|
|
132
|
+
const standard = value["~standard"];
|
|
133
|
+
if (!isPlainObject(standard)) return null;
|
|
134
|
+
return standard;
|
|
135
|
+
}
|
|
136
|
+
function isStandardInputValidatorSchema(value) {
|
|
137
|
+
const standard = readStandardProperties(value);
|
|
138
|
+
return Boolean(standard && standard.version === 1 && typeof standard.validate === "function");
|
|
139
|
+
}
|
|
140
|
+
function isStandardInputJsonSchema(value) {
|
|
141
|
+
const standard = readStandardProperties(value);
|
|
142
|
+
if (!standard || standard.version !== 1 || !isPlainObject(standard.jsonSchema)) return false;
|
|
143
|
+
return typeof standard.jsonSchema.input === "function";
|
|
144
|
+
}
|
|
145
|
+
/** Narrows a Standard Schema that also converts to JSON Schema, as the MCP server requires. */
|
|
146
|
+
function isMcpStandardSchema(value) {
|
|
147
|
+
const standard = readStandardProperties(value);
|
|
148
|
+
return Boolean(standard && standard.version === 1 && typeof standard.vendor === "string" && typeof standard.validate === "function" && isPlainObject(standard.jsonSchema) && typeof standard.jsonSchema.input === "function" && typeof standard.jsonSchema.output === "function");
|
|
149
|
+
}
|
|
150
|
+
function convertStandardInputSchema(schema) {
|
|
151
|
+
for (const target of STANDARD_JSON_SCHEMA_TARGETS) try {
|
|
152
|
+
const converted = schema["~standard"].jsonSchema.input({ target });
|
|
153
|
+
const parsed = JSON.parse(serializeInputSchema(converted));
|
|
154
|
+
if (isPlainObject(parsed)) return parsed;
|
|
155
|
+
} catch {}
|
|
156
|
+
throw new Error("Failed to convert Standard JSON Schema inputSchema to a JSON Schema object");
|
|
157
|
+
}
|
|
158
|
+
function normalizeInputSchema(inputSchema) {
|
|
159
|
+
if (inputSchema === void 0) return { inputSchema: DEFAULT_INPUT_SCHEMA };
|
|
160
|
+
if (isStandardInputJsonSchema(inputSchema)) {
|
|
161
|
+
const converted = convertStandardInputSchema(inputSchema);
|
|
162
|
+
const registeredInputSchema = serializeInputSchema(converted);
|
|
163
|
+
if (isStandardInputValidatorSchema(inputSchema)) Object.defineProperty(converted, "~standard", { value: inputSchema["~standard"] });
|
|
164
|
+
return {
|
|
165
|
+
inputSchema: converted,
|
|
166
|
+
registeredInputSchema
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
if (isStandardInputValidatorSchema(inputSchema)) throw new Error("Standard Schema inputSchema must provide ~standard.jsonSchema.input() for tool metadata");
|
|
170
|
+
const registeredInputSchema = serializeInputSchema(inputSchema);
|
|
171
|
+
const jsonSchema = JSON.parse(registeredInputSchema);
|
|
172
|
+
if (!isPlainObject(jsonSchema) || Object.keys(jsonSchema).length === 0) return {
|
|
173
|
+
inputSchema: DEFAULT_INPUT_SCHEMA,
|
|
174
|
+
registeredInputSchema
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
inputSchema: jsonSchema.type === void 0 ? {
|
|
178
|
+
type: "object",
|
|
179
|
+
...jsonSchema
|
|
180
|
+
} : jsonSchema,
|
|
181
|
+
registeredInputSchema
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//#endregion
|
|
186
|
+
export { createInvalidStateError as a, coerceWebMcpToolDescriptor as i, normalizeInputSchema as n, isPlainObject as o, normalizeToolResponse as r, serializeInputSchema as s, isMcpStandardSchema as t };
|
|
187
|
+
//# sourceMappingURL=schema-FbP7xLdQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-FbP7xLdQ.js","names":[],"sources":["../src/normalize.ts","../src/schema.ts"],"sourcesContent":["import type { WebMcpToolInput, WebMcpToolObjectInput } from './common.js';\nimport type { ToolAnnotations, ToolDescriptor } from './tool.js';\n\nconst VALID_TOOL_NAME_RE = /^[A-Za-z0-9_.-]{1,128}$/u;\n\n/** Narrows a non-null, non-array object to WebMCP's tool callback input. */\nexport function isPlainObject(value: unknown): value is WebMcpToolObjectInput {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isWebIdlObject(value: unknown): value is object {\n return value !== null && (typeof value === 'object' || typeof value === 'function');\n}\n\nfunction toDomString(value: unknown): string {\n if (typeof value === 'symbol') {\n throw new TypeError('Symbol values cannot be converted to a DOMString');\n }\n return String(value);\n}\n\n/** Unconverted Web IDL tool members; each is coerced or validated before invocation. */\nexport interface ToolRegistrationDictionary {\n name?: unknown;\n description?: unknown;\n title?: unknown;\n annotations?: unknown;\n inputSchema?: ToolDescriptor<WebMcpToolInput>['inputSchema'];\n outputSchema?: ToolDescriptor<WebMcpToolInput>['outputSchema'];\n execute?: unknown;\n}\n\nexport function coerceWebMcpToolDescriptor(\n tool: ToolRegistrationDictionary\n): ToolDescriptor<WebMcpToolInput> {\n const { name, description, title } = tool;\n if (name === undefined) {\n throw new TypeError('Tool \"name\" is required');\n }\n if (description === undefined) {\n throw new TypeError('Tool \"description\" is required');\n }\n const { annotations, inputSchema, outputSchema, execute } = tool;\n\n const coercedName = toDomString(name);\n const coercedTitle = title === undefined ? undefined : toDomString(title).toWellFormed();\n const descriptor: Omit<ToolDescriptor<WebMcpToolInput>, 'execute'> & { execute: unknown } = {\n name: coercedName,\n description: toDomString(description),\n execute,\n };\n if (coercedTitle !== undefined) descriptor.title = coercedTitle;\n if (inputSchema !== undefined) descriptor.inputSchema = inputSchema;\n if (outputSchema !== undefined) descriptor.outputSchema = outputSchema;\n if (annotations !== undefined) {\n const members = isPlainObject(annotations) ? annotations : {};\n const normalized: ToolAnnotations = {\n readOnlyHint: Boolean(members.readOnlyHint),\n untrustedContentHint: Boolean(members.untrustedContentHint),\n };\n if (members.title !== undefined) normalized.title = toDomString(members.title).toWellFormed();\n for (const hint of [\n 'destructiveHint',\n 'idempotentHint',\n 'openWorldHint',\n 'consequentialHint',\n 'debugging',\n ] as const) {\n const value = members[hint];\n if (value !== undefined) normalized[hint] = Boolean(value);\n }\n descriptor.annotations = normalized;\n }\n validateWebMcpToolDescriptor(descriptor);\n return descriptor;\n}\n\nexport function createInvalidStateError(message: string): Error {\n return new DOMException(message, 'InvalidStateError');\n}\n\nfunction validateWebMcpToolDescriptor<\n T extends { name: string; description: string; execute: unknown },\n>(tool: T): asserts tool is T & { execute: ToolDescriptor<WebMcpToolInput>['execute'] } {\n if (tool.name === '') {\n throw createInvalidStateError('Tool \"name\" must be a non-empty string');\n }\n if (!VALID_TOOL_NAME_RE.test(tool.name)) {\n throw createInvalidStateError(\n 'Tool \"name\" must be 1–128 characters and contain only ASCII alphanumeric, underscore, hyphen, or period'\n );\n }\n if (tool.description.length === 0) {\n throw createInvalidStateError('Tool \"description\" must be a non-empty string');\n }\n if (typeof tool.execute !== 'function') {\n throw new TypeError('Tool \"execute\" must be a function');\n }\n}\n\nexport function serializeInputSchema(schema: unknown): string {\n if (!isWebIdlObject(schema)) {\n throw new TypeError('inputSchema must be an object');\n }\n const serialized = JSON.stringify(schema);\n if (serialized === undefined) {\n throw new TypeError('inputSchema must be JSON-serializable');\n }\n return serialized;\n}\n","import type {\n CallToolResult,\n ContentBlock,\n StandardSchemaWithJSON,\n JSONValue as JsonValue,\n} from '@modelcontextprotocol/server';\nimport type { InputSchema, WebMcpToolInput, WebMcpToolObjectInput } from './common.js';\nimport { isPlainObject, serializeInputSchema } from './normalize.js';\nimport type { StandardJSONSchemaV1, StandardSchemaV1 } from '@standard-schema/spec';\n\ntype StandardInputValidatorSchema = StandardSchemaV1<WebMcpToolInput, WebMcpToolInput>;\ntype StandardInputJsonSchema = StandardJSONSchemaV1<WebMcpToolInput, WebMcpToolInput>;\n\nconst DEFAULT_INPUT_SCHEMA: InputSchema = { type: 'object', properties: {} };\nconst STANDARD_JSON_SCHEMA_TARGETS = ['draft-2020-12', 'draft-07'] as const;\n\nexport type ToolInputSchema = InputSchema | StandardInputJsonSchema;\n\nexport interface NormalizedInputSchema {\n inputSchema: InputSchema;\n registeredInputSchema?: string;\n}\n\nfunction isJsonObjectRecord(value: unknown): value is WebMcpToolObjectInput {\n if (!isPlainObject(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction isJsonValue(value: unknown, seen = new WeakSet<object>()): value is JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') {\n return true;\n }\n\n if (typeof value === 'number') {\n return Number.isFinite(value);\n }\n\n if (typeof value !== 'object') {\n return false;\n }\n\n if (seen.has(value)) {\n return false;\n }\n\n seen.add(value);\n try {\n const entries = Array.isArray(value)\n ? value\n : isJsonObjectRecord(value)\n ? Object.values(value)\n : null;\n return entries?.every((entry) => isJsonValue(entry, seen)) ?? false;\n } catch {\n return false;\n } finally {\n seen.delete(value);\n }\n}\n\nfunction isContentBlock(value: unknown): value is ContentBlock {\n if (!isPlainObject(value)) return false;\n switch (value.type) {\n case 'text':\n return typeof value.text === 'string';\n case 'image':\n case 'audio':\n return typeof value.data === 'string' && typeof value.mimeType === 'string';\n case 'resource_link':\n return typeof value.uri === 'string' && typeof value.name === 'string';\n case 'resource': {\n const resource = value.resource;\n return (\n isPlainObject(resource) &&\n typeof resource.uri === 'string' &&\n (typeof resource.text === 'string' || typeof resource.blob === 'string')\n );\n }\n default:\n return false;\n }\n}\n\nfunction isProtocolToolResponse(value: unknown): value is CallToolResult {\n return (\n isPlainObject(value) &&\n isJsonValue(value) &&\n Array.isArray(value.content) &&\n value.content.every(isContentBlock) &&\n (value.isError === undefined || typeof value.isError === 'boolean') &&\n (value._meta === undefined || isPlainObject(value._meta))\n );\n}\n\nfunction serializeTextContent(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n\nexport function normalizeToolResponse(value: unknown): CallToolResult {\n if (isProtocolToolResponse(value)) return value;\n const result: CallToolResult = {\n content: [{ type: 'text', text: serializeTextContent(value) }],\n isError: false,\n };\n if (isJsonValue(value)) result.structuredContent = value;\n return result;\n}\n\ninterface StandardProperties {\n version?: unknown;\n vendor?: unknown;\n validate?: unknown;\n jsonSchema?: unknown;\n}\n\nfunction readStandardProperties(value: unknown): StandardProperties | null {\n if (!isPlainObject(value)) {\n return null;\n }\n\n const standard = value['~standard'];\n if (!isPlainObject(standard)) {\n return null;\n }\n\n return standard;\n}\n\nfunction isStandardInputValidatorSchema(value: unknown): value is StandardInputValidatorSchema {\n const standard = readStandardProperties(value);\n return Boolean(standard && standard.version === 1 && typeof standard.validate === 'function');\n}\n\nfunction isStandardInputJsonSchema(value: unknown): value is StandardInputJsonSchema {\n const standard = readStandardProperties(value);\n if (!standard || standard.version !== 1 || !isPlainObject(standard.jsonSchema)) {\n return false;\n }\n\n return typeof standard.jsonSchema.input === 'function';\n}\n\n/** Narrows a Standard Schema that also converts to JSON Schema, as the MCP server requires. */\nexport function isMcpStandardSchema(\n value: unknown\n): value is StandardSchemaWithJSON<WebMcpToolObjectInput> {\n const standard = readStandardProperties(value);\n return Boolean(\n standard &&\n standard.version === 1 &&\n typeof standard.vendor === 'string' &&\n typeof standard.validate === 'function' &&\n isPlainObject(standard.jsonSchema) &&\n typeof standard.jsonSchema.input === 'function' &&\n typeof standard.jsonSchema.output === 'function'\n );\n}\n\nfunction convertStandardInputSchema(schema: StandardInputJsonSchema): InputSchema {\n for (const target of STANDARD_JSON_SCHEMA_TARGETS) {\n try {\n const converted = schema['~standard'].jsonSchema.input({ target });\n const parsed: unknown = JSON.parse(serializeInputSchema(converted));\n if (isPlainObject(parsed)) return parsed;\n } catch {}\n }\n\n throw new Error('Failed to convert Standard JSON Schema inputSchema to a JSON Schema object');\n}\n\nexport function normalizeInputSchema(\n inputSchema: ToolInputSchema | undefined\n): NormalizedInputSchema {\n if (inputSchema === undefined) {\n return { inputSchema: DEFAULT_INPUT_SCHEMA };\n }\n\n if (isStandardInputJsonSchema(inputSchema)) {\n const converted = convertStandardInputSchema(inputSchema);\n const registeredInputSchema = serializeInputSchema(converted);\n // Non-enumerable: the MCP server validates with the vendor schema, while JSON\n // metadata and clones stay plain.\n if (isStandardInputValidatorSchema(inputSchema)) {\n Object.defineProperty(converted, '~standard', { value: inputSchema['~standard'] });\n }\n return { inputSchema: converted, registeredInputSchema };\n }\n\n if (isStandardInputValidatorSchema(inputSchema)) {\n throw new Error(\n 'Standard Schema inputSchema must provide ~standard.jsonSchema.input() for tool metadata'\n );\n }\n\n const registeredInputSchema = serializeInputSchema(inputSchema);\n const jsonSchema: unknown = JSON.parse(registeredInputSchema);\n // Empty {} is valid JSON Schema but lacks type:\"object\" required by MCP.\n if (!isPlainObject(jsonSchema) || Object.keys(jsonSchema).length === 0) {\n return { inputSchema: DEFAULT_INPUT_SCHEMA, registeredInputSchema };\n }\n\n return {\n inputSchema: jsonSchema.type === undefined ? { type: 'object', ...jsonSchema } : jsonSchema,\n registeredInputSchema,\n };\n}\n"],"mappings":"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"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { c as WebMcpToolInput, l as WebMcpToolObjectInput, r as InputSchema } from "./common-CRzM40Z0.js";
|
|
2
|
+
import { CallToolResult, StandardSchemaWithJSON } from "@modelcontextprotocol/server";
|
|
3
|
+
import { StandardJSONSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
|
|
5
|
+
//#region src/schema.d.ts
|
|
6
|
+
type StandardInputJsonSchema = StandardJSONSchemaV1<WebMcpToolInput, WebMcpToolInput>;
|
|
7
|
+
type ToolInputSchema = InputSchema | StandardInputJsonSchema;
|
|
8
|
+
interface NormalizedInputSchema {
|
|
9
|
+
inputSchema: InputSchema;
|
|
10
|
+
registeredInputSchema?: string;
|
|
11
|
+
}
|
|
12
|
+
declare function normalizeToolResponse(value: unknown): CallToolResult;
|
|
13
|
+
/** Narrows a Standard Schema that also converts to JSON Schema, as the MCP server requires. */
|
|
14
|
+
declare function isMcpStandardSchema(value: unknown): value is StandardSchemaWithJSON<WebMcpToolObjectInput>;
|
|
15
|
+
declare function normalizeInputSchema(inputSchema: ToolInputSchema | undefined): NormalizedInputSchema;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { NormalizedInputSchema, ToolInputSchema, isMcpStandardSchema, normalizeInputSchema, normalizeToolResponse };
|
|
18
|
+
//# sourceMappingURL=schema.d.ts.map
|
package/dist/schema.js
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-b/webmcp-ts-sdk",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "WebMCP browser adapter extending the upstream API with MCP capabilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adapter",
|
|
7
7
|
"ai-agents",
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
".": {
|
|
52
52
|
"types": "./dist/index.d.ts",
|
|
53
53
|
"import": "./dist/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./schema": {
|
|
56
|
+
"types": "./dist/schema.d.ts",
|
|
57
|
+
"import": "./dist/schema.js"
|
|
54
58
|
}
|
|
55
59
|
},
|
|
56
60
|
"publishConfig": {
|
|
@@ -59,8 +63,9 @@
|
|
|
59
63
|
},
|
|
60
64
|
"dependencies": {
|
|
61
65
|
"@modelcontextprotocol/server": "2.0.0",
|
|
62
|
-
"@
|
|
63
|
-
"
|
|
66
|
+
"@standard-schema/spec": "^1.1.0",
|
|
67
|
+
"webmcp-types": "0.1.9",
|
|
68
|
+
"@mcp-b/webmcp-polyfill": "6.0.0"
|
|
64
69
|
},
|
|
65
70
|
"devDependencies": {
|
|
66
71
|
"@modelcontextprotocol/client": "2.0.0",
|
|
@@ -74,7 +79,7 @@
|
|
|
74
79
|
"node": ">=20"
|
|
75
80
|
},
|
|
76
81
|
"scripts": {
|
|
77
|
-
"build": "vp pack",
|
|
82
|
+
"build": "vp pack && pnpm run typecheck:consumer",
|
|
78
83
|
"check": "vp check --fix",
|
|
79
84
|
"clean": "rm -rf dist",
|
|
80
85
|
"format": "vp fmt --write",
|
|
@@ -83,6 +88,7 @@
|
|
|
83
88
|
"publish:npm": "pnpm publish --access public",
|
|
84
89
|
"test": "vp test run",
|
|
85
90
|
"test:coverage": "vp test run --coverage",
|
|
86
|
-
"typecheck": "tsc --noEmit"
|
|
91
|
+
"typecheck": "tsc --noEmit",
|
|
92
|
+
"typecheck:consumer": "tsc --noEmit --strict --skipLibCheck --module preserve --moduleResolution bundler --lib ES2022,DOM type-tests/consumer.ts"
|
|
87
93
|
}
|
|
88
94
|
}
|