How to Implement WebMCP on Your Website: A Step-by-Step Technical Guide (2026)
Every important web standard has a moment when developers shift from reading about it to actually building with it.
For WebMCP, that moment is now.
Chrome 146 supports WebMCP behind a flag. Microsoft Edge 147 is on board. Official demo repositories exist. Debugging tooling is live. The API shape is stable enough to build against. Early implementations are already demonstrating an 89% reduction in AI agent token consumption compared to DOM-scraping approaches.
If you're a developer who wants to understand precisely how WebMCP works at the code level — and how to start integrating it today — this is the guide you need. We'll cover both APIs, real code examples drawn directly from the official specification and community implementations, testing methodology, and a complete implementation checklist you can use as your rollout roadmap.
Prerequisites Before You Start
Before writing a single line of WebMCP code, you need three things in place:
HTTPS: The WebMCP API is only available in secure contexts. If you're testing locally, use localhost (which qualifies as a secure context) or a local dev environment with a self-signed certificate. On production, your site must be on HTTPS — which it should already be.
Chrome 146+ Canary with the flag enabled: Open Chrome Canary, navigate to chrome://flags, and search for "WebMCP for testing." Enable the flag and relaunch. If the specific flag doesn't appear, search for "Experimental Web Platform features" and enable that as a prerequisite.
The Model Context Tool Inspector extension: This is the official Chrome extension from the Chrome Labs team for debugging WebMCP implementations. It lists all registered tools on the active tab, lets you call them manually with custom parameters, and shows the returned results — invaluable for testing without needing a live AI agent. Install it from the GoogleChromeLabs repository.
With these in place, you're ready to build.
Understanding the Two APIs
WebMCP exposes your website's capabilities through the browser's navigator.modelContext interface using two complementary approaches:
The Declarative API is HTML-first. You add three new attributes to existing <form> elements and your forms become WebMCP tools. Minimal JavaScript required. Perfect for contact forms, search bars, subscription flows, and any other form-based interaction that already exists on your site.
The Imperative API is JavaScript-first. You call navigator.modelContext.registerTool() with a tool definition object. More powerful, more flexible, required for workflows that involve application state, dynamic data fetching, or sequences of actions that go beyond form submission.
Both approaches result in tools that are discoverable by AI agents through the same navigator.modelContext interface. The choice between them is purely about what fits your use case and existing codebase.
Part 1: The Declarative API
How It Works
The Declarative API introduces three new HTML attributes for <form> elements:
toolname (required) — The machine-readable identifier for this tool. Use camelCase. This is the name an AI agent will use to call it. For example: searchProducts, submitSupportTicket, bookAppointment.
tooldescription (required) — A natural-language description of what this tool does. Write this for the AI agent to read, not for humans. Be precise and specific. "Search for products by name, category, price range, or availability" is better than "Search our store."
toolautosubmit (optional) — When present, the form is submitted automatically after the agent fills in all fields. When absent, the agent fills the form but the user must click submit manually. For most forms, omitting this attribute is the safer choice — it keeps the human in the loop for the final action.
Code Example: Contact Form
Here's a standard contact form before WebMCP:
<form id="contact-form" action="/submit-contact" method="POST">
<label for="name">Your Name</label>
<input type="text" id="name" name="name" required />
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required />
<label for="subject">Subject</label>
<input type="text" id="subject" name="subject" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send Message</button>
</form>
Here's the same form after WebMCP Declarative API annotation — notice that only the <form> opening tag changes:
<form
id="contact-form"
action="/submit-contact"
method="POST"
toolname="sendContactMessage"
tooldescription="Send a contact message to the business team. Use this when the user wants to reach out, ask a question, report an issue, or request information."
>
<label for="name">Your Name</label>
<input type="text" id="name" name="name" required />
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required />
<label for="subject">Subject</label>
<input type="text" id="subject" name="subject" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send Message</button>
</form>
Three attributes. That's the entire implementation for a contact form. The agent can now discover this tool, understand its purpose from the tooldescription, infer the input parameters from the form fields and their labels, and fill them correctly.
Code Example: E-commerce Search Form
<form
action="/search"
method="GET"
toolname="searchProducts"
tooldescription="Search the product catalog by keyword, category, price range, or availability. Returns a list of matching products with name, price, and product URL."
toolautosubmit
>
<label for="query">Search</label>
<input type="search" id="query" name="q" placeholder="Search products..." />
<label for="category">Category</label>
<select id="category" name="category">
<option value="">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
<option value="home">Home & Garden</option>
</select>
<label for="max-price">Maximum Price</label>
<input type="number" id="max-price" name="maxPrice" min="0" />
<button type="submit">Search</button>
</form>
Note the use of toolautosubmit here — a product search is a read-only query where automatic submission is appropriate. The user can always refine results without risk.
Code Example: Appointment Booking Form
<form
action="/appointments/book"
method="POST"
toolname="bookAppointment"
tooldescription="Book a service appointment. Requires the service type, preferred date, preferred time, and customer contact information. Returns a confirmation number on success."
>
<label for="service">Service Type</label>
<select id="service" name="serviceType" required>
<option value="consultation">Initial Consultation</option>
<option value="followup">Follow-up Visit</option>
<option value="procedure">Procedure</option>
</select>
<label for="date">Preferred Date</label>
<input type="date" id="date" name="preferredDate" required />
<label for="time">Preferred Time</label>
<input type="time" id="time" name="preferredTime" required />
<label for="patient-name">Full Name</label>
<input type="text" id="patient-name" name="fullName" required />
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone" required />
<button type="submit">Book Appointment</button>
</form>
No toolautosubmit here — booking an appointment is a write action with real-world consequences. The user should confirm before submission.
Declarative API Best Practices
Write descriptions for the agent, not the human. The tooldescription attribute is the most important thing you'll write in your entire WebMCP implementation. It's what the agent reads to decide whether to use your tool. Be explicit about what it does, what it returns, and when to use it.
Every significant form should be a WebMCP tool. The implementation cost is trivially low — two HTML attributes. The downside of not annotating a form is that agents interact with it poorly, not that they skip it. Annotate everything that matters.
Use semantic, descriptive input names. An input with name="q" is less informative than name="searchQuery". Your existing field labels help agents understand intent, but meaningful name attributes make the tool schema more precise.
Test each form in isolation first. Use the Model Context Tool Inspector extension to verify the tool appears, has the right description, and generates the correct schema from your form fields before testing with a live agent.
Part 2: The Imperative API
How It Works
The Imperative API gives you full programmatic control over WebMCP tool registration. You call navigator.modelContext.registerTool() with a tool definition object containing the tool's name, description, input schema, optional metadata, and the execute function that runs when an agent calls it.
Always start with a feature detection guard:
if ("modelContext" in navigator) {
// WebMCP is available — register your tools here
}
This ensures your code doesn't throw errors in browsers without WebMCP support. Your site continues to work normally; agents just don't get the structured tools until the user is on a supporting browser.
Code Example: Product Search Tool
if ("modelContext" in navigator) {
navigator.modelContext.registerTool({
name: "searchProducts",
description: "Search the product catalog. Returns products matching the query, " +
"optionally filtered by category, maximum price, and in-stock availability. " +
"Returns an array of product objects with name, price, URL, and stock status.",
readOnly: true, // This tool only reads data — no confirmation required
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search keyword or product name"
},
category: {
type: "string",
description: "Product category to filter by",
enum: ["electronics", "clothing", "home", "sports", "beauty"]
},
maxPrice: {
type: "number",
description: "Maximum price in USD"
},
inStockOnly: {
type: "boolean",
description: "If true, only return products currently in stock",
default: false
}
},
required: ["query"]
},
async execute(params) {
try {
const url = new URL("/api/products/search", window.location.origin);
url.searchParams.set("q", params.query);
if (params.category) url.searchParams.set("category", params.category);
if (params.maxPrice) url.searchParams.set("maxPrice", params.maxPrice);
if (params.inStockOnly) url.searchParams.set("inStock", "true");
const response = await fetch(url.toString());
const data = await response.json();
return {
content: [{
type: "text",
text: JSON.stringify(data.products)
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: `Search failed: ${error.message}`
}],
isError: true
};
}
}
});
}
Code Example: Add to Cart Tool
if ("modelContext" in navigator) {
navigator.modelContext.registerTool({
name: "addToCart",
description: "Add a specific product to the shopping cart. " +
"Requires the product ID and quantity. " +
"Returns the updated cart total and item count on success.",
readOnly: false, // This modifies state — agent will request user confirmation
inputSchema: {
type: "object",
properties: {
productId: {
type: "string",
description: "The unique product identifier (from searchProducts results)"
},
quantity: {
type: "integer",
description: "Number of units to add",
minimum: 1,
maximum: 99,
default: 1
},
size: {
type: "string",
description: "Product size, required for clothing and shoes",
enum: ["XS", "S", "M", "L", "XL", "XXL"]
}
},
required: ["productId", "quantity"]
},
async execute(params) {
try {
const response = await fetch("/api/cart/add", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
productId: params.productId,
quantity: params.quantity,
size: params.size || null
})
});
const cart = await response.json();
// Update the cart UI to reflect the new state
document.getElementById("cart-count").textContent = cart.itemCount;
document.getElementById("cart-total").textContent = `$${cart.total.toFixed(2)}`;
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
cartItemCount: cart.itemCount,
cartTotal: cart.total,
message: `Added ${params.quantity} item(s) to cart`
})
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: `Failed to add to cart: ${error.message}`
}],
isError: true
};
}
}
});
}
Code Example: Get User Account Summary (Session-Aware Tool)
This example demonstrates WebMCP's unique advantage: accessing the user's live authenticated session context, something a backend MCP server can't do without rebuilding auth from scratch.
if ("modelContext" in navigator) {
navigator.modelContext.registerTool({
name: "getAccountSummary",
description: "Retrieve the current user's account summary including recent orders, " +
"saved addresses, payment methods on file, and loyalty points balance. " +
"Only works when the user is logged in.",
readOnly: true,
inputSchema: {
type: "object",
properties: {
includeOrders: {
type: "boolean",
description: "Include recent order history (last 10 orders)",
default: true
}
},
required: []
},
async execute(params) {
// The user's session cookie is automatically included in this fetch
// because it's running in the browser context — no separate auth needed
const response = await fetch("/api/account/summary", {
credentials: "same-origin" // Uses the existing logged-in session
});
if (response.status === 401) {
return {
content: [{
type: "text",
text: "User is not logged in. Cannot retrieve account summary."
}],
isError: true
};
}
const summary = await response.json();
return {
content: [{
type: "text",
text: JSON.stringify(summary)
}]
};
}
});
}
Understanding readOnly
The readOnly flag is how WebMCP communicates trust level to both the agent and the user:
readOnly: true — The tool only reads data and makes no changes. Agents can call read-only tools without requesting user confirmation. Use for search, retrieval, status checks, and any operation that has no side effects.
readOnly: false (or omitting the property) — The tool modifies state. Agents will prompt the user to confirm before executing. Use for add-to-cart, form submission, booking, purchase, deletion — any operation that changes something the user would want to consciously approve.
Getting this classification right is essential both for user experience and for trust. An agent that quietly submits forms without confirmation will frustrate users and erode trust in your site.
Part 3: Managing Tool Lifecycle
Tools should be registered when relevant and unregistered when they're not. A checkout tool shouldn't be available when the cart is empty. A filter tool shouldn't be registered when there are no results to filter.
// Register the checkout tool only when the cart has items
function updateCartToolRegistration(cartItemCount) {
if ("modelContext" in navigator) {
if (cartItemCount > 0) {
// Register the tool if it isn't already registered
registerCheckoutTool();
} else {
// Unregister it when cart empties
try {
navigator.modelContext.unregisterTool("proceedToCheckout");
} catch (e) {
// Tool wasn't registered — that's fine
}
}
}
}
This pattern keeps your tool manifest clean and contextually accurate. Agents see only the tools that are actually usable in the current page state.
Part 4: Testing Your Implementation
Using the Model Context Tool Inspector
Once your Chrome Canary has the WebMCP flag enabled and the Model Context Tool Inspector extension installed:
- Navigate to any page on your site with WebMCP tools registered
- Open the extension — it will automatically list all registered tools on the current tab
- For each tool, you'll see the name, description, and complete JSON Schema
- Use the "Call Tool" interface to manually execute any tool with custom parameters
- Inspect the returned results and any error messages
This lets you test every tool without needing an AI agent, making it easy to catch schema mismatches, parameter validation issues, and runtime errors before they affect real users.
Testing Checklist Per Tool
For each WebMCP tool you register:
Schema validation: Does the tool appear correctly in the Inspector with the right name and description? Is the input schema complete and accurate?
Required parameter handling: Does the execute function handle missing required fields gracefully? Test with empty inputs.
Optional parameter handling: Does the tool work correctly when optional parameters are omitted?
Error states: What happens when the API call fails? Does the tool return a clean error response rather than throwing an uncaught exception?
State mutations: For non-readOnly tools, does the UI update correctly after the tool executes? Cart counts, availability indicators, confirmation messages — all of these need to reflect the tool's side effects.
Session handling: For session-aware tools, does the tool return the right response when the user is logged out versus logged in?
Part 5: Using the Polyfill for Current Browsers
While Chrome 146+ and Edge 147+ support WebMCP natively behind a flag, you can test in current stable browsers using the community polyfills:
@mcp-b/global — A drop-in polyfill that implements navigator.modelContext with the same API surface as the spec. Install via npm or include as a script tag.
webmcp-core — A zero-dependency polyfill at 2.94 KB (IIFE build). Minimal footprint for production exploration.
<!-- Add before your WebMCP implementation scripts -->
<script src="https://unpkg.com/webmcp-core/dist/webmcp.iife.js"></script>
These polyfills won't give you AI agent interaction in current browsers, but they let you test the API surface, tool registration behavior, and execution logic without requiring Chrome Canary.
The Complete WebMCP Implementation Checklist
Use this as your rollout roadmap. Work through it in order — the foundation items make everything else easier.
Phase 1: Foundation (Do This First)
- Confirm site is on HTTPS
- Audit semantic HTML across all key pages
- Ensure all form inputs have descriptive
nameattributes and associated<label>elements - Verify form validation is explicit and predictable (no JavaScript-only validation that silently fails)
- Add or audit Schema.org structured data on core pages
- Install Chrome 146 Canary and enable WebMCP flag
- Install Model Context Tool Inspector extension
Phase 2: Declarative API (Quick Wins)
- Identify all forms on your site that represent meaningful user actions
- Prioritize by business value: search, contact, booking, signup, support ticket
- Add
toolnameandtooldescriptionto each priority form - Decide
toolautosubmitappropriateness per form (yes for read-only queries, no for write actions) - Test each annotated form in the Model Context Tool Inspector
- Verify schema generation is correct for each form's fields
Phase 3: Imperative API (Core Workflows)
- Map your 3–5 highest-value user workflows
- Design input schemas for each (what does the agent need to provide?)
- Implement
executefunctions with properasync/awaitand error handling - Classify each tool correctly with
readOnly: trueorfalse - Implement UI state updates within
executefunctions for non-readOnly tools - Test each tool manually via Model Context Tool Inspector with edge case inputs
- Add lifecycle management (register/unregister based on page state)
Phase 4: Quality and Security
- All tool descriptions are agent-readable, specific, and accurate
- All execute functions have try/catch error handling
- Non-readOnly tools require confirmed user session context
- No sensitive personal data is returned unnecessarily in tool outputs
- Tool schemas validated against JSON Schema spec
- Staging environment testing complete
Phase 5: Monitoring
- Implement logging for tool call events
- Track which tools are called, call frequency, and success/error rates
- Monitor for unexpected tool call patterns
- Set up alerts for anomalous execution spikes
Frequently Asked Questions: WebMCP Implementation
Do I need to rewrite my website to add WebMCP? No. The Declarative API requires only HTML attribute additions to existing forms. The Imperative API wraps your existing JavaScript application logic. WebMCP is explicitly designed to augment what you have, not replace it.
How do I know which forms to annotate first? Start with your highest-conversion forms — the ones where completion means the most business value. Contact forms, booking forms, search, checkout. If an agent completing that form for a user drives revenue, it's a priority.
What's the best way to write tooldescription attributes?
Write them as instructions to a smart assistant who has never visited your site. Describe exactly what the tool does, what the expected inputs are, what the output looks like, and when the tool should be used versus not used. The more precise, the better the agent's performance.
Should I use the Declarative or Imperative API for a complex multi-step checkout? Imperative API. Multi-step workflows with conditional logic, state management between steps, and dynamic data fetching require the full power of JavaScript. The Declarative API is for simpler, single-form interactions.
How do I test without a live AI agent? The Model Context Tool Inspector extension lets you call any registered tool with arbitrary parameters and inspect the results — entirely without an AI agent. It's the fastest way to validate your implementation logic.
What happens to my WebMCP tools in browsers that don't support it?
Nothing. The feature detection guard (if ("modelContext" in navigator)) ensures your registration code is silently skipped in unsupported browsers. Your site functions normally for all users; agents just don't get the structured tools until they're on a WebMCP-supporting browser.
Check Your Implementation Score
Building WebMCP tools is just half the work. Knowing whether they're implemented correctly — and what gaps remain across your site — is equally important.
AgentReady's AI Readiness Analyzer scans your site for WebMCP implementation quality, semantic HTML health, and structured data completeness. It gives you a scored breakdown of your current agent-readiness and a prioritized list of the highest-impact improvements remaining.
→ Scan Your Site for Free at AgentReady
Published by the AgentReady Team at MagicMakersLab. AgentReady is the AI Readiness Analyzer purpose-built for the agentic web — measuring WebMCP implementation quality, structured data health, and semantic HTML readiness so developers and businesses know exactly where they stand.
Related Articles:
- What Is WebMCP? The Complete Guide to the Protocol Reshaping the Internet in 2026
- Why Your Website Needs to Be WebMCP Ready Before Your Competitors Are
- WebMCP vs MCP: The Complete Comparison (And Why Your Website Needs Both)
Is Your Website Ready for WebMCP?
Test your site to see your AI Readiness Score and understand exactly what you need to fix.
Check Your AI Readiness Score