---
title: WebMCP
description: Expose documentation search, page reading, and Ask AI to browser agents.
---

Geistdocs uses [mcp-handler's WebMCP bridge](https://github.com/vercel/mcp-handler/blob/main/docs/WEBMCP.md) for search, and browser-local tools for reading the current page and, optionally, asking the site's Ask AI chat. Enable `webmcp: { enabled: true }` in `lib/geistdocs/config.tsx` and add `app/api/mcp/route.ts`:

```ts
import { createMcpRoute } from "@vercel/geistdocs/routes/mcp";
import { config } from "@/lib/geistdocs/config";
import { GET as search } from "../search/route";

const handler = createMcpRoute({ config, search });

export { handler as GET, handler as POST };
```

The canonical template includes this setup. Existing consumers must add the route themselves: `geistdocs update` does not overwrite local adapters. There is no fallback to the old browser search transport.

## Tools

| Tool | Input | Result |
| --- | --- | --- |
| `search_docs` | Nonblank `query` up to 500 characters; optional configured `locale` | MCP result containing search results as JSON text |
| `read_current_page` | None | Current page as Markdown |
| `ask_ai` | `question` of 2 to 2,000 characters after trimming whitespace | Confirmation that the question was submitted to the site's Ask AI chat |

The provider loads `/api/mcp?webmcp-script` once through `next/script`. The script discovers the MCP server's tools and registers only `search_docs`. Do not add another copy of the script or register search yourself. Remote MCP clients connect to `/api/mcp` directly. Geistdocs prefixes public paths with `basePath`.

Search calls the supplied search handler directly, retaining its visibility filters and request headers/cookies without another network hop. Pass `locale` explicitly for translated results; omitting it selects `defaultLanguage`, even after navigating to another language. `search_docs` and `read_current_page` don't modify documentation or send it to an external model.

## Let browser agents ask Ask AI

`ask_ai` is opt-in. Set `webmcp.askAI` to `true` to register it when Ask AI is enabled:

```tsx title="lib/geistdocs/config.tsx"
webmcp: { enabled: true, askAI: true },
```

`ask_ai` opens the site's Ask AI chat and submits the question as a user message, the same way the `ask` action from [`useGeistdocsChat`](/docs/ask-ai#control-ask-ai-from-your-own-components) does. The tool returns as soon as the question is queued and doesn't return the answer, which streams into the chat panel on the page. Questions sent while a response is streaming wait for it to finish. The tool rejects a missing `question`, or one shorter than 2 or longer than 2,000 characters after trimming whitespace, without opening the chat.

`ask_ai` isn't registered when `webmcp.askAI` is unset, when `ai.enabled` is `false`, or when `webmcp.enabled` is `false`. Unlike the read-only tools, `ask_ai` sets `readOnlyHint: false` because it changes the page and sends the question to your Ask AI model or agent, which counts toward your usage. Like `read_current_page`, it runs in the browser and isn't part of the `/api/mcp` server, so remote MCP clients and the `?webmcp-script` bridge don't list it.

## Lifecycle and safety

Search follows the upstream bridge contract: MCP result envelopes are returned unchanged, including `isError`; browser-provided cancellation reaches fetch, but there is no additional request deadline. The bridge preserves `readOnlyHint` but does not emit WebMCP's explicit `untrustedContentHint`. Search results are still untrusted documentation, not agent instructions.

Search registration lasts for the document and is not tied to React unmounts. Reload after changing feature configuration. With `webmcp.enabled` disabled, the endpoint returns 404 and new documents do not load the bridge. Unsupported browsers continue to work normally.

`read_current_page` remains browser-local: it reads the live URL without its query or fragment, requires a Markdown response, and retains its 15-second timeout, cancellation, untrusted-content hint and registration cleanup.

For protected documentation, authorize the MCP route and supplied search handler. Direct handler reuse does not execute middleware scoped only to `/api/search`. Cross-origin cookie requests are rejected; protocol responses use `Cache-Control: no-store`. Tool allowlists and read-only annotations are not authorization. Never put tokens in client config.

Behind a trusted reverse proxy, the MCP route resolves its public URL using `X-Forwarded-Host`/`X-Forwarded-Proto` or `Forwarded`. The generated bridge and cookie-origin checks use that public origin instead of Next.js's internal listener. Configure the proxy to overwrite untrusted incoming forwarding headers. Requests without forwarding headers retain their original URL.

The remote discovery manifest remains independent; configured external servers are not replaced.

## Verify locally

Use a compatible browser with WebMCP enabled. With agent-browser 0.36.0 or newer:

```bash
agent-browser --session docs-check open http://localhost:3000/docs
agent-browser --session docs-check webmcp list
agent-browser --session docs-check webmcp invoke search_docs --params '{"query":"configuration","locale":"en"}'
agent-browser --session docs-check webmcp invoke read_current_page --params '{}'
# Requires webmcp.askAI: true
agent-browser --session docs-check webmcp invoke ask_ai --params '{"question":"How do I configure search?"}'
agent-browser --session docs-check close
```

Check the invocation's `status` and the search result's `isError`, not just command delivery. Navigate to another page and confirm reading follows the new URL; switch language and search with an explicit locale. Repeat under a configured base path. Disable the feature and reload to verify registration and endpoint opt-out.
