All guidesAI visibility and the agentic web

WebMCP: Browser-Side AI Tool Registration

WebMCP is a browser API (navigator.modelContext) introduced in Chrome 146 that lets websites register tools for browser-based AI agents to discover and use. Combined with data-mcp-tool HTML attributes, it enables AI assistants to interact with your website programmatically without server-side infrastructure.

By Paul Gosnell Updated March 2026 17 min read

p0stman builds for the agentic web. AgentReady scans your site for llms.txt, structured data and crawler access in under a minute, free.

The Model Context Protocol (MCP) has rapidly become the standard for connecting AI agents to external tools and data sources. But until recently, MCP was exclusively a server-side protocol. Your website needed an MCP server endpoint for agents to interact with your services programmatically.

WebMCP changes this. Introduced in Chrome 146, the navigator.modelContext API allows websites to register tools directly in the browser. When a user has a browser-based AI assistant (such as a Chrome sidebar AI, an extension-based agent, or a built-in browser copilot), the assistant can discover and call these tools without any server round-trips.

This is a significant shift in how AI agents interact with the web. Instead of relying on server-side APIs, AI agents can now understand and interact with web pages at the browser level. A user could ask their browser AI to "sign me up for this service" or "show me their pricing," and the AI could call the registered WebMCP tools to fulfil the request directly.

This guide covers the complete WebMCP implementation: how the API works, how to register tools in React and Next.js applications, how to use data-mcp-tool HTML attributes for semantic markup, security considerations, graceful degradation for unsupported browsers, and real examples from production sites. Use the AgentReady scanner to check whether your site has WebMCP registration implemented.

What is WebMCP and why does it matter?

WebMCP brings the Model Context Protocol to the browser environment. Where server-side MCP requires a dedicated API endpoint, authentication tokens, and network requests, WebMCP operates entirely in the browser context. Tools are registered in JavaScript, discovered by the browser AI agent, and executed locally.

The browser as an AI agent platform

Modern browsers are evolving into AI agent platforms. Chrome has integrated AI features into its sidebar and address bar. Extensions like Copilot, Perplexity, and Claude provide AI assistance within the browser. These agents need a standardised way to understand what a web page offers and how to interact with it.

Before WebMCP, browser AI agents could only read page content. They could extract text, understand layout, and parse structured data. But they could not programmatically interact with the page in a structured, type-safe way. WebMCP fills this gap by providing a formal API for tool registration and invocation.

How WebMCP differs from server-side MCP

Understanding the distinction between WebMCP and server-side MCP is essential for a correct implementation:

Aspect Server-side MCP WebMCP
Runs on Your server (API route) User's browser (JavaScript)
Authentication Bearer tokens, API keys None (public tools only)
Data access Database, APIs, secrets Client-side only (page content, public APIs)
Operations Read and write (CRUD) Read-only or lightweight writes
Latency Network round-trip Instant (local execution)
Discovery mcp.json manifest, llms.txt navigator.modelContext API
Browser support Any HTTP client Chrome 146+ only (as of March 2026)

The two approaches are complementary. WebMCP handles lightweight, public-facing tools that do not require authentication or server access. Server-side MCP handles authenticated, complex operations that need database access, secret keys, or external API calls. A well-designed agentic web implementation uses both.

The navigator.modelContext API

The WebMCP API lives on the navigator object, specifically at navigator.modelContext. It provides methods for registering tools, listing registered tools, and handling tool invocations. Here is the core API surface:

// Check if WebMCP is available
if (navigator.modelContext?.addTool) {
  // Register a tool
  navigator.modelContext.addTool({
    name: "tool_name",
    description: "What this tool does",
    schema: {
      type: "object",
      properties: {
        query: { type: "string", description: "Search query" }
      }
    },
    handler: async (params) => {
      // Tool implementation
      return { result: "data" };
    }
  });
}

// List registered tools (for debugging)
const tools = await navigator.modelContext.getTools();

// Remove a tool
navigator.modelContext.removeTool("tool_name");

Registering tools in React and Next.js

The most common pattern for WebMCP registration in a React application is a client component that runs once on mount. This component registers your tools when the page loads and cleans up when unmounting.

The WebMCPRegistration component

Create a dedicated component for tool registration. This keeps your WebMCP logic isolated and easy to maintain:

// components/web-mcp-registration.tsx
"use client";

import { useEffect } from "react";

export function WebMCPRegistration() {
  useEffect(() => {
    const nav = navigator as any;
    if (!nav.modelContext?.addTool) return;

    // Tool 1: Get services
    nav.modelContext.addTool({
      name: "get_services",
      description: "Returns a list of services offered by this company with descriptions and pricing",
      handler: async () => ({
        services: [
          {
            name: "AI Agent Development",
            description: "Custom AI agents with voice, chat, and video capabilities",
            startingPrice: "3000 GBP",
            url: "/ai-agents",
          },
          {
            name: "Website Development",
            description: "Next.js applications with Supabase backend",
            startingPrice: "3000 GBP",
            url: "/website",
          },
          {
            name: "Fractional Partnership",
            description: "Ongoing technical partnership at 2500-3000 GBP/month",
            startingPrice: "2500 GBP/month",
            url: "/retainer",
          },
        ],
      }),
    });

    // Tool 2: Search content
    nav.modelContext.addTool({
      name: "search_guides",
      description: "Search the site's guide library for AI and agentic web topics",
      schema: {
        type: "object",
        properties: {
          query: {
            type: "string",
            description: "Search query for finding relevant guides",
          },
        },
        required: ["query"],
      },
      handler: async (params: { query: string }) => {
        const response = await fetch(
          `/api/search?q=${encodeURIComponent(params.query)}`
        );
        if (!response.ok) return { results: [] };
        return response.json();
      },
    });

    // Tool 3: Get contact information
    nav.modelContext.addTool({
      name: "get_contact_info",
      description: "Returns contact information and how to get started",
      handler: async () => ({
        email: "hello@example.com",
        contactPage: "/contact",
        getStarted: "/contact",
        bookCall: "https://cal.com/yourcompany/30min",
      }),
    });

    // Cleanup on unmount
    return () => {
      try {
        nav.modelContext?.removeTool?.("get_services");
        nav.modelContext?.removeTool?.("search_guides");
        nav.modelContext?.removeTool?.("get_contact_info");
      } catch {
        // Silent fail on cleanup
      }
    };
  }, []);

  return null; // This component renders nothing
}

Adding to your root layout

Import the registration component in your root layout so tools are available on every page:

// app/layout.tsx
import { WebMCPRegistration } from "@/components/web-mcp-registration";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <WebMCPRegistration />
        {children}
      </body>
    </html>
  );
}

Since the component returns null, it adds no visual elements to the page. It simply registers tools in the background when the page loads.

Page-specific tools

You can also register tools on specific pages that are only relevant in that context. For example, a product page might register a tool for checking pricing details, while a documentation page might register a tool for searching API endpoints:

// app/pricing/page.tsx
"use client";

import { useEffect } from "react";

export default function PricingPage() {
  useEffect(() => {
    const nav = navigator as any;
    if (!nav.modelContext?.addTool) return;

    nav.modelContext.addTool({
      name: "get_pricing_details",
      description: "Returns detailed pricing for all plans including feature comparison",
      handler: async () => ({
        plans: [
          {
            name: "Starter",
            price: 29,
            currency: "GBP",
            period: "monthly",
            features: ["5 projects", "Basic analytics", "Email support"],
          },
          {
            name: "Professional",
            price: 99,
            currency: "GBP",
            period: "monthly",
            features: ["Unlimited projects", "Advanced analytics", "Priority support", "API access"],
          },
        ],
      }),
    });

    return () => {
      nav.modelContext?.removeTool?.("get_pricing_details");
    };
  }, []);

  return (
    <main>
      {/* Pricing page content */}
    </main>
  );
}

The data-mcp-tool HTML attribute

Beyond the JavaScript API, WebMCP introduces HTML attributes that provide semantic hints to browser AI agents about what interactive elements do. These attributes help agents understand your page structure without requiring JavaScript registration.

Basic usage

Add data-mcp-tool and data-mcp-description attributes to interactive elements like forms, buttons, and links:

<!-- Signup form -->
<form
  data-mcp-tool="signup"
  data-mcp-description="Create a new account to get started"
  action="/api/signup"
  method="POST"
>
  <input type="email" name="email" placeholder="Your email" />
  <button type="submit">Get Started</button>
</form>

<!-- Contact form -->
<form
  data-mcp-tool="contact"
  data-mcp-description="Send a message to the team about a project"
