Skip to content

feat: experimental WebMCP bridge (mcp-handler/webmcp) - #183

Draft
blurrah wants to merge 3 commits into
mainfrom
blurrah/webmcp-poc
Draft

feat: experimental WebMCP bridge (mcp-handler/webmcp)#183
blurrah wants to merge 3 commits into
mainfrom
blurrah/webmcp-poc

Conversation

@blurrah

@blurrah blurrah commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

What this adds

An experimental mcp-handler/webmcp subpath export that bridges server-side MCP tools into WebMCP — the W3C proposal (Microsoft + Google) that lets pages expose tools to in-page AI agents via navigator.modelContext / document.modelContext.

// app/webmcp.js/route.ts
import { experimental_createWebMcpScriptHandler } from "mcp-handler/webmcp";

const handler = experimental_createWebMcpScriptHandler({
  endpoint: "/api/mcp",
  // Required allowlist — only these tools are exposed to in-page agents.
  tools: ["roll_dice", "search_docs"],
});

export { handler as GET };
<script src="/webmcp.js" async></script>

The served script is a small dependency-free IIFE: it runs a minimal stateless MCP client against the endpoint (initializetools/list), filters to the allowlist, and registers each tool with the page's WebMCP provider, forwarding execute to tools/call. No provider in the browser → no-op.

Why it's cool

The auth story. Bridged tool calls go through the page's fetch with credentials: "same-origin", so they carry the user's session cookie. An in-page agent (extension, browser built-in) calls your tools as the signed-in user — no OAuth server, no dynamic client registration, no consent redirect, no token storage. Kill the session and the agent's access dies with it. withMcpAuth already supports this unchanged: its verifier receives the full Request, so one endpoint can serve OAuth bearer tokens to remote MCP clients and cookie sessions to the page.

Production precedent. Shopify ships this pattern today (cdn.shopify.com/storefront/webmcp/webmcp-0.1.0.js): catalog/search/product reads go straight to their same-origin Storefront GraphQL API, cart writes route through the theme-integrated window.Shopify.actions layer so the live UI stays in sync. The WebMCP registry is additive, so apps compose the same way here — bridge the server tools with this handler, hand-register client-side tools next to the state they manipulate, and use the allowlist as the partition between the two.

Design decisions

  • tools allowlist is required. Any script or agent in the page can invoke registered tools with the user's credentials, so exposure is opt-in per tool. The MCP endpoint itself is unaffected — it still serves its full tool set to regular MCP clients.
  • experimental_ prefix (same convention as experimental_withMcpAuth): WebMCP has no shipping browser support yet — this targets polyfills and extension agents, and the API may change with the spec. The subpath stays mcp-handler/webmcp so imports don't move on graduation.
  • Config is JSON-embedded with < escaped, so the script is safe to inline. GET/HEAD only, Cache-Control configurable.
  • Hardening documented in docs/WEBMCP.md: gate cookie auth on Sec-Fetch-Site: same-origin in the verifier, and use a CSP nonce on the script tag under strict CSP.

Docs in docs/WEBMCP.md, changeset included (minor).

Pretty cool as you can use webmcp as easy distribution for your MCP server and use the browser as an authed client with cookies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant