Skip to main content

MCP Server Testing

The expect-mcp library provides utilities for testing MCP servers that communicate over stdin/stdout using JSON-RPC 2.0.

mcpShell(shellCommand: string, processOptions?: MCPStdinSubprocessOptions)

Creates and spawns an MCP subprocess that communicates over stdin/stdout using JSON-RPC 2.0.

import { mcpShell } from 'expect-mcp';

const app = mcpShell('node path/to/mcp-server.js');
await app.initialize();

// Test that the server provides expected tools and resources
await expect(app).toHaveTool('read_file');
await expect(app).toHaveResource('project_files');

// Clean up
app.close();

Parameters

  • shellCommand: The shell command to execute (can include arguments)
  • processOptions: Optional configuration options:
    • requestTimeout: Timeout in milliseconds for MCP requests (default: 5000)
    • allowDebugLogging: Enable debug logging for MCP communications (default: false)

Returns

An MCPStdinSubprocess instance with MCP-specific functionality.

MCPStdinSubprocess

The mcpShell function returns an MCPStdinSubprocess instance which extends the JSON-RPC subprocess with MCP-specific functionality.

Constructor Options

interface MCPStdinSubprocessOptions {
requestTimeout?: number;
allowDebugLogging?: boolean;
// ... other JsonRpcSubprocessOptions
}

const app = new MCPStdinSubprocess({
requestTimeout: 10000,
allowDebugLogging: true,
command: 'node',
args: ['path/to/mcp-server.js'],
});

Methods

initialize(params?: Partial<MCPInitializeParams>): Promise<MCPInitializeResult>

Perform MCP handshake and capability negotiation.

const result = await app.initialize();
console.log('Server info:', result.serverInfo);

getTools(): Promise<MCPTool[]>

Get list of available tools from the server.

const tools = await app.getTools();
console.log(
'Available tools:',
tools.map(t => t.name)
);

getResources(): Promise<MCPResource[]>

Get list of available resources from the server.

const resources = await app.getResources();
console.log(
'Available resources:',
resources.map(r => r.name)
);

hasTool(name: string): Promise<boolean>

Check if a specific tool is available.

const hasReadFile = await app.hasTool('read_file');

hasResource(name: string): Promise<boolean>

Check if a specific resource is available.

const hasConfig = await app.hasResource('config.json');

callTool(name: string, arguments?: any): Promise<any>

Call a tool on the MCP server.

const result = await app.callTool('read_file', {
path: '/path/to/file.txt',
});

readResource(uri: string): Promise<MCPReadResourceResult>

Read a resource from the MCP server.

const result = await app.readResource('file:///example.txt');
console.log('Resource contents:', result.contents[0].text);

isInitialized(): boolean

Check if the MCP server has been initialized.

if (!app.isInitialized()) {
await app.initialize();
}

Example Test

import { mcpShell } from 'expect-mcp';
import { describe, test, expect } from 'vitest';

describe('File Server MCP', () => {
test('provides file operations', async () => {
const app = mcpShell('node file-server.js');

try {
await app.initialize();

// Test capabilities
await expect(app).toHaveTool('read_file');
await expect(app).toHaveTool('write_file');
await expect(app).toHaveResource('project_files');

// Test tool execution
const toolResult = await app.callTool('read_file', {
path: 'package.json',
});

expect(toolResult).toBeDefined();
expect(toolResult.content).toBeDefined();

// Test resource reading
const resourceResult = await app.readResource('project://files');

expect(resourceResult.contents).toBeDefined();
expect(resourceResult.contents[0]).toBeDefined();
} finally {
app.close();
}
});
});

Types

MCPTool

interface MCPTool {
name: string;
description?: string;
inputSchema: {
type: 'object';
properties?: Record\<string, any\>;
required?: string[];
};
}

MCPResource

interface MCPResource {
uri: string;
name: string;
description?: string;
mimeType?: string;
}

MCPInitializeResult

interface MCPInitializeResult {
protocolVersion: string;
capabilities: MCPCapabilities;
serverInfo: {
name: string;
version: string;
};
instructions?: string;
}

MCPReadResourceResult

interface MCPReadResourceResult {
contents: MCPResourceContents[];
}

interface MCPTextResourceContents {
uri: string;
mimeType?: string;
text: string;
}

interface MCPBlobResourceContents {
uri: string;
mimeType?: string;
blob: string;
}

type MCPResourceContents = MCPTextResourceContents | MCPBlobResourceContents;