Dev ToolsΒ·
advanced
Β·13 min readΒ·Jul 9, 2026

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.

testingJestVitestmockingJSON-RPCunit-test
Interactive Tool
1-Click Export

Generate & Validate Multi-Client MCP Config

One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.

Open in Generator

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

  1. β–ΈA modern testing framework installed (like Vitest or Jest).
  2. β–Έ@modelcontextprotocol/sdk installed as a dependency.
  3. β–Έ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:

typescript
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_PARAMS errors 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-RPC Errors: 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.
Ready to Deploy?

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.

Customize in Generator

Related Guides