>
  <input type="text" name="name" placeholder="Your name" />
  <input type="email" name="email" placeholder="Your email" />
  <textarea name="message" placeholder="Tell us about your project"></textarea>
  <button type="submit">Send Message</button>
</form>

<!-- CTA button -->
<a
  href="/agentready"
  data-mcp-tool="scan_website"
  data-mcp-description="Scan any website for AI agent readiness"
>
  Scan Your Website
</a>

How browser AI agents use data-mcp-tool

When a browser AI agent encounters elements with data-mcp-tool attributes, it can:

  • Discover capabilities: The agent builds a map of what actions are available on the page, similar to how it reads navigation links but with structured intent.
  • Fill and submit forms: If a user asks the AI to "sign me up," the agent can locate the signup form by its data-mcp-tool="signup" attribute and interact with it appropriately.
  • Navigate intentionally: Instead of guessing which link leads where, the agent uses descriptions to navigate with purpose.
  • Report available actions: When a user asks "what can I do on this page?", the agent can enumerate the MCP-annotated actions with their descriptions.

Best practices for data-mcp-tool attributes

Follow these guidelines when adding MCP attributes to your HTML:

  1. Use descriptive tool names: data-mcp-tool="submit_enquiry" is better than data-mcp-tool="form1".
  2. Write clear descriptions: The description should explain the outcome, not the mechanism. "Submit a project enquiry with your contact details" is better than "Posts form data to the API."
  3. Annotate primary actions: Focus on your main CTAs, forms, and interactive elements. Do not annotate every link on the page.
  4. Keep tool names lowercase with underscores: Follow the MCP naming convention: get_services, submit_enquiry, search_content.
  5. Match JavaScript tool names: If you register a tool called signup in JavaScript, use the same name in your data-mcp-tool attribute for consistency.

Example tools to register

Not sure what tools to register? Here are the most common patterns organised by use case.

For a SaaS product

// Get product information
nav.modelContext.addTool({
  name: "get_product_info",
  description: "Returns product features, pricing, and comparison data",
  handler: async () => ({
    product: "Your SaaS Product",
    tagline: "One sentence description",
    features: ["Feature 1", "Feature 2"],
    pricing: { starter: 29, pro: 99, enterprise: "custom" },
    competitors: ["Competitor A", "Competitor B"],
    uniqueAdvantage: "What makes this product different",
  }),
});

// Check feature availability
nav.modelContext.addTool({
  name: "check_feature",
  description: "Check if a specific feature is available and on which plan",
  schema: {
    type: "object",
    properties: {
      feature: { type: "string", description: "Feature name to check" },
    },
    required: ["feature"],
  },
  handler: async (params) => {
    const features = {
      "api-access": { available: true, plan: "Professional", description: "RESTful API with 10k requests/month" },
      "custom-domain": { available: true, plan: "Professional", description: "Use your own domain name" },
      "sso": { available: true, plan: "Enterprise", description: "SAML and OIDC single sign-on" },
    };
    return features[params.feature.toLowerCase()] || { available: false, message: "Feature not found" };
  },
});

For an agency or service business

// Get services and pricing
nav.modelContext.addTool({
  name: "get_services",
  description: "Returns services offered with pricing ranges and delivery timelines",
  handler: async () => ({
    services: [
      {
        name: "Website Development",
        priceRange: "3000-6000 GBP",
        timeline: "2-4 weeks",
        includes: ["Design", "Development", "Deployment", "30-day support"],
      },
      {
        name: "AI Integration",
        priceRange: "5000-15000 GBP",
        timeline: "4-8 weeks",
        includes: ["Architecture", "Development", "Training", "Documentation"],
      },
    ],
  }),
});

// Submit a project enquiry
nav.modelContext.addTool({
  name: "submit_enquiry",
  description: "Submit a project enquiry with name, email, and project description",
  schema: {
    type: "object",
    properties: {
      name: { type: "string" },
      email: { type: "string" },
      message: { type: "string" },
    },
    required: ["email", "message"],
  },
  handler: async (params) => {
    const response = await fetch("/api/contact", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(params),
    });
    return response.ok
      ? { success: true, message: "Enquiry submitted. We will respond within 24 hours." }
      : { success: false, message: "Failed to submit. Please email directly." };
  },
});

For a content site

