mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

AI Agents

WebMCP: How Browser-Exposed Tools Let AI Agents Execute Actions Inside the Page Without Scraping

WebMCP inverts browser automation: pages expose discoverable tools that agents call directly. Here's how tool discovery, state management, and sandboxin...

Source: dev.to
WebMCP: How Browser-Exposed Tools Let AI Agents Execute Actions Inside the Page Without Scraping

WebMCP flips the browser automation model. Instead of agents driving Playwright from outside, the page itself exposes discoverable tools that agents can call directly. This changes the boundary between agent orchestration and browser state.

Most browser automation follows a familiar pattern: your agent script opens a browser, navigates to a page, and issues commands through a driver API (Selenium, Playwright, Puppeteer). The agent owns the control flow. The page is passive.

WebMCP inverts this. The page declares capabilities through the Model Context Protocol. The agent discovers those capabilities, then calls them as tools. The page owns the execution surface. The agent becomes a consumer of declared functions.

This matters when you want to build agents that interact with web applications without writing brittle selectors or maintaining scraping logic. The page author defines the contract. The agent reads it at runtime.

Architecture: Tool Discovery and Execution Flow

WebMCP sits on top of the Model Context Protocol (MCP), which defines how clients discover and invoke tools. In the browser context, the page exposes a modelContext object on the window. This object implements the MCP server interface.

Here’s the flow:

  1. Page load: The agent opens the target URL in a real browser (Playwright-controlled Chrome).
  2. Discovery: The agent injects JavaScript to check if window.modelContext exists.
  3. Schema fetch: The agent calls modelContext.listTools() to retrieve the tool manifest (names, parameters, descriptions).
  4. Tool invocation: The agent passes tool calls from the LLM (Gemini, GPT-4, Claude) into modelContext.callTool(toolName, args).
  5. Result return: The page executes the tool inside its own context and returns structured data.

The agent never writes CSS selectors or XPath queries. The page defines what actions are possible.

Code: Checking for WebMCP and Reading Tools

// Injected into the page via Playwright
const hasWebMCP = await page.evaluate(() => {
  return typeof window.modelContext !== 'undefined';
});

if (!hasWebMCP) {
  throw new Error('Page does not expose modelContext');
}

// Fetch the tool manifest
const tools = await page.evaluate(async () => {
  const result = await window.modelContext.listTools();
  return result.tools;
});

// tools is now an array of { name, description, inputSchema }

Each tool includes a JSON Schema for its parameters. The agent passes this schema to the LLM so it knows how to construct valid tool calls.

Code: Executing a Tool Call

// LLM returns a tool call: { name: 'submitGuess', arguments: { guess: 42 } }
const toolResult = await page.evaluate(async (toolName, args) => {
  return await window.modelContext.callTool(toolName, args);
}, toolCall.name, toolCall.arguments);

// toolResult contains the page's response

The page handles the execution. The agent just marshals data in and out.

State Management and Persistence

WebMCP tools run inside the page’s JavaScript context. That means they have access to the DOM, local storage, session storage, and any in-memory state the page maintains.

But what happens when the page reloads?

  • State loss: If the agent navigates away or the page refreshes, all in-memory state disappears unless the page persists it (localStorage, IndexedDB, cookies).
  • Session continuity: The agent must re-discover tools after every navigation. There is no persistent connection.
  • Tool versioning: If the page updates its tool manifest between agent sessions, the agent must handle schema drift.

This is different from traditional browser automation, where the agent script maintains state externally (in Python variables, a database, or a state machine). With WebMCP, the page is the source of truth.

If you need durable state across sessions, the page must implement its own persistence layer. The agent cannot rely on browser memory.

Security and Sandboxing

WebMCP introduces a new attack surface: malicious pages can expose fake or dangerous tools to agents.

Consider these scenarios:

  • Phishing tools: A fake banking page exposes a transferMoney tool that sends funds to an attacker’s account.
  • Data exfiltration: A compromised page exposes a getUserData tool that leaks credentials to a remote server.
  • Denial of service: A tool that triggers infinite loops or resource exhaustion inside the agent’s browser session.

Right now, WebMCP has no built-in sandboxing or trust model. The agent must validate the page origin before calling tools.

Mitigation Strategies

RiskMitigation
Malicious tool exposureWhitelist trusted domains. Reject tools from unknown origins.
Parameter injectionValidate tool arguments against the JSON Schema before execution.
State tamperingUse read-only tools for sensitive data. Require user confirmation for write operations.
Resource exhaustionSet execution timeouts on tool calls. Monitor memory and CPU usage.

The agent should treat WebMCP tools like external API calls: validate inputs, handle errors, and assume the page could be hostile.

Deployment Shape

A minimal WebMCP agent requires three components:

  1. Browser runtime: Playwright or Puppeteer to control a real browser instance.
  2. LLM client: Gemini API, OpenAI API, or Anthropic API to generate tool calls.
  3. Orchestration loop: A script that fetches tools, passes them to the LLM, and executes the returned tool calls.

Here’s the deployment shape:

  • Local development: Run Playwright headless on your machine. Point it at localhost or a staging URL.
  • CI/CD testing: Spin up a browser in a Docker container. Run agent tests against your WebMCP-enabled page.
  • Production: Deploy the agent as a long-running service (Node.js, Python) that opens browser sessions on demand. Use a headless browser pool (Browserless, Selenium Grid) to handle concurrency.

