@wp-playground/mcp 3.1.61 → 3.1.63

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/client.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("./tool-executors-BhDxY6BQ.cjs"),w=require("@php-wasm/logger"),E=5e3;function P(n,o){const a=crypto.randomUUID();let e=null,s="",t=null,u=!1;function d(f){const l=n.list(),p=JSON.stringify(l);p!==s&&(s=p,f.send(JSON.stringify({type:"register",tabId:a,sites:l})))}async function r(){try{const f=await fetch(`http://127.0.0.1:${o}/bridge-token`);if(!f.ok){c();return}const{token:l}=await f.json();e=new WebSocket(`ws://127.0.0.1:${o}?token=${l}`)}catch{c();return}e.addEventListener("open",()=>{var f;s="",d(e),(f=n.onConnect)==null||f.call(n)}),e.addEventListener("message",async f=>{let l;try{l=JSON.parse(f.data)}catch{return}if(l.type!=="command")return;const{id:p,method:h,args:S,siteSlug:_}=l;try{const y=await C(n,h,S||[],_,o);(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify({id:p,type:"response",value:y}))}catch(y){const v=y instanceof Error?y.message:String(y);(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify({id:p,type:"response",error:v}))}}),e.addEventListener("close",()=>{e=null,c()}),e.addEventListener("error",()=>{})}function c(){u||(t=setTimeout(r,E))}return r(),{notifySitesChanged:()=>{(e==null?void 0:e.readyState)===WebSocket.OPEN&&d(e)},stop:()=>{u=!0,t!==null&&(clearTimeout(t),t=null),e&&(e.close(),e=null)}}}async function C(n,o,a,e,s){if(o==="__open_site_in_new_tab"){const r=new URL(window.location.href);if(r.searchParams.set("mcp-port",String(s)),r.searchParams.set("site-slug",e),!window.open(r.toString(),"_blank"))throw new Error("Pop-up blocked by browser. The user must allow pop-ups for this site.");return!0}if(o==="__rename_site"){const[r]=a;return await n.rename(r),!0}if(o==="__save_site")return await n.saveInBrowser();const t=n.getClient();if(!t)throw new Error(`No active client for site: ${e}`);const d=i.createToolClient(t)[o];if(typeof d!="function")throw new Error(`Unknown method: ${o}`);return await d(...a)}const m=i.getSiteToolDefinitions();let g=null;function T(n){const a=n.list().find(e=>e.isActive);if(!a)throw new Error("No active Playground site");return a}async function x(n){const o=b();if(!o)return;g==null||g.abort(),g=new AbortController;const a=g,e=a.signal;function s(){const r=n.getClient();if(!r)throw new Error("No client for active site");return r}const t=Object.entries(i.toolDefinitions).map(([r,c])=>({name:r,description:c.description,inputSchema:i.paramsToJsonSchema(c.params),annotations:c.annotations,execute:async f=>{try{const l=i.toolExecutors[r];if(!l)return{error:`No executor for "${r}"`};const p=i.createToolClient(s());return await l(p,f)}catch(l){return{error:`${c.errorPrefix}: ${i.stringifyError(l)}`}}}}));t.push(...$(n));const u=await Promise.allSettled(t.map(async r=>{await o.registerTool(r,{signal:e})})),d=[];for(const[r,c]of u.entries())c.status==="rejected"&&d.push({name:t[r].name,reason:c.reason});if(d.length>0)throw a.abort(),g===a&&(g=null),new Error("Failed to register WebMCP tools: "+d.map(({name:r,reason:c})=>`${r} (${i.stringifyError(c)})`).join(", "))}function b(){if(typeof document>"u")return;const n=document.modelContext;return typeof(n==null?void 0:n.registerTool)=="function"?n:void 0}function $(n){const o=m.playground_list_sites,a=m.playground_save_in_browser,e=m.playground_rename_site,s=m.playground_get_website_url;return[{name:"playground_list_sites",description:o.description,annotations:o.annotations,execute:async()=>{try{return{connectedTabs:1,sites:n.list().map(t=>({siteId:t.slug,name:t.name,storage:i.formatStorageLabel(t.storage),isActive:t.isActive}))}}catch(t){return{error:`${o.errorPrefix}: ${i.stringifyError(t)}`}}}},{name:"playground_save_in_browser",description:a.description,annotations:a.annotations,execute:async()=>{try{const t=T(n),u=i.formatStorageLabel(t.storage);if(u!=="temporary")return{success:!0,alreadySaved:!0,siteId:t.slug,name:t.name,storage:u};const d=await n.saveInBrowser();return{success:!0,alreadySaved:!1,siteId:d.slug,name:t.name??d.slug,storage:i.formatStorageLabel(d.storage)}}catch(t){return{error:`${a.errorPrefix}: ${i.stringifyError(t)}`}}}},{name:"playground_rename_site",description:e.description,inputSchema:i.paramsToJsonSchema(e.params),annotations:e.annotations,execute:async t=>{try{const u=t.newName,r=n.list().find(c=>c.isActive);return await n.rename(u),{success:!0,siteId:r==null?void 0:r.slug,newName:u}}catch(u){return{error:`${e.errorPrefix}: ${i.stringifyError(u)}`}}}},{name:"playground_get_website_url",description:s.description,annotations:s.annotations,execute:async()=>{try{return{url:window.location.href}}catch(t){return{error:`${s.errorPrefix}: ${i.stringifyError(t)}`}}}}]}function N(n){const o=b();if(!o)return{stop:()=>{}};const a=o,e=M();let s=null,t=!1,u="";async function d(r){if(t)return;const c=JSON.stringify(r);if(c===u)return;u=c,s==null||s.abort(),s=new AbortController;const{signal:f}=s;for(const l of r){if(e.has(l.name)){w.logger.warn(`Skipping the WebMCP tool "${l.name}" registered by the site: Playground already provides a tool under that name.`);continue}try{await a.registerTool(W(n,l),{signal:f})}catch(p){w.logger.warn(`Failed to register the site's WebMCP tool "${l.name}": ${i.stringifyError(p)}`)}if(f.aborted)return}}return n.onWebMCPToolsChanged(r=>{d(r)}).catch(r=>{w.logger.warn("Failed to observe the site's WebMCP tools:",r)}),{stop(){t=!0,s==null||s.abort(),s=null,u=""}}}function M(){return new Set([...Object.keys(i.toolDefinitions),...Object.keys(i.getSiteToolDefinitions())])}function W(n,o){return{name:o.name,description:o.description,inputSchema:o.inputSchema,annotations:o.annotations,execute:async a=>{try{return await n.callWebMCPTool(o.name,a??{})}catch(e){return{error:`Error running the WordPress site's "${o.name}" tool: ${i.stringifyError(e)}`}}}}}exports.registerWebMCPTools=x;exports.startMcpBridge=P;exports.startWebMCPSiteToolProxy=N;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./tool-executors-CkOyDA_-.cjs"),b=require("@php-wasm/logger"),T=5e3;function E(a,c){const d=crypto.randomUUID();let e=null,o="",u=null,n=!1;function s(f){const i=a.list(),p=JSON.stringify(i);p!==o&&(o=p,f.send(JSON.stringify({type:"register",tabId:d,sites:i})))}async function t(){try{const f=await fetch(`http://127.0.0.1:${c}/bridge-token`);if(!f.ok){r();return}const{token:i}=await f.json();e=new WebSocket(`ws://127.0.0.1:${c}?token=${i}`)}catch{r();return}e.addEventListener("open",()=>{var f;o="",s(e),(f=a.onConnect)==null||f.call(a)}),e.addEventListener("message",async f=>{let i;try{i=JSON.parse(f.data)}catch{return}if(i.type!=="command")return;const{id:p,method:y,args:w,siteSlug:S}=i;try{const m=await C(a,y,w||[],S,c);(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify({id:p,type:"response",value:m}))}catch(m){const v=m instanceof Error?m.message:String(m);(e==null?void 0:e.readyState)===WebSocket.OPEN&&e.send(JSON.stringify({id:p,type:"response",error:v}))}}),e.addEventListener("close",()=>{e=null,r()}),e.addEventListener("error",()=>{})}function r(){n||(u=setTimeout(t,T))}return t(),{notifySitesChanged:()=>{(e==null?void 0:e.readyState)===WebSocket.OPEN&&s(e)},stop:()=>{n=!0,u!==null&&(clearTimeout(u),u=null),e&&(e.close(),e=null)}}}async function C(a,c,d,e,o){if(c==="__open_site_in_new_tab"){const t=new URL(window.location.href);if(t.searchParams.set("mcp-port",String(o)),t.searchParams.set("site-slug",e),!window.open(t.toString(),"_blank"))throw new Error("Pop-up blocked by browser. The user must allow pop-ups for this site.");return!0}if(c==="__rename_site"){const[t]=d;return await a.rename(t),!0}if(c==="__save_site")return await a.saveInBrowser();const u=a.getClient();if(!u)throw new Error(`No active client for site: ${e}`);const s=l.createToolClient(u)[c];if(typeof s!="function")throw new Error(`Unknown method: ${c}`);return await s(...d)}const h=l.getSiteToolDefinitions();let g=null;function P(a){const d=a.list().find(e=>e.isActive);if(!d)throw new Error("No active Playground site");return d}async function x(a){const c=_();if(!c)return;g==null||g.abort(),g=new AbortController;const d=g,e=d.signal;function o(){const t=a.getClient();if(!t)throw new Error("No client for active site");return t}const u=Object.entries(l.toolDefinitions).map(([t,r])=>({name:t,description:r.description,inputSchema:l.paramsToJsonSchema(r.params),annotations:r.annotations,execute:async(f,i)=>{var p,y;try{(p=i==null?void 0:i.signal)==null||p.throwIfAborted();const w=l.toolExecutors[t];if(!w)return{error:`No executor for "${t}"`};const S=l.createToolClient(o()),m=await w(S,f,i==null?void 0:i.signal);return(y=i==null?void 0:i.signal)==null||y.throwIfAborted(),m}catch(w){return{error:`${r.errorPrefix}: ${l.stringifyError(w)}`}}}}));u.push(...$(a));const n=await Promise.allSettled(u.map(async t=>{await c.registerTool(t,{signal:e})})),s=[];for(const[t,r]of n.entries())r.status==="rejected"&&s.push({name:u[t].name,reason:r.reason});if(s.length>0)throw d.abort(),g===d&&(g=null),new Error("Failed to register WebMCP tools: "+s.map(({name:t,reason:r})=>`${t} (${l.stringifyError(r)})`).join(", "))}function _(){if(typeof document>"u")return;const a=document.modelContext;return typeof(a==null?void 0:a.registerTool)=="function"?a:void 0}function $(a){const c=h.playground_list_sites,d=h.playground_save_in_browser,e=h.playground_rename_site,o=h.playground_get_website_url;return[{name:"playground_list_sites",description:c.description,inputSchema:l.paramsToJsonSchema(c.params),annotations:c.annotations,execute:async(u,n)=>{var s;try{return(s=n==null?void 0:n.signal)==null||s.throwIfAborted(),{connectedTabs:1,sites:a.list().map(t=>({siteId:t.slug,name:t.name,storage:l.formatStorageLabel(t.storage),isActive:t.isActive}))}}catch(t){return{error:`${c.errorPrefix}: ${l.stringifyError(t)}`}}}},{name:"playground_save_in_browser",description:d.description,inputSchema:l.paramsToJsonSchema(d.params),annotations:d.annotations,execute:async(u,n)=>{var s,t;try{(s=n==null?void 0:n.signal)==null||s.throwIfAborted();const r=P(a),f=l.formatStorageLabel(r.storage);if(f!=="temporary")return{success:!0,alreadySaved:!0,siteId:r.slug,name:r.name,storage:f};const i=await a.saveInBrowser();return(t=n==null?void 0:n.signal)==null||t.throwIfAborted(),{success:!0,alreadySaved:!1,siteId:i.slug,name:r.name??i.slug,storage:l.formatStorageLabel(i.storage)}}catch(r){return{error:`${d.errorPrefix}: ${l.stringifyError(r)}`}}}},{name:"playground_rename_site",description:e.description,inputSchema:l.paramsToJsonSchema(e.params),annotations:e.annotations,execute:async(u,n)=>{var s,t;try{(s=n==null?void 0:n.signal)==null||s.throwIfAborted();const r=u.newName,i=a.list().find(p=>p.isActive);return await a.rename(r),(t=n==null?void 0:n.signal)==null||t.throwIfAborted(),{success:!0,siteId:i==null?void 0:i.slug,newName:r}}catch(r){return{error:`${e.errorPrefix}: ${l.stringifyError(r)}`}}}},{name:"playground_get_website_url",description:o.description,inputSchema:l.paramsToJsonSchema(o.params),annotations:o.annotations,execute:async(u,n)=>{var s;try{return(s=n==null?void 0:n.signal)==null||s.throwIfAborted(),{url:window.location.href}}catch(t){return{error:`${o.errorPrefix}: ${l.stringifyError(t)}`}}}}]}function I(a){const c=_();if(!c)return{stop:()=>{}};const d=c,e=M();let o=null,u=!1,n="",s=null;async function t(r){if(u)return;const f=JSON.stringify(r);if(f===n)return;n=f,o==null||o.abort(),o=new AbortController;const{signal:i}=o;for(const p of r){if(e.has(p.name)){b.logger.warn(`Skipping the WebMCP tool "${p.name}" registered by the site: Playground already provides a tool under that name.`);continue}try{await d.registerTool(N(a,p),{signal:i})}catch(y){b.logger.warn(`Failed to register the site's WebMCP tool "${p.name}": ${l.stringifyError(y)}`)}if(i.aborted)return}}return a.onWebMCPToolsChanged(r=>{t(r)}).then(r=>{u?r():s=r}).catch(r=>{b.logger.warn("Failed to observe the site's WebMCP tools:",r)}),{stop(){u=!0,s==null||s(),s=null,o==null||o.abort(),o=null,n=""}}}function M(){return new Set([...Object.keys(l.toolDefinitions),...Object.keys(l.getSiteToolDefinitions())])}function N(a,c){return{name:c.name,description:c.description,inputSchema:c.inputSchema,annotations:c.annotations,execute:async(d,e)=>{const o=e==null?void 0:e.signal,u=crypto.randomUUID(),n=()=>{a.cancelWebMCPTool(u).catch(s=>{b.logger.warn("Failed to cancel the site tool:",s)})};try{o==null||o.throwIfAborted(),o==null||o.addEventListener("abort",n,{once:!0});const s=await a.callWebMCPTool(c.name,d??{},u);return o==null||o.throwIfAborted(),s}catch(s){return{error:`Error running the WordPress site's "${c.name}" tool: ${l.stringifyError(s)}`}}finally{o==null||o.removeEventListener("abort",n)}}}}exports.getModelContext=_;exports.registerWebMCPTools=x;exports.startMcpBridge=E;exports.startWebMCPSiteToolProxy=I;
2
2
  //# sourceMappingURL=client.cjs.map
package/client.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","sources":["../../../../packages/playground/mcp/src/bridge-client.ts","../../../../packages/playground/mcp/src/webmcp.ts","../../../../packages/playground/mcp/src/webmcp-site-tools.ts"],"sourcesContent":["import type { PlaygroundClient } from '@wp-playground/remote';\nimport { createToolClient } from './tools/tool-executors';\nimport type { ToolClient } from './tools/tool-executors';\n\n/**\n * Configuration accepted by `startMcpBridge`. Only includes the\n * methods the bridge actually calls — callers can pass any wider\n * object (e.g. the full site-management API) and TypeScript will\n * accept it structurally.\n */\nexport interface PlaygroundBridgeConfig {\n\tlist(): Array<{\n\t\tslug: string;\n\t\tname: string;\n\t\tstorage: string;\n\t\tisActive: boolean;\n\t}>;\n\tgetClient(): PlaygroundClient | undefined;\n\trename(newName: string): Promise<void>;\n\tsaveInBrowser(): Promise<{ slug: string; storage: string }>;\n\tonConnect?: () => void;\n}\n\nexport interface McpBridgeHandle {\n\tnotifySitesChanged: () => void;\n\tstop: () => void;\n}\n\nconst RECONNECT_INTERVAL_MS = 5000;\n\nexport function startMcpBridge(\n\tconfig: PlaygroundBridgeConfig,\n\tport: number\n): McpBridgeHandle {\n\tconst tabId = crypto.randomUUID();\n\tlet ws: WebSocket | null = null;\n\tlet previousSitesSerialized = '';\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet stopped = false;\n\n\tfunction sendSitesRegistration(socket: WebSocket) {\n\t\tconst sites = config.list();\n\t\tconst serialized = JSON.stringify(sites);\n\t\tif (serialized === previousSitesSerialized) {\n\t\t\treturn;\n\t\t}\n\t\tpreviousSitesSerialized = serialized;\n\t\tsocket.send(JSON.stringify({ type: 'register', tabId, sites }));\n\t}\n\n\tasync function connect() {\n\t\ttry {\n\t\t\tconst response = await fetch(\n\t\t\t\t`http://127.0.0.1:${port}/bridge-token`\n\t\t\t);\n\t\t\tif (!response.ok) {\n\t\t\t\tscheduleReconnect();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { token } = await response.json();\n\t\t\tws = new WebSocket(`ws://127.0.0.1:${port}?token=${token}`);\n\t\t} catch {\n\t\t\tscheduleReconnect();\n\t\t\treturn;\n\t\t}\n\n\t\tws.addEventListener('open', () => {\n\t\t\tpreviousSitesSerialized = '';\n\t\t\tsendSitesRegistration(ws!);\n\t\t\tconfig.onConnect?.();\n\t\t});\n\n\t\tws.addEventListener('message', async (event) => {\n\t\t\tlet message;\n\t\t\ttry {\n\t\t\t\tmessage = JSON.parse(event.data as string);\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (message.type !== 'command') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { id, method, args, siteSlug } = message;\n\t\t\ttry {\n\t\t\t\tconst value = await handleCommand(\n\t\t\t\t\tconfig,\n\t\t\t\t\tmethod,\n\t\t\t\t\targs || [],\n\t\t\t\t\tsiteSlug,\n\t\t\t\t\tport\n\t\t\t\t);\n\t\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t\tws.send(JSON.stringify({ id, type: 'response', value }));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMsg =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t\tws.send(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'response',\n\t\t\t\t\t\t\terror: errorMsg,\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tws.addEventListener('close', () => {\n\t\t\tws = null;\n\t\t\tscheduleReconnect();\n\t\t});\n\n\t\tws.addEventListener('error', () => {\n\t\t\t// Error will be followed by close event,\n\t\t\t// which handles reconnect\n\t\t});\n\t}\n\n\tfunction scheduleReconnect() {\n\t\tif (stopped) {\n\t\t\treturn;\n\t\t}\n\t\treconnectTimer = setTimeout(connect, RECONNECT_INTERVAL_MS);\n\t}\n\n\tconnect();\n\n\treturn {\n\t\tnotifySitesChanged: () => {\n\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\tsendSitesRegistration(ws);\n\t\t\t}\n\t\t},\n\t\tstop: () => {\n\t\t\tstopped = true;\n\t\t\tif (reconnectTimer !== null) {\n\t\t\t\tclearTimeout(reconnectTimer);\n\t\t\t\treconnectTimer = null;\n\t\t\t}\n\t\t\tif (ws) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t},\n\t};\n}\n\nasync function handleCommand(\n\tconfig: PlaygroundBridgeConfig,\n\tmethod: string,\n\targs: unknown[],\n\tsiteSlug: string,\n\tport: number\n): Promise<unknown> {\n\tif (method === '__open_site_in_new_tab') {\n\t\tconst url = new URL(window.location.href);\n\t\turl.searchParams.set('mcp-port', String(port));\n\t\turl.searchParams.set('site-slug', siteSlug);\n\t\tconst newWindow = window.open(url.toString(), '_blank');\n\t\tif (!newWindow) {\n\t\t\tthrow new Error(\n\t\t\t\t'Pop-up blocked by browser. The user ' +\n\t\t\t\t\t'must allow pop-ups for this site.'\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (method === '__rename_site') {\n\t\tconst [newName] = args as [string];\n\t\tawait config.rename(newName);\n\t\treturn true;\n\t}\n\n\tif (method === '__save_site') {\n\t\treturn await config.saveInBrowser();\n\t}\n\n\tconst playgroundClient = config.getClient();\n\tif (!playgroundClient) {\n\t\tthrow new Error(`No active client for site: ${siteSlug}`);\n\t}\n\n\tconst client = createToolClient(playgroundClient);\n\tconst fn = client[method as keyof ToolClient];\n\tif (typeof fn !== 'function') {\n\t\tthrow new Error(`Unknown method: ${method}`);\n\t}\n\treturn await (fn as (...a: unknown[]) => Promise<unknown>)(...args);\n}\n","/**\n * WebMCP registration for WordPress Playground.\n *\n * Registers playground tools with `document.modelContext` (the\n * Chrome WebMCP API) so that browser-side AI agents can interact\n * with the running Playground site.\n */\n\nimport type { PlaygroundClient } from '@wp-playground/remote';\nimport {\n\ttoolDefinitions,\n\tgetSiteToolDefinitions,\n\tformatStorageLabel,\n\tparamsToJsonSchema,\n\tstringifyError,\n} from './tools/tool-definitions';\nimport { toolExecutors, createToolClient } from './tools/tool-executors';\nimport type { PlaygroundBridgeConfig } from './bridge-client';\n\nconst siteToolDefinitions = getSiteToolDefinitions();\n\n// -- WebMCP type declarations --\n\nexport interface ModelContextTool {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: Record<string, unknown>;\n\texecute: (\n\t\tinput: Record<string, unknown>,\n\t\tclient: ModelContextClient\n\t) => Promise<unknown>;\n\tannotations?: { readOnlyHint?: boolean; destructiveHint?: boolean };\n}\n\ninterface ModelContextClient {\n\trequestUserInteraction(callback: () => Promise<unknown>): Promise<unknown>;\n}\n\ninterface ModelContext {\n\tprovideContext(options: { tools: ModelContextTool[] }): void;\n\tregisterTool(\n\t\ttool: ModelContextTool,\n\t\toptions?: { signal?: AbortSignal }\n\t): Promise<void> | void;\n\treadonly tools: ModelContextTool[];\n}\n\ndeclare global {\n\tinterface Document {\n\t\tmodelContext?: ModelContext;\n\t}\n}\n\n// -- Registration --\n\nlet registrationController: AbortController | null = null;\n\nfunction getActiveSite(config: PlaygroundBridgeConfig) {\n\tconst sites = config.list();\n\tconst active = sites.find((s) => s.isActive);\n\tif (!active) {\n\t\tthrow new Error('No active Playground site');\n\t}\n\treturn active;\n}\n\nexport async function registerWebMCPTools(\n\tconfig: PlaygroundBridgeConfig\n): Promise<void> {\n\tconst modelContext = getModelContext();\n\tif (!modelContext) {\n\t\treturn;\n\t}\n\n\t// Abort any previous registration before re-registering.\n\tregistrationController?.abort();\n\tregistrationController = new AbortController();\n\tconst controller = registrationController;\n\tconst signal = controller.signal;\n\n\tfunction getActiveClient(): PlaygroundClient {\n\t\tconst client = config.getClient();\n\t\tif (!client) {\n\t\t\tthrow new Error('No client for active site');\n\t\t}\n\t\treturn client;\n\t}\n\n\t// Per-site tools\n\tconst tools: ModelContextTool[] = Object.entries(toolDefinitions).map(\n\t\t([name, def]) => ({\n\t\t\tname,\n\t\t\tdescription: def.description,\n\t\t\tinputSchema: paramsToJsonSchema(def.params),\n\t\t\tannotations: def.annotations,\n\t\t\texecute: async (input) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst executor = toolExecutors[name];\n\t\t\t\t\tif (!executor) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\terror: `No executor for \"${name}\"`,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst adapter = createToolClient(getActiveClient());\n\t\t\t\t\treturn await executor(adapter, input);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${def.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t);\n\n\t// Site management tools\n\ttools.push(...createSiteManagementTools(config));\n\n\tconst results = await Promise.allSettled(\n\t\ttools.map(async (tool) => {\n\t\t\tawait modelContext.registerTool(tool, { signal });\n\t\t})\n\t);\n\tconst failedRegistrations: Array<{ name: string; reason: unknown }> = [];\n\tfor (const [index, result] of results.entries()) {\n\t\tif (result.status === 'rejected') {\n\t\t\tfailedRegistrations.push({\n\t\t\t\tname: tools[index].name,\n\t\t\t\treason: result.reason,\n\t\t\t});\n\t\t}\n\t}\n\tif (failedRegistrations.length > 0) {\n\t\tcontroller.abort();\n\t\tif (registrationController === controller) {\n\t\t\tregistrationController = null;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'Failed to register WebMCP tools: ' +\n\t\t\t\tfailedRegistrations\n\t\t\t\t\t.map(\n\t\t\t\t\t\t({ name, reason }) =>\n\t\t\t\t\t\t\t`${name} (${stringifyError(reason)})`\n\t\t\t\t\t)\n\t\t\t\t\t.join(', ')\n\t\t);\n\t}\n}\n\nexport function getModelContext(): ModelContext | undefined {\n\tif (typeof document === 'undefined') {\n\t\treturn undefined;\n\t}\n\tconst modelContext = document.modelContext;\n\treturn typeof modelContext?.registerTool === 'function'\n\t\t? modelContext\n\t\t: undefined;\n}\n\nfunction createSiteManagementTools(\n\tconfig: PlaygroundBridgeConfig\n): ModelContextTool[] {\n\tconst listDef = siteToolDefinitions['playground_list_sites'];\n\tconst saveDef = siteToolDefinitions['playground_save_in_browser'];\n\tconst renameDef = siteToolDefinitions['playground_rename_site'];\n\tconst websiteUrlDef = siteToolDefinitions['playground_get_website_url'];\n\n\treturn [\n\t\t{\n\t\t\tname: 'playground_list_sites',\n\t\t\tdescription: listDef.description,\n\t\t\tannotations: listDef.annotations,\n\t\t\texecute: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tconnectedTabs: 1,\n\t\t\t\t\t\tsites: config.list().map((s) => ({\n\t\t\t\t\t\t\tsiteId: s.slug,\n\t\t\t\t\t\t\tname: s.name,\n\t\t\t\t\t\t\tstorage: formatStorageLabel(s.storage),\n\t\t\t\t\t\t\tisActive: s.isActive,\n\t\t\t\t\t\t})),\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${listDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_save_in_browser',\n\t\t\tdescription: saveDef.description,\n\t\t\tannotations: saveDef.annotations,\n\t\t\texecute: async () => {\n\t\t\t\ttry {\n\t\t\t\t\tconst site = getActiveSite(config);\n\t\t\t\t\tconst storage = formatStorageLabel(site.storage);\n\t\t\t\t\tif (storage !== 'temporary') {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t\talreadySaved: true,\n\t\t\t\t\t\t\tsiteId: site.slug,\n\t\t\t\t\t\t\tname: site.name,\n\t\t\t\t\t\t\tstorage,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst saved = await config.saveInBrowser();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\talreadySaved: false,\n\t\t\t\t\t\tsiteId: saved.slug,\n\t\t\t\t\t\tname: site.name ?? saved.slug,\n\t\t\t\t\t\tstorage: formatStorageLabel(saved.storage),\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${saveDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_rename_site',\n\t\t\tdescription: renameDef.description,\n\t\t\tinputSchema: paramsToJsonSchema(renameDef.params),\n\t\t\tannotations: renameDef.annotations,\n\t\t\texecute: async (input) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst newName = input['newName'] as string;\n\t\t\t\t\tconst sites = config.list();\n\t\t\t\t\tconst activeSite = sites.find((s) => s.isActive);\n\t\t\t\t\tawait config.rename(newName);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\tsiteId: activeSite?.slug,\n\t\t\t\t\t\tnewName,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${renameDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_get_website_url',\n\t\t\tdescription: websiteUrlDef.description,\n\t\t\tannotations: websiteUrlDef.annotations,\n\t\t\texecute: async () => {\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\turl: window.location.href,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${websiteUrlDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t];\n}\n","/**\n * Re-advertises the WebMCP tools registered inside the WordPress document as\n * tools of the Playground page itself.\n *\n * A plugin running in Playground can register tools with\n * `document.modelContext`, but that registry lives in a nested,\n * service-worker-served iframe an agent never sees. This proxy mirrors those\n * tools onto the top-level `document.modelContext` and forwards each call back\n * into the WordPress document:\n *\n * agent → document.modelContext (this page)\n * → PlaygroundClient.callWebMCPTool() (Comlink)\n * → remote frame (postMessage)\n * → WordPress document (the plugin's execute())\n */\n\nimport type {\n\tPlaygroundClient,\n\tWebMCPToolDescriptor,\n} from '@wp-playground/remote';\nimport { logger } from '@php-wasm/logger';\nimport {\n\ttoolDefinitions,\n\tgetSiteToolDefinitions,\n\tstringifyError,\n} from './tools/tool-definitions';\nimport type { ModelContextTool } from './webmcp';\nimport { getModelContext } from './webmcp';\n\nexport interface WebMCPSiteToolProxy {\n\tstop(): void;\n}\n\n/**\n * Starts mirroring `client`'s in-site WebMCP tools onto this page.\n *\n * Every announcement carries the full tool list, so the previous registration\n * is aborted and the new list registered in its place. Returns a handle that\n * unregisters everything it registered.\n */\nexport function startWebMCPSiteToolProxy(\n\tclient: PlaygroundClient\n): WebMCPSiteToolProxy {\n\tconst maybeModelContext = getModelContext();\n\tif (!maybeModelContext) {\n\t\t// Nothing can be advertised, so there is nothing to observe for.\n\t\treturn { stop: () => {} };\n\t}\n\t// `register` is hoisted, so it does not inherit the narrowing above.\n\tconst modelContext = maybeModelContext;\n\n\tconst reserved = reservedToolNames();\n\tlet registration: AbortController | null = null;\n\tlet stopped = false;\n\tlet registeredDescriptors = '';\n\n\tasync function register(tools: WebMCPToolDescriptor[]) {\n\t\tif (stopped) {\n\t\t\treturn;\n\t\t}\n\t\t// Registration is asynchronous, so a burst of announcements could\n\t\t// otherwise re-register an unchanged list several times over.\n\t\tconst descriptors = JSON.stringify(tools);\n\t\tif (descriptors === registeredDescriptors) {\n\t\t\treturn;\n\t\t}\n\t\tregisteredDescriptors = descriptors;\n\n\t\tregistration?.abort();\n\t\tregistration = new AbortController();\n\t\tconst { signal } = registration;\n\n\t\tfor (const tool of tools) {\n\t\t\tif (reserved.has(tool.name)) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Skipping the WebMCP tool \"${tool.name}\" registered by ` +\n\t\t\t\t\t\t`the site: Playground already provides a tool under ` +\n\t\t\t\t\t\t`that name.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait modelContext.registerTool(proxyTool(client, tool), {\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to register the site's WebMCP tool ` +\n\t\t\t\t\t\t`\"${tool.name}\": ${stringifyError(error)}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (signal.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tclient\n\t\t.onWebMCPToolsChanged((tools: WebMCPToolDescriptor[]) => {\n\t\t\tvoid register(tools);\n\t\t})\n\t\t.catch((error) => {\n\t\t\tlogger.warn(\"Failed to observe the site's WebMCP tools:\", error);\n\t\t});\n\n\treturn {\n\t\tstop() {\n\t\t\tstopped = true;\n\t\t\tregistration?.abort();\n\t\t\tregistration = null;\n\t\t\tregisteredDescriptors = '';\n\t\t},\n\t};\n}\n\n/**\n * Names Playground registers itself. A site tool may not take one of them\n * over, or an agent asking to execute PHP would reach the site's plugin\n * instead.\n */\nfunction reservedToolNames(): Set<string> {\n\treturn new Set([\n\t\t...Object.keys(toolDefinitions),\n\t\t...Object.keys(getSiteToolDefinitions()),\n\t]);\n}\n\nfunction proxyTool(\n\tclient: PlaygroundClient,\n\ttool: WebMCPToolDescriptor\n): ModelContextTool {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tinputSchema: tool.inputSchema,\n\t\tannotations: tool.annotations,\n\t\texecute: async (input) => {\n\t\t\ttry {\n\t\t\t\treturn await client.callWebMCPTool(tool.name, input ?? {});\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Error running the WordPress site's \"${tool.name}\" ` +\n\t\t\t\t\t\t`tool: ${stringifyError(error)}`,\n\t\t\t\t};\n\t\t\t}\n\t\t},\n\t};\n}\n"],"names":["RECONNECT_INTERVAL_MS","startMcpBridge","config","port","tabId","ws","previousSitesSerialized","reconnectTimer","stopped","sendSitesRegistration","socket","sites","serialized","connect","response","scheduleReconnect","token","_a","event","message","id","method","args","siteSlug","value","handleCommand","error","errorMsg","url","newName","playgroundClient","fn","createToolClient","siteToolDefinitions","getSiteToolDefinitions","registrationController","getActiveSite","active","s","registerWebMCPTools","modelContext","getModelContext","controller","signal","getActiveClient","client","tools","toolDefinitions","name","def","paramsToJsonSchema","input","executor","toolExecutors","adapter","stringifyError","createSiteManagementTools","results","tool","failedRegistrations","index","result","reason","listDef","saveDef","renameDef","websiteUrlDef","formatStorageLabel","site","storage","saved","activeSite","startWebMCPSiteToolProxy","maybeModelContext","reserved","reservedToolNames","registration","registeredDescriptors","register","descriptors","logger","proxyTool"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs","sources":["../../../../packages/playground/mcp/src/bridge-client.ts","../../../../packages/playground/mcp/src/webmcp.ts","../../../../packages/playground/mcp/src/webmcp-site-tools.ts"],"sourcesContent":["import type { PlaygroundClient } from '@wp-playground/remote';\nimport { createToolClient } from './tools/tool-executors';\nimport type { ToolClient } from './tools/tool-executors';\n\n/**\n * Configuration accepted by `startMcpBridge`. Only includes the\n * methods the bridge actually calls — callers can pass any wider\n * object (e.g. the full site-management API) and TypeScript will\n * accept it structurally.\n */\nexport interface PlaygroundBridgeConfig {\n\tlist(): Array<{\n\t\tslug: string;\n\t\tname: string;\n\t\tstorage: string;\n\t\tisActive: boolean;\n\t}>;\n\tgetClient(): PlaygroundClient | undefined;\n\trename(newName: string): Promise<void>;\n\tsaveInBrowser(): Promise<{ slug: string; storage: string }>;\n\tonConnect?: () => void;\n}\n\nexport interface McpBridgeHandle {\n\tnotifySitesChanged: () => void;\n\tstop: () => void;\n}\n\nconst RECONNECT_INTERVAL_MS = 5000;\n\nexport function startMcpBridge(\n\tconfig: PlaygroundBridgeConfig,\n\tport: number\n): McpBridgeHandle {\n\tconst tabId = crypto.randomUUID();\n\tlet ws: WebSocket | null = null;\n\tlet previousSitesSerialized = '';\n\tlet reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\tlet stopped = false;\n\n\tfunction sendSitesRegistration(socket: WebSocket) {\n\t\tconst sites = config.list();\n\t\tconst serialized = JSON.stringify(sites);\n\t\tif (serialized === previousSitesSerialized) {\n\t\t\treturn;\n\t\t}\n\t\tpreviousSitesSerialized = serialized;\n\t\tsocket.send(JSON.stringify({ type: 'register', tabId, sites }));\n\t}\n\n\tasync function connect() {\n\t\ttry {\n\t\t\tconst response = await fetch(\n\t\t\t\t`http://127.0.0.1:${port}/bridge-token`\n\t\t\t);\n\t\t\tif (!response.ok) {\n\t\t\t\tscheduleReconnect();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst { token } = await response.json();\n\t\t\tws = new WebSocket(`ws://127.0.0.1:${port}?token=${token}`);\n\t\t} catch {\n\t\t\tscheduleReconnect();\n\t\t\treturn;\n\t\t}\n\n\t\tws.addEventListener('open', () => {\n\t\t\tpreviousSitesSerialized = '';\n\t\t\tsendSitesRegistration(ws!);\n\t\t\tconfig.onConnect?.();\n\t\t});\n\n\t\tws.addEventListener('message', async (event) => {\n\t\t\tlet message;\n\t\t\ttry {\n\t\t\t\tmessage = JSON.parse(event.data as string);\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (message.type !== 'command') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { id, method, args, siteSlug } = message;\n\t\t\ttry {\n\t\t\t\tconst value = await handleCommand(\n\t\t\t\t\tconfig,\n\t\t\t\t\tmethod,\n\t\t\t\t\targs || [],\n\t\t\t\t\tsiteSlug,\n\t\t\t\t\tport\n\t\t\t\t);\n\t\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t\tws.send(JSON.stringify({ id, type: 'response', value }));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tconst errorMsg =\n\t\t\t\t\terror instanceof Error ? error.message : String(error);\n\t\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\t\tws.send(\n\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\ttype: 'response',\n\t\t\t\t\t\t\terror: errorMsg,\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tws.addEventListener('close', () => {\n\t\t\tws = null;\n\t\t\tscheduleReconnect();\n\t\t});\n\n\t\tws.addEventListener('error', () => {\n\t\t\t// Error will be followed by close event,\n\t\t\t// which handles reconnect\n\t\t});\n\t}\n\n\tfunction scheduleReconnect() {\n\t\tif (stopped) {\n\t\t\treturn;\n\t\t}\n\t\treconnectTimer = setTimeout(connect, RECONNECT_INTERVAL_MS);\n\t}\n\n\tconnect();\n\n\treturn {\n\t\tnotifySitesChanged: () => {\n\t\t\tif (ws?.readyState === WebSocket.OPEN) {\n\t\t\t\tsendSitesRegistration(ws);\n\t\t\t}\n\t\t},\n\t\tstop: () => {\n\t\t\tstopped = true;\n\t\t\tif (reconnectTimer !== null) {\n\t\t\t\tclearTimeout(reconnectTimer);\n\t\t\t\treconnectTimer = null;\n\t\t\t}\n\t\t\tif (ws) {\n\t\t\t\tws.close();\n\t\t\t\tws = null;\n\t\t\t}\n\t\t},\n\t};\n}\n\nasync function handleCommand(\n\tconfig: PlaygroundBridgeConfig,\n\tmethod: string,\n\targs: unknown[],\n\tsiteSlug: string,\n\tport: number\n): Promise<unknown> {\n\tif (method === '__open_site_in_new_tab') {\n\t\tconst url = new URL(window.location.href);\n\t\turl.searchParams.set('mcp-port', String(port));\n\t\turl.searchParams.set('site-slug', siteSlug);\n\t\tconst newWindow = window.open(url.toString(), '_blank');\n\t\tif (!newWindow) {\n\t\t\tthrow new Error(\n\t\t\t\t'Pop-up blocked by browser. The user ' +\n\t\t\t\t\t'must allow pop-ups for this site.'\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tif (method === '__rename_site') {\n\t\tconst [newName] = args as [string];\n\t\tawait config.rename(newName);\n\t\treturn true;\n\t}\n\n\tif (method === '__save_site') {\n\t\treturn await config.saveInBrowser();\n\t}\n\n\tconst playgroundClient = config.getClient();\n\tif (!playgroundClient) {\n\t\tthrow new Error(`No active client for site: ${siteSlug}`);\n\t}\n\n\tconst client = createToolClient(playgroundClient);\n\tconst fn = client[method as keyof ToolClient];\n\tif (typeof fn !== 'function') {\n\t\tthrow new Error(`Unknown method: ${method}`);\n\t}\n\treturn await (fn as (...a: unknown[]) => Promise<unknown>)(...args);\n}\n","/**\n * WebMCP registration for WordPress Playground.\n *\n * Registers playground tools with `document.modelContext` (the\n * Chrome WebMCP API) so that browser-side AI agents can interact\n * with the running Playground site.\n */\n\nimport type { PlaygroundClient } from '@wp-playground/remote';\nimport {\n\ttoolDefinitions,\n\tgetSiteToolDefinitions,\n\tformatStorageLabel,\n\tparamsToJsonSchema,\n\tstringifyError,\n} from './tools/tool-definitions';\nimport { toolExecutors, createToolClient } from './tools/tool-executors';\nimport type { PlaygroundBridgeConfig } from './bridge-client';\n\nconst siteToolDefinitions = getSiteToolDefinitions();\n\n// -- WebMCP type declarations --\n\nexport interface ModelContextTool {\n\tname: string;\n\tdescription: string;\n\tinputSchema?: Record<string, unknown>;\n\texecute: (\n\t\tinput: Record<string, unknown>,\n\t\tclient?: ModelContextClient\n\t) => Promise<unknown>;\n\tannotations?: {\n\t\treadOnlyHint?: boolean;\n\t\tdestructiveHint?: boolean;\n\t\tconsequentialHint?: boolean;\n\t\tuntrustedContentHint?: boolean;\n\t\tdebugging?: boolean;\n\t};\n}\n\ninterface ModelContextClient {\n\tsignal?: AbortSignal;\n\trequestUserInteraction?(callback: () => Promise<unknown>): Promise<unknown>;\n}\n\ninterface ModelContext {\n\tprovideContext(options: { tools: ModelContextTool[] }): void;\n\tregisterTool(\n\t\ttool: ModelContextTool,\n\t\toptions?: { signal?: AbortSignal }\n\t): Promise<void> | void;\n\treadonly tools: ModelContextTool[];\n}\n\ndeclare global {\n\tinterface Document {\n\t\tmodelContext?: ModelContext;\n\t}\n}\n\n// -- Registration --\n\nlet registrationController: AbortController | null = null;\n\nfunction getActiveSite(config: PlaygroundBridgeConfig) {\n\tconst sites = config.list();\n\tconst active = sites.find((s) => s.isActive);\n\tif (!active) {\n\t\tthrow new Error('No active Playground site');\n\t}\n\treturn active;\n}\n\nexport async function registerWebMCPTools(\n\tconfig: PlaygroundBridgeConfig\n): Promise<void> {\n\tconst modelContext = getModelContext();\n\tif (!modelContext) {\n\t\treturn;\n\t}\n\n\t// Abort any previous registration before re-registering.\n\tregistrationController?.abort();\n\tregistrationController = new AbortController();\n\tconst controller = registrationController;\n\tconst signal = controller.signal;\n\n\tfunction getActiveClient(): PlaygroundClient {\n\t\tconst client = config.getClient();\n\t\tif (!client) {\n\t\t\tthrow new Error('No client for active site');\n\t\t}\n\t\treturn client;\n\t}\n\n\t// Per-site tools\n\tconst tools: ModelContextTool[] = Object.entries(toolDefinitions).map(\n\t\t([name, def]) => ({\n\t\t\tname,\n\t\t\tdescription: def.description,\n\t\t\tinputSchema: paramsToJsonSchema(def.params),\n\t\t\tannotations: def.annotations,\n\t\t\texecute: async (input, client) => {\n\t\t\t\ttry {\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\tconst executor = toolExecutors[name];\n\t\t\t\t\tif (!executor) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\terror: `No executor for \"${name}\"`,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst adapter = createToolClient(getActiveClient());\n\t\t\t\t\tconst result = await executor(\n\t\t\t\t\t\tadapter,\n\t\t\t\t\t\tinput,\n\t\t\t\t\t\tclient?.signal\n\t\t\t\t\t);\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\treturn result;\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${def.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t})\n\t);\n\n\t// Site management tools\n\ttools.push(...createSiteManagementTools(config));\n\n\tconst results = await Promise.allSettled(\n\t\ttools.map(async (tool) => {\n\t\t\tawait modelContext.registerTool(tool, { signal });\n\t\t})\n\t);\n\tconst failedRegistrations: Array<{ name: string; reason: unknown }> = [];\n\tfor (const [index, result] of results.entries()) {\n\t\tif (result.status === 'rejected') {\n\t\t\tfailedRegistrations.push({\n\t\t\t\tname: tools[index].name,\n\t\t\t\treason: result.reason,\n\t\t\t});\n\t\t}\n\t}\n\tif (failedRegistrations.length > 0) {\n\t\tcontroller.abort();\n\t\tif (registrationController === controller) {\n\t\t\tregistrationController = null;\n\t\t}\n\t\tthrow new Error(\n\t\t\t'Failed to register WebMCP tools: ' +\n\t\t\t\tfailedRegistrations\n\t\t\t\t\t.map(\n\t\t\t\t\t\t({ name, reason }) =>\n\t\t\t\t\t\t\t`${name} (${stringifyError(reason)})`\n\t\t\t\t\t)\n\t\t\t\t\t.join(', ')\n\t\t);\n\t}\n}\n\nexport function getModelContext(): ModelContext | undefined {\n\tif (typeof document === 'undefined') {\n\t\treturn undefined;\n\t}\n\tconst modelContext = document.modelContext;\n\treturn typeof modelContext?.registerTool === 'function'\n\t\t? modelContext\n\t\t: undefined;\n}\n\nfunction createSiteManagementTools(\n\tconfig: PlaygroundBridgeConfig\n): ModelContextTool[] {\n\tconst listDef = siteToolDefinitions['playground_list_sites'];\n\tconst saveDef = siteToolDefinitions['playground_save_in_browser'];\n\tconst renameDef = siteToolDefinitions['playground_rename_site'];\n\tconst websiteUrlDef = siteToolDefinitions['playground_get_website_url'];\n\n\treturn [\n\t\t{\n\t\t\tname: 'playground_list_sites',\n\t\t\tdescription: listDef.description,\n\t\t\tinputSchema: paramsToJsonSchema(listDef.params),\n\t\t\tannotations: listDef.annotations,\n\t\t\texecute: async (_input, client) => {\n\t\t\t\ttry {\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tconnectedTabs: 1,\n\t\t\t\t\t\tsites: config.list().map((s) => ({\n\t\t\t\t\t\t\tsiteId: s.slug,\n\t\t\t\t\t\t\tname: s.name,\n\t\t\t\t\t\t\tstorage: formatStorageLabel(s.storage),\n\t\t\t\t\t\t\tisActive: s.isActive,\n\t\t\t\t\t\t})),\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${listDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_save_in_browser',\n\t\t\tdescription: saveDef.description,\n\t\t\tinputSchema: paramsToJsonSchema(saveDef.params),\n\t\t\tannotations: saveDef.annotations,\n\t\t\texecute: async (_input, client) => {\n\t\t\t\ttry {\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\tconst site = getActiveSite(config);\n\t\t\t\t\tconst storage = formatStorageLabel(site.storage);\n\t\t\t\t\tif (storage !== 'temporary') {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\t\talreadySaved: true,\n\t\t\t\t\t\t\tsiteId: site.slug,\n\t\t\t\t\t\t\tname: site.name,\n\t\t\t\t\t\t\tstorage,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\t// Storage operations do not currently expose an interrupt API.\n\t\t\t\t\tconst saved = await config.saveInBrowser();\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\talreadySaved: false,\n\t\t\t\t\t\tsiteId: saved.slug,\n\t\t\t\t\t\tname: site.name ?? saved.slug,\n\t\t\t\t\t\tstorage: formatStorageLabel(saved.storage),\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${saveDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_rename_site',\n\t\t\tdescription: renameDef.description,\n\t\t\tinputSchema: paramsToJsonSchema(renameDef.params),\n\t\t\tannotations: renameDef.annotations,\n\t\t\texecute: async (input, client) => {\n\t\t\t\ttry {\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\tconst newName = input['newName'] as string;\n\t\t\t\t\tconst sites = config.list();\n\t\t\t\t\tconst activeSite = sites.find((s) => s.isActive);\n\t\t\t\t\tawait config.rename(newName);\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsuccess: true,\n\t\t\t\t\t\tsiteId: activeSite?.slug,\n\t\t\t\t\t\tnewName,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${renameDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tname: 'playground_get_website_url',\n\t\t\tdescription: websiteUrlDef.description,\n\t\t\tinputSchema: paramsToJsonSchema(websiteUrlDef.params),\n\t\t\tannotations: websiteUrlDef.annotations,\n\t\t\texecute: async (_input, client) => {\n\t\t\t\ttry {\n\t\t\t\t\tclient?.signal?.throwIfAborted();\n\t\t\t\t\treturn {\n\t\t\t\t\t\turl: window.location.href,\n\t\t\t\t\t};\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\terror: `${websiteUrlDef.errorPrefix}: ${stringifyError(error)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t];\n}\n","/**\n * Re-advertises the WebMCP tools registered inside the WordPress document as\n * tools of the Playground page itself.\n *\n * A plugin running in Playground can register tools with\n * `document.modelContext`, but that registry lives in a nested,\n * service-worker-served iframe an agent never sees. This proxy mirrors those\n * tools onto the top-level `document.modelContext` and forwards each call back\n * into the WordPress document:\n *\n * agent → document.modelContext (this page)\n * → PlaygroundClient.callWebMCPTool() (Comlink)\n * → remote frame (postMessage)\n * → WordPress document (the plugin's execute())\n */\n\nimport type { WebMCPToolDescriptor } from '@wp-playground/remote';\nimport { logger } from '@php-wasm/logger';\nimport {\n\ttoolDefinitions,\n\tgetSiteToolDefinitions,\n\tstringifyError,\n} from './tools/tool-definitions';\nimport type { ModelContextTool } from './webmcp';\nimport { getModelContext } from './webmcp';\n\nexport interface WebMCPSiteToolProxy {\n\tstop(): void;\n}\n\ninterface WebMCPSiteToolClient {\n\tonWebMCPToolsChanged(\n\t\tlistener: (tools: WebMCPToolDescriptor[]) => void\n\t): Promise<() => void>;\n\tcallWebMCPTool(\n\t\tname: string,\n\t\targs: Record<string, unknown>,\n\t\tcallId?: string\n\t): Promise<unknown>;\n\tcancelWebMCPTool(callId: string): Promise<void>;\n}\n\n/**\n * Starts mirroring `client`'s in-site WebMCP tools onto this page.\n *\n * Every announcement carries the full tool list, so the previous registration\n * is aborted and the new list registered in its place. Returns a handle that\n * unregisters everything it registered.\n */\nexport function startWebMCPSiteToolProxy(\n\tclient: WebMCPSiteToolClient\n): WebMCPSiteToolProxy {\n\tconst maybeModelContext = getModelContext();\n\tif (!maybeModelContext) {\n\t\t// Nothing can be advertised, so there is nothing to observe for.\n\t\treturn { stop: () => {} };\n\t}\n\t// `register` is hoisted, so it does not inherit the narrowing above.\n\tconst modelContext = maybeModelContext;\n\n\tconst reserved = reservedToolNames();\n\tlet registration: AbortController | null = null;\n\tlet stopped = false;\n\tlet registeredDescriptors = '';\n\tlet unsubscribe: (() => void) | null = null;\n\n\tasync function register(tools: WebMCPToolDescriptor[]) {\n\t\tif (stopped) {\n\t\t\treturn;\n\t\t}\n\t\t// Registration is asynchronous, so a burst of announcements could\n\t\t// otherwise re-register an unchanged list several times over.\n\t\tconst descriptors = JSON.stringify(tools);\n\t\tif (descriptors === registeredDescriptors) {\n\t\t\treturn;\n\t\t}\n\t\tregisteredDescriptors = descriptors;\n\n\t\tregistration?.abort();\n\t\tregistration = new AbortController();\n\t\tconst { signal } = registration;\n\n\t\tfor (const tool of tools) {\n\t\t\tif (reserved.has(tool.name)) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Skipping the WebMCP tool \"${tool.name}\" registered by ` +\n\t\t\t\t\t\t`the site: Playground already provides a tool under ` +\n\t\t\t\t\t\t`that name.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tawait modelContext.registerTool(proxyTool(client, tool), {\n\t\t\t\t\tsignal,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to register the site's WebMCP tool ` +\n\t\t\t\t\t\t`\"${tool.name}\": ${stringifyError(error)}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (signal.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tclient\n\t\t.onWebMCPToolsChanged((tools: WebMCPToolDescriptor[]) => {\n\t\t\tvoid register(tools);\n\t\t})\n\t\t.then((remove) => {\n\t\t\tif (stopped) {\n\t\t\t\tremove();\n\t\t\t} else {\n\t\t\t\tunsubscribe = remove;\n\t\t\t}\n\t\t})\n\t\t.catch((error) => {\n\t\t\tlogger.warn(\"Failed to observe the site's WebMCP tools:\", error);\n\t\t});\n\n\treturn {\n\t\tstop() {\n\t\t\tstopped = true;\n\t\t\tunsubscribe?.();\n\t\t\tunsubscribe = null;\n\t\t\tregistration?.abort();\n\t\t\tregistration = null;\n\t\t\tregisteredDescriptors = '';\n\t\t},\n\t};\n}\n\n/**\n * Names Playground registers itself. A site tool may not take one of them\n * over, or an agent asking to execute PHP would reach the site's plugin\n * instead.\n */\nfunction reservedToolNames(): Set<string> {\n\treturn new Set([\n\t\t...Object.keys(toolDefinitions),\n\t\t...Object.keys(getSiteToolDefinitions()),\n\t]);\n}\n\nfunction proxyTool(\n\tclient: WebMCPSiteToolClient,\n\ttool: WebMCPToolDescriptor\n): ModelContextTool {\n\treturn {\n\t\tname: tool.name,\n\t\tdescription: tool.description,\n\t\tinputSchema: tool.inputSchema,\n\t\tannotations: tool.annotations,\n\t\texecute: async (input, clientArg) => {\n\t\t\tconst signal = clientArg?.signal;\n\t\t\tconst callId = crypto.randomUUID();\n\t\t\tconst abort = () => {\n\t\t\t\tvoid client.cancelWebMCPTool(callId).catch((error) => {\n\t\t\t\t\tlogger.warn('Failed to cancel the site tool:', error);\n\t\t\t\t});\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tsignal?.throwIfAborted();\n\t\t\t\tsignal?.addEventListener('abort', abort, { once: true });\n\t\t\t\tconst result = await client.callWebMCPTool(\n\t\t\t\t\ttool.name,\n\t\t\t\t\tinput ?? {},\n\t\t\t\t\tcallId\n\t\t\t\t);\n\t\t\t\tsignal?.throwIfAborted();\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Error running the WordPress site's \"${tool.name}\" ` +\n\t\t\t\t\t\t`tool: ${stringifyError(error)}`,\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\tsignal?.removeEventListener('abort', abort);\n\t\t\t}\n\t\t},\n\t};\n}\n"],"names":["RECONNECT_INTERVAL_MS","startMcpBridge","config","port","tabId","ws","previousSitesSerialized","reconnectTimer","stopped","sendSitesRegistration","socket","sites","serialized","connect","response","scheduleReconnect","token","_a","event","message","id","method","args","siteSlug","value","handleCommand","error","errorMsg","url","newName","playgroundClient","fn","createToolClient","siteToolDefinitions","getSiteToolDefinitions","registrationController","getActiveSite","active","s","registerWebMCPTools","modelContext","getModelContext","controller","signal","getActiveClient","client","tools","toolDefinitions","name","def","paramsToJsonSchema","input","executor","toolExecutors","adapter","result","_b","stringifyError","createSiteManagementTools","results","tool","failedRegistrations","index","reason","listDef","saveDef","renameDef","websiteUrlDef","_input","formatStorageLabel","site","storage","saved","activeSite","startWebMCPSiteToolProxy","maybeModelContext","reserved","reservedToolNames","registration","registeredDescriptors","unsubscribe","register","descriptors","logger","proxyTool","remove","clientArg","callId","abort"],"mappings":"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"}
package/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { startMcpBridge } from './bridge-client';
2
2
  export type { PlaygroundBridgeConfig, McpBridgeHandle } from './bridge-client';
3
- export { registerWebMCPTools } from './webmcp';
3
+ export { registerWebMCPTools, getModelContext } from './webmcp';
4
4
  export { startWebMCPSiteToolProxy } from './webmcp-site-tools';
5
5
  export type { WebMCPSiteToolProxy } from './webmcp-site-tools';