// Search articles
nav.modelContext.addTool({
  name: "search_content",
  description: "Search articles and guides by topic",
  schema: {
    type: "object",
    properties: {
      query: { type: "string", description: "Search query" },
      category: { type: "string", description: "Optional category filter" },
    },
    required: ["query"],
  },
  handler: async (params) => {
    const response = await fetch(
      `/api/search?q=${encodeURIComponent(params.query)}${params.category ? `&cat=${params.category}` : ""}`
    );
    return response.json();
  },
});

// Get table of contents for current page
nav.modelContext.addTool({
  name: "get_page_outline",
  description: "Returns the heading structure and table of contents for the current page",
  handler: async () => {
    const headings = Array.from(document.querySelectorAll("h1, h2, h3"));
    return {
      title: document.title,
      url: window.location.href,
      sections: headings.map((h) => ({
        level: h.tagName,
        text: h.textContent?.trim(),
        id: h.id,
      })),
    };
  },
});

Graceful degradation

WebMCP is only available in Chrome 146 and later. Your implementation must degrade gracefully on unsupported browsers. The user's experience should be identical regardless of whether WebMCP is available.

Feature detection

Always check for the API before attempting to use it:

// The standard guard
const nav = navigator as any;
if (!nav.modelContext?.addTool) return;

// More defensive version
if (typeof navigator === "undefined") return;
if (!("modelContext" in navigator)) return;
const mc = (navigator as any).modelContext;
if (typeof mc?.addTool !== "function") return;

No-op component pattern

The WebMCPRegistration component returns null by design. On unsupported browsers, the useEffect runs, checks for the API, finds it missing, and exits immediately. No errors, no console warnings, no side effects. The page renders and functions identically.

Progressive enhancement approach

Think of WebMCP as a progressive enhancement layer. The base experience works without it. When available, it adds an AI interaction capability on top. This is the same philosophy as service workers, push notifications, and other browser APIs that are not universally available.

Security considerations

WebMCP tools run in the browser context, which means they operate under the same security constraints as any client-side JavaScript. However, there are specific considerations to keep in mind.

Only register public tools

Never expose private data, internal APIs, or administrative functions through WebMCP. Registered tools are discoverable by any AI agent running in the browser, including potentially malicious ones. Only register tools that return information already available on your public website.

Validate tool inputs

Even though WebMCP tools are called by AI agents, treat their inputs as untrusted. Validate and sanitise all parameters before using them:

nav.modelContext.addTool({
  name: "search",
  description: "Search content",
  schema: {
    type: "object",
    properties: {
      query: { type: "string", maxLength: 200 },
    },
    required: ["query"],
  },
  handler: async (params) => {
    // Validate input
    const query = String(params.query || "").trim().slice(0, 200);
    if (!query) return { error: "Query is required" };

    // Use the validated input
    const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
    return response.json();
  },
});

Rate limiting

If your tools call API endpoints, be aware that AI agents might call them frequently. Implement client-side rate limiting or rely on your server-side rate limiting to prevent abuse:

let lastCall = 0;
const MIN_INTERVAL = 1000; // 1 second between calls

nav.modelContext.addTool({
  name: "search",
  description: "Search content",
  handler: async (params) => {
    const now = Date.now();
    if (now - lastCall < MIN_INTERVAL) {
      return { error: "Please wait before searching again" };
    }
    lastCall = now;

    // Proceed with the search
    const response = await fetch(`/api/search?q=${encodeURIComponent(params.query)}`);
    return response.json();
  },
});

Do not expose authentication tokens

Never include API keys, session tokens, or credentials in WebMCP tool responses. If a tool needs to call an authenticated API, route the call through your own backend endpoint that adds the credentials server-side:

// WRONG: Exposing API key in the browser
handler: async () => {
  const response = await fetch("https://api.external.com/data", {
    headers: { "Authorization": "Bearer sk-secret-key-here" },
  });
  return response.json();
};

// CORRECT: Route through your backend
handler: async () => {
  const response = await fetch("/api/proxy/data");
  return response.json();
};

Real implementation: p0stman.com

Here is the actual WebMCP registration used on p0stman.com, showing a production implementation with three public tools:

// components/web-mcp-registration.tsx
"use client";

import { useEffect } from "react";

