
An AI agent asks: "What's the Svelte 5 equivalent of useEffect?" Today it has two options β scrape the page HTML and parse it, or fetch api/data.json and filter 100+ items in context. Both work ok, but they both waste tokens.
WebMCP gives our AI agent a third option: call get_svelte_equivalent({ framework: 'react', concept: 'Side Effects' }) and get a structured answer directly. The data is the same. The interface is purpose-built for agents.
What WebMCP Is
WebMCP is a W3C Community Group Draft that adds navigator.modelContext to browsers. It lets websites register MCP tools β the same protocol that powers Claude's tool use, Cursor's context, and other agent frameworks β directly in a webpage. An AI agent browsing the site can discover and call those tools without scraping.
Chrome Canary (146+) has WebMCP behind a flag, and Microsoft Edge appears to support it out of the box β no flags or settings needed. For other browsers, @mcp-b/global from the MCP-B project fills in, until native support ships. Don't confuse this with Anthropic's MCP server protocol β WebMCP is a client-side browser API that happens to speak the same message format.
The App
My site svelte.cogley.jp is a migration reference showing how concepts from React, Vue, Angular, and now Svelte 4 map to Svelte 5. There are 120+ structured mappings across four categories: overview, syntax, architecture, and ecosystem. Each mapping has a concept name, source framework code, Svelte equivalent code, notes, doc links, and bilingual support (English/Japanese, well, because I can).
The data already has machine interfaces: a JSON API at /api/data.json, content negotiation via Accept: text/markdown, and an llms.txt describing the site for crawlers. WebMCP adds another layer β typed tools that agents can discover and call in-page without fetching or parsing anything.
Loading Strategy
The polyfill weighs ~285KB. Most visitors are humans browsing migration cards, not AI agents calling tools β so shipping it in the initial bundle would be wasteful. Dynamic import:
onMount(async () => {
theme.init();
language.init(data.lang);
// Force polyfill mode β Chrome Canary's native modelContext is
// incomplete (missing listTools/registerTool), which crashes the
// native adapter. Disable auto-init, wipe, then reinitialize.
const win = window as unknown as Record;
win.__webModelContextOptions = { autoInitialize: false };
const { cleanupWebModelContext, initializeWebModelContext } =
await import('@mcp-b/global');
cleanupWebModelContext();
try {
Object.defineProperty(navigator, 'modelContext', {
value: undefined, configurable: true, writable: true,
});
} catch { /* non-configurable β already cleaned */ }
initializeWebModelContext();
const { registerMigrationTools } = await import('$lib/webmcp');
registerMigrationTools();
});
Vite code-splits the polyfill into its own chunk. The __webModelContextOptions flag prevents the module's auto-initialization from crashing on browsers (like Chrome Canary) where the native navigator.modelContext exists but is incomplete β missing listTools() and registerTool(). After wiping the incomplete native API, initializeWebModelContext() installs the full polyfill. On Edge and browsers without a native API, cleanupWebModelContext() is a no-op and the polyfill installs normally.
The registerMigrationTools() import is dynamic too, keeping tool definitions out of both the server bundle and the initial page load.
Designing the Tools
Six read-only tools answer questions that AI agents might want to do, like "what's the Svelte equivalent of X?"
search_mappings
Full-text search across concepts, code, and notes. Same filter logic as the UI's search box:
mc.registerTool({
name: 'search_mappings',
description: 'Search migration mappings by keyword...',
inputSchema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search keyword' },
framework: { type: 'string', enum: ['react', 'vue', 'angular', 'svelte4'] },
category: { type: 'string', enum: ['overview', 'syntax', 'architecture', 'ecosystem'] },
lang: { type: 'string', enum: ['en', 'ja'] },
},
required: ['query'],
},
annotations: { readOnlyHint: true },
execute: async (args) => {
// Filter pool by framework/category, then substring-match on query
// Return structured JSON with framework/category context per match
},
});
An agent searching for "useState" gets React entries; searching for "routing" gets results across all four frameworks. The optional framework and category filters let agents narrow results when they already know what they're looking for.
get_svelte_equivalent
Direct lookup: give it a framework and concept name, get the best match. Uses exact match first, then substring fallback. If the agent asks for { framework: 'react', concept: 'Reactive State' }, it gets the $state mapping with full code examples and notes.
list_ecosystem_gaps
Items where the to field contains "No equivalent" or "β οΈ". This is the kind of query that's awkward to express via JSON filtering but natural as a tool call: "What can't I do in Svelte that I can do in React?"
The Other Three
- get_site_info β overview: frameworks, categories, total count, API URLs. The "hello world" tool.
- get_changelog β recent updates, bilingual, with configurable limit.
-
compare_frameworks β side-by-side: how React, Vue, Angular, and Svelte 4 each handle the same concept. An agent comparing "Reactive State" gets
useStatevsref()vssignal()vslet count = 0β$statein one call.
The Registration Module
The entire module is ~180 lines of TypeScript. Shared helpers handle filtering and matching:
function applyFilter(pool: MappingItem[], query: string): MappingItem[] {
if (!query.trim()) return pool;
const q = query.toLowerCase();
return pool.filter(
(item) =>
item.concept.toLowerCase().includes(q) ||
item.concept_ja?.toLowerCase().includes(q) ||
item.from?.toLowerCase().includes(q) ||
item.to?.toLowerCase().includes(q) ||
item.notes?.toLowerCase().includes(q) ||
item.notes_ja?.toLowerCase().includes(q) ||
item.checklist?.some((s) => s.toLowerCase().includes(q)) ||
item.checklist_ja?.some((s) => s.toLowerCase().includes(q))
);
}
Same logic that drives the $derived block in +page.svelte. The UI and the tools search identically β one filter function, two consumers.
Every tool returns MCP's standard content format ({ content: [{ type: 'text', text: JSON.stringify(...) }] }) and carries annotations: { readOnlyHint: true }. Query only, no mutations.
Testing
Microsoft Edge works out of the box. Chrome Canary needs the WebMCP flag (chrome://flags β "WebMCP for testing"). Alternatively, install the MCP-B extension. Open the console:
// List tools
navigator.modelContext.listTools()
// β Array of 6 tools with names, descriptions, input schemas
// Search for useState
await navigator.modelContext.callTool({
name: 'search_mappings',
arguments: { query: 'useState' }
})
// Direct lookup
await navigator.modelContext.callTool({
name: 'get_svelte_equivalent',
arguments: { framework: 'react', concept: 'Reactive State' }
})
// Compare across frameworks
await navigator.modelContext.callTool({
name: 'compare_frameworks',
arguments: { concept: 'Reactive State' }
})
In browsers without native support, the polyfill loads silently with no visible UI change and no console errors. Here it is in Chrome Canary, but I tested in Edge too and it worked without any special settings:
Updating llms.txt
I added a WebMCP section to llms.txt listing all six tools with their parameters. An agent that discovers the site via llms.txt now knows it can call tools directly β it doesn't have to guess whether the site supports WebMCP or fall back to fetching JSON.
Update: Svelte 4 β 5 Upgrade Data
22 Feb 2026 β I added Svelte 4 as a fourth source framework. This one's different from the other three β it's not a cross-framework migration, it's an upgrade guide for developers already on Svelte who need to move from v4 to v5 (runes, snippets, new event syntax, stores β reactive classes).
The data includes 25 new mappings: 4 overview items, 12 syntax mappings, 5 architecture patterns, and 4 ecosystem entries. The overview category has a new card type β a ChecklistCard β that renders a step-by-step migration checklist with numbered steps instead of the usual two-column code comparison. The checklist covers everything from npm install svelte@5 through running sv migrate to testing $$props edge cases.
A new checklist field on MappingItem holds the step arrays, with checklist_ja for Japanese translations. All four machine-readable interfaces were updated:
-
WebMCP tools β
search_mappingsandget_svelte_equivalentnow acceptframework: 'svelte4'; search covers checklist text;localizeItemreturns the checklist array -
llms-full.txtβ Svelte 4 section renders checklist steps as numbered lists -
llms.txtβ framework list and tool descriptions updated -
data.jsonβ includes the full svelte4 data structure automatically
An agent can now do things like get_svelte_equivalent({ framework: 'svelte4', concept: 'Props' }) to learn that export let prop β let { prop } = $props(), or search_mappings({ query: 'stores', framework: 'svelte4' }) to find the stores β reactive classes migration path.
What It Cost
The registration module is ~200 lines of TypeScript, with six tools. Zero bytes added to the initial page bundle of https://svelte.cogley.jp because everything loads dynamically β the polyfill chunk (429KB) only fires if the browser doesn't have native support yet.
The migration data was already structured and queryable. Now β with four frameworks and 120+ mappings including the Svelte 4 β 5 upgrade path β the site has an interface that AI agents can use without scraping.
Originally published at cogley.jp
Rick Cogley is CEO of eSolia Inc., providing bilingual IT outsourcing and infrastructure services in Tokyo, Japan.
United States
NORTH AMERICA
Related News
Jeff Bezos Seeking $100 Billion to Buy Manufacturing Companies, 'Transform' Them With AI
7h ago
Officer Leaks Location of French Aircraft Carrier With Strava Run
7h ago
Microsoft Says It Is Fixing Windows 11
7h ago
CBS News Shutters Radio Service After Nearly a Century
7h ago
Firefox Announces Built-In VPN and Other New Features - and Introduces Its New Mascot
7h ago
