Domain Docs MCP Servers
Overview
The platform provides four per-domain documentation search MCP servers, each scoped to a specific subdirectory of the Docusaurus documentation tree. All four servers share the same architecture, using a generic createDomainDocsServer() factory and domain-scoped DocsIndexer instances.
Shared Architecture
All domain docs servers are implemented in src/mastra/mcp-servers/domain-docs-server.ts using a single generic factory function. Each server gets:
- A
DocsIndexerinstance scoped to a specific subdirectory - A set of tools created by
createScopedDocsTools()fromsrc/mastra/tools/docs-search/create-scoped-tools.ts - Tool descriptions that include the domain label for clarity
Server Inventory
| Server | Factory | Subdirectory | Domain Label | Version |
|---|---|---|---|---|
| K12 Docs | createK12DocsMcpServer() | k12/external | k12 | 1.0.0 |
| SDAC Docs | createSdacDocsMcpServer() | sdac/external | sdac | 1.0.0 |
| TAP Docs | createTapDocsMcpServer() | tap/internal | tap | 1.0.0 |
| RE Docs | createReasoningEngineDocsMcpServer() | reasoning-engine | reasoning-engine | 1.0.0 |
All four servers share the same skip flag: MASTRA_SKIP_DOCS_MCP.
Tool Registry (Per Server)
Each domain docs server exposes the same 4 tool IDs, scoped to its domain. The tool IDs are identical across servers but unique within each MCP server scope:
| Tool ID | Description |
|---|---|
docs-search | Full-text search scoped to the domain's documentation subdirectory |
docs-list | List all indexed pages within the domain's subdirectory |
docs-get-page | Retrieve the full content of a page by path (within domain scope) |
docs-refresh-index | Force a rebuild of the domain-scoped in-memory search index |
Tool descriptions automatically include the domain label to help MCP clients distinguish between servers. For example, the K12 server's docs-search tool description might read: "Search K12 documentation pages."
Generic Factory Implementation
// src/mastra/mcp-servers/domain-docs-server.ts
import { join } from 'node:path';
import { MCPServer } from '@mastra/mcp';
import { DocsIndexer } from '../tools/docs-search/indexer.ts';
import { createScopedDocsTools } from '../tools/docs-search/create-scoped-tools.ts';
import { resolveDocsRoot } from '../tools/shared/docs/resolve-docs-root.ts';
interface DomainDocsConfig {
name: string;
description: string;
subdir: string;
domainLabel: string;
}
function createDomainDocsServer(config: DomainDocsConfig): MCPServerWithIndexer {
const rootPath = join(resolveDocsRoot(), config.subdir);
const indexer = new DocsIndexer(rootPath, { domainLabel: config.domainLabel });
const tools = createScopedDocsTools(indexer, config.domainLabel);
const server = new MCPServer({
name: config.name,
version: '1.0.0',
description: config.description,
tools,
});
// Attach indexer for eager startup build
(server as MCPServerWithIndexer)._indexer = indexer;
return server as MCPServerWithIndexer;
}
// Convenience factory exports
export const createK12DocsMcpServer = () =>
createDomainDocsServer({
name: 'K12 Docs MCP Server',
description: 'Full-text search over K12 external documentation.',
subdir: 'k12/external',
domainLabel: 'k12',
});
export const createSdacDocsMcpServer = () =>
createDomainDocsServer({
name: 'SDAC Docs MCP Server',
description: 'Full-text search over SDAC external documentation.',
subdir: 'sdac/external',
domainLabel: 'sdac',
});
// TAP and RE follow the same pattern...
Use the committed stdio launcher and smoke script when validating these servers for a local agent client:
npm run mcp:docs:start -- sdac-docs
npm run docs:mcp:smoke -- --server sdac-docs
DocsIndexer Class Details
The DocsIndexer class (from src/mastra/tools/docs-search/indexer.ts) is the core component shared by all docs servers.
Constructor
class DocsIndexer {
constructor(rootPath: string, options?: { domainLabel?: string });
}
- rootPath: Absolute or relative path to the documentation subdirectory to index
- domainLabel: Optional override for the domain label. If not provided, the domain is auto-detected from the first path segment of the root path
Key Behaviors
- Eager index build: When a domain docs server is created, the
DocsIndexerbegins building its index immediately. The_indexerproperty on the MCPServer instance holds the reference. - Concurrent-safe promise sharing: If
buildIndex()is called while a build is already in progress, the second call awaits the same promise rather than starting a duplicate build. - Domain scoping: The indexer only scans
.mdxfiles within its configuredrootPath. This ensures each domain server's search results are isolated to its own documentation.
MCPServerWithIndexer Type
The domain docs servers use an extended type to attach the indexer instance:
type MCPServerWithIndexer = MCPServer & { _indexer: DocsIndexer };
This allows the composition layer to access the indexer for health checks or manual refresh operations.
Scoped Tools Factory
The createScopedDocsTools(indexer, domainLabel) function in src/mastra/tools/docs-search/create-scoped-tools.ts creates the 4 tools wired to a specific DocsIndexer instance:
export function createScopedDocsTools(
indexer: DocsIndexer,
domainLabel: string,
): Record<string, Tool> {
return {
'docs-search': createDocsSearchTool(indexer, domainLabel),
'docs-list': createDocsListTool(indexer, domainLabel),
'docs-get-page': createDocsGetPageTool(indexer, domainLabel),
'docs-refresh-index': createDocsRefreshIndexTool(indexer, domainLabel),
};
}
Each tool function receives the DocsIndexer instance via closure, so all operations (search, list, get, refresh) operate on the same scoped index.
As with the global docs server, scoped docs tool output schemas are top-level objects for MCP discovery compatibility. docs-get-page uses a success boolean plus optional content/error fields rather than a top-level discriminated union.
Implementation Notes
Single Skip Flag
All four domain docs servers (plus the global docs server) are controlled by the
single MASTRA_SKIP_DOCS_MCP flag. There is no per-domain skip flag for
documentation servers. If you need to disable docs search for one domain but
not others, modify the docs artifact loader that attaches scoped docs MCP
servers rather than the src/mastra/mcp-servers/index.ts barrel export.
Subdirectory Conventions
The subdirectory paths follow the Docusaurus documentation structure:
k12/external-- Public-facing K12 documentationsdac/external-- Public-facing SDAC documentationtap/internal-- Internal TAP documentation (note: "internal" in the path, not "external")reasoning-engine-- Reasoning engine documentation (top-level, no external/internal split)
No Database Dependencies
Like the global docs server, domain docs servers have no database dependencies. They are purely filesystem-based with in-memory indexing.
Code Locations
- Generic factory:
src/mastra/mcp-servers/domain-docs-server.ts - Scoped tools factory:
src/mastra/tools/docs-search/create-scoped-tools.ts - Indexer class:
src/mastra/tools/docs-search/indexer.ts - Tests:
tests/shared/unit/mcp-servers/mcp-servers.test.ts(domain docs describe blocks) - Indexer tests:
tests/shared/unit/docs-search/indexer-class.test.ts