docusaurus-plugin-mcp-server · git:20261010.97a5ca9 · 2026-10-10 · sha256 b47e924d7cd4158a

docusaurus-plugin-mcp-server git:20261010.97a5ca9A

Immutable. This exact content never changes and is served at /api/v1/blob/b47e924d7cd4158a.

---
name: "docusaurus-plugin-mcp-server"
description: "Expose a Docusaurus site's docs as an MCP server for AI agents — add the build-time plugin, deploy the MCP endpoint to any web-standard serverless/edge runtime, run it locally, serve Agent Skills over MCP, or add the install button. Load when working with docusaurus-plugin-mcp-server or its /adapters or /theme entry points."
---

# docusaurus-plugin-mcp-server

A Docusaurus plugin that, at `docusaurus build`, writes an artifact bundle (`build/mcp/bundle.json`: documents, search index, skills, manifest; 2.x also writes each as its own file), plus runtime handlers that serve them as an MCP endpoint (`docs_search` + `docs_fetch` tools, and Agent Skills via the `io.modelcontextprotocol/skills` extension) to AI agents. The endpoint speaks MCP 2026-07-28 and still serves 2025-era (`initialize`) clients.

## When to use

Load this skill when the task involves:

- Adding/configuring the plugin in `docusaurus.config.js`.
- Standing up the MCP HTTP endpoint — deploying to a serverless/edge runtime (Cloudflare Workers, modern Netlify functions, Vercel Edge, Deno, Bun) or running it locally on Node.
- Adding the `McpInstallButton` to a docs site.
- Marking page content for agents only or people only (`ForAgents`/`ForHumans`).
- Writing setup or troubleshooting pages that compile into agent guides (`AgentGuide`, `Step`, `Check`, `Symptom`).
- Writing a custom indexer or search provider.
- Shipping Agent Skills with the docs (the `skills` plugin option, `skills.json`).

Trigger imports: `docusaurus-plugin-mcp-server`, `docusaurus-plugin-mcp-server/adapters`, `docusaurus-plugin-mcp-server/adapters/node`, `docusaurus-plugin-mcp-server/theme`.

## Install & import

```bash
npm install docusaurus-plugin-mcp-server
```

ESM-only. Four entry points:

- `docusaurus-plugin-mcp-server` — the plugin (default export) + `McpDocsServer`, provider types, `DEFAULT_PLUGIN_OPTIONS`.
- `docusaurus-plugin-mcp-server/adapters` — the web-standard deploy handler `createWebRequestHandler`.
- `docusaurus-plugin-mcp-server/adapters/node` — `createNodeServer`/`createNodeHandler` for local dev (Node `http`), and `readArtifactBundle(dir)`.
- `docusaurus-plugin-mcp-server/theme` — `McpInstallButton`, `ForAgents`, `ForHumans`, the agent guide components (`AgentGuide`, `DoneWhen`, `Prerequisites`, `Step`, `Check`, `Symptom`), and `mdxComponents`. MDX pages don't need to import them.

Peers: `zod` (>= 4.2) is required. `@docusaurus/core` (and `react`/`react-dom` for the theme button) are optional peer deps; provide them from your Docusaurus app.

## Authoritative API

The authoritative API is the published TypeScript types. Read the `.d.ts` files referenced by `exports` in `package.json` before writing calls — do not guess signatures. `dist/` is a build artifact (git-ignored), so in a fresh clone run `npm run build` first, or read the corresponding `src/*.ts`:

- `.` → `dist/index.d.ts` (plugin options, `McpDocsServer`, provider/`ProcessedDoc` types)
- `./adapters` → `dist/adapters-entry.d.ts` (`WebRequestHandlerConfig`, `ArtifactBundle`)
- `./adapters/node` → `dist/adapters-node.d.ts` (`createNodeServer`/`createNodeHandler`, `NodeAdapterOptions`, `McpServerBundleDirConfig`, `readArtifactBundle`)
- `./theme` → `dist/theme/index.d.ts` (`McpInstallButton` props)

Config shape in particular (`artifacts`/`artifactsDir`, overrides such as `instructions`/`tools`) lives in those types — read them rather than copying field lists. `McpServerFileConfig` (`docsPath`/`indexPath`) and `McpServerDataConfig` (`docs`/`searchIndexData`) are deprecated since 2.2, as are the 2.1 unions `McpServerConfig`, `WebRequestAdapterConfig`, and `NodeServerOptions` (use `McpDocsServerConfig`, `WebRequestHandlerConfig`, `NodeAdapterOptions`); don't write new code against them.

