Skip to main content

I Built a Bridge for Google's New WebMCP Draft Spec — Here's What Broke

A developer shares insights and real bugs encountered while building a custom Chrome Extension and MCP Server to test W3C's WebMCP draft spec on Chrome for Testing.

AI-written
Inewgen
03 Aug 2026Source: Dev.to4 min read (0 views)Last updated 29 Aug 2026
Share
I Built a Bridge for Google's New WebMCP Draft Spec — Here's What Broke

Stock photo for illustration only, not from the actual event

Font size
  • WebMCP is a W3C draft spec allowing web pages to declare their features as AI Agent tools.
  • The author built a Chrome Extension and MCP Server pair to bridge native browser gaps.
  • Real issues included getTools() returning a Promise and executeTool requiring object arguments.
  • File protocol restrictions and MV3 Service Worker lifecycle quirks added unique hurdles.

Hi, everyone. I usually go by tanahiro2010 in Japan. I'm a member of GDG Greater Kwansai. I gave the first-half talk at the Google I/O Extended Osaka 2026 hands-on session, "Let's Build WebMCP and Call It from an AI Agent!" This is a write-up of that hands-on session for Qiita, translated here for Dev.to, and the codelab we used can be found at https://learn.gdgs.jp/webmcp-agent/

This article is tailored for individuals who are already familiar with MCP (Model Context Protocol) but are new to WebMCP, or those curious about what Google's newly released spec actually feels like in practice. Once I dove into the spec and implemented it, it turned out to be far quirkier than anticipated. In this piece, I will walk through its internal mechanics and what I learned from getting my hands dirty.

Before diving into WebMCP, let's briefly recap MCP, which serves as a common interface for connecting external tools to an AI Agent. WebMCP itself is a draft specification published by the W3C Web Machine Learning Community Group. As of writing, it is the February 2026 draft, sitting firmly at the proposal stage, enabling web pages to declare their own features as tools directly via JavaScript or annotated HTML forms.

browser developer tools debugging code

Stock photo for illustration only, not from the actual event

The W3C's push toward Web Machine Learning standards like WebMCP represents a pivotal shift in transforming web browsers into primary runtimes for AI applications rather than relying solely on server-side logic. Establishing standard APIs for web pages to expose tools directly helps bridge the gap between traditional web architectures and intelligent agents.

Due to the similarity in naming and API design, my initial impression was roughly that it was simply the web version of MCP. However, digging deeper revealed clear differences along multiple axes, particularly regarding session lifetime and the fact that it remains an upcoming, non-native feature in most attendee browsers at workshop venues.

Never miss the latest news?

Subscribe to get news summaries by email - not often enough to be annoying.

โฆษณา

This exact gap drove me to build a solution: a paired Chrome Extension and MCP Server. I was very particular about only detecting and executing APIs defined by the WebMCP spec as-is (document.modelContext and annotated forms), avoiding any custom protocols to ensure the hands-on learning experience mirrored real-world specs accurately.

The WebSocket binds to ws://127.0.0.1:58787, deliberately avoiding port 8787 to prevent collisions with wrangler dev for Cloudflare Workers. The extension utilizes an MV3 architecture with a two-layer structure exposing six distinct tools to the agent.

This brings me to the implementation details discovered on real hardware running Chrome for Testing 150. Contrary to summary impressions of a synchronous function, document.modelContext.getTools() actually returns a Promise<ModelContextTool[]>. Furthermore, executeTool() requires the actual tool object rather than a string identifier, throwing a TypeError otherwise.

Additionally, during postMessage communication between content.ts and injected.ts, utilizing window.location.origin on pages opened via file:// resulted in the literal string "null", breaking the handshake entirely. Shifting to "*" with a random channel ID resolved this issue, highlighting bugs that only surface when testing local file protocols directly.

Source: Dev.to

Comments

Leave a Comment
0/2000

Found something wrong in this article? Report an issue with this article