Testing and Mocking: Unit Testing and Mocking JSON-RPC Payloads for MCP
Write bulletproof unit tests for your MCP servers by mocking Stdio transports and validating JSON-RPC message exchanges.
Generate & Validate Multi-Client MCP Config
One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.
Testing and Mocking: Unit Testing & JSON-RPC
Building reliable MCP servers requires writing comprehensive test suites. Because MCP servers communicate asynchronously via JSON-RPC payloads over standard input/output streams or network sockets, you must mock transport interfaces and validate payload formats accurately to ensure deterministic testing.
Prerequisites
- βΈA modern testing framework installed (like Vitest or Jest).
- βΈ
@modelcontextprotocol/sdkinstalled as a dependency. - βΈTypeScript configured for your testing environment.
Mocking Stdio Transports with Vitest
Rather than actually spawning child processes and piping stdin/stdout during unit tests, you can mock the transport layer entirely and pass raw JSON-RPC objects directly to the MCP Server instance.
Here is a comprehensive unit-test setup using Vitest to test MCP tool registration and response formats:
import { describe, it, expect } from 'vitest';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
describe('MCP Server Unit Tests', () => {
it('should return correct compound interest calculations', async () => {
// 1. Initialize Server
const testServer = new Server(
{ name: 'test-server', version: '1.0.0' },
{ capabilities: { tools: {} } }
);
// 2. Register Tool Handlers
testServer.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'calculate') {
return { content: [{ type: 'text', text: '42' }] };
}
throw new Error('Tool not found');
});
// 3. Mock the JSON-RPC Request Payload
const mockRequest = {
jsonrpc: '2.0' as const,
id: 1,
method: 'tools/call' as const,
params: {
name: 'calculate',
arguments: {}
}
};
// 4. Execute and Assert
const response = await testServer.handleRequest(mockRequest);
expect(response).toHaveProperty('result');
expect(response.result.content[0].text).toBe('42');
});
});Best Practices
- βΈValidate Input Schemas: Your tests should pass invalid arguments (e.g., strings instead of numbers) to ensure your Zod schemas correctly throw
INVALID_PARAMSerrors before your tool logic executes. - βΈMock External APIs: If your tool makes external HTTP calls (e.g., fetching GitHub data), use libraries like
msw(Mock Service Worker) to intercept those requests rather than hitting production endpoints during CI/CD.
Troubleshooting
- βΈ
Invalid JSON-RPCErrors: Ensure your mock requests strictly include"jsonrpc": "2.0"and a unique"id". The MCP SDK will reject payloads that don't adhere to the exact RPC specification. - βΈHanging Tests: If your test suite hangs, ensure that any streams or transports initialized during tests are explicitly closed or disconnected in an
afterAll()cleanup block.
Build your full agent toolstack in the Visual Generator
Combine Testing and Mocking: Unit Testing and Mocking JSON-RPC Payloads for MCP with databases, search APIs, and memory graphs in a single configuration file.
Related Guides
How to Build a Custom MCP Server from Scratch
Learn how to create your own MCP server using the TypeScript or Python SDK. Expose custom tools and resources for AI agents to use.
Dev ToolsHow to Use the Puppeteer MCP Server for Web Scraping & Automation
Automate web browsers using the Puppeteer MCP server. Navigate websites, take screenshots, extract data, and automate web interactions through AI.
Dev ToolsHow to Use the Git MCP Server for Version Control Operations
Manage local Git repositories through AI agents. Clone repos, create branches, make commits, and view diffs using the Git MCP server.