Skip to main content

MCP Testing

Overview

MCP server testing covers metadata validation, tool wiring, instance isolation, domain scoping, backward compatibility, docs-loader behavior, docs-chat routing, and Docusaurus SSE parsing. The core MCP/docs search suite is split across these files:

  1. MCP server tests: tests/shared/unit/mcp-servers/mcp-servers.test.ts -- 41 tests across 9 server describe blocks
  2. DocsIndexer tests: tests/shared/unit/docs-search/indexer-class.test.ts -- 19 tests for the DocsIndexer class

The focused MCP/docs-chat validation run also includes docs loader, docs-chat agent/route, Docusaurus hook, and SSE parser tests. Current recorded evidence: 6 files and 73 tests passed.

Test Suite: MCP Servers

File: tests/shared/unit/mcp-servers/mcp-servers.test.ts

Structure

The test file is organized into 8 MCP server describe blocks plus one registry metadata integration block:

Describe BlockTestsServer
K12 Safety MCP Server5createK12SafetyMcpServer()
Reasoning Engine MCP Server4createReasoningEngineMcpServer()
Admin MCP Server4createAdminMcpServer()
Docs MCP Server5createDocsMcpServer()
K12 Docs MCP Server6createK12DocsMcpServer()
SDAC Docs MCP Server3createSdacDocsMcpServer()
TAP Docs MCP Server3createTapDocsMcpServer()
RE Docs MCP Server3createReasoningEngineDocsMcpServer()
Server info integration8Registry metadata across the MCP factories

What Is Tested

Each server describe block validates:

  1. Metadata -- Server name, version, and description match expected values
  2. Tool wiring -- The correct number of tools are registered and their IDs match the expected set
  3. Instance isolation -- Calling the factory twice returns two independent instances (no shared state)
  4. Domain scoping (docs servers only) -- The indexer is scoped to the correct subdirectory
  5. Backward compatibility -- Server names and versions have not changed unexpectedly (semver contract)

Mocking Strategy

The MCPServer class is mocked with a stub that captures constructor arguments:

// Simplified mock pattern
vi.mock('@mastra/mcp', () => ({
MCPServer: vi.fn().mockImplementation((config) => ({
config,
})),
}));

This allows tests to verify the arguments passed to the MCPServer constructor without needing a real MCP runtime. The mock captures:

  • config.name -- Server identifier
  • config.version -- Semver version string
  • config.description -- Human-readable description
  • config.tools -- The tool registry object (verified by checking keys)

Example Test Pattern

describe('Admin MCP Server', () => {
it('should have correct metadata', () => {
const server = createAdminMcpServer();
expect(server.config.name).toBe('Admin MCP Server');
expect(server.config.version).toBe('1.0.0');
});

it('should wire all expected admin tools', () => {
const server = createAdminMcpServer();
const toolIds = Object.keys(server.config.tools);
expect(toolIds).toHaveLength(EXPECTED_ADMIN_TOOL_COUNT);
expect(toolIds).toContain('admin-update-llm-params');
expect(toolIds).toContain('admin-db-health-check');
// ... remaining tool assertions
});

it('should return independent instances', () => {
const server1 = createAdminMcpServer();
const server2 = createAdminMcpServer();
expect(server1).not.toBe(server2);
});
});

Test Suite: DocsIndexer

File: tests/shared/unit/docs-search/indexer-class.test.ts

What Is Tested

The DocsIndexer test suite covers 19 tests across these areas:

  • Index construction -- Verifies that .mdx files are parsed and indexed correctly
  • Search functionality -- Tests full-text search with boosting, prefix matching, and fuzzy matching
  • Domain scoping -- Verifies that indexers scoped to subdirectories only index files within their scope
  • Concurrent safety -- Tests that concurrent buildIndex() calls share a single promise
  • Refresh behavior -- Verifies that docs-refresh-index rebuilds the index from scratch
  • Content truncation -- Tests that content beyond MAX_CONTENT_LENGTH (8000 chars) is truncated
  • Frontmatter parsing -- Verifies extraction of title, description, and other metadata

Runtime Verification

Beyond unit tests, MCP servers can be verified at runtime by starting the development server and checking the discovery endpoints.

Step 1: Start the Dev Server

npm run dev

Step 2: Check Discovery Metadata

curl http://localhost:4111/mcp-servers.json