## Usage patterns

**1. Build step.** Add the plugin to the `plugins` array in `docusaurus.config.js` with a `server.name`. `docusaurus build` then writes `build/mcp/`.

**2. Deploy to a serverless/edge runtime.** Edge/Worker runtimes can't read the filesystem, so import `bundle.json` as a module and pass it as `artifacts` to `createWebRequestHandler`, which returns a standard `(request: Request) => Promise<Response>`. The handler is identical across runtimes — only the export wrapper and platform config differ:

```js
import { createWebRequestHandler } from 'docusaurus-plugin-mcp-server/adapters';
import bundle from './build/mcp/bundle.json' with { type: 'json' };

const handler = createWebRequestHandler({ artifacts: bundle });
```

Keep `with { type: 'json' }`: Node.js (Vercel's runtime) and Deno require it, and esbuild, Wrangler, and Bun accept it. `name`, `version`, and `baseUrl` default to what the site was built with; pass them only to override. Skills are in the bundle, so there's nothing to wire up. Serve the endpoint at `/mcp` (what the install button advertises) or set the plugin's `server.url`.

Per-platform glue to scaffold (complete, tested setups: https://docusaurus-plugin-mcp-server.vercel.app/docs/deploy):

- **Vercel** — `api/mcp.mjs` with `export default { fetch: handler }` (Node.js runtime; no Edge config needed), plus `vercel.json` with `"cleanUrls": true` (pages 404 without it when `trailingSlash: false`) and `"rewrites": [{ "source": "/mcp", "destination": "/api/mcp" }]`. Import path `../build/mcp/bundle.json`.
- **Netlify** — `netlify/functions/mcp.mjs` with `export default (request) => handler(request)` and `export const config = { path: '/mcp' }`; `netlify.toml` with `publish = "build"` and `[functions] node_bundler = "esbuild"`. Import path `../../build/mcp/bundle.json`.
- **Cloudflare Workers** — `worker.js` routing `/mcp` to `handler` and everything else to `env.ASSETS.fetch(request)`; `wrangler.jsonc` with `assets: { directory: './build', binding: 'ASSETS', run_worker_first: ['/mcp'] }`. No `nodejs_compat` needed. Wrangler imports `.json` files as parsed JSON on its own; add no `[[rules]]` for them.
- **Deno / Bun** — `Deno.serve(...)` / `Bun.serve({ routes: { '/mcp': handler }, ... })`, serving `build/` for other paths.
- **GitHub Pages / static hosts** — can't run the handler; deploy it elsewhere from the same build and set the plugin's `server.url` to it.

Use `.mjs` for function files unless the site's `package.json` has `"type": "module"` (most Docusaurus sites don't).

**3. Run locally.** From `docusaurus-plugin-mcp-server/adapters/node`, `createNodeServer({ artifactsDir: './build/mcp' })` returns an `http.Server` you `.listen()`. Use `createNodeHandler(...)` to mount into an existing `http.createServer` or Express app (`app.all('/mcp', ...)`; it uses `req.body` if `express.json()` ran first). `McpDocsServer.handleHttpRequest` is deprecated in its favor. For `new McpDocsServer(...)` in Node, pass `artifacts: await readArtifactBundle('./build/mcp')`.

**Custom indexers and search providers.** The plugin always writes the documents. An indexer's `finalize()` may return `search-index.json` (becomes the bundle's search index; only one indexer may) and other relative ASCII filenames (indexer extras); `bundle.json`/`manifest.json`/`skills.json`, or anything that would overwrite them, fails the build. A runtime search provider is the server config's `search` option. Since 2.2 it only needs to be a `SearchRanker`: `{ name, search(query, options) }`, a plain object or a class, passed as an instance or as a module path (`search: './my-search.js'`) that default-exports one; `initialize`, `getDocument`, and `getDocCount` are optional (without the last two, `docs_fetch` and the status count use the bundle). Only `loadSearchProvider()` called directly with a module path still requires a full `SearchProvider`. With an `artifacts`/`artifactsDir` server config, `initialize` gets it all as `initData.bundle` (`docs`, `searchIndex`, `extras`); with the deprecated configs it gets the 2.1 `initData`. Don't write `isReady()` or `healthCheck()` in new providers: both are deprecated since 2.2 (reject from `initialize()` or throw from `search()` instead; the server never called `healthCheck()`), and 3.0 drops them. Existing `SearchProvider` implementations and callers still compile.

