Docs MCP Server
Overview
The Docs MCP Server provides full-text search over the entire Docusaurus documentation tree. It uses the DocsIndexer class with an in-process weighted search index over all .mdx files under docusaurus-docs/docs/. This is the global docs server -- for per-domain scoped search, see Domain Docs Servers.
Server Metadata
| Property | Value |
|---|---|
| Factory | createDocsMcpServer() |
| Source | src/mastra/mcp-servers/docs-server.ts |
| Version | 1.0.0 |
| Tool Count | 4 |
| Skip Flag | MASTRA_SKIP_DOCS_MCP |
| Tool Registry | src/mastra/tools/docs-search/index.ts |
Factory Implementation
// src/mastra/mcp-servers/docs-server.ts
import { MCPServer } from '@mastra/mcp';
import { docsSearchTools } from '../tools/docs-search/index.ts';
export function createDocsMcpServer(): MCPServer {
return new MCPServer({
name: 'Docs MCP Server',
version: '1.0.0',
description: 'Full-text search over Docusaurus project documentation.',
tools: docsSearchTools,
});
}
Tool Registry
All 4 tools are exported from src/mastra/tools/docs-search/index.ts:
| Tool ID | Description |
|---|---|
docs-search | Full-text search across all indexed documentation pages. Returns ranked results with snippets. |
docs-list | List all indexed documentation pages with their titles and paths. |
docs-get-page | Retrieve the full content of a specific documentation page by path. |
docs-refresh-index | Force a rebuild of the in-memory search index. Useful after documentation changes. |
The MCP discovery contract requires each tool's outputSchema to be a top-level object schema. docs-get-page returns a success boolean plus optional page or error fields instead of exposing a top-level discriminated union, so MCP clients can safely call listTools.
DocsIndexer Implementation
The search functionality is powered by the DocsIndexer class in src/mastra/tools/docs-search/indexer.ts.
Index Construction
The indexer scans all .mdx files under docusaurus-docs/docs/, parses frontmatter and content, and builds a lightweight weighted full-text index.
// Simplified view of DocsIndexer
class DocsIndexer {
private index: LightweightDocsSearchIndex;
async buildIndex(): Promise<void> {
const files = glob('docusaurus-docs/docs/**/*.mdx');
for (const file of files) {
const { frontmatter, sections } = parseMarkdown(file);
for (const section of sections) {
this.index.addSection({
pageTitle: frontmatter.title,
pageDescription: frontmatter.description,
sectionHeading: section.heading,
content: section.content,
});
}
}
}
}
Search Ranking
The in-memory index applies field-level weighting to prioritize title and description matches:
| Field | Weight | Purpose |
|---|---|---|
pageTitle | 5 | Highest priority -- matches on page titles rank first |
pageDescription | 3 | Frontmatter description text |
sectionHeading | 2 | Section headings within a page |
content | 1 | Body content (lowest priority but largest volume) |
Additional search options:
- Prefix search: Partial word matches are supported (for example, "deploy" matches "deployment")
- Typo tolerance: Long tokens tolerate one character mismatch for minor typos
- MAX_CONTENT_LENGTH:
8000characters -- returned result content is truncated to this limit
Index Lifecycle
- Startup: The index is built eagerly when the MCP server is created. The
DocsIndexerinstance starts indexing immediately. - Caching: Once built, the index is cached in memory for all subsequent search calls. No disk persistence.
- Refresh: The
docs-refresh-indextool forces a complete rebuild. This is useful after adding or editing documentation files without restarting the server. - Concurrent safety: The
buildIndex()method uses promise sharing to prevent duplicate concurrent builds. If two requests trigger a build simultaneously, both await the same promise.
// Promise-sharing pattern for concurrent safety
async buildIndex(): Promise<void> {
if (this._buildPromise) {
return this._buildPromise;
}
this._buildPromise = this._doBuildIndex();
try {
await this._buildPromise;
} finally {
this._buildPromise = null;
}
}
Implementation Notes
Local MCP Client Smoke
Use the committed stdio launcher when validating the server in Replit or a local MCP client. The launcher avoids npm lifecycle output on stdout, which can corrupt MCP stdio framing.
npm run mcp:docs:start -- docs
npm run docs:mcp:smoke -- --server docs
Global vs. Domain Scoped
The global Docs MCP Server indexes all documentation under docusaurus-docs/docs/. For clients that only need domain-specific documentation, the Domain Docs Servers provide scoped search restricted to a single subdirectory.
Skip Flag Scope
Setting MASTRA_SKIP_DOCS_MCP disables all documentation servers (global and per-domain). There is no way to selectively disable only the global server while keeping per-domain servers active.
No Database Dependencies
The Docs MCP Server has no database dependencies. It reads .mdx files from the local filesystem and maintains an in-memory index. This makes it self-contained and suitable for local development without a database connection.
Code Locations
- Server factory:
src/mastra/mcp-servers/docs-server.ts - Tool registry:
src/mastra/tools/docs-search/index.ts - Indexer class:
src/mastra/tools/docs-search/indexer.ts - Tests:
tests/shared/unit/mcp-servers/mcp-servers.test.ts(Docs MCP Server describe block) - Indexer tests:
tests/shared/unit/docs-search/indexer-class.test.ts