@writechoice/fumadocs-mcp
v0.1.1
Published
MCP server route handler for Fumadocs projects
Readme
@writechoice/fumadocs-mcp
MCP (Model Context Protocol) server route handler for Fumadocs projects. Exposes your documentation as an MCP endpoint that AI assistants can query directly — no separate indexing step, no static JSON file. It reads from the Fumadocs source API you already have.
Installation
npm install @writechoice/fumadocs-mcpSetup
1. Add to next.config.ts
const config: NextConfig = {
transpilePackages: ["@writechoice/fumadocs-mcp"],
// ...rest of your config
};2. Create the MCP route
// src/app/mcp/route.ts
import { createMCPHandler } from "@writechoice/fumadocs-mcp";
import { source } from "@/lib/source";
export const { GET, POST, OPTIONS } = createMCPHandler(source, {
server: { name: "My Docs", version: "1.0.0" },
});That's it. Your MCP server is live at /mcp.
Options
createMCPHandler(source, {
server: {
name: string; // displayed in GET /mcp and MCP initialize response
version: string; // semver string
};
});Endpoints
| Method | Path | Description |
| --------- | ------ | ---------------------------------------- |
| GET | /mcp | Server info and capabilities (tool list) |
| POST | /mcp | MCP JSON-RPC 2.0 handler |
| OPTIONS | /mcp | CORS preflight |
MCP Tools
list_docs
Lists all documentation pages grouped by section, with title, URL, and description.
{ "method": "tools/call", "params": { "name": "list_docs", "arguments": {} } }get_doc
Fetches the full processed markdown content of one or more pages by URL path. Accepts a single path or an array for batch reads.
{
"method": "tools/call",
"params": {
"name": "get_doc",
"arguments": { "path": "/api-reference/charges/create-charge" }
}
}{
"method": "tools/call",
"params": {
"name": "get_doc",
"arguments": { "path": ["/documentation/introduction", "/api-reference/get-started/authentication"] }
}
}search_docs
Fast keyword search over page titles and descriptions. Good for finding a page by name.
{
"method": "tools/call",
"params": {
"name": "search_docs",
"arguments": { "query": "webhook", "limit": 5, "scoreThreshold": 0.1 }
}
}search_docs_fulltext
Full-text search using the Fumadocs Orama index. Searches page bodies, headings, and paragraphs. Use this when search_docs returns no results or you need to find mentions within content.
{
"method": "tools/call",
"params": {
"name": "search_docs_fulltext",
"arguments": { "query": "idempotency key", "limit": 10 }
}
}Testing
With your dev server running:
# Server info
curl http://localhost:3000/mcp
# Initialize MCP session
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'
# List all docs
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_docs","arguments":{}}}'
# Full-text search
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_docs_fulltext","arguments":{"query":"charges"}}}'How it works
createMCPHandler closes over your Fumadocs source instance and uses it directly:
| MCP Tool | Fumadocs API |
| ---------------------- | ---------------------------------------------------------------- |
| list_docs | source.getPages() |
| get_doc | source.getPage(slugs) + page.data.getText('processed') |
| search_docs | Keyword scoring over page.data.title / page.data.description |
| search_docs_fulltext | createFromSource(source) — same Orama index as /api/search |
No filesystem walking, no static JSON index. Content is always in sync with your docs at build time.
Requirements
fumadocs-core>= 16next>= 15source.config.tsmust havepostprocess: { includeProcessedMarkdown: true }forget_docto return full content
