Serving the snapshot
The plugin only produces a snapshot. Serving it is a separate step, because static hosting can't serve a live endpoint. There are two paths: a CLI for local dev, and a serverless function for production.
Local dev
After a build, serve the snapshot on :3100:
npx docusaurus-plugin-mcp serve
Or build and serve in one step, skipping the full Docusaurus build:
npx docusaurus-plugin-mcp serve --site . --openapi api=openapi/api.json
Point a client at http://localhost:3100/mcp, or inspect it with npx @modelcontextprotocol/inspector over Streamable HTTP.
Production
Add one serverless function that imports the snapshot. The handler is a standard Node (req, res), so it drops into any Node serverless runtime or an Express route. This site deploys to Vercel, which is exactly what api/mcp.ts here does:
// api/mcp.ts
import { createNodeHandler } from 'docusaurus-plugin-mcp/server';
import snapshot from '../build/mcp/snapshot.json' with { type: 'json' };
export const config = { maxDuration: 60 };
export default createNodeHandler(snapshot, { name: 'my-docs', version: '1.0.0' });
Vercel builds the site first, so build/mcp/snapshot.json exists when it traces the function. A vercel.json rewrite maps the clean /mcp path onto the function:
{ "rewrites": [{ "source": "/mcp", "destination": "/api/mcp" }] }
It's stateless: a fresh server is created per request, so it scales horizontally with no session store. Rebuild (redeploy) to refresh the snapshot. See examples/vercel for the upstream example.
Programmatic use
For custom pipelines, the snapshot builder and server are exported directly:
import { buildSnapshot, resolveOptions } from 'docusaurus-plugin-mcp';
import { createMcpServer, createNodeHandler, loadSnapshot } from 'docusaurus-plugin-mcp/server';
buildSnapshot({ siteDir, baseUrl, options })— build a snapshot in memorycreateMcpServer(snapshot, opts)— a configuredMcpServerfrom the SDKcreateNodeHandler(snapshot, opts)— a stateless Node request handlerloadSnapshot(file)— read a snapshot from disk
Limitations
- Doc URLs are derived from
routeBasePathplus the file path orslugfrontmatter. That covers the common cases; exotic routing or path aliases may not match exactly. - Refreshing happens at build. Rebuild to pick up doc changes — the CLI's build-on-the-fly mode is for dev only.
- Runtime targets Node. Web-standard and edge runtimes aren't supported yet.