@mcp-b/mcp-iframe 2.2.0 → 2.3.1-beta.20260528050333

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 CHANGED
@@ -36,23 +36,23 @@ Tools registered inside the iframe (e.g. `calculate`) appear on the parent as `m
36
36
 
37
37
  ## Attributes
38
38
 
39
- | Attribute | Description |
40
- |-----------|-------------|
41
- | `src` | URL of the iframe page |
42
- | `id` | Used as the tool name prefix |
43
- | `target-origin` | Override the postMessage target origin |
44
- | `channel` | Channel ID for transport (default: `mcp-iframe`) |
45
- | `call-timeout` | Timeout in ms for tool calls (default: `30000`) |
39
+ | Attribute | Description |
40
+ | ------------------ | ------------------------------------------------ |
41
+ | `src` | URL of the iframe page |
42
+ | `id` | Used as the tool name prefix |
43
+ | `target-origin` | Override the postMessage target origin |
44
+ | `channel` | Channel ID for transport (default: `mcp-iframe`) |
45
+ | `call-timeout` | Timeout in ms for tool calls (default: `30000`) |
46
46
  | `prefix-separator` | Separator between prefix and name (default: `_`) |
47
47
 
48
48
  Standard iframe attributes (`sandbox`, `allow`, `width`, `height`, etc.) are also mirrored.
49
49
 
50
50
  ## Events
51
51
 
52
- | Event | Detail |
53
- |-------|--------|
54
- | `mcp-iframe-ready` | `{ tools, resources, prompts }` - Fired when connected |
55
- | `mcp-iframe-error` | `{ error }` - Fired on connection failure |
52
+ | Event | Detail |
53
+ | -------------------------- | --------------------------------------------------------- |
54
+ | `mcp-iframe-ready` | `{ tools, resources, prompts }` - Fired when connected |
55
+ | `mcp-iframe-error` | `{ error }` - Fired on connection failure |
56
56
  | `mcp-iframe-tools-changed` | `{ tools, resources, prompts }` - Fired after `refresh()` |
57
57
 
58
58
  ## Related Packages
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { Client, Prompt, Resource, Tool } from "@mcp-b/webmcp-ts-sdk";
2
2
 
3
3
  //#region src/MCPIframeElement.d.ts
4
-
5
4
  /** Custom event detail for mcp-iframe-ready */
6
5
  interface MCPIframeReadyEventDetail {
7
6
  tools: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/MCPIframeElement.ts"],"sourcesContent":[],"mappings":";;;;;UAkHiB,yBAAA;;;;;;UAOA,yBAAA;;;;UAKA,gCAAA;;;;;;;;;;;;;;;cAoBJ,gBAAA,SAAyB,WAAA;;;;;;;;gBAmGtB;;gBAKA;;;;;;;;;;kBAyBE;;sBAKI;;oBAKF;;;;;;aAuBD;;kBAqBK;;;iBAsWR,wBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/MCPIframeElement.ts"],"mappings":";;;;UAkHiB,yBAAA;EACf,KAAA;EACA,SAAA;EACA,OAAA;AAAA;;UAIe,yBAAA;EACf,KAAA;AAAA;;UAIe,gCAAA;EACf,KAAA;EACA,SAAA;EACA,OAAA;AAAA;;;;;;;;;;;cAiBW,gBAAA,SAAyB,WAAA;EAAA;aAwBzB,kBAAA,CAAA;;EAWX,iBAAA,CAAA;EAIA,oBAAA,CAAA;EAIA,wBAAA,CAAyB,IAAA,UAAc,QAAA,iBAAyB,QAAA;EA4I1C;EAAA,IApFlB,MAAA,CAAA,GAAU,iBAAA;EAoFe;EAAA,IA/EzB,MAAA,CAAA,GAAU,MAAA;EAqbwB;EAAA,IAhblC,KAAA,CAAA;EAgbmC;EAAA,IA3anC,YAAA,CAAA;;MAKA,gBAAA,CAAA;;MAKA,cAAA,CAAA;;MAKA,QAAA,CAAA,GAAY,IAAA;;MAKZ,YAAA,CAAA,GAAgB,QAAA;;MAKhB,UAAA,CAAA,GAAc,MAAA;;MAKd,UAAA,CAAA;;MAaA,UAAA,CAAA;;EAKE,OAAA,CAAA,GAAW,OAAA;;EAqBX,YAAA,CAAA,GAAgB,OAAA;AAAA;;iBAsWR,wBAAA,CAAyB,OAAA"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#createIframe","#cleanup","#targetOrigin","#ready","#reconnect","#channelId","#callTimeout","#prefixSeparator","#unregisterAll","#registerAllOnModelContext","#iframe","#client","#registeredTools","#registeredResources","#registeredPrompts","#mcpTools","#mcpResources","#mcpPrompts","#fetchAllFromIframe","#connect","#connecting","#getTargetOrigin","#transport","#registerToolsOnModelContext","#registerResourcesOnModelContext","#registerPromptsOnModelContext","#callIframeTool","descriptor: ResourceDescriptor","#readIframeResource","descriptor: PromptDescriptor","#getIframePrompt","#disconnect"],"sources":["../src/MCPIframeElement.ts"],"sourcesContent":["/**\n * MCPIframe Custom Element\n *\n * A custom element that wraps an iframe and automatically exposes tools,\n * resources, and prompts registered in the iframe's MCP server to the\n * parent page's Model Context API.\n *\n * The iframe should have the MCP polyfill installed, which creates an MCP server\n * that exposes items registered via `navigator.modelContext`.\n *\n * @example\n * ```html\n * <mcp-iframe src=\"./child-app.html\" id=\"my-app\"></mcp-iframe>\n * ```\n *\n * Items from the iframe will be exposed with the element's ID as prefix:\n * - Child registers tool \"calculate\" -> Parent sees \"my-app_calculate\"\n * - Child registers resource \"config://settings\" -> Parent sees \"my-app_config://settings\"\n * - Child registers prompt \"help\" -> Parent sees \"my-app_help\"\n *\n * Note: The prefix separator defaults to underscore (_) to ensure MCP compatibility.\n * Tool and prompt names must match the pattern: ^[a-zA-Z0-9_-]{1,128}$\n *\n * @example\n * ```typescript\n * const mcpIframe = document.querySelector('mcp-iframe');\n * mcpIframe.addEventListener('mcp-iframe-ready', (e) => {\n * console.log('Tools:', e.detail.tools);\n * console.log('Resources:', e.detail.resources);\n * console.log('Prompts:', e.detail.prompts);\n * });\n * ```\n */\n\nimport { IframeParentTransport } from '@mcp-b/transports';\nimport type {\n GetPromptResult,\n Prompt,\n ReadResourceResult,\n Resource,\n Tool,\n} from '@mcp-b/webmcp-ts-sdk';\nimport {\n type BrowserMcpServer,\n Client,\n type PromptDescriptor,\n type ResourceDescriptor,\n} from '@mcp-b/webmcp-ts-sdk';\nimport type {\n CallToolResult,\n InputSchema,\n RegistrationHandle,\n ToolDescriptor,\n} from '@mcp-b/webmcp-types';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst DEFAULT_CALL_TIMEOUT = 30000;\nconst DEFAULT_PREFIX_SEPARATOR = '_';\nconst DEFAULT_CHANNEL_ID = 'mcp-iframe';\n\n/**\n * MCP name validation pattern.\n * Tool/prompt names must match: ^[a-zA-Z0-9_-]{1,128}$\n */\nconst MCP_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/;\nconst MCP_NAME_MAX_LENGTH = 128;\n\n/**\n * Validates that a string contains only valid MCP name characters.\n * Valid characters: a-z, A-Z, 0-9, underscore (_), hyphen (-)\n */\nfunction isValidMCPNameChars(str: string): boolean {\n return /^[a-zA-Z0-9_-]*$/.test(str);\n}\n\n/**\n * Validates a complete MCP name (tool name, prompt name).\n * Must be 1-128 characters and contain only valid characters.\n */\nfunction isValidMCPName(name: string): boolean {\n return MCP_NAME_PATTERN.test(name);\n}\n\n/**\n * Sanitizes a string to contain only valid MCP name characters.\n * Replaces invalid characters with underscores.\n */\nfunction sanitizeMCPNamePart(str: string): string {\n return str.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/** Standard iframe attributes that are mirrored to the internal iframe */\nconst IFRAME_ATTRIBUTES = [\n 'src',\n 'srcdoc',\n 'name',\n 'sandbox',\n 'allow',\n 'allowfullscreen',\n 'width',\n 'height',\n 'loading',\n 'referrerpolicy',\n 'credentialless',\n] as const;\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Custom event detail for mcp-iframe-ready */\nexport interface MCPIframeReadyEventDetail {\n tools: string[];\n resources: string[];\n prompts: string[];\n}\n\n/** Custom event detail for mcp-iframe-error */\nexport interface MCPIframeErrorEventDetail {\n error: unknown;\n}\n\n/** Custom event detail for mcp-iframe-tools-changed */\nexport interface MCPIframeToolsChangedEventDetail {\n tools: string[];\n resources: string[];\n prompts: string[];\n}\n\n// ============================================================================\n// MCPIframeElement\n// ============================================================================\n\n/**\n * MCPIframe Custom Element\n *\n * Wraps an iframe and exposes its MCP tools, resources, and prompts\n * to the parent's Model Context API.\n *\n * @fires mcp-iframe-ready - When connected to iframe's MCP server\n * @fires mcp-iframe-error - When connection fails\n * @fires mcp-iframe-tools-changed - When items are refreshed\n */\nexport class MCPIframeElement extends HTMLElement {\n // Internal state\n #iframe: HTMLIFrameElement | null = null;\n #client: Client | null = null;\n #transport: IframeParentTransport | null = null;\n #ready = false;\n #connecting = false;\n\n // MCP items from iframe\n #mcpTools: Tool[] = [];\n #mcpResources: Resource[] = [];\n #mcpPrompts: Prompt[] = [];\n\n // Registered items on parent\n #registeredTools = new Set<string>();\n #registeredResources = new Map<string, RegistrationHandle>();\n #registeredPrompts = new Map<string, RegistrationHandle>();\n\n // Configuration\n #callTimeout = DEFAULT_CALL_TIMEOUT;\n #prefixSeparator = DEFAULT_PREFIX_SEPARATOR;\n #channelId = DEFAULT_CHANNEL_ID;\n #targetOrigin: string | null = null;\n\n static get observedAttributes(): string[] {\n return [...IFRAME_ATTRIBUTES, 'target-origin', 'channel', 'call-timeout', 'prefix-separator'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n // ==================== Lifecycle ====================\n\n connectedCallback(): void {\n this.#createIframe();\n }\n\n disconnectedCallback(): void {\n void this.#cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'target-origin':\n this.#targetOrigin = newValue;\n if (this.#ready) void this.#reconnect();\n break;\n\n case 'channel':\n this.#channelId = newValue ?? DEFAULT_CHANNEL_ID;\n if (this.#ready) void this.#reconnect();\n break;\n\n case 'call-timeout':\n this.#callTimeout = newValue ? Number.parseInt(newValue, 10) : DEFAULT_CALL_TIMEOUT;\n break;\n\n case 'prefix-separator': {\n const separator = newValue ?? DEFAULT_PREFIX_SEPARATOR;\n if (!isValidMCPNameChars(separator)) {\n console.warn(\n `[MCPIframe] Invalid prefix-separator \"${separator}\". ` +\n 'Only alphanumeric characters, underscores, and hyphens are allowed. ' +\n `Using sanitized value: \"${sanitizeMCPNamePart(separator)}\"`\n );\n this.#prefixSeparator = sanitizeMCPNamePart(separator);\n } else {\n this.#prefixSeparator = separator;\n }\n if (this.#ready) {\n this.#unregisterAll();\n this.#registerAllOnModelContext();\n }\n break;\n }\n\n default:\n // Mirror standard iframe attributes\n if (this.#iframe && (IFRAME_ATTRIBUTES as readonly string[]).includes(name)) {\n if (newValue === null) {\n this.#iframe.removeAttribute(name);\n } else {\n this.#iframe.setAttribute(name, newValue);\n }\n // Reconnect when source changes\n if (name === 'src' || name === 'srcdoc') {\n void this.#reconnect();\n }\n }\n }\n }\n\n // ==================== Public API ====================\n\n /** The wrapped iframe element */\n get iframe(): HTMLIFrameElement | null {\n return this.#iframe;\n }\n\n /** The MCP client (if connected) */\n get client(): Client | null {\n return this.#client;\n }\n\n /** Whether the element is connected to the iframe's MCP server */\n get ready(): boolean {\n return this.#ready;\n }\n\n /** List of exposed tool names (with prefix) */\n get exposedTools(): string[] {\n return Array.from(this.#registeredTools.values());\n }\n\n /** List of exposed resource URIs (with prefix) */\n get exposedResources(): string[] {\n return Array.from(this.#registeredResources.keys());\n }\n\n /** List of exposed prompt names (with prefix) */\n get exposedPrompts(): string[] {\n return Array.from(this.#registeredPrompts.keys());\n }\n\n /** Raw tools from the iframe's MCP server (without prefix) */\n get mcpTools(): Tool[] {\n return [...this.#mcpTools];\n }\n\n /** Raw resources from the iframe's MCP server (without prefix) */\n get mcpResources(): Resource[] {\n return [...this.#mcpResources];\n }\n\n /** Raw prompts from the iframe's MCP server (without prefix) */\n get mcpPrompts(): Prompt[] {\n return [...this.#mcpPrompts];\n }\n\n /** The item name prefix (id + separator), sanitized for MCP compatibility */\n get itemPrefix(): string {\n const rawId = this.id || this.getAttribute('name') || 'iframe';\n const id = sanitizeMCPNamePart(rawId);\n if (id !== rawId) {\n console.warn(\n `[MCPIframe] ID/name \"${rawId}\" contains invalid characters for MCP names. ` +\n `Using sanitized value: \"${id}\"`\n );\n }\n return `${id}${this.#prefixSeparator}`;\n }\n\n /** @deprecated Use itemPrefix instead */\n get toolPrefix(): string {\n return this.itemPrefix;\n }\n\n /** Manually refresh all items from the iframe */\n async refresh(): Promise<void> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n await this.#fetchAllFromIframe();\n this.#unregisterAll();\n this.#registerAllOnModelContext();\n\n this.dispatchEvent(\n new CustomEvent<MCPIframeToolsChangedEventDetail>('mcp-iframe-tools-changed', {\n detail: {\n tools: this.exposedTools,\n resources: this.exposedResources,\n prompts: this.exposedPrompts,\n },\n })\n );\n }\n\n /** @deprecated Use refresh() instead */\n async refreshTools(): Promise<void> {\n return this.refresh();\n }\n\n // ==================== Private Methods ====================\n\n #createIframe(): void {\n this.#iframe = document.createElement('iframe');\n\n // Mirror all iframe attributes\n for (const attr of IFRAME_ATTRIBUTES) {\n const value = this.getAttribute(attr);\n if (value !== null) {\n this.#iframe.setAttribute(attr, value);\n }\n }\n\n // Default styling\n this.#iframe.style.border = 'none';\n this.#iframe.style.width = this.getAttribute('width') ?? '100%';\n this.#iframe.style.height = this.getAttribute('height') ?? '100%';\n\n // Connect when iframe loads\n this.#iframe.addEventListener('load', () => void this.#connect());\n\n this.shadowRoot?.appendChild(this.#iframe);\n }\n\n async #connect(): Promise<void> {\n if (this.#connecting || !this.#iframe) return;\n this.#connecting = true;\n\n try {\n const targetOrigin = this.#getTargetOrigin();\n if (!targetOrigin) {\n console.warn('[MCPIframe] Cannot determine target origin. Set target-origin attribute.');\n return;\n }\n\n // Create transport and client\n this.#transport = new IframeParentTransport({\n iframe: this.#iframe,\n targetOrigin,\n channelId: this.#channelId,\n });\n\n this.#client = new Client({\n name: `MCPIframe:${this.id || 'anonymous'}`,\n version: '1.0.0',\n });\n\n // Connect to iframe's MCP server\n await this.#client.connect(this.#transport);\n this.#ready = true;\n\n // Fetch all items from iframe\n await this.#fetchAllFromIframe();\n\n // Register on parent's Model Context\n this.#registerAllOnModelContext();\n\n this.dispatchEvent(\n new CustomEvent<MCPIframeReadyEventDetail>('mcp-iframe-ready', {\n detail: {\n tools: this.exposedTools,\n resources: this.exposedResources,\n prompts: this.exposedPrompts,\n },\n })\n );\n } catch (error) {\n console.error('[MCPIframe] Failed to connect:', error);\n this.dispatchEvent(\n new CustomEvent<MCPIframeErrorEventDetail>('mcp-iframe-error', {\n detail: { error },\n })\n );\n } finally {\n this.#connecting = false;\n }\n }\n\n async #fetchAllFromIframe(): Promise<void> {\n if (!this.#client) return;\n\n // Fetch tools, resources, and prompts in parallel\n const [toolsResult, resourcesResult, promptsResult] = await Promise.all([\n this.#client.listTools(),\n this.#client.listResources().catch((err) => {\n console.warn('[MCPIframeElement] listResources failed, defaulting to empty:', err);\n return { resources: [] };\n }),\n this.#client.listPrompts().catch((err) => {\n console.warn('[MCPIframeElement] listPrompts failed, defaulting to empty:', err);\n return { prompts: [] };\n }),\n ]);\n\n this.#mcpTools = toolsResult.tools;\n this.#mcpResources = resourcesResult.resources;\n this.#mcpPrompts = promptsResult.prompts;\n }\n\n #getTargetOrigin(): string | null {\n // Use explicit attribute if set\n if (this.#targetOrigin) {\n return this.#targetOrigin;\n }\n\n // Infer from src attribute\n const src = this.getAttribute('src');\n if (src) {\n try {\n return new URL(src, window.location.href).origin;\n } catch (error) {\n console.warn('[MCPIframeElement] Invalid src URL for origin detection:', src, error);\n }\n }\n\n // Default to same origin\n return window.location.origin;\n }\n\n #registerAllOnModelContext(): void {\n const mc = navigator.modelContext;\n if (!mc) {\n console.warn('[MCPIframe] Model Context API not available on parent');\n return;\n }\n const modelContext = mc as unknown as BrowserMcpServer;\n\n this.#registerToolsOnModelContext(modelContext);\n this.#registerResourcesOnModelContext(modelContext);\n this.#registerPromptsOnModelContext(modelContext);\n }\n\n #registerToolsOnModelContext(modelContext: BrowserMcpServer): void {\n for (const tool of this.#mcpTools) {\n const prefixedName = `${this.itemPrefix}${tool.name}`;\n\n // Validate the final tool name\n if (!isValidMCPName(prefixedName)) {\n if (prefixedName.length > MCP_NAME_MAX_LENGTH) {\n console.error(\n `[MCPIframe] Cannot register tool \"${tool.name}\": ` +\n `prefixed name \"${prefixedName}\" exceeds ${MCP_NAME_MAX_LENGTH} characters ` +\n `(${prefixedName.length} chars). Skipping registration.`\n );\n } else {\n console.error(\n `[MCPIframe] Cannot register tool \"${tool.name}\": ` +\n `prefixed name \"${prefixedName}\" contains invalid characters. ` +\n 'Tool names must match pattern: ^[a-zA-Z0-9_-]{1,128}$. Skipping registration.'\n );\n }\n continue;\n }\n\n (modelContext.registerTool as (tool: ToolDescriptor) => void)({\n name: prefixedName,\n description: tool.description ?? `Tool from iframe: ${tool.name}`,\n ...(tool.inputSchema && { inputSchema: tool.inputSchema as InputSchema }),\n execute: (args) => this.#callIframeTool(tool.name, args),\n });\n\n this.#registeredTools.add(prefixedName);\n }\n }\n\n #registerResourcesOnModelContext(modelContext: BrowserMcpServer): void {\n for (const resource of this.#mcpResources) {\n const prefixedUri = `${this.itemPrefix}${resource.uri}`;\n\n const descriptor: ResourceDescriptor = {\n uri: prefixedUri,\n name: resource.name,\n ...(resource.description !== undefined && { description: resource.description }),\n ...(resource.mimeType !== undefined && { mimeType: resource.mimeType }),\n read: (_uri, _params) =>\n this.#readIframeResource(resource.uri) as ReturnType<ResourceDescriptor['read']>,\n };\n const registration = modelContext.registerResource(descriptor);\n this.#registeredResources.set(prefixedUri, registration);\n }\n }\n\n #registerPromptsOnModelContext(modelContext: BrowserMcpServer): void {\n for (const prompt of this.#mcpPrompts) {\n const prefixedName = `${this.itemPrefix}${prompt.name}`;\n\n // Validate the final prompt name\n if (!isValidMCPName(prefixedName)) {\n if (prefixedName.length > MCP_NAME_MAX_LENGTH) {\n console.error(\n `[MCPIframe] Cannot register prompt \"${prompt.name}\": ` +\n `prefixed name \"${prefixedName}\" exceeds ${MCP_NAME_MAX_LENGTH} characters ` +\n `(${prefixedName.length} chars). Skipping registration.`\n );\n } else {\n console.error(\n `[MCPIframe] Cannot register prompt \"${prompt.name}\": ` +\n `prefixed name \"${prefixedName}\" contains invalid characters. ` +\n 'Prompt names must match pattern: ^[a-zA-Z0-9_-]{1,128}$. Skipping registration.'\n );\n }\n continue;\n }\n\n const descriptor: PromptDescriptor = {\n name: prefixedName,\n ...(prompt.description !== undefined && { description: prompt.description }),\n ...(prompt.arguments &&\n prompt.arguments.length > 0 && {\n argsSchema: {\n type: 'object',\n properties: Object.fromEntries(\n prompt.arguments.map((arg) => [\n arg.name,\n {\n type: 'string',\n ...(arg.description !== undefined && { description: arg.description }),\n },\n ])\n ),\n required: prompt.arguments.filter((a) => a.required).map((a) => a.name),\n } satisfies InputSchema,\n }),\n get: (args) => this.#getIframePrompt(prompt.name, args),\n };\n const registration = modelContext.registerPrompt(descriptor);\n this.#registeredPrompts.set(prefixedName, registration);\n }\n }\n\n #unregisterAll(): void {\n const mc = navigator.modelContext;\n if (mc) {\n const modelContext = mc as unknown as BrowserMcpServer;\n for (const toolName of this.#registeredTools.values()) {\n try {\n modelContext.unregisterTool(toolName);\n } catch (error) {\n console.warn(\n `[MCPIframeElement] Failed to unregister tool \"${toolName}\" during cleanup:`,\n error\n );\n }\n }\n }\n this.#registeredTools.clear();\n\n for (const registration of this.#registeredResources.values()) {\n registration.unregister();\n }\n this.#registeredResources.clear();\n\n for (const registration of this.#registeredPrompts.values()) {\n registration.unregister();\n }\n this.#registeredPrompts.clear();\n }\n\n async #callIframeTool(toolName: string, args: Record<string, unknown>): Promise<CallToolResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.callTool({ name: toolName, arguments: args }, undefined, {\n signal: controller.signal,\n });\n return result as CallToolResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #readIframeResource(uri: string): Promise<ReadResourceResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.readResource({ uri }, { signal: controller.signal });\n return result as ReadResourceResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #getIframePrompt(name: string, args: Record<string, unknown>): Promise<GetPromptResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.getPrompt(\n { name, arguments: args as Record<string, string> },\n { signal: controller.signal }\n );\n return result as GetPromptResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #reconnect(): Promise<void> {\n await this.#disconnect();\n // Brief delay for iframe to be ready\n await new Promise((resolve) => setTimeout(resolve, 100));\n await this.#connect();\n }\n\n async #disconnect(): Promise<void> {\n this.#ready = false;\n this.#mcpTools = [];\n this.#mcpResources = [];\n this.#mcpPrompts = [];\n this.#unregisterAll();\n\n if (this.#client) {\n try {\n await this.#client.close();\n } catch (error) {\n console.warn('[MCPIframeElement] Error closing client during disconnect:', error);\n }\n this.#client = null;\n }\n\n if (this.#transport) {\n try {\n await this.#transport.close();\n } catch (error) {\n console.warn('[MCPIframeElement] Error closing transport during disconnect:', error);\n }\n this.#transport = null;\n }\n }\n\n async #cleanup(): Promise<void> {\n await this.#disconnect();\n }\n}\n\n// ============================================================================\n// Registration\n// ============================================================================\n\n/** Register the custom element with a custom tag name */\nexport function registerMCPIframeElement(tagName = 'mcp-iframe'): void {\n if (typeof customElements !== 'undefined' && !customElements.get(tagName)) {\n customElements.define(tagName, MCPIframeElement);\n }\n}\n\n// Auto-register in browser environments\nif (typeof window !== 'undefined' && typeof customElements !== 'undefined') {\n registerMCPIframeElement();\n}\n"],"mappings":"wGA2DA,MAAM,EAAuB,IAEvB,EAAqB,aAMrB,EAAmB,yBAOzB,SAAS,EAAoB,EAAsB,CACjD,MAAO,mBAAmB,KAAK,EAAI,CAOrC,SAAS,EAAe,EAAuB,CAC7C,OAAO,EAAiB,KAAK,EAAK,CAOpC,SAAS,EAAoB,EAAqB,CAChD,OAAO,EAAI,QAAQ,kBAAmB,IAAI,CAI5C,MAAM,EAAoB,CACxB,MACA,SACA,OACA,UACA,QACA,kBACA,QACA,SACA,UACA,iBACA,iBACD,CAuCD,IAAa,EAAb,cAAsC,WAAY,CAEhD,GAAoC,KACpC,GAAyB,KACzB,GAA2C,KAC3C,GAAS,GACT,GAAc,GAGd,GAAoB,EAAE,CACtB,GAA4B,EAAE,CAC9B,GAAwB,EAAE,CAG1B,GAAmB,IAAI,IACvB,GAAuB,IAAI,IAC3B,GAAqB,IAAI,IAGzB,GAAe,EACf,GAAmB,IACnB,GAAa,EACb,GAA+B,KAE/B,WAAW,oBAA+B,CACxC,MAAO,CAAC,GAAG,EAAmB,gBAAiB,UAAW,eAAgB,mBAAmB,CAG/F,aAAc,CACZ,OAAO,CACP,KAAK,aAAa,CAAE,KAAM,OAAQ,CAAC,CAKrC,mBAA0B,CACxB,MAAA,GAAoB,CAGtB,sBAA6B,CACtB,MAAA,GAAe,CAGtB,yBAAyB,EAAc,EAAyB,EAA+B,CACzF,OAAa,EAEjB,OAAQ,EAAR,CACE,IAAK,gBACH,MAAA,EAAqB,EACjB,MAAA,GAAkB,MAAA,GAAiB,CACvC,MAEF,IAAK,UACH,MAAA,EAAkB,GAAY,EAC1B,MAAA,GAAkB,MAAA,GAAiB,CACvC,MAEF,IAAK,eACH,MAAA,EAAoB,EAAW,OAAO,SAAS,EAAU,GAAG,CAAG,EAC/D,MAEF,IAAK,mBAAoB,CACvB,IAAM,EAAY,GAAY,IACzB,EAAoB,EAAU,CAQjC,MAAA,EAAwB,GAPxB,QAAQ,KACN,yCAAyC,EAAU,iGAEtB,EAAoB,EAAU,CAAC,GAC7D,CACD,MAAA,EAAwB,EAAoB,EAAU,EAIpD,MAAA,IACF,MAAA,GAAqB,CACrB,MAAA,GAAiC,EAEnC,MAGF,QAEM,MAAA,GAAiB,EAAwC,SAAS,EAAK,GACrE,IAAa,KACf,MAAA,EAAa,gBAAgB,EAAK,CAElC,MAAA,EAAa,aAAa,EAAM,EAAS,EAGvC,IAAS,OAAS,IAAS,WACxB,MAAA,GAAiB,GAShC,IAAI,QAAmC,CACrC,OAAO,MAAA,EAIT,IAAI,QAAwB,CAC1B,OAAO,MAAA,EAIT,IAAI,OAAiB,CACnB,OAAO,MAAA,EAIT,IAAI,cAAyB,CAC3B,OAAO,MAAM,KAAK,MAAA,EAAsB,QAAQ,CAAC,CAInD,IAAI,kBAA6B,CAC/B,OAAO,MAAM,KAAK,MAAA,EAA0B,MAAM,CAAC,CAIrD,IAAI,gBAA2B,CAC7B,OAAO,MAAM,KAAK,MAAA,EAAwB,MAAM,CAAC,CAInD,IAAI,UAAmB,CACrB,MAAO,CAAC,GAAG,MAAA,EAAe,CAI5B,IAAI,cAA2B,CAC7B,MAAO,CAAC,GAAG,MAAA,EAAmB,CAIhC,IAAI,YAAuB,CACzB,MAAO,CAAC,GAAG,MAAA,EAAiB,CAI9B,IAAI,YAAqB,CACvB,IAAM,EAAQ,KAAK,IAAM,KAAK,aAAa,OAAO,EAAI,SAChD,EAAK,EAAoB,EAAM,CAOrC,OANI,IAAO,GACT,QAAQ,KACN,wBAAwB,EAAM,uEACD,EAAG,GACjC,CAEI,GAAG,IAAK,MAAA,IAIjB,IAAI,YAAqB,CACvB,OAAO,KAAK,WAId,MAAM,SAAyB,CAC7B,GAAI,CAAC,MAAA,GAAgB,CAAC,MAAA,EACpB,MAAU,MAAM,qCAAqC,CAGvD,MAAM,MAAA,GAA0B,CAChC,MAAA,GAAqB,CACrB,MAAA,GAAiC,CAEjC,KAAK,cACH,IAAI,YAA8C,2BAA4B,CAC5E,OAAQ,CACN,MAAO,KAAK,aACZ,UAAW,KAAK,iBAChB,QAAS,KAAK,eACf,CACF,CAAC,CACH,CAIH,MAAM,cAA8B,CAClC,OAAO,KAAK,SAAS,CAKvB,IAAsB,CACpB,MAAA,EAAe,SAAS,cAAc,SAAS,CAG/C,IAAK,IAAM,KAAQ,EAAmB,CACpC,IAAM,EAAQ,KAAK,aAAa,EAAK,CACjC,IAAU,MACZ,MAAA,EAAa,aAAa,EAAM,EAAM,CAK1C,MAAA,EAAa,MAAM,OAAS,OAC5B,MAAA,EAAa,MAAM,MAAQ,KAAK,aAAa,QAAQ,EAAI,OACzD,MAAA,EAAa,MAAM,OAAS,KAAK,aAAa,SAAS,EAAI,OAG3D,MAAA,EAAa,iBAAiB,WAAc,KAAK,MAAA,GAAe,CAAC,CAEjE,KAAK,YAAY,YAAY,MAAA,EAAa,CAG5C,MAAA,GAAgC,CAC1B,WAAA,GAAoB,CAAC,MAAA,GACzB,OAAA,EAAmB,GAEnB,GAAI,CACF,IAAM,EAAe,MAAA,GAAuB,CAC5C,GAAI,CAAC,EAAc,CACjB,QAAQ,KAAK,2EAA2E,CACxF,OAIF,MAAA,EAAkB,IAAI,EAAsB,CAC1C,OAAQ,MAAA,EACR,eACA,UAAW,MAAA,EACZ,CAAC,CAEF,MAAA,EAAe,IAAI,EAAO,CACxB,KAAM,aAAa,KAAK,IAAM,cAC9B,QAAS,QACV,CAAC,CAGF,MAAM,MAAA,EAAa,QAAQ,MAAA,EAAgB,CAC3C,MAAA,EAAc,GAGd,MAAM,MAAA,GAA0B,CAGhC,MAAA,GAAiC,CAEjC,KAAK,cACH,IAAI,YAAuC,mBAAoB,CAC7D,OAAQ,CACN,MAAO,KAAK,aACZ,UAAW,KAAK,iBAChB,QAAS,KAAK,eACf,CACF,CAAC,CACH,OACM,EAAO,CACd,QAAQ,MAAM,iCAAkC,EAAM,CACtD,KAAK,cACH,IAAI,YAAuC,mBAAoB,CAC7D,OAAQ,CAAE,QAAO,CAClB,CAAC,CACH,QACO,CACR,MAAA,EAAmB,KAIvB,MAAA,GAA2C,CACzC,GAAI,CAAC,MAAA,EAAc,OAGnB,GAAM,CAAC,EAAa,EAAiB,GAAiB,MAAM,QAAQ,IAAI,CACtE,MAAA,EAAa,WAAW,CACxB,MAAA,EAAa,eAAe,CAAC,MAAO,IAClC,QAAQ,KAAK,gEAAiE,EAAI,CAC3E,CAAE,UAAW,EAAE,CAAE,EACxB,CACF,MAAA,EAAa,aAAa,CAAC,MAAO,IAChC,QAAQ,KAAK,8DAA+D,EAAI,CACzE,CAAE,QAAS,EAAE,CAAE,EACtB,CACH,CAAC,CAEF,MAAA,EAAiB,EAAY,MAC7B,MAAA,EAAqB,EAAgB,UACrC,MAAA,EAAmB,EAAc,QAGnC,IAAkC,CAEhC,GAAI,MAAA,EACF,OAAO,MAAA,EAIT,IAAM,EAAM,KAAK,aAAa,MAAM,CACpC,GAAI,EACF,GAAI,CACF,OAAO,IAAI,IAAI,EAAK,OAAO,SAAS,KAAK,CAAC,aACnC,EAAO,CACd,QAAQ,KAAK,2DAA4D,EAAK,EAAM,CAKxF,OAAO,OAAO,SAAS,OAGzB,IAAmC,CACjC,IAAM,EAAK,UAAU,aACrB,GAAI,CAAC,EAAI,CACP,QAAQ,KAAK,wDAAwD,CACrE,OAEF,IAAM,EAAe,EAErB,MAAA,EAAkC,EAAa,CAC/C,MAAA,EAAsC,EAAa,CACnD,MAAA,EAAoC,EAAa,CAGnD,GAA6B,EAAsC,CACjE,IAAK,IAAM,KAAQ,MAAA,EAAgB,CACjC,IAAM,EAAe,GAAG,KAAK,aAAa,EAAK,OAG/C,GAAI,CAAC,EAAe,EAAa,CAAE,CAC7B,EAAa,OAAS,IACxB,QAAQ,MACN,qCAAqC,EAAK,KAAK,oBAC3B,EAAa,4BAC3B,EAAa,OAAO,iCAC3B,CAED,QAAQ,MACN,qCAAqC,EAAK,KAAK,oBAC3B,EAAa,+GAElC,CAEH,SAGD,EAAa,aAAgD,CAC5D,KAAM,EACN,YAAa,EAAK,aAAe,qBAAqB,EAAK,OAC3D,GAAI,EAAK,aAAe,CAAE,YAAa,EAAK,YAA4B,CACxE,QAAU,GAAS,MAAA,EAAqB,EAAK,KAAM,EAAK,CACzD,CAAC,CAEF,MAAA,EAAsB,IAAI,EAAa,EAI3C,GAAiC,EAAsC,CACrE,IAAK,IAAM,KAAY,MAAA,EAAoB,CACzC,IAAM,EAAc,GAAG,KAAK,aAAa,EAAS,MAE5C2B,EAAiC,CACrC,IAAK,EACL,KAAM,EAAS,KACf,GAAI,EAAS,cAAgB,IAAA,IAAa,CAAE,YAAa,EAAS,YAAa,CAC/E,GAAI,EAAS,WAAa,IAAA,IAAa,CAAE,SAAU,EAAS,SAAU,CACtE,MAAO,EAAM,IACX,MAAA,EAAyB,EAAS,IAAI,CACzC,CACK,EAAe,EAAa,iBAAiB,EAAW,CAC9D,MAAA,EAA0B,IAAI,EAAa,EAAa,EAI5D,GAA+B,EAAsC,CACnE,IAAK,IAAM,KAAU,MAAA,EAAkB,CACrC,IAAM,EAAe,GAAG,KAAK,aAAa,EAAO,OAGjD,GAAI,CAAC,EAAe,EAAa,CAAE,CAC7B,EAAa,OAAS,IACxB,QAAQ,MACN,uCAAuC,EAAO,KAAK,oBAC/B,EAAa,4BAC3B,EAAa,OAAO,iCAC3B,CAED,QAAQ,MACN,uCAAuC,EAAO,KAAK,oBAC/B,EAAa,iHAElC,CAEH,SAGF,IAAME,EAA+B,CACnC,KAAM,EACN,GAAI,EAAO,cAAgB,IAAA,IAAa,CAAE,YAAa,EAAO,YAAa,CAC3E,GAAI,EAAO,WACT,EAAO,UAAU,OAAS,GAAK,CAC7B,WAAY,CACV,KAAM,SACN,WAAY,OAAO,YACjB,EAAO,UAAU,IAAK,GAAQ,CAC5B,EAAI,KACJ,CACE,KAAM,SACN,GAAI,EAAI,cAAgB,IAAA,IAAa,CAAE,YAAa,EAAI,YAAa,CACtE,CACF,CAAC,CACH,CACD,SAAU,EAAO,UAAU,OAAQ,GAAM,EAAE,SAAS,CAAC,IAAK,GAAM,EAAE,KAAK,CACxE,CACF,CACH,IAAM,GAAS,MAAA,EAAsB,EAAO,KAAM,EAAK,CACxD,CACK,EAAe,EAAa,eAAe,EAAW,CAC5D,MAAA,EAAwB,IAAI,EAAc,EAAa,EAI3D,IAAuB,CACrB,IAAM,EAAK,UAAU,aACrB,GAAI,EAAI,CACN,IAAM,EAAe,EACrB,IAAK,IAAM,KAAY,MAAA,EAAsB,QAAQ,CACnD,GAAI,CACF,EAAa,eAAe,EAAS,OAC9B,EAAO,CACd,QAAQ,KACN,iDAAiD,EAAS,mBAC1D,EACD,EAIP,MAAA,EAAsB,OAAO,CAE7B,IAAK,IAAM,KAAgB,MAAA,EAA0B,QAAQ,CAC3D,EAAa,YAAY,CAE3B,MAAA,EAA0B,OAAO,CAEjC,IAAK,IAAM,KAAgB,MAAA,EAAwB,QAAQ,CACzD,EAAa,YAAY,CAE3B,MAAA,EAAwB,OAAO,CAGjC,MAAA,EAAsB,EAAkB,EAAwD,CAC9F,GAAI,CAAC,MAAA,GAAgB,CAAC,MAAA,EACpB,MAAU,MAAM,qCAAqC,CAGvD,IAAM,EAAa,IAAI,gBACjB,EAAY,eAAiB,EAAW,OAAO,CAAE,MAAA,EAAkB,CAEzE,GAAI,CAIF,OAHe,MAAM,MAAA,EAAa,SAAS,CAAE,KAAM,EAAU,UAAW,EAAM,CAAE,IAAA,GAAW,CACzF,OAAQ,EAAW,OACpB,CAAC,QAEM,CACR,aAAa,EAAU,EAI3B,MAAA,EAA0B,EAA0C,CAClE,GAAI,CAAC,MAAA,GAAgB,CAAC,MAAA,EACpB,MAAU,MAAM,qCAAqC,CAGvD,IAAM,EAAa,IAAI,gBACjB,EAAY,eAAiB,EAAW,OAAO,CAAE,MAAA,EAAkB,CAEzE,GAAI,CAEF,OADe,MAAM,MAAA,EAAa,aAAa,CAAE,MAAK,CAAE,CAAE,OAAQ,EAAW,OAAQ,CAAC,QAE9E,CACR,aAAa,EAAU,EAI3B,MAAA,EAAuB,EAAc,EAAyD,CAC5F,GAAI,CAAC,MAAA,GAAgB,CAAC,MAAA,EACpB,MAAU,MAAM,qCAAqC,CAGvD,IAAM,EAAa,IAAI,gBACjB,EAAY,eAAiB,EAAW,OAAO,CAAE,MAAA,EAAkB,CAEzE,GAAI,CAKF,OAJe,MAAM,MAAA,EAAa,UAChC,CAAE,OAAM,UAAW,EAAgC,CACnD,CAAE,OAAQ,EAAW,OAAQ,CAC9B,QAEO,CACR,aAAa,EAAU,EAI3B,MAAA,GAAkC,CAChC,MAAM,MAAA,GAAkB,CAExB,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,IAAI,CAAC,CACxD,MAAM,MAAA,GAAe,CAGvB,MAAA,GAAmC,CAOjC,GANA,MAAA,EAAc,GACd,MAAA,EAAiB,EAAE,CACnB,MAAA,EAAqB,EAAE,CACvB,MAAA,EAAmB,EAAE,CACrB,MAAA,GAAqB,CAEjB,MAAA,EAAc,CAChB,GAAI,CACF,MAAM,MAAA,EAAa,OAAO,OACnB,EAAO,CACd,QAAQ,KAAK,6DAA8D,EAAM,CAEnF,MAAA,EAAe,KAGjB,GAAI,MAAA,EAAiB,CACnB,GAAI,CACF,MAAM,MAAA,EAAgB,OAAO,OACtB,EAAO,CACd,QAAQ,KAAK,gEAAiE,EAAM,CAEtF,MAAA,EAAkB,MAItB,MAAA,GAAgC,CAC9B,MAAM,MAAA,GAAkB,GAS5B,SAAgB,EAAyB,EAAU,aAAoB,CACjE,OAAO,eAAmB,KAAe,CAAC,eAAe,IAAI,EAAQ,EACvE,eAAe,OAAO,EAAS,EAAiB,CAKhD,OAAO,OAAW,KAAe,OAAO,eAAmB,KAC7D,GAA0B"}
