loading…
Search for a command to run...
loading…
A Docusaurus plugin that exposes an MCP server endpoint for AI agents to search and retrieve documentation
A Docusaurus plugin that exposes an MCP server endpoint for AI agents to search and retrieve documentation
A Docusaurus plugin that exposes an MCP (Model Context Protocol) server endpoint, allowing AI agents like Claude, Cursor, and other MCP-compatible tools to search and retrieve your documentation.
npm install docusaurus-plugin-mcp-server
// docusaurus.config.js
module.exports = {
plugins: [
[
'docusaurus-plugin-mcp-server',
{
server: {
name: 'my-docs',
version: '1.0.0',
},
},
],
],
};
Choose your deployment platform:
Create api/mcp.js:
import { createVercelHandler } from 'docusaurus-plugin-mcp-server/adapters';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default createVercelHandler({
docsPath: path.join(__dirname, '../build/mcp/docs.json'),
indexPath: path.join(__dirname, '../build/mcp/search-index.json'),
name: 'my-docs',
baseUrl: 'https://docs.example.com',
});
Add to vercel.json:
{
"functions": {
"api/mcp.js": {
"includeFiles": "build/mcp/**"
}
},
"rewrites": [{ "source": "/mcp", "destination": "/api/mcp" }]
}
Create netlify/functions/mcp.js:
import { createNetlifyHandler } from 'docusaurus-plugin-mcp-server/adapters';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export const handler = createNetlifyHandler({
docsPath: path.join(__dirname, '../../build/mcp/docs.json'),
indexPath: path.join(__dirname, '../../build/mcp/search-index.json'),
name: 'my-docs',
baseUrl: 'https://docs.example.com',
});
Add to netlify.toml:
[build]
publish = "build"
[functions]
directory = "netlify/functions"
included_files = ["build/mcp/**"]
[[redirects]]
from = "/mcp"
to = "/.netlify/functions/mcp"
status = 200
Cloudflare Workers can't access the filesystem, so you need to import the data directly:
import { createCloudflareHandler } from 'docusaurus-plugin-mcp-server/adapters';
import docs from '../build/mcp/docs.json';
import searchIndex from '../build/mcp/search-index.json';
export default {
fetch: createCloudflareHandler({
docs,
searchIndexData: searchIndex,
name: 'my-docs',
baseUrl: 'https://docs.example.com',
}),
};
npm run build
# Deploy to your platform
Claude Code:
claude mcp add --transport http my-docs https://docs.example.com/mcp
Cursor / VS Code:
{
"mcpServers": {
"my-docs": {
"url": "https://docs.example.com/mcp"
}
}
}
Add a dropdown button to your docs site so users can easily install the MCP server in their AI tool:
import { McpInstallButton } from 'docusaurus-plugin-mcp-server/theme';
function NavbarItems() {
return <McpInstallButton serverUrl="https://docs.example.com/mcp" serverName="my-docs" />;
}
The button shows a dropdown with copy-to-clipboard configurations for all supported MCP clients.
| Light Mode | Dark Mode |
|---|---|
![]() |
![]() |
Props:
| Prop | Type | Default | Description |
|---|---|---|---|
serverUrl |
string |
required | Your MCP server endpoint URL |
serverName |
string |
required | Name for the MCP server |
label |
string |
(none) | Button label. If omitted, shows only the MCP icon |
headerText |
string |
"Choose your AI tool:" |
Text shown at the top of the dropdown |
className |
string |
"" |
Optional CSS class |
clients |
ClientId[] |
All HTTP-capable | Which clients to show |
The server exposes two tools for AI agents:
docs_searchSearch across documentation with relevance ranking. Returns matching documents with URLs, snippets, and relevance scores.
{
"name": "docs_search",
"arguments": {
"query": "authentication",
"limit": 16
}
}
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string |
required | Search query |
limit |
number |
16 |
Max results (1-20) |
Response includes:
docs_fetch)docs_fetchRetrieve full page content as markdown. Use this after searching to get the complete content of a specific page.
{
"name": "docs_fetch",
"arguments": {
"url": "https://docs.example.com/docs/authentication"
}
}
| Parameter | Type | Description |
|---|---|---|
url |
string |
Full URL of the page (from search results) |
Response includes:
| Option | Type | Default | Description |
|---|---|---|---|
outputDir |
string |
'mcp' |
Output directory for MCP artifacts (relative to build dir) |
contentSelectors |
string[] |
['article', 'main', ...] |
CSS selectors for finding content |
excludeSelectors |
string[] |
['nav', 'header', ...] |
CSS selectors for elements to remove |
minContentLength |
number |
50 |
Minimum content length to consider a page valid |
server.name |
string |
'docs-mcp-server' |
Name of the MCP server |
server.version |
string |
'1.0.0' |
Version of the MCP server |
excludeRoutes |
string[] |
['/404*', '/search*'] |
Routes to exclude (glob patterns) |
indexers |
string[] | false |
['flexsearch'] |
Indexers to run during build. Use false to disable. Supports built-in ('flexsearch'), relative paths, or npm packages. |
search |
string |
'flexsearch' |
Search provider module for runtime queries. Supports built-in ('flexsearch'), relative paths, or npm packages. |
Content selectors (in priority order):
['article', 'main', '.main-wrapper', '[role="main"]'];
Exclude selectors:
[
'nav',
'header',
'footer',
'aside',
'[role="navigation"]',
'[role="banner"]',
'[role="contentinfo"]',
];
The plugin uses a two-phase provider model: indexers run at build time to process documents, and search providers handle queries at runtime. Both are pluggable.
Implement ContentIndexer to push documents to an external system during build:
import type { ContentIndexer, ProviderContext, ProcessedDoc } from 'docusaurus-plugin-mcp-server';
export default class AlgoliaIndexer implements ContentIndexer {
readonly name = 'algolia';
shouldRun(): boolean {
return process.env.ALGOLIA_SYNC === 'true';
}
async initialize(context: ProviderContext): Promise<void> {
console.log(`[Algolia] Initializing for ${context.baseUrl}`);
}
async indexDocuments(docs: ProcessedDoc[]): Promise<void> {
// Push docs to Algolia
}
async finalize(): Promise<Map<string, unknown>> {
// No local artifacts needed
return new Map();
}
}
Implement SearchProvider to delegate runtime search to an external service:
import type {
SearchProvider,
ProviderContext,
SearchOptions,
SearchResult,
} from 'docusaurus-plugin-mcp-server';
export default class GleanSearchProvider implements SearchProvider {
readonly name = 'glean';
private apiEndpoint = process.env.GLEAN_API_ENDPOINT!;
private apiToken = process.env.GLEAN_API_TOKEN!;
async initialize(context: ProviderContext): Promise<void> {
if (!this.apiEndpoint || !this.apiToken) {
throw new Error('GLEAN_API_ENDPOINT and GLEAN_API_TOKEN required');
}
}
isReady(): boolean {
return !!this.apiEndpoint && !!this.apiToken;
}
async search(query: string, options?: SearchOptions): Promise<SearchResult[]> {
// Call Glean Search API and transform results
return [];
}
}
// docusaurus.config.js
module.exports = {
plugins: [
[
'docusaurus-plugin-mcp-server',
{
// Run both the built-in FlexSearch indexer and a custom one
indexers: ['flexsearch', './my-algolia-indexer.js'],
// Use a custom search provider at runtime
search: '@myorg/glean-search',
},
],
],
};
For the runtime adapters:
| Option | Type | Required | Description |
|---|---|---|---|
docsPath |
string |
Yes* | Path to docs.json |
indexPath |
string |
Yes* | Path to search-index.json |
docs |
object |
Yes* | Pre-loaded docs (Cloudflare) |
searchIndexData |
object |
Yes* | Pre-loaded search index (Cloudflare) |
name |
string |
Yes | Server name |
version |
string |
No | Server version |
baseUrl |
string |
No | Base URL for full page URLs in responses |
*Use either file paths (Node.js) or pre-loaded data (Workers).
After running npm run build, use the included CLI to verify the MCP output:
npx docusaurus-mcp-verify
This checks that:
docs.json, search-index.json, manifest.json)You can specify a custom build directory:
npx docusaurus-mcp-verify ./custom-build
Example output:
🔍 MCP Build Verification
==================================================
Build directory: /path/to/your/project/build
📁 Checking build output...
✓ Found 42 documents
✓ All required files present
✓ File structure valid
🚀 Testing MCP server...
✓ Server initialized with 42 documents
✅ All checks passed!
The easiest way to test your MCP server is with the official MCP Inspector:
npx @modelcontextprotocol/inspector
This opens a visual interface where you can:
Alternatively, test with curl:
# List available tools
curl -X POST https://docs.example.com/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Search documentation
curl -X POST https://docs.example.com/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"id":2,
"method":"tools/call",
"params":{
"name":"docs_search",
"arguments":{"query":"getting started"}
}
}'
The plugin operates in two phases:
Build Time: During docusaurus build, the plugin's postBuild hook processes all rendered HTML pages, extracts content, converts to markdown, builds a FlexSearch index, and outputs artifacts to build/mcp/.
Runtime: A serverless function loads the pre-built artifacts and handles MCP JSON-RPC requests from AI agents. The server is stateless and fast since all indexing happens at build time.
Run a local MCP server for testing using the built-in Node adapter:
// mcp-server.mjs
import { createNodeServer } from 'docusaurus-plugin-mcp-server/adapters';
createNodeServer({
docsPath: './build/mcp/docs.json',
indexPath: './build/mcp/search-index.json',
name: 'my-docs',
baseUrl: 'http://localhost:3000',
}).listen(3456, () => {
console.log('MCP server at http://localhost:3456');
});
The Node adapter handles CORS, preflight requests, and health checks (GET) automatically.
Connect Claude Code:
claude mcp add --transport http my-docs http://localhost:3456
import {
// Docusaurus plugin (default export)
mcpServerPlugin,
// MCP Server class
McpDocsServer,
// Tool definitions
docsSearchTool,
docsFetchTool,
// Utilities
htmlToMarkdown,
extractContent,
extractHeadingsFromMarkdown,
buildSearchIndex,
// Provider types (for custom implementations)
loadIndexer,
loadSearchProvider,
FlexSearchIndexer,
FlexSearchProvider,
// Default options
DEFAULT_OPTIONS,
} from 'docusaurus-plugin-mcp-server';
import {
createVercelHandler,
createNetlifyHandler,
createCloudflareHandler,
createNodeServer,
createNodeHandler,
generateAdapterFiles,
} from 'docusaurus-plugin-mcp-server/adapters';
createNodeServer(options) — Creates a complete Node.js HTTP server for local development. Returns an http.Server ready to .listen().createNodeHandler(options) — Creates a request handler function compatible with http.createServer(). Use this when you need to integrate with an existing server.import {
McpInstallButton,
type McpInstallButtonProps,
useMcpRegistry,
createDocsRegistry,
createDocsRegistryOptions,
type McpConfig,
} from 'docusaurus-plugin-mcp-server/theme';
McpInstallButton — Dropdown button for users to install the MCP server in their AI tool.useMcpRegistry() — React hook that returns the MCP config registry from plugin global data. Returns undefined if the plugin is not installed.createDocsRegistry(config) — Creates a pre-configured MCPConfigRegistry for documentation servers.createDocsRegistryOptions(config) — Returns registry options without creating the registry.McpConfig — Type for { serverUrl: string; serverName: string }.MIT
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"docusaurus-plugin-mcp-server": {
"command": "npx",
"args": [
"-y",
"docusaurus-plugin-mcp-server"
]
}
}
}pro-tip
Поставил Docusaurus Plugin Mcp Server? Скажи Claude: «запомни почему я установил Docusaurus Plugin Mcp Server и что хочу попробовать» — попадёт в твой Vault.
как это работает →