Expected output: JSON metadata for all registered MCP servers with their names, versions, and tool counts. The audited runtime route exposes /mcp-servers.json; it does not expose a separate /mcp-servers HTML directory.

Step 3: Verify Individual Server

Use an MCP client or deployment-verified transport URL to check a specific server. The source-backed registry proves the server IDs and metadata, while the exact HTTP/SSE transport paths are owned by the Mastra runtime/APIM deployment layer and should be smoke-tested in the target environment.

For local stdio validation of the docs MCP servers, use the committed launcher and smoke script. This is the preferred Replit/client setup path because it uses the real MCP client transport and keeps stdout reserved for protocol messages.

npm run docs:mcp:smoke -- --server docs
npm run docs:mcp:smoke -- --server sdac-docs
npm run docs:mcp:smoke -- --server k12-docs
npm run docs:mcp:smoke -- --server tap-docs
npm run docs:mcp:smoke -- --server reasoning-engine-docs
npm run docs:mcp:smoke -- --all

For the trusted-collaborator diagnostics workbench MCP, validate the local stdio adapter and generated internal context bundle with:

npm run diagnostics:workbench:smoke

After the testing diagnostics control-plane image is deployed, validate the hosted streamable HTTP endpoint with a diagnostics token:

DIAGNOSTICS_TOKEN_CODEX=<diagnostics token> npm run diagnostics:workbench:smoke -- \
--remote-url https://test-aitools-llfc-diagnostics.azurewebsites.net/mcp \
--token-env DIAGNOSTICS_TOKEN_CODEX

The hosted diagnostics workbench endpoint is /mcp on the diagnostics control plane, not an APIM /ai/api/mcp/{serverId}/mcp runtime route.

Step 4: Test via VS Code

  1. Configure a local MCP client entry for the server URL you want to test
  2. Open VS Code with the Copilot extension
  3. Invoke an MCP tool through the Copilot chat interface
  4. Verify the tool executes and returns expected results

Adding Tests for a New Server

When adding a new MCP server, follow this template to add tests:

// In tests/shared/unit/mcp-servers/mcp-servers.test.ts

describe('New Domain MCP Server', () => {
it('should have correct metadata', () => {
const server = createNewDomainMcpServer();
expect(server.config.name).toBe('New Domain MCP Server');
expect(server.config.version).toBe('1.0.0');
expect(server.config.description).toBeDefined();
});

it('should wire all expected tools', () => {
const server = createNewDomainMcpServer();
const toolIds = Object.keys(server.config.tools);
expect(toolIds).toHaveLength(EXPECTED_TOOL_COUNT);
// Assert each tool ID explicitly
for (const expectedId of EXPECTED_TOOL_IDS) {
expect(toolIds).toContain(expectedId);
}
});

it('should return independent instances', () => {
const a = createNewDomainMcpServer();
const b = createNewDomainMcpServer();
expect(a).not.toBe(b);
});
});

Checklist for New Server Tests

  • Add a new describe block in mcp-servers.test.ts
  • Test metadata (name, version, description)
  • Test tool wiring with explicit tool ID assertions
  • Test instance isolation
  • If a docs server, test domain scoping via indexer path
  • Update the test count in this documentation

Troubleshooting

Tests fail with "Cannot find module"

The MCP server factories import from tool registries. If a tool file was moved or renamed, the import path in the factory file may be stale. Check src/mastra/mcp-servers/*.ts for broken imports.

Tool count mismatch

If a test expects N tools but the server has N+1, a new tool was added to the domain's tool registry without updating the test assertion. Add the new tool ID to the expected list in the test.

Instance isolation test fails

If two factory calls return the same object reference, the factory is caching its result. MCP server factories must create a new MCPServer instance on every call -- check for module-level caching in the factory file.

Indexer tests fail on CI

The DocsIndexer reads .mdx files from the filesystem. On CI, the working directory may differ from local development. Ensure the test setup sets the correct rootPath relative to the project root.

Code Locations

  • MCP server tests: tests/shared/unit/mcp-servers/mcp-servers.test.ts
  • DocsIndexer tests: tests/shared/unit/docs-search/indexer-class.test.ts
  • Server factories under test: src/mastra/mcp-servers/*.ts
  • Tool registries under test: src/mastra/tools/*/index.ts