@mcp-b/mcp-iframe 0.1.0-beta.1
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/LICENSE +21 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 mcp-b contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { Prompt, Resource, Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/MCPIframeElement.d.ts
|
|
5
|
+
|
|
6
|
+
/** Custom event detail for mcp-iframe-ready */
|
|
7
|
+
interface MCPIframeReadyEventDetail {
|
|
8
|
+
tools: string[];
|
|
9
|
+
resources: string[];
|
|
10
|
+
prompts: string[];
|
|
11
|
+
}
|
|
12
|
+
/** Custom event detail for mcp-iframe-error */
|
|
13
|
+
interface MCPIframeErrorEventDetail {
|
|
14
|
+
error: unknown;
|
|
15
|
+
}
|
|
16
|
+
/** Custom event detail for mcp-iframe-tools-changed */
|
|
17
|
+
interface MCPIframeToolsChangedEventDetail {
|
|
18
|
+
tools: string[];
|
|
19
|
+
resources: string[];
|
|
20
|
+
prompts: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* MCPIframe Custom Element
|
|
24
|
+
*
|
|
25
|
+
* Wraps an iframe and exposes its MCP tools, resources, and prompts
|
|
26
|
+
* to the parent's Model Context API.
|
|
27
|
+
*
|
|
28
|
+
* @fires mcp-iframe-ready - When connected to iframe's MCP server
|
|
29
|
+
* @fires mcp-iframe-error - When connection fails
|
|
30
|
+
* @fires mcp-iframe-tools-changed - When items are refreshed
|
|
31
|
+
*/
|
|
32
|
+
declare class MCPIframeElement extends HTMLElement {
|
|
33
|
+
#private;
|
|
34
|
+
static get observedAttributes(): string[];
|
|
35
|
+
constructor();
|
|
36
|
+
connectedCallback(): void;
|
|
37
|
+
disconnectedCallback(): void;
|
|
38
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
39
|
+
/** The wrapped iframe element */
|
|
40
|
+
get iframe(): HTMLIFrameElement | null;
|
|
41
|
+
/** The MCP client (if connected) */
|
|
42
|
+
get client(): Client | null;
|
|
43
|
+
/** Whether the element is connected to the iframe's MCP server */
|
|
44
|
+
get ready(): boolean;
|
|
45
|
+
/** List of exposed tool names (with prefix) */
|
|
46
|
+
get exposedTools(): string[];
|
|
47
|
+
/** List of exposed resource URIs (with prefix) */
|
|
48
|
+
get exposedResources(): string[];
|
|
49
|
+
/** List of exposed prompt names (with prefix) */
|
|
50
|
+
get exposedPrompts(): string[];
|
|
51
|
+
/** Raw tools from the iframe's MCP server (without prefix) */
|
|
52
|
+
get mcpTools(): Tool[];
|
|
53
|
+
/** Raw resources from the iframe's MCP server (without prefix) */
|
|
54
|
+
get mcpResources(): Resource[];
|
|
55
|
+
/** Raw prompts from the iframe's MCP server (without prefix) */
|
|
56
|
+
get mcpPrompts(): Prompt[];
|
|
57
|
+
/** The item name prefix (id + separator) */
|
|
58
|
+
get itemPrefix(): string;
|
|
59
|
+
/** @deprecated Use itemPrefix instead */
|
|
60
|
+
get toolPrefix(): string;
|
|
61
|
+
/** Manually refresh all items from the iframe */
|
|
62
|
+
refresh(): Promise<void>;
|
|
63
|
+
/** @deprecated Use refresh() instead */
|
|
64
|
+
refreshTools(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/** Register the custom element with a custom tag name */
|
|
67
|
+
declare function registerMCPIframeElement(tagName?: string): void;
|
|
68
|
+
//#endregion
|
|
69
|
+
export { MCPIframeElement, type MCPIframeErrorEventDetail, type MCPIframeReadyEventDetail, type MCPIframeToolsChangedEventDetail, registerMCPIframeElement };
|
|
70
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/MCPIframeElement.ts"],"sourcesContent":[],"mappings":";;;;;;UAyGiB,yBAAA;;;;;;UAOA,yBAAA;;;;UAKA,gCAAA;;;;;;;;;;;;;;;cAoBJ,gBAAA,SAAyB,WAAA;;;;;;;;gBAwFtB;;gBAKA;;;;;;;;;;kBAyBE;;sBAKI;;oBAKF;;;;;;aAgBD;;kBAqBK;;;iBAmTR,wBAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{IframeParentTransport as e}from"@mcp-b/transports";import{Client as t}from"@modelcontextprotocol/sdk/client/index.js";const n=3e4,r=`mcp-iframe`,i=[`src`,`srcdoc`,`name`,`sandbox`,`allow`,`allowfullscreen`,`width`,`height`,`loading`,`referrerpolicy`,`credentialless`];var a=class extends HTMLElement{#iframe=null;#client=null;#transport=null;#ready=!1;#connecting=!1;#mcpTools=[];#mcpResources=[];#mcpPrompts=[];#registeredTools=new Map;#registeredResources=new Map;#registeredPrompts=new Map;#callTimeout=n;#prefixSeparator=`:`;#channelId=r;#targetOrigin=null;static get observedAttributes(){return[...i,`target-origin`,`channel`,`call-timeout`,`prefix-separator`]}constructor(){super(),this.attachShadow({mode:`open`})}connectedCallback(){this.#createIframe()}disconnectedCallback(){this.#cleanup()}attributeChangedCallback(e,t,a){if(t!==a)switch(e){case`target-origin`:this.#targetOrigin=a,this.#ready&&this.#reconnect();break;case`channel`:this.#channelId=a??r,this.#ready&&this.#reconnect();break;case`call-timeout`:this.#callTimeout=a?Number.parseInt(a,10):n;break;case`prefix-separator`:this.#prefixSeparator=a??`:`,this.#ready&&(this.#unregisterAll(),this.#registerAllOnModelContext());break;default:this.#iframe&&i.includes(e)&&(a===null?this.#iframe.removeAttribute(e):this.#iframe.setAttribute(e,a),(e===`src`||e===`srcdoc`)&&this.#reconnect())}}get iframe(){return this.#iframe}get client(){return this.#client}get ready(){return this.#ready}get exposedTools(){return Array.from(this.#registeredTools.keys())}get exposedResources(){return Array.from(this.#registeredResources.keys())}get exposedPrompts(){return Array.from(this.#registeredPrompts.keys())}get mcpTools(){return[...this.#mcpTools]}get mcpResources(){return[...this.#mcpResources]}get mcpPrompts(){return[...this.#mcpPrompts]}get itemPrefix(){return`${this.id||this.getAttribute(`name`)||`iframe`}${this.#prefixSeparator}`}get toolPrefix(){return this.itemPrefix}async refresh(){if(!this.#client||!this.#ready)throw Error(`Not connected to iframe MCP server`);await this.#fetchAllFromIframe(),this.#unregisterAll(),this.#registerAllOnModelContext(),this.dispatchEvent(new CustomEvent(`mcp-iframe-tools-changed`,{detail:{tools:this.exposedTools,resources:this.exposedResources,prompts:this.exposedPrompts}}))}async refreshTools(){return this.refresh()}#createIframe(){this.#iframe=document.createElement(`iframe`);for(let e of i){let t=this.getAttribute(e);t!==null&&this.#iframe.setAttribute(e,t)}this.#iframe.style.border=`none`,this.#iframe.style.width=this.getAttribute(`width`)??`100%`,this.#iframe.style.height=this.getAttribute(`height`)??`100%`,this.#iframe.addEventListener(`load`,()=>void this.#connect()),this.shadowRoot?.appendChild(this.#iframe)}async#connect(){if(!(this.#connecting||!this.#iframe)){this.#connecting=!0;try{let n=this.#getTargetOrigin();if(!n){console.warn(`[MCPIframe] Cannot determine target origin. Set target-origin attribute.`);return}this.#transport=new e({iframe:this.#iframe,targetOrigin:n,channelId:this.#channelId}),this.#client=new t({name:`MCPIframe:${this.id||`anonymous`}`,version:`1.0.0`}),await this.#client.connect(this.#transport),this.#ready=!0,await this.#fetchAllFromIframe(),this.#registerAllOnModelContext(),this.dispatchEvent(new CustomEvent(`mcp-iframe-ready`,{detail:{tools:this.exposedTools,resources:this.exposedResources,prompts:this.exposedPrompts}}))}catch(e){console.error(`[MCPIframe] Failed to connect:`,e),this.dispatchEvent(new CustomEvent(`mcp-iframe-error`,{detail:{error:e}}))}finally{this.#connecting=!1}}}async#fetchAllFromIframe(){if(!this.#client)return;let[e,t,n]=await Promise.all([this.#client.listTools(),this.#client.listResources().catch(()=>({resources:[]})),this.#client.listPrompts().catch(()=>({prompts:[]}))]);this.#mcpTools=e.tools,this.#mcpResources=t.resources,this.#mcpPrompts=n.prompts}#getTargetOrigin(){if(this.#targetOrigin)return this.#targetOrigin;let e=this.getAttribute(`src`);if(e)try{return new URL(e,window.location.href).origin}catch{}return window.location.origin}#registerAllOnModelContext(){let e=navigator.modelContext;if(!e){console.warn(`[MCPIframe] Model Context API not available on parent`);return}this.#registerToolsOnModelContext(e),this.#registerResourcesOnModelContext(e),this.#registerPromptsOnModelContext(e)}#registerToolsOnModelContext(e){for(let t of this.#mcpTools){let n=`${this.itemPrefix}${t.name}`,r=e.registerTool({name:n,description:t.description??`Tool from iframe: ${t.name}`,inputSchema:t.inputSchema,execute:e=>this.#callIframeTool(t.name,e)});this.#registeredTools.set(n,r)}}#registerResourcesOnModelContext(e){for(let t of this.#mcpResources){let n=`${this.itemPrefix}${t.uri}`,r={uri:n,name:t.name,read:(e,n)=>this.#readIframeResource(t.uri)};t.description!==void 0&&(r.description=t.description),t.mimeType!==void 0&&(r.mimeType=t.mimeType);let i=e.registerResource(r);this.#registeredResources.set(n,i)}}#registerPromptsOnModelContext(e){for(let t of this.#mcpPrompts){let n=`${this.itemPrefix}${t.name}`,r={name:n,get:e=>this.#getIframePrompt(t.name,e)};t.description!==void 0&&(r.description=t.description),t.arguments&&t.arguments.length>0&&(r.argsSchema={type:`object`,properties:Object.fromEntries(t.arguments.map(e=>[e.name,{type:`string`,description:e.description}])),required:t.arguments.filter(e=>e.required).map(e=>e.name)});let i=e.registerPrompt(r);this.#registeredPrompts.set(n,i)}}#unregisterAll(){for(let e of this.#registeredTools.values())e.unregister();this.#registeredTools.clear();for(let e of this.#registeredResources.values())e.unregister();this.#registeredResources.clear();for(let e of this.#registeredPrompts.values())e.unregister();this.#registeredPrompts.clear()}async#callIframeTool(e,t){if(!this.#client||!this.#ready)throw Error(`Not connected to iframe MCP server`);let n=new AbortController,r=setTimeout(()=>n.abort(),this.#callTimeout);try{return await this.#client.callTool({name:e,arguments:t},void 0,{signal:n.signal})}finally{clearTimeout(r)}}async#readIframeResource(e){if(!this.#client||!this.#ready)throw Error(`Not connected to iframe MCP server`);let t=new AbortController,n=setTimeout(()=>t.abort(),this.#callTimeout);try{return await this.#client.readResource({uri:e},{signal:t.signal})}finally{clearTimeout(n)}}async#getIframePrompt(e,t){if(!this.#client||!this.#ready)throw Error(`Not connected to iframe MCP server`);let n=new AbortController,r=setTimeout(()=>n.abort(),this.#callTimeout);try{return await this.#client.getPrompt({name:e,arguments:t},{signal:n.signal})}finally{clearTimeout(r)}}async#reconnect(){await this.#disconnect(),await new Promise(e=>setTimeout(e,100)),await this.#connect()}async#disconnect(){if(this.#ready=!1,this.#mcpTools=[],this.#mcpResources=[],this.#mcpPrompts=[],this.#unregisterAll(),this.#client){try{await this.#client.close()}catch{}this.#client=null}if(this.#transport){try{await this.#transport.close()}catch{}this.#transport=null}}async#cleanup(){await this.#disconnect()}};function o(e=`mcp-iframe`){typeof customElements<`u`&&!customElements.get(e)&&customElements.define(e,a)}typeof window<`u`&&typeof customElements<`u`&&o();export{a as MCPIframeElement,o as registerMCPIframeElement};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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","resourceDescriptor: Parameters<ModelContext['registerResource']>[0]","#readIframeResource","promptDescriptor: Parameters<ModelContext['registerPrompt']>[0]","#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 * @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 { Client } from '@modelcontextprotocol/sdk/client/index.js';\nimport type {\n CallToolResult,\n GetPromptResult,\n Prompt,\n ReadResourceResult,\n Resource,\n Tool,\n} from '@modelcontextprotocol/sdk/types.js';\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst DEFAULT_CALL_TIMEOUT = 30000;\nconst DEFAULT_PREFIX_SEPARATOR = ':';\nconst DEFAULT_CHANNEL_ID = 'mcp-iframe';\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/** Registration handle returned by navigator.modelContext register methods */\ninterface RegistrationHandle {\n unregister: () => void;\n}\n\n/** Minimal ModelContext interface for registering tools, resources, and prompts */\ninterface ModelContext {\n registerTool(tool: {\n name: string;\n description: string;\n inputSchema: Tool['inputSchema'];\n execute: (args: Record<string, unknown>) => Promise<CallToolResult>;\n }): RegistrationHandle;\n\n registerResource(resource: {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n read: (uri: URL, params?: Record<string, string>) => Promise<ReadResourceResult>;\n }): RegistrationHandle;\n\n registerPrompt(prompt: {\n name: string;\n description?: string;\n argsSchema?: Record<string, unknown>;\n get: (args: Record<string, unknown>) => Promise<GetPromptResult>;\n }): RegistrationHandle;\n}\n\n/** Navigator with optional modelContext */\ninterface NavigatorWithModelContext extends Navigator {\n modelContext?: ModelContext;\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 Map<string, RegistrationHandle>();\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 this.#prefixSeparator = newValue ?? DEFAULT_PREFIX_SEPARATOR;\n if (this.#ready) {\n this.#unregisterAll();\n this.#registerAllOnModelContext();\n }\n break;\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.keys());\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) */\n get itemPrefix(): string {\n const id = this.id || this.getAttribute('name') || 'iframe';\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(() => ({ resources: [] })),\n this.#client.listPrompts().catch(() => ({ prompts: [] })),\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 {\n // Invalid URL\n }\n }\n\n // Default to same origin\n return window.location.origin;\n }\n\n #registerAllOnModelContext(): void {\n const modelContext = (navigator as NavigatorWithModelContext).modelContext;\n if (!modelContext) {\n console.warn('[MCPIframe] Model Context API not available on parent');\n return;\n }\n\n this.#registerToolsOnModelContext(modelContext);\n this.#registerResourcesOnModelContext(modelContext);\n this.#registerPromptsOnModelContext(modelContext);\n }\n\n #registerToolsOnModelContext(modelContext: ModelContext): void {\n for (const tool of this.#mcpTools) {\n const prefixedName = `${this.itemPrefix}${tool.name}`;\n\n const registration = modelContext.registerTool({\n name: prefixedName,\n description: tool.description ?? `Tool from iframe: ${tool.name}`,\n inputSchema: tool.inputSchema,\n execute: (args) => this.#callIframeTool(tool.name, args),\n });\n\n this.#registeredTools.set(prefixedName, registration);\n }\n }\n\n #registerResourcesOnModelContext(modelContext: ModelContext): void {\n for (const resource of this.#mcpResources) {\n const prefixedUri = `${this.itemPrefix}${resource.uri}`;\n\n const resourceDescriptor: Parameters<ModelContext['registerResource']>[0] = {\n uri: prefixedUri,\n name: resource.name,\n read: (_uri, _params) => this.#readIframeResource(resource.uri),\n };\n if (resource.description !== undefined) {\n resourceDescriptor.description = resource.description;\n }\n if (resource.mimeType !== undefined) {\n resourceDescriptor.mimeType = resource.mimeType;\n }\n\n const registration = modelContext.registerResource(resourceDescriptor);\n this.#registeredResources.set(prefixedUri, registration);\n }\n }\n\n #registerPromptsOnModelContext(modelContext: ModelContext): void {\n for (const prompt of this.#mcpPrompts) {\n const prefixedName = `${this.itemPrefix}${prompt.name}`;\n\n const promptDescriptor: Parameters<ModelContext['registerPrompt']>[0] = {\n name: prefixedName,\n get: (args) => this.#getIframePrompt(prompt.name, args),\n };\n if (prompt.description !== undefined) {\n promptDescriptor.description = prompt.description;\n }\n if (prompt.arguments && prompt.arguments.length > 0) {\n promptDescriptor.argsSchema = {\n type: 'object',\n properties: Object.fromEntries(\n prompt.arguments.map((arg) => [\n arg.name,\n { type: 'string', description: arg.description },\n ])\n ),\n required: prompt.arguments.filter((a) => a.required).map((a) => a.name),\n };\n }\n\n const registration = modelContext.registerPrompt(promptDescriptor);\n this.#registeredPrompts.set(prefixedName, registration);\n }\n }\n\n #unregisterAll(): void {\n for (const registration of this.#registeredTools.values()) {\n registration.unregister();\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 {\n // Ignore\n }\n this.#client = null;\n }\n\n if (this.#transport) {\n try {\n await this.#transport.close();\n } catch {\n // Ignore\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
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-b/mcp-iframe",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "Custom element for exposing iframe MCP tools, resources, and prompts to parent page",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"iframe",
|
|
9
|
+
"custom-element",
|
|
10
|
+
"web-component",
|
|
11
|
+
"browser",
|
|
12
|
+
"web-model-context"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/MiguelsPizza/WebMCP#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/MiguelsPizza/WebMCP/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/MiguelsPizza/WebMCP.git",
|
|
21
|
+
"directory": "mcp-iframe"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Alex Nahas",
|
|
25
|
+
"sideEffects": true,
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"main": "./dist/index.js",
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@mcp-b/transports": "1.1.2-beta.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "22.17.2",
|
|
45
|
+
"tsdown": "^0.15.10",
|
|
46
|
+
"typescript": "^5.8.3"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@modelcontextprotocol/sdk": "^1.15.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependenciesMeta": {
|
|
52
|
+
"@modelcontextprotocol/sdk": {
|
|
53
|
+
"optional": false
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=18"
|
|
58
|
+
},
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public",
|
|
61
|
+
"registry": "https://registry.npmjs.org/"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsdown",
|
|
65
|
+
"check": "biome check --write .",
|
|
66
|
+
"clean": "rm -rf dist .turbo",
|
|
67
|
+
"format": "biome format --write .",
|
|
68
|
+
"lint": "biome lint --write .",
|
|
69
|
+
"publish:dry": "pnpm publish --access public --dry-run",
|
|
70
|
+
"publish:npm": "pnpm publish --access public",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"version:major": "pnpm version major --no-git-tag-version",
|
|
73
|
+
"version:minor": "pnpm version minor --no-git-tag-version",
|
|
74
|
+
"version:patch": "pnpm version patch --no-git-tag-version"
|
|
75
|
+
}
|
|
76
|
+
}
|