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;