**Skills.** By default the build packages a built-in `docs-research` skill (search → fetch → cite), loaded from the package's `skills-builtin/docs-research/SKILL.md`. Its description is built from the site `title`, URL and `tagline`, and it gets a generated "Where things are" section grouping the indexed pages by URL path. For a skill that knows the product, write your own `docs-research` in the skills dir (same name replaces the built-in); if you start from a copy of the built-in, replace its `{{siteDocs}}`/`{{siteSummary}}`/`{{siteMap}}` placeholders, which only the built-in gets filled. Add site skills with the plugin option `skills: { dir: 'mcp-skills' }` (site-relative; one directory per skill, each with a `SKILL.md` whose frontmatter `name` matches the directory). `skills: { builtin: false, dir }` ships only yours; `skills: false` disables skills. The server serves them as `skill://<name>/<path>` resources, implements `skills/list`/`skills/get`, and lists the URIs in `instructions` for clients without the extension. Those clients read skill files with `docs_fetch` (it accepts `skill://` URIs whenever skills are served), since many hosts don't let the model call `resources/read`.

**`docs_fetch` URLs.** The server resolves what agents pass (trailing slash, `.md`/`.html`, `/index.html`, query strings, root-relative paths) to the document ID, never rewriting the host; `#heading-id` returns one section. A custom provider's `getDocument` is asked first with the URL as sent, then with the document ID, and the bundle answers if both miss; it only ever receives absolute URLs. The exported `docsFetchTool`/`docsFetchInputSchema` still require an absolute URL (unchanged since 2.0); only the schema the server registers is looser. Resolution lives in `src/mcp/resolve.ts`.

**MDX components.** The plugin adds `McpInstallButton`, `ForAgents`, `ForHumans`, and the agent guide components to the theme's `MDXComponents` (option `mdxComponents`, default `true`), so pages use them without an import; an explicit import from `docusaurus-plugin-mcp-server/theme` still works and a page's own import of the same name wins. A swizzled `MDXComponents` that was ejected (not wrapping `@theme-original/MDXComponents`) drops them: spread `mdxComponents` from `./theme` into it. A theme with no `MDXComponents` fails the build on `@theme-init/MDXComponents`: set `mdxComponents: false` and import in each page.

**Agent view.** `<ForAgents>` content is `hidden` on the rendered page but kept in everything agents get (`docs_fetch`, search, headings); `<ForHumans>` content is shown to people and left out for agents. Both are block-level `div`s: put them on their own lines with a blank line inside each tag so the Markdown parses. Keep headings out of `ForAgents` (Docusaurus would list them in the page TOC). Agent content is public, since it's in the HTML. The attribute contract (`data-mcp-audience`) lives in `src/agent-view/audience.ts`; extraction applies it in `src/agent-view/tree.ts`.

**Agent guides.** A setup or troubleshooting procedure written in a page and compiled at build time into a skill named after the guide (format v1: `docs/agent-guide-format.md`). Wrap it in `<AgentGuide name kind="setup"|"troubleshooting" description>` with one `<DoneWhen>`, optional `<Prerequisites>`, and `<Step id>` blocks (title from the `title` prop or the first heading, leading `1.` dropped; `needs="user"`, `confirm`, `symptoms="id id"`), each with a `<Check>`. `<Symptom id guide="name">` can live on another page, and can name several guides (`guide="a b"`) so they share it; links in compiled guides become absolute URLs; its title is the `title` prop or its first heading; **Cause:**/**Fix:**/**Escalate if:** paragraphs are read by label. The contract is the HTML (`data-mcp-*` attributes), so a site's own components can render it. The build fails with `GuideValidationError` listing every problem (missing name/kind/description/DoneWhen/ids, unknown symptom references, misplaced markup) and fails with `SkillValidationError` if a guide's name matches another skill; it warns on steps without checks and guides without symptoms, and records the warnings in the manifest for `docusaurus-mcp-verify`. Guides are served only when skills are on. Code: contract `src/guides/contract.ts`, page reading `src/guides/extract.ts`, compiler `src/guides/compile.ts` (pure).

**4. Install button.** Render `McpInstallButton` (from `./theme`); with no props it reads the URL and name from the plugin. For the navbar, register it as a custom item type by swizzle-wrapping `src/theme/NavbarItem/ComponentTypes.js` (`{ ...ComponentTypes, 'custom-mcpInstall': MyItem }`) and add `{ type: 'custom-mcpInstall', position: 'right' }` to `themeConfig.navbar.items`.