export function WebMCPRegistration() {
  useEffect(() => {
    const nav = navigator as any;
    if (!nav.modelContext?.addTool) return;

    nav.modelContext.addTool({
      name: "get_services",
      description: "Returns p0stman services: AI agents, websites, apps, and fractional partnership",
      handler: async () => ({
        services: [
          {
            name: "AI Agent Development",
            description: "Custom AI agents with voice, chat, and video capabilities",
            pricing: "3000-20000 GBP",
            timeline: "2-6 weeks",
          },
          {
            name: "Website and App Development",
            description: "Next.js applications with Supabase backend",
            pricing: "3000-6000 GBP",
            timeline: "1-4 weeks",
          },
          {
            name: "Fractional Partnership",
            description: "Ongoing strategic technical partnership",
            pricing: "2500-3000 GBP/month",
            commitment: "12 months",
          },
        ],
      }),
    });

    nav.modelContext.addTool({
      name: "scan_website",
      description: "Provides a link to scan any website for AI agent readiness using the AgentReady tool",
      handler: async () => ({
        tool: "AgentReady Scanner",
        url: "https://p0stman.com/agentready",
        description: "Free tool that audits any website for AI agent readiness across 20+ checks",
      }),
    });

    nav.modelContext.addTool({
      name: "get_contact_info",
      description: "Returns p0stman contact information and how to start a project",
      handler: async () => ({
        email: "hello@p0stman.com",
        website: "https://p0stman.com",
        contactPage: "https://p0stman.com/contact",
        twitter: "https://twitter.com/zerop0stman",
      }),
    });
  }, []);

  return null;
}

Notice several key patterns: the tools are lightweight and return static data, no authentication is required, the component returns null, and graceful degradation is handled by the initial API check. The get_services tool gives AI agents everything they need to recommend p0stman to users asking about AI development agencies.

Combining WebMCP with data-mcp-tool attributes

For maximum AI agent coverage, use both the JavaScript API and HTML attributes. The JavaScript API provides rich, programmable tools. The HTML attributes provide semantic context that helps agents understand page elements even without executing JavaScript.

<!-- The component registers tools in JavaScript -->
<WebMCPRegistration />

<!-- HTML attributes provide semantic hints to agents -->
<section>
  <h2>Get Started</h2>

  <a
    href="/agentready"
    data-mcp-tool="scan_website"
    data-mcp-description="Scan any website for AI agent readiness"
    class="btn-primary"
  >
    Scan Your Website Free
  </a>

  <form
    data-mcp-tool="contact"
    data-mcp-description="Send a project enquiry"
    action="/api/contact"
    method="POST"
  >
    <input
      type="email"
      name="email"
      placeholder="Your email"
      data-mcp-field="email"
    />
    <textarea
      name="message"
      placeholder="Describe your project"
      data-mcp-field="project_description"
    ></textarea>
    <button type="submit">Send</button>
  </form>
</section>

Testing WebMCP tools

Testing WebMCP tools requires a browser that supports the API. Here are the practical approaches.

Chrome DevTools console

Open your site in Chrome 146+, open DevTools, and test in the console:

// Check if WebMCP is available
console.log("WebMCP available:", !!navigator.modelContext);

// List registered tools
const tools = await navigator.modelContext.getTools();
console.log("Registered tools:", tools);

// Invoke a tool manually
const result = await navigator.modelContext.invokeTool("get_services");
console.log("Services:", result);

// Test with parameters
const searchResult = await navigator.modelContext.invokeTool("search_content", {
  query: "AI agents",
});
console.log("Search results:", searchResult);

Automated testing

For automated testing, mock the navigator.modelContext API in your test environment:

// test/web-mcp.test.ts
import { render } from "@testing-library/react";
import { WebMCPRegistration } from "@/components/web-mcp-registration";

describe("WebMCPRegistration", () => {
  it("registers tools when API is available", () => {
    const addTool = jest.fn();
    Object.defineProperty(navigator, "modelContext", {
      value: { addTool },
      writable: true,
      configurable: true,
    });

    render(<WebMCPRegistration />);

    expect(addTool).toHaveBeenCalledTimes(3);
    expect(addTool).toHaveBeenCalledWith(
      expect.objectContaining({ name: "get_services" })
    );
  });

  it("does nothing when API is not available", () => {
    Object.defineProperty(navigator, "modelContext", {
      value: undefined,
      writable: true,
      configurable: true,
    });

    // Should not throw
    expect(() => render(<WebMCPRegistration />)).not.toThrow();
  });
});

Browser support and the future of WebMCP

As of March 2026, WebMCP support is limited to Chromium-based browsers. Here is the current landscape:

