# MCP server

> For the complete documentation index, see [llms.txt](https://preview.writedocs.io/llms.txt).

An MCP server at /mcp, so AI tools like Claude and Cursor can search and read your docs.

Every writedocs site can run an [MCP](https://modelcontextprotocol.io) server at `/mcp`. An AI tool connected to it searches and reads your docs directly, always the published version, instead of relying on what it remembers.

It's on by default. The built site includes everything it needs, and `writedocs dev` serves it at `http://localhost:4321/mcp` while you write.

## What an AI tool gets

Three tools, answered from your pages:

- **`list_docs`** — every page, with its title, URL and description.
- **`search_docs`** — the best-matching pages for a query, optionally only one docs version or language (taken from your navigation's `versions` and `languages`).
- **`get_doc`** — a page's full content as Markdown. It accepts the page's path or URL, as the tool or a reader would write it.

Pages read the way they show on the site: imported snippets included, [`variables`](https://preview.writedocs.io/docs/content/variables/) filled in, code examples exactly as written. Pages with `seo.noindex` are left out, as they are from `llms.txt`.

## Connecting

Point the client at your site's `/mcp` address:

```json title=".claude/settings.json (Claude Code)"
{
  "mcpServers": {
    "acme-docs": { "url": "https://docs.example.com/mcp" }
  }
}
```

In Cursor: **Settings → MCP → Add server**, and paste the URL. Opening `/mcp` in a browser shows a short description of the server.

Readers don't need to find the URL themselves: every page's [contextual menu](https://preview.writedocs.io/docs/configuration/context-menu/) has **Copy MCP server URL**, **Connect to Cursor** and **Connect to VS Code** - the last two add the server to the editor in one click.

## Deploying

The built site (`dist/`) includes these files:

| File | What it's for |
| --- | --- |
| `mcp-index.json` | Your pages, as the server reads them |
| `_worker.js` | The server, ready to run on Cloudflare |
| `_routes.json` | Cloudflare Pages: only `/mcp` runs the server; every other path stays a static file |
| `.assetsignore` | Cloudflare Workers: keeps `_worker.js` and `_routes.json` from being published as files |

**Cloudflare Pages** — deploy `dist/` as usual. Pages picks up `_worker.js` on its own, and `/mcp` works.

**Cloudflare Workers** (static assets) — use `dist/_worker.js` as the Worker and `dist/` as its assets:

```jsonc title="wrangler.jsonc"
{
  "name": "my-docs",
  "main": "dist/_worker.js",
  "compatibility_date": "2026-09-01",
  "assets": { "directory": "dist", "binding": "ASSETS" }
}
```

**Other hosts that run code** (Netlify, Vercel, your own server) — the same server is part of the package. Serve `dist/` as usual and route `/mcp` to it:

```js
import { handleMcpHttp } from '@writedocs/generator/mcp';

// Any runtime with Web-standard Request/Response - a Netlify or Vercel function, a Worker, Node 18+.
export default async function mcp(request) {
  return handleMcpHttp(request, {
    loadIndex: async () => (await fetch(new URL('/mcp-index.json', request.url))).json(),
  });
}
```

**Static-only hosts** (GitHub Pages, S3) can't run a server, so `/mcp` isn't available there. `llms.txt` and `llms-full.txt` still are.

> A project that already has its own `_worker.js` or `_routes.json` in `public/`, or a Cloudflare Pages `functions/` folder, keeps them: the build doesn't add `_worker.js` (Pages ignores `functions/` once one exists), and says so. Add `/mcp` to your own worker with `@writedocs/generator/mcp`.

## Turning it off

```json title="writedocs.json"
{
  "mcp": false
}
```

The build then leaves out `mcp-index.json`, `_worker.js`, `_routes.json` and `.assetsignore`.