The agent does not need to run inside the browser. It controls the browser from outside, just like traditional automation. The difference is that it reads the page’s tool manifest instead of hard-coding selectors.

Failure Modes and Recovery

WebMCP agents fail in predictable ways. Here’s how to handle each:

Tool not found: The LLM requests a tool that doesn’t exist in the manifest. Recovery: catch the error, log the requested tool name, and ask the LLM to retry with available tools. If the LLM repeatedly requests invalid tools, re-send the full tool manifest in the next prompt.

Schema mismatch: The LLM generates arguments that don’t match the tool’s JSON Schema. The page rejects the call. Recovery: validate arguments against the schema before calling the tool. If validation fails, send the error back to the LLM with the correct schema and ask it to regenerate the call.

Execution timeout: The tool takes too long to execute. Recovery: set a timeout (5-30 seconds depending on tool complexity) using Playwright’s page.evaluate timeout option. If the timeout fires, abort the call, log the failure, and report to the LLM that the tool is unavailable. Consider implementing a fallback tool or asking the LLM to choose a different approach.

Page crash: The browser tab crashes mid-execution. Recovery: wrap tool calls in a try-catch block that detects page disconnection. Restart the browser session, re-navigate to the page, re-discover tools, and retry the last tool call once. If the crash repeats, mark the tool as unstable and exclude it from future calls in this session.

Network partition: The page loses connectivity. Tool calls fail silently or hang. Recovery: implement health checks (ping a known tool or check page.isConnected()) before each tool call. If the check fails, restart the session. Log network failures separately from tool execution failures so you can distinguish infrastructure issues from page bugs.

The orchestration loop must handle these failures explicitly. WebMCP does not provide automatic retries or error recovery.

Observability

To debug WebMCP agents, you need visibility into three layers:

  1. LLM requests: Log every tool call the LLM generates (name, arguments, reasoning).
  2. Page execution: Log every tool invocation inside the browser (success, failure, return value).
  3. Browser state: Capture screenshots and DOM snapshots before and after each tool call.

Playwright makes this easy:

// Enable tracing
await context.tracing.start({ screenshots: true, snapshots: true });

// Execute tool calls
// ...

// Save trace
await context.tracing.stop({ path: 'trace.zip' });

The trace file includes a timeline of all page interactions, network requests, and console logs. You can replay it in Playwright’s trace viewer.

Structured Logging for Production

For production agents, ship traces to an observability backend (Honeycomb, Datadog, Grafana). Use structured JSON logs with these fields:

  • trace_id: unique identifier for the entire agent session
  • tool_name: the WebMCP tool being invoked
  • model_version: LLM model and version (e.g., gemini-1.5-pro-002)
  • page_url: the page exposing the tools
  • execution_time_ms: how long the tool took to execute
  • success: boolean indicating success or failure
  • error_type: if failed, the failure mode (timeout, schema_mismatch, tool_not_found)

This lets you correlate LLM reasoning logs with page execution logs in distributed setups. When an agent fails, you can query for all events with the same trace_id to see the full conversation history, tool calls, and browser state changes.

Add a correlation ID to every Playwright page context so browser-side errors (console logs, exceptions) can be linked back to the agent session. Pass this ID as a query parameter or inject it into the page’s localStorage on load.

When to Use WebMCP

WebMCP makes sense when:

  • You control the page and can add tool declarations.
  • The page’s functionality is complex enough that selectors would be brittle.
  • You want to version the agent-page contract explicitly.
  • You need the page to enforce business logic (validation, authorization) during tool execution.

WebMCP does not make sense when:

  • You’re automating third-party sites that don’t expose tools.
  • The page is static and doesn’t need dynamic tool discovery.
  • You need to scrape data that the page doesn’t expose as a tool.
  • You want to avoid running a real browser (headless or otherwise).

Technical Verdict

Use WebMCP if you own both the page and the agent, the page schema changes less than twice per quarter, and you have CI/CD budget for browser pools (expect $50-200/month for Browserless or similar services at moderate scale). The tool manifest becomes your API contract. This pays off when page structure changes frequently but the underlying actions remain stable. You trade selector maintenance (brittle, breaks on every DOM change) for schema versioning (explicit, breaks only when tool signatures change).

Avoid WebMCP if you’re automating legacy third-party sites with no API contract, the page author cannot commit to schema stability, or you need offline-first automation without browser state dependency. Traditional Playwright automation gives you more control when you can’t rely on the page to expose a stable contract. Also avoid if your agent needs to run in environments where spinning up a full browser is cost-prohibitive (serverless functions with tight memory limits, edge workers).

The tool discovery overhead (checking for modelContext, fetching schemas, validating arguments) adds 200-500ms latency to every session. This matters less when the page’s internal logic is complex and would require 5+ selector-based interactions to achieve the same result. It matters more when you’re automating simple, stable pages where a single CSS selector would suffice.

WebMCP shifts the automation boundary from the agent to the page. This reduces coupling between agent scripts and page structure, but it requires the page author to maintain a tool manifest. If you own both the page and the agent, this is a clean contract. If you’re automating someone else’s page, you’re back to traditional scraping.

The lack of sandboxing and trust primitives means you must validate page origins and tool schemas yourself. Treat WebMCP tools like external API calls: validate, timeout, and log everything. Budget for browser pool costs and observability infrastructure before deploying to production.

Tags

agentic-ai orchestration infrastructure

Primary Source

dev.to