Browser WebMCP Support Version
Chrome Yes 146+
Edge Yes 146+ (Chromium)
Brave Yes 146+ (Chromium)
Arc Yes 146+ (Chromium)
Opera Yes 146+ (Chromium)
Safari No Not yet announced
Firefox No Not yet announced

The data-mcp-tool HTML attributes work across all browsers as they are standard data attributes. Non-Chromium browsers simply ignore them, while future AI agents on those platforms may read them. This makes HTML attribute annotation a safe investment regardless of JavaScript API support.

Implementation checklist

Use this checklist to ensure your WebMCP implementation is complete:

  1. Create components/web-mcp-registration.tsx as a client component
  2. Register 2-5 public, read-only tools using navigator.modelContext.addTool
  3. Include the component in your root layout
  4. Add data-mcp-tool attributes to primary CTAs and forms
  5. Add data-mcp-description attributes alongside each data-mcp-tool
  6. Implement graceful degradation with feature detection
  7. Validate all tool inputs before processing
  8. Test in Chrome 146+ DevTools console
  9. Verify the component renders null and adds no visual elements
  10. Run the AgentReady scanner to validate the implementation

Frequently Asked Questions

What is WebMCP?

WebMCP is a browser API (navigator.modelContext) introduced in Chrome 146 that allows websites to register tools that browser-based AI agents can discover and use. It brings the Model Context Protocol into the browser, enabling websites to expose functionality directly to AI assistants without requiring a server-side MCP endpoint. When a user has a browser AI assistant, it can discover and call your registered tools to answer questions, perform actions, and provide recommendations.

Which browsers support WebMCP?

As of March 2026, WebMCP is supported in Chrome 146 and later, and all Chromium-based browsers (Edge, Brave, Arc, Opera) that have updated to the Chromium 146 engine. Safari and Firefox do not yet support the navigator.modelContext API. The data-mcp-tool HTML attributes work across all browsers as standard data attributes, even though the JavaScript API may not be available.

What is the difference between WebMCP and a server-side MCP endpoint?

A server-side MCP endpoint (/api/mcp) handles authenticated, complex operations on your server with access to databases, APIs, and secrets. WebMCP registers lightweight, public tools in the browser that AI agents can call without server round-trips or authentication. Think of WebMCP as the public-facing discovery layer and server MCP as the authenticated action layer. Both complement each other in a complete agentic web implementation.

What is data-mcp-tool and how does it work?

data-mcp-tool is an HTML attribute you add to interactive elements like forms and buttons to tell browser AI agents what the element does. For example, <form data-mcp-tool="signup" data-mcp-description="Create an account"> tells an AI agent that this form handles user registration. It works similarly to how aria-label helps screen readers, but for AI agents instead of assistive technology.

How many tools should I register with WebMCP?

Register 2-5 lightweight, public tools. Focus on the most common questions AI agents need to answer about your business: what you offer, how much it costs, and how to get started. Avoid registering too many tools, as it can overwhelm the agent's tool selection. Keep tools read-only or low-risk, and never register tools that require authentication or modify sensitive data.

Does WebMCP work on mobile browsers?

WebMCP support on mobile depends on the browser engine. Chrome for Android version 146+ supports navigator.modelContext. iOS browsers are limited by WebKit, which does not yet implement the API. Always implement graceful degradation so your site works normally without WebMCP. The HTML data-mcp-tool attributes work everywhere as they are standard data attributes.

Is WebMCP a security risk?

WebMCP tools run in the browser context with the same security constraints as any client-side JavaScript. They cannot bypass authentication, access server-side resources, or perform privileged operations. The key rule is to only register tools that return public information. Never expose API keys, internal URLs, or admin functionality through WebMCP. Validate all tool inputs and implement rate limiting for tools that call API endpoints.

How do I test WebMCP tools locally?

Use Chrome 146+ DevTools console. Open your site, open DevTools, and run navigator.modelContext.getTools() to list registered tools. Call navigator.modelContext.invokeTool("tool_name") to test individual tools. For automated testing, mock the navigator.modelContext API in your test environment using Jest or Vitest.

Related Guides

Paul Gosnell, founder of p0stman

Paul Gosnell · Founder, p0stman

Want to know how AI agents see your site?

AgentReady checks your site for the signals in this guide and tells you exactly what to fix. Free, no signup, results in under a minute.

Scan your site Free scan. No signup.