## Common mistakes

- **Filesystem paths on edge/Workers.** `artifactsDir` (and the deprecated `docsPath`/`indexPath`) only work where there's a filesystem (local Node). On Workers/edge, import `bundle.json` and pass it as `artifacts`.
- **Passing the wrong file as `artifacts`.** It must be `bundle.json`, not `docs.json`; the server rejects anything without a `formatVersion` and says what it expected.
- **Don't add a Wrangler `Data` rule for JSON.** A `[[rules]] type = "Data"` rule for `**/*.json` turns the `bundle.json` import into raw bytes, so the server rejects it ("missing formatVersion"). Wrangler already imports JSON as parsed objects.
- **Reaching for removed handlers.** `createVercelHandler`, `createNetlifyHandler`, `createCloudflareHandler`, and `generateAdapterFiles` were all removed — there is one generic deploy handler, `createWebRequestHandler`. The Node server lives at `docusaurus-plugin-mcp-server/adapters/node`, not `/adapters`.
- **Wrong page URLs.** Page URLs in `docs_search` and `docs_fetch` come from the build: set `url` (and `baseUrl`) in `docusaurus.config.*` and rebuild. The server's `baseUrl` option doesn't change them; it only changes what the status reports and what search providers receive.
- **Deploying before building.** The handler needs `build/mcp/*` — run `docusaurus build` first.
- **Forgetting to pass skills (deprecated configs only).** With `artifacts`/`artifactsDir`, skills come from the bundle. With the deprecated configs, the handler only serves skills when you pass `skills` or `skillsPath`.
- **Invalid skill directories fail the build.** Frontmatter must have `name` (lowercase, hyphens, matching the directory) and `description`; each skill is capped at 512 files / 16 MiB.
- **zod 3.** 2.x requires zod >= 4.2 (MCP SDK v2).
- **1.x search options.** The built-in search is `'local'` (BM25). `'flexsearch'` in `indexers`/`search`, and the `flexsearch` plugin/server option, now throw. A 1.x `search-index.json` is rejected until the site is rebuilt; the error is returned in MCP responses and the GET status. Tune ranking with the server option `localSearch: { fieldBoosts }`. The plugin's `search` option does not choose the runtime provider (it has done nothing since 2.0, is deprecated since 2.2, and is removed in 3.0); the server config's `search` does.
- **Very long queries.** `docs_search` accepts up to 500 characters and searches the first 16 distinct terms.
- **Guessing whether search is good enough.** Measure it: `evaluateSearch(provider, [{ query, expected: [routes] }])` reports top-k hits and MRR for any provider.

## Version notes

**On 2.2+ with the deprecated server configs?** Follow `node_modules/docusaurus-plugin-mcp-server/migrations/2.x-3.0.0.md`; its "For agents" checklist moves a project to `artifacts`/`artifactsDir` so 3.0 needs nothing more.

**Migrating a project from 1.x to 2.0?** Follow `node_modules/docusaurus-plugin-mcp-server/migrations/1.x-2.0.0.md` (published with the package, and on GitHub at `scalvert/docusaurus-plugin-mcp-server`). Its "For agents" section is a step-by-step checklist; errors thrown for 1.x configuration link to it.

Check the installed version with `npm ls docusaurus-plugin-mcp-server`. 2.0 requires Node.js >= 22, moved to the MCP TypeScript SDK v2 (`@modelcontextprotocol/server`) and protocol 2026-07-28 (2025-era clients still served), added skills, made `docsSearchTool.inputSchema`/`docsFetchTool.inputSchema` `z.object(...)` schemas (raw shapes remain as `docsSearchInputSchema`/`docsFetchInputSchema`), returns JSON-RPC `-32602` for unknown tools, and replaced the FlexSearch index with BM25 local search (`'local'`, `localSearch.fieldBoosts`, `evaluateSearch`, and exported `LocalSearchIndexer`/`LocalSearchProvider`). The adapter surface consolidated to one web-standard `createWebRequestHandler`; `createVercelHandler`/`createNetlifyHandler`/`generateAdapterFiles` are gone, and `createCloudflareHandler` was removed in 1.0.0 (it was a deprecated alias through 0.13.0). The Node server/handler moved to the `./adapters/node` subpath. Confirm exports against `dist/adapters-entry.d.ts` and `dist/adapters-node.d.ts` for the version you have.