AI agents are starting to use websites the way people do: opening pages, reading content, clicking buttons, filling forms, and completing tasks. The problem is that most websites were built only as visual interfaces. They were not designed to tell an agent what actions are available or how those actions should be called safely.
This is part of a broader shift called agentic browsing: instead of only browsing the web ourselves, we increasingly ask agents to browse with us, compare options, prepare actions, and sometimes complete workflows. For that to work well, websites need to become easier for agents to understand without becoming less usable for humans.
WebMCP is an emerging browser-side idea that helps solve this. It lets a page expose a small set of structured tools to an AI agent. Instead of making the agent guess which button to press, the page can say: here is a tool, here is what it does, here is the input it accepts, and here is how to run it.
WebMCP in simple terms
Think of WebMCP as a way for your page to publish capabilities. A capability might be search_articles, compare_plans, prepare_export, or fill_contact_form. The normal UI still exists for humans, but the agent gets a clearer contract than raw HTML and screenshots.
- The user still sees and controls the website.
- The page registers tools the agent can understand.
- Each tool defines the input it accepts.
- Your app still validates the final action on the server.
Why developers should care
A human can understand a messy interface and recover from small mistakes. An agent is more brittle. If a page has five similar buttons, hidden state, weak labels, or unclear validation, the agent has to guess. WebMCP reduces that guessing by giving the agent a typed path through the workflow.
A small example
Start with something low-risk. Search is a good first tool because it does not change account state. This example registers a page tool that lets an agent search articles.
type ModelContextDocument = Document & {
modelContext?: {
registerTool: (
tool: {
name: string;
description: string;
inputSchema?: Record<string, unknown>;
execute: (input: Record<string, unknown>) => Promise<unknown> | unknown;
},
options?: { signal?: AbortSignal }
) => Promise<void>;
};
};
export function registerArticleSearchTool(
searchArticles: (query: string) => Promise<unknown[]>
) {
const modelContext = (document as ModelContextDocument).modelContext;
if (!modelContext) return () => {};
const controller = new AbortController();
void modelContext.registerTool(
{
name: "search_articles",
description: "Search published articles on the current website.",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
minLength: 2,
description: "The topic, phrase, or question to search for.",
},
},
required: ["query"],
additionalProperties: false,
},
async execute(input) {
const query = String(input.query ?? "").trim();
if (query.length < 2) {
throw new Error("Search query must be at least 2 characters.");
}
const articles = await searchArticles(query);
return {
articles,
message: `Found ${articles.length} matching article(s).`,
};
},
},
{ signal: controller.signal }
);
return () => controller.abort();
}Using it in Next.js
Because WebMCP depends on the browser document, registration belongs in a client component. Mount this bridge only on the page where the tool should exist.
"use client";
import { useEffect } from "react";
export function ArticleSearchWebMcpBridge() {
useEffect(() => {
const cleanup = registerArticleSearchTool(async (query) => {
const response = await fetch(`/api/articles/search?q=${encodeURIComponent(query)}`);
if (!response.ok) throw new Error("Article search failed");
return response.json();
});
return cleanup;
}, []);
return null;
}Design the tool like an API
A WebMCP tool is part of your product surface. Give it a stable name, a clear description, strict inputs, and predictable output. Avoid vague tools like do_task or update_page because they give the agent too much room to improvise.
- Use names based on user intent, not internal code names.
- Keep each tool focused on one job.
- Reject unknown fields in the input schema.
- Return structured data the agent can reason about.
WebMCP does not replace MCP
MCP usually connects an agent to services such as databases, files, APIs, CRMs, or internal tools. WebMCP is page-local. It exposes actions available inside the current document, current session, and current UI state. In practice, many products may use both.
Security cannot be optional
A WebMCP tool call should never bypass your normal security model. Treat it like a form submit or API request. The browser can describe the tool, but your server must still decide whether the user is allowed to perform the action.
- Validate input on the server.
- Check permissions on every action.
- Require confirmation before destructive changes.
- Log tool calls for debugging and audit trails.
Where to start
Do not begin with your most sensitive workflow. Start with a small tool that helps users but cannot damage state. Search, filtering, documentation lookup, and report preparation are good candidates. Once the pattern feels stable, move toward workflows that require review and confirmation.
- Pick one low-risk workflow.
- Expose it as a narrow page-level tool.
- Reuse existing application logic.
- Add validation and logs before expanding the surface area.