1
+ {"version":3,"file":"index.js","names":["#createIframe","#cleanup","#targetOrigin","#ready","#reconnect","#channelId","#callTimeout","#prefixSeparator","#unregisterAll","#registerAllOnModelContext","#iframe","#client","#registeredTools","#registeredResources","#registeredPrompts","#mcpTools","#mcpResources","#mcpPrompts","#fetchAllFromIframe","#connect","#connecting","#getTargetOrigin","#transport","#registerToolsOnModelContext","#registerResourcesOnModelContext","#registerPromptsOnModelContext","#callIframeTool","#readIframeResource","#getIframePrompt","#disconnect"],"sources":["../src/MCPIframeElement.ts"],"sourcesContent":["/**\n * MCPIframe Custom Element\n *\n * A custom element that wraps an iframe and automatically exposes tools,\n * resources, and prompts registered in the iframe's MCP server to the\n * parent page's Model Context API.\n *\n * The iframe should have the MCP polyfill installed, which creates an MCP server\n * that exposes items registered via `navigator.modelContext`.\n *\n * @example\n * ```html\n * <mcp-iframe src=\"./child-app.html\" id=\"my-app\"></mcp-iframe>\n * ```\n *\n * Items from the iframe will be exposed with the element's ID as prefix:\n * - Child registers tool \"calculate\" -> Parent sees \"my-app_calculate\"\n * - Child registers resource \"config://settings\" -> Parent sees \"my-app_config://settings\"\n * - Child registers prompt \"help\" -> Parent sees \"my-app_help\"\n *\n * Note: The prefix separator defaults to underscore (_) to ensure MCP compatibility.\n * Tool and prompt names must match the pattern: ^[a-zA-Z0-9_-]{1,128}$\n *\n * @example\n * ```typescript\n * const mcpIframe = document.querySelector('mcp-iframe');\n * mcpIframe.addEventListener('mcp-iframe-ready', (e) => {\n * console.log('Tools:', e.detail.tools);\n * console.log('Resources:', e.detail.resources);\n * console.log('Prompts:', e.detail.prompts);\n * });\n * ```\n */\n\nimport { IframeParentTransport } from '@mcp-b/transports';\nimport type {\n GetPromptResult,\n Prompt,\n ReadResourceResult,\n Resource,\n Tool,\n} from '@mcp-b/webmcp-ts-sdk';\nimport {\n type BrowserMcpServer,\n Client,\n type PromptDescriptor,\n type ResourceDescriptor,\n} from '@mcp-b/webmcp-ts-sdk';\nimport type {\n CallToolResult,\n InputSchema,\n RegistrationHandle,\n ToolDescriptor,\n} from '@mcp-b/webmcp-types';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst DEFAULT_CALL_TIMEOUT = 30000;\nconst DEFAULT_PREFIX_SEPARATOR = '_';\nconst DEFAULT_CHANNEL_ID = 'mcp-iframe';\n\n/**\n * MCP name validation pattern.\n * Tool/prompt names must match: ^[a-zA-Z0-9_-]{1,128}$\n */\nconst MCP_NAME_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/;\nconst MCP_NAME_MAX_LENGTH = 128;\n\n/**\n * Validates that a string contains only valid MCP name characters.\n * Valid characters: a-z, A-Z, 0-9, underscore (_), hyphen (-)\n */\nfunction isValidMCPNameChars(str: string): boolean {\n return /^[a-zA-Z0-9_-]*$/.test(str);\n}\n\n/**\n * Validates a complete MCP name (tool name, prompt name).\n * Must be 1-128 characters and contain only valid characters.\n */\nfunction isValidMCPName(name: string): boolean {\n return MCP_NAME_PATTERN.test(name);\n}\n\n/**\n * Sanitizes a string to contain only valid MCP name characters.\n * Replaces invalid characters with underscores.\n */\nfunction sanitizeMCPNamePart(str: string): string {\n return str.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\n/** Standard iframe attributes that are mirrored to the internal iframe */\nconst IFRAME_ATTRIBUTES = [\n 'src',\n 'srcdoc',\n 'name',\n 'sandbox',\n 'allow',\n 'allowfullscreen',\n 'width',\n 'height',\n 'loading',\n 'referrerpolicy',\n 'credentialless',\n] as const;\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Custom event detail for mcp-iframe-ready */\nexport interface MCPIframeReadyEventDetail {\n tools: string[];\n resources: string[];\n prompts: string[];\n}\n\n/** Custom event detail for mcp-iframe-error */\nexport interface MCPIframeErrorEventDetail {\n error: unknown;\n}\n\n/** Custom event detail for mcp-iframe-tools-changed */\nexport interface MCPIframeToolsChangedEventDetail {\n tools: string[];\n resources: string[];\n prompts: string[];\n}\n\n// ============================================================================\n// MCPIframeElement\n// ============================================================================\n\n/**\n * MCPIframe Custom Element\n *\n * Wraps an iframe and exposes its MCP tools, resources, and prompts\n * to the parent's Model Context API.\n *\n * @fires mcp-iframe-ready - When connected to iframe's MCP server\n * @fires mcp-iframe-error - When connection fails\n * @fires mcp-iframe-tools-changed - When items are refreshed\n */\nexport class MCPIframeElement extends HTMLElement {\n // Internal state\n #iframe: HTMLIFrameElement | null = null;\n #client: Client | null = null;\n #transport: IframeParentTransport | null = null;\n #ready = false;\n #connecting = false;\n\n // MCP items from iframe\n #mcpTools: Tool[] = [];\n #mcpResources: Resource[] = [];\n #mcpPrompts: Prompt[] = [];\n\n // Registered items on parent\n #registeredTools = new Set<string>();\n #registeredResources = new Map<string, RegistrationHandle>();\n #registeredPrompts = new Map<string, RegistrationHandle>();\n\n // Configuration\n #callTimeout = DEFAULT_CALL_TIMEOUT;\n #prefixSeparator = DEFAULT_PREFIX_SEPARATOR;\n #channelId = DEFAULT_CHANNEL_ID;\n #targetOrigin: string | null = null;\n\n static get observedAttributes(): string[] {\n return [...IFRAME_ATTRIBUTES, 'target-origin', 'channel', 'call-timeout', 'prefix-separator'];\n }\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n // ==================== Lifecycle ====================\n\n connectedCallback(): void {\n this.#createIframe();\n }\n\n disconnectedCallback(): void {\n void this.#cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'target-origin':\n this.#targetOrigin = newValue;\n if (this.#ready) void this.#reconnect();\n break;\n\n case 'channel':\n this.#channelId = newValue ?? DEFAULT_CHANNEL_ID;\n if (this.#ready) void this.#reconnect();\n break;\n\n case 'call-timeout':\n this.#callTimeout = newValue ? Number.parseInt(newValue, 10) : DEFAULT_CALL_TIMEOUT;\n break;\n\n case 'prefix-separator': {\n const separator = newValue ?? DEFAULT_PREFIX_SEPARATOR;\n if (!isValidMCPNameChars(separator)) {\n console.warn(\n `[MCPIframe] Invalid prefix-separator \"${separator}\". ` +\n 'Only alphanumeric characters, underscores, and hyphens are allowed. ' +\n `Using sanitized value: \"${sanitizeMCPNamePart(separator)}\"`\n );\n this.#prefixSeparator = sanitizeMCPNamePart(separator);\n } else {\n this.#prefixSeparator = separator;\n }\n if (this.#ready) {\n this.#unregisterAll();\n this.#registerAllOnModelContext();\n }\n break;\n }\n\n default:\n // Mirror standard iframe attributes\n if (this.#iframe && (IFRAME_ATTRIBUTES as readonly string[]).includes(name)) {\n if (newValue === null) {\n this.#iframe.removeAttribute(name);\n } else {\n this.#iframe.setAttribute(name, newValue);\n }\n // Reconnect when source changes\n if (name === 'src' || name === 'srcdoc') {\n void this.#reconnect();\n }\n }\n }\n }\n\n // ==================== Public API ====================\n\n /** The wrapped iframe element */\n get iframe(): HTMLIFrameElement | null {\n return this.#iframe;\n }\n\n /** The MCP client (if connected) */\n get client(): Client | null {\n return this.#client;\n }\n\n /** Whether the element is connected to the iframe's MCP server */\n get ready(): boolean {\n return this.#ready;\n }\n\n /** List of exposed tool names (with prefix) */\n get exposedTools(): string[] {\n return Array.from(this.#registeredTools.values());\n }\n\n /** List of exposed resource URIs (with prefix) */\n get exposedResources(): string[] {\n return Array.from(this.#registeredResources.keys());\n }\n\n /** List of exposed prompt names (with prefix) */\n get exposedPrompts(): string[] {\n return Array.from(this.#registeredPrompts.keys());\n }\n\n /** Raw tools from the iframe's MCP server (without prefix) */\n get mcpTools(): Tool[] {\n return [...this.#mcpTools];\n }\n\n /** Raw resources from the iframe's MCP server (without prefix) */\n get mcpResources(): Resource[] {\n return [...this.#mcpResources];\n }\n\n /** Raw prompts from the iframe's MCP server (without prefix) */\n get mcpPrompts(): Prompt[] {\n return [...this.#mcpPrompts];\n }\n\n /** The item name prefix (id + separator), sanitized for MCP compatibility */\n get itemPrefix(): string {\n const rawId = this.id || this.getAttribute('name') || 'iframe';\n const id = sanitizeMCPNamePart(rawId);\n if (id !== rawId) {\n console.warn(\n `[MCPIframe] ID/name \"${rawId}\" contains invalid characters for MCP names. ` +\n `Using sanitized value: \"${id}\"`\n );\n }\n return `${id}${this.#prefixSeparator}`;\n }\n\n /** @deprecated Use itemPrefix instead */\n get toolPrefix(): string {\n return this.itemPrefix;\n }\n\n /** Manually refresh all items from the iframe */\n async refresh(): Promise<void> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n await this.#fetchAllFromIframe();\n this.#unregisterAll();\n this.#registerAllOnModelContext();\n\n this.dispatchEvent(\n new CustomEvent<MCPIframeToolsChangedEventDetail>('mcp-iframe-tools-changed', {\n detail: {\n tools: this.exposedTools,\n resources: this.exposedResources,\n prompts: this.exposedPrompts,\n },\n })\n );\n }\n\n /** @deprecated Use refresh() instead */\n async refreshTools(): Promise<void> {\n return this.refresh();\n }\n\n // ==================== Private Methods ====================\n\n #createIframe(): void {\n this.#iframe = document.createElement('iframe');\n\n // Mirror all iframe attributes\n for (const attr of IFRAME_ATTRIBUTES) {\n const value = this.getAttribute(attr);\n if (value !== null) {\n this.#iframe.setAttribute(attr, value);\n }\n }\n\n // Default styling\n this.#iframe.style.border = 'none';\n this.#iframe.style.width = this.getAttribute('width') ?? '100%';\n this.#iframe.style.height = this.getAttribute('height') ?? '100%';\n\n // Connect when iframe loads\n this.#iframe.addEventListener('load', () => void this.#connect());\n\n this.shadowRoot?.appendChild(this.#iframe);\n }\n\n async #connect(): Promise<void> {\n if (this.#connecting || !this.#iframe) return;\n this.#connecting = true;\n\n try {\n const targetOrigin = this.#getTargetOrigin();\n if (!targetOrigin) {\n console.warn('[MCPIframe] Cannot determine target origin. Set target-origin attribute.');\n return;\n }\n\n // Create transport and client\n this.#transport = new IframeParentTransport({\n iframe: this.#iframe,\n targetOrigin,\n channelId: this.#channelId,\n });\n\n this.#client = new Client({\n name: `MCPIframe:${this.id || 'anonymous'}`,\n version: '1.0.0',\n });\n\n // Connect to iframe's MCP server\n await this.#client.connect(this.#transport);\n this.#ready = true;\n\n // Fetch all items from iframe\n await this.#fetchAllFromIframe();\n\n // Register on parent's Model Context\n this.#registerAllOnModelContext();\n\n this.dispatchEvent(\n new CustomEvent<MCPIframeReadyEventDetail>('mcp-iframe-ready', {\n detail: {\n tools: this.exposedTools,\n resources: this.exposedResources,\n prompts: this.exposedPrompts,\n },\n })\n );\n } catch (error) {\n console.error('[MCPIframe] Failed to connect:', error);\n this.dispatchEvent(\n new CustomEvent<MCPIframeErrorEventDetail>('mcp-iframe-error', {\n detail: { error },\n })\n );\n } finally {\n this.#connecting = false;\n }\n }\n\n async #fetchAllFromIframe(): Promise<void> {\n if (!this.#client) return;\n\n // Fetch tools, resources, and prompts in parallel\n const [toolsResult, resourcesResult, promptsResult] = await Promise.all([\n this.#client.listTools(),\n this.#client.listResources().catch((err) => {\n console.warn('[MCPIframeElement] listResources failed, defaulting to empty:', err);\n return { resources: [] };\n }),\n this.#client.listPrompts().catch((err) => {\n console.warn('[MCPIframeElement] listPrompts failed, defaulting to empty:', err);\n return { prompts: [] };\n }),\n ]);\n\n this.#mcpTools = toolsResult.tools;\n this.#mcpResources = resourcesResult.resources;\n this.#mcpPrompts = promptsResult.prompts;\n }\n\n #getTargetOrigin(): string | null {\n // Use explicit attribute if set\n if (this.#targetOrigin) {\n return this.#targetOrigin;\n }\n\n // Infer from src attribute\n const src = this.getAttribute('src');\n if (src) {\n try {\n return new URL(src, window.location.href).origin;\n } catch (error) {\n console.warn('[MCPIframeElement] Invalid src URL for origin detection:', src, error);\n }\n }\n\n // Default to same origin\n return window.location.origin;\n }\n\n #registerAllOnModelContext(): void {\n const mc = navigator.modelContext;\n if (!mc) {\n console.warn('[MCPIframe] Model Context API not available on parent');\n return;\n }\n const modelContext = mc as unknown as BrowserMcpServer;\n\n this.#registerToolsOnModelContext(modelContext);\n this.#registerResourcesOnModelContext(modelContext);\n this.#registerPromptsOnModelContext(modelContext);\n }\n\n #registerToolsOnModelContext(modelContext: BrowserMcpServer): void {\n for (const tool of this.#mcpTools) {\n const prefixedName = `${this.itemPrefix}${tool.name}`;\n\n // Validate the final tool name\n if (!isValidMCPName(prefixedName)) {\n if (prefixedName.length > MCP_NAME_MAX_LENGTH) {\n console.error(\n `[MCPIframe] Cannot register tool \"${tool.name}\": ` +\n `prefixed name \"${prefixedName}\" exceeds ${MCP_NAME_MAX_LENGTH} characters ` +\n `(${prefixedName.length} chars). Skipping registration.`\n );\n } else {\n console.error(\n `[MCPIframe] Cannot register tool \"${tool.name}\": ` +\n `prefixed name \"${prefixedName}\" contains invalid characters. ` +\n 'Tool names must match pattern: ^[a-zA-Z0-9_-]{1,128}$. Skipping registration.'\n );\n }\n continue;\n }\n\n (modelContext.registerTool as (tool: ToolDescriptor) => void)({\n name: prefixedName,\n description: tool.description ?? `Tool from iframe: ${tool.name}`,\n ...(tool.inputSchema && { inputSchema: tool.inputSchema as InputSchema }),\n execute: (args) => this.#callIframeTool(tool.name, args),\n });\n\n this.#registeredTools.add(prefixedName);\n }\n }\n\n #registerResourcesOnModelContext(modelContext: BrowserMcpServer): void {\n for (const resource of this.#mcpResources) {\n const prefixedUri = `${this.itemPrefix}${resource.uri}`;\n\n const descriptor: ResourceDescriptor = {\n uri: prefixedUri,\n name: resource.name,\n ...(resource.description !== undefined && { description: resource.description }),\n ...(resource.mimeType !== undefined && { mimeType: resource.mimeType }),\n read: (_uri, _params) =>\n this.#readIframeResource(resource.uri) as ReturnType<ResourceDescriptor['read']>,\n };\n const registration = modelContext.registerResource(descriptor);\n this.#registeredResources.set(prefixedUri, registration);\n }\n }\n\n #registerPromptsOnModelContext(modelContext: BrowserMcpServer): void {\n for (const prompt of this.#mcpPrompts) {\n const prefixedName = `${this.itemPrefix}${prompt.name}`;\n\n // Validate the final prompt name\n if (!isValidMCPName(prefixedName)) {\n if (prefixedName.length > MCP_NAME_MAX_LENGTH) {\n console.error(\n `[MCPIframe] Cannot register prompt \"${prompt.name}\": ` +\n `prefixed name \"${prefixedName}\" exceeds ${MCP_NAME_MAX_LENGTH} characters ` +\n `(${prefixedName.length} chars). Skipping registration.`\n );\n } else {\n console.error(\n `[MCPIframe] Cannot register prompt \"${prompt.name}\": ` +\n `prefixed name \"${prefixedName}\" contains invalid characters. ` +\n 'Prompt names must match pattern: ^[a-zA-Z0-9_-]{1,128}$. Skipping registration.'\n );\n }\n continue;\n }\n\n const descriptor: PromptDescriptor = {\n name: prefixedName,\n ...(prompt.description !== undefined && { description: prompt.description }),\n ...(prompt.arguments &&\n prompt.arguments.length > 0 && {\n argsSchema: {\n type: 'object',\n properties: Object.fromEntries(\n prompt.arguments.map((arg) => [\n arg.name,\n {\n type: 'string',\n ...(arg.description !== undefined && { description: arg.description }),\n },\n ])\n ),\n required: prompt.arguments.filter((a) => a.required).map((a) => a.name),\n } satisfies InputSchema,\n }),\n get: (args) => this.#getIframePrompt(prompt.name, args),\n };\n const registration = modelContext.registerPrompt(descriptor);\n this.#registeredPrompts.set(prefixedName, registration);\n }\n }\n\n #unregisterAll(): void {\n const mc = navigator.modelContext;\n if (mc) {\n const modelContext = mc as unknown as BrowserMcpServer;\n for (const toolName of this.#registeredTools.values()) {\n try {\n modelContext.unregisterTool(toolName);\n } catch (error) {\n console.warn(\n `[MCPIframeElement] Failed to unregister tool \"${toolName}\" during cleanup:`,\n error\n );\n }\n }\n }\n this.#registeredTools.clear();\n\n for (const registration of this.#registeredResources.values()) {\n registration.unregister();\n }\n this.#registeredResources.clear();\n\n for (const registration of this.#registeredPrompts.values()) {\n registration.unregister();\n }\n this.#registeredPrompts.clear();\n }\n\n async #callIframeTool(toolName: string, args: Record<string, unknown>): Promise<CallToolResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.callTool({ name: toolName, arguments: args }, undefined, {\n signal: controller.signal,\n });\n return result as CallToolResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #readIframeResource(uri: string): Promise<ReadResourceResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.readResource({ uri }, { signal: controller.signal });\n return result as ReadResourceResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #getIframePrompt(name: string, args: Record<string, unknown>): Promise<GetPromptResult> {\n if (!this.#client || !this.#ready) {\n throw new Error('Not connected to iframe MCP server');\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.#callTimeout);\n\n try {\n const result = await this.#client.getPrompt(\n { name, arguments: args as Record<string, string> },\n { signal: controller.signal }\n );\n return result as GetPromptResult;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n async #reconnect(): Promise<void> {\n await this.#disconnect();\n // Brief delay for iframe to be ready\n await new Promise((resolve) => setTimeout(resolve, 100));\n await this.#connect();\n }\n\n async #disconnect(): Promise<void> {\n this.#ready = false;\n this.#mcpTools = [];\n this.#mcpResources = [];\n this.#mcpPrompts = [];\n this.#unregisterAll();\n\n if (this.#client) {\n try {\n await this.#client.close();\n } catch (error) {\n console.warn('[MCPIframeElement] Error closing client during disconnect:', error);\n }\n this.#client = null;\n }\n\n if (this.#transport) {\n try {\n await this.#transport.close();\n } catch (error) {\n console.warn('[MCPIframeElement] Error closing transport during disconnect:', error);\n }\n this.#transport = null;\n }\n }\n\n async #cleanup(): Promise<void> {\n await this.#disconnect();\n }\n}\n\n// ============================================================================\n// Registration\n// ============================================================================\n\n/** Register the custom element with a custom tag name */\nexport function registerMCPIframeElement(tagName = 'mcp-iframe'): void {\n if (typeof customElements !== 'undefined' && !customElements.get(tagName)) {\n customElements.define(tagName, MCPIframeElement);\n }\n}\n\n// Auto-register in browser environments\nif (typeof window !== 'undefined' && typeof customElements !== 'undefined') {\n registerMCPIframeElement();\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,29 +1,35 @@
1
1
  {
2
2
  "name": "@mcp-b/mcp-iframe",
3
- "version": "2.2.0",
3
+ "version": "2.3.1-beta.20260528050333",
4
4
  "description": "Custom element for exposing iframe MCP tools, resources, and prompts to parent page",
5
5
  "keywords": [
6
+ "browser",
7
+ "custom-element",
8
+ "iframe",
6
9
  "mcp",
7
10
  "model-context-protocol",
8
- "iframe",
9
- "custom-element",
10
11
  "web-component",
11
- "browser",
12
12
  "web-model-context"
13
13
  ],
14
14
  "homepage": "https://github.com/WebMCP-org/npm-packages#readme",
15
15
  "bugs": {
16
16
  "url": "https://github.com/WebMCP-org/npm-packages/issues"
17
17
  },
18
+ "license": "MIT",
19
+ "author": "Alex Nahas",
18
20
  "repository": {
19
21
  "type": "git",
20
22
  "url": "git+https://github.com/WebMCP-org/npm-packages.git",
21
23
  "directory": "packages/mcp-iframe"
22
24
  },
23
- "license": "MIT",
24
- "author": "Alex Nahas",
25
- "sideEffects": true,
25
+ "files": [
26
+ "dist"
27
+ ],
26
28
  "type": "module",
29
+ "sideEffects": true,
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
27
33
  "exports": {
28
34
  ".": {
29
35
  "types": "./dist/index.d.ts",
@@ -31,35 +37,29 @@
31
37
  "default": "./dist/index.js"
32
38
  }
33
39
  },
34
- "main": "./dist/index.js",
35
- "module": "./dist/index.js",
36
- "types": "./dist/index.d.ts",
37
- "files": [
38
- "dist"
39
- ],
40
+ "publishConfig": {
41
+ "access": "public",
42
+ "registry": "https://registry.npmjs.org/"
43
+ },
40
44
  "dependencies": {
41
- "@mcp-b/transports": "2.2.0",
42
- "@mcp-b/webmcp-ts-sdk": "2.2.0",
43
- "@mcp-b/webmcp-types": "2.2.0"
45
+ "@mcp-b/transports": "2.3.1-beta.20260528050333",
46
+ "@mcp-b/webmcp-types": "2.3.1-beta.20260528050333",
47
+ "@mcp-b/webmcp-ts-sdk": "2.3.1-beta.20260528050333"
44
48
  },
45
49
  "devDependencies": {
46
50
  "@types/node": "22.17.2",
47
- "tsdown": "^0.15.10",
48
- "typescript": "^5.8.3"
51
+ "typescript": "^5.8.3",
52
+ "vite-plus": "^0.1.22"
49
53
  },
50
54
  "engines": {
51
55
  "node": ">=18"
52
56
  },
53
- "publishConfig": {
54
- "access": "public",
55
- "registry": "https://registry.npmjs.org/"
56
- },
57
57
  "scripts": {
58
- "build": "tsdown",
59
- "check": "biome check --write .",
60
- "clean": "rm -rf dist .turbo",
61
- "format": "biome format --write .",
62
- "lint": "biome lint --write .",
58
+ "build": "vp pack",
59
+ "check": "vp check --fix",
60
+ "clean": "rm -rf dist",
61
+ "format": "vp fmt --write",
62
+ "lint": "vp lint --fix",
63
63
  "publish:dry": "pnpm publish --access public --dry-run",
64
64
  "publish:npm": "pnpm publish --access public",
65
65
  "typecheck": "tsc --noEmit",