AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Mcp Dev Kit

mcp-gnana997-mcp-dev-kit · by gnana997

Complete testing & debugging toolkit for MCP (Model Context Protocol) servers

No reviews yet
0 installs
19 views
0.0% view→install

Install

$ agentstack add mcp-gnana997-mcp-dev-kit

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-gnana997-mcp-dev-kit)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
9mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Mcp Dev Kit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

mcp-dev-kit

[](https://www.npmjs.com/package/mcp-dev-kit) [](https://github.com/gnana997/mcp-dev-kit/actions) [](https://opensource.org/licenses/MIT)

Complete testing and debugging toolkit for Model Context Protocol (MCP) servers

Build reliable MCP servers with comprehensive testing utilities, intelligent snapshot testing, and stdio-safe debug logging.

Why mcp-dev-kit?

Developing MCP servers comes with unique challenges:

  • Testing is hard - No built-in test utilities for MCP servers
  • Snapshots break - Timestamps and IDs change on every run
  • Logging breaks stdio - console.log() corrupts JSON-RPC communication
  • Manual assertions - Repetitive boilerplate for common checks

mcp-dev-kit solves all of these:

  • MCPTestClient - Full-featured test client for MCP servers
  • Smart snapshots - Auto-exclude dynamic fields (timestamps, IDs)
  • Custom matchers - Readable assertions for tools, resources, prompts
  • Safe logging - Debug without breaking JSON-RPC protocol

Quick Start

Installation

npm install --save-dev mcp-dev-kit vitest

Basic Test Setup

1. Create vitest.setup.ts:

import { installMCPMatchers } from 'mcp-dev-kit/matchers';

installMCPMatchers();

2. Configure vitest.config.ts:

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,
    environment: 'node',
    setupFiles: ['./vitest.setup.ts'],
  },
});

3. Write tests (server.test.ts):

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { MCPTestClient } from 'mcp-dev-kit/client';

describe('My MCP Server', () => {
  let client: MCPTestClient;

  beforeAll(async () => {
    client = new MCPTestClient({
      command: 'node',
      args: ['./my-server.js'],
    });
    await client.connect();
  });

  afterAll(async () => {
    await client.disconnect();
  });

  it('should list available tools', async () => {
    const tools = await client.listTools();
    expect(tools).toHaveLength(2);
    expect(tools[0]).toHaveToolProperty('name', 'echo');
  });

  it('should execute tools successfully', async () => {
    const result = await client.callTool('echo', { message: 'hello' });
    await expect(result).toReturnToolResult('hello');
  });

  it('should have stable response structure', async () => {
    const result = await client.callTool('list_files', { path: '/' });
    expect(result).toMatchToolResponseSnapshot();
  });
});

4. Add debug logging to your server:

// At the top of your MCP server file
import 'mcp-dev-kit/logger';

// Now console.log works without breaking JSON-RPC!
console.log('Server started');
console.error('Connection error', error);

5. Run tests:

npx vitest

Features

MCP Test Client

Comprehensive test client for spawning and testing MCP servers via stdio.

import { MCPTestClient } from 'mcp-dev-kit/client';

const client = new MCPTestClient({
  command: 'node',
  args: ['./my-server.js'],
  env: { DEBUG: 'true' },
  timeout: 30000,
});

await client.connect();

// Test server capabilities
const serverInfo = client.getServerInfo();
const capabilities = client.getServerCapabilities();

// List and call tools
const tools = await client.listTools();
const result = await client.callTool('my-tool', { param: 'value' });

// List and read resources
const resources = await client.listResources();
const content = await client.readResource('file://config.json');

// List and get prompts
const prompts = await client.listPrompts();
const prompt = await client.getPrompt('greeting', { name: 'Alice' });

// Helper methods for common patterns
const toolResult = await client.expectToolCallSuccess('my-tool', { input: 'test' });
const error = await client.expectToolCallError('bad-tool', {});

await client.disconnect();

Key Features:

  • Automatic process lifecycle management
  • Request/response matching with timeouts
  • Server notification handling
  • Comprehensive error handling
  • TypeScript-first with full type safety

Custom Vitest Matchers

Readable, expressive assertions for MCP-specific testing.

import { installMCPMatchers } from 'mcp-dev-kit/matchers';

installMCPMatchers();

Available Matchers:

// Tool assertions
await expect(client).toHaveTool('echo');
const tools = await client.listTools();
expect(tools[0]).toHaveToolProperty('description', 'Echoes back the message');
expect(tools[0]).toMatchToolSchema({
  type: 'object',
  required: ['message']
});

// Resource assertions
await expect(client).toHaveResource('config://app.json');
const resources = await client.listResources();
expect(resources[0]).toHaveProperty('uri', 'config://app.json');

// Prompt assertions
await expect(client).toHavePrompt('greeting');
const prompts = await client.listPrompts();
expect(prompts[0]).toHaveProperty('name', 'greeting');

// Tool result assertions
const result = await client.callTool('echo', { message: 'test' });
await expect(result).toReturnToolResult('test');
await expect(client.callTool('unknown', {})).toThrowToolError();

Benefits:

  • Clear, self-documenting test code
  • Better error messages when tests fail
  • Reduces boilerplate in test files
  • Type-safe with TypeScript

Snapshot Testing

MCP-aware snapshot testing with intelligent field exclusion.

Why Snapshot Testing for MCP?

MCP server responses often contain dynamic data that changes on every run:

  • Timestamps (2024-11-03T10:30:00.000Z)
  • Request IDs (abc123)
  • Execution times (42.5ms)
  • Auto-increment IDs, file inodes, git SHAs

Regular snapshot testing would fail on every run. mcp-dev-kit automatically excludes these fields while capturing the stable response structure.

Quick Example
import { installMCPMatchers } from 'mcp-dev-kit/matchers';

installMCPMatchers();

describe('File System Server', () => {
  it('should return consistent file listing structure', async () => {
    const result = await client.callTool('list_files', { path: '/project' });

    // Timestamps, IDs, and dynamic fields automatically excluded!
    expect(result).toMatchToolResponseSnapshot();
  });

  it('should have stable tool definitions', async () => {
    const tools = await client.listTools();

    // Captures tool schemas for regression detection
    expect(tools).toMatchToolListSnapshot();
  });

  it('should snapshot custom data structures', async () => {
    const data = {
      users: [...],
      timestamp: new Date().toISOString(), // Auto-excluded
      requestId: 'abc123',                   // Auto-excluded
    };

    expect(data).toMatchMCPSnapshot();
  });
});
Available Snapshot Matchers

toMatchMCPSnapshot(options?) - Generic snapshot matcher for any MCP data

expect(serverResponse).toMatchMCPSnapshot();
expect(data).toMatchMCPSnapshot({ exclude: ['user.id', 'files.*.size'] });

toMatchToolResponseSnapshot(options?) - For tool call results

const result = await client.callTool('query_database', { query: 'SELECT * FROM orders' });
expect(result).toMatchToolResponseSnapshot();

toMatchToolListSnapshot(options?) - For tool definitions

const tools = await client.listTools();
expect(tools).toMatchToolListSnapshot();

toMatchResourceListSnapshot(options?) - For resource listings

const resources = await client.listResources();
expect(resources).toMatchResourceListSnapshot();

toMatchPromptListSnapshot(options?) - For prompt definitions

const prompts = await client.listPrompts();
expect(prompts).toMatchPromptListSnapshot();
Smart Defaults

These fields are automatically excluded from all snapshots:

  • timestamp
  • requestId
  • executionTime
  • cacheKey
  • _meta.timestamp
  • serverInfo.startedAt
  • serverInfo.uptime

Example:

// Original response
{
  "users": [...],
  "timestamp": "2024-11-03T10:30:00.000Z",  // ❌ Excluded
  "requestId": "abc123",                     // ❌ Excluded
  "executionTime": 42.5                      // ❌ Excluded
}

// Snapshot (only stable data)
{
  "users": [...]  // ✅ Captured
}
Custom Exclusions

Exclude additional fields using glob patterns:

// Exclude file system-specific fields
expect(result).toMatchToolResponseSnapshot({
  exclude: ['files.*.size', 'files.*.inode', 'files.*.modified']
});

// Exclude all auto-increment IDs
expect(data).toMatchMCPSnapshot({
  exclude: ['*.id', '*.userId', 'rows.*.orderId']
});

// Exclude nested timestamps with custom names
expect(response).toMatchMCPSnapshot({
  exclude: ['data.users.*.createdAt', 'metadata.generatedAt']
});

Pattern Syntax:

  • field - Excludes top-level field
  • nested.field - Excludes nested field
  • array.*.field - Excludes field from all array items
  • data.users.*.createdAt - Excludes createdAt from all users in data.users
Performance

Snapshot testing with property exclusion adds negligible overhead:

| Data Size | Normalization Overhead | Notes | |-----------|----------------------|-------| | 10-100 items | { const result = await client.callTool('list_users', {}); const parsed = JSON.parse(result.content[0]?.text || '{}');

// Explicit assertions for critical properties expect(parsed.users).toHaveLength(50); expect(parsed.users[0]).toHaveProperty('name'); expect(parsed.users[0]).toHaveProperty('email');

// Snapshot for structure regression detection expect(result).toMatchToolResponseSnapshot(); });


See [examples/snapshot-example/](./examples/snapshot-example/) for complete working examples with benchmarks.

### Debug Logging

Safe debug logging that doesn't break JSON-RPC stdio communication.

#### The Problem

MCP servers communicate via JSON-RPC over stdio. Every message must be a single line of JSON on stdout:

{"jsonrpc":"2.0","method":"tools/list","params":{...}}\n


If you write anything else to stdout (like `console.log()`), it corrupts the stream:

Server starting... ← Breaks protocol! {"jsonrpc":"2.0","method":"tools/list","params":{...}}\n


Result: `SyntaxError: Unexpected token 'S'`

#### The Solution

**mcp-dev-kit redirects all console output to stderr**, keeping stdout clean:
- **stdout** = pure JSON-RPC (protocol)
- **stderr** = all your logs (debugging)

#### Auto-Patch (Recommended)

```typescript
// At the top of your MCP server file
import 'mcp-dev-kit/logger';

// Now console.log works without breaking JSON-RPC!
console.log('Server started', { port: 3000 });
console.info('Configuration loaded');
console.warn('Deprecated feature used');
console.error('Connection failed', error);

Opt-out:

MCP_DEV_KIT_NO_AUTO_PATCH=true node server.js
Manual Logger

For more control, create a custom logger instance:

import { createLogger } from 'mcp-dev-kit';

const logger = createLogger({
  timestamps: true,
  colors: true,
  level: 'info', // Only show info and above
  logFile: './server.log', // Optional file output
});

logger.info('Server starting...');
logger.warn('Configuration may need updating');
logger.error('Connection failed', { reason: 'timeout' });

// Cleanup when done
await logger.close();
Logger Features
  • Auto-patching - Just import and console.log works
  • Colored output - Color-coded log levels (auto-detects TTY)
  • Timestamps - ISO8601 timestamps on all logs
  • Object formatting - Pretty-print objects with util.inspect()
  • File logging - Optional async file output
  • Cleanup - Graceful restoration of original console
  • Zero overhead - Lightweight, uses picocolors (7 KB)
Configuration

Log Levels:

const logger = createLogger({ level: 'warn' });

logger.debug('Not shown');
logger.info('Not shown');
logger.warn('Shown');     // ✓
logger.error('Shown');    // ✓

Colors:

createLogger({ colors: false }); // Force disable
createLogger({ colors: true });  // Force enable
// Auto-detected by default based on process.stderr.isTTY

Timestamps:

createLogger({ timestamps: false }); // Disable
// ISO8601 format: 2024-11-03T12:34:56.789Z

File Logging:

const logger = createLogger({
  logFile: './server.log',
});

logger.info('This goes to both stderr and server.log');

// Flush pending writes
await logger.close();

Testing Guidelines

Test Structure

Organize your tests by MCP capabilities:

describe('My MCP Server', () => {
  let client: MCPTestClient;

  beforeAll(async () => {
    client = new MCPTestClient({ command: 'node', args: ['./server.js'] });
    await client.connect();
  });

  afterAll(async () => {
    await client.disconnect();
  });

  describe('Server Initialization', () => {
    it('should expose correct server info', () => {
      const info = client.getServerInfo();
      expect(info.name).toBe('my-server');
      expect(info.version).toBe('1.0.0');
    });

    it('should declare required capabilities', () => {
      const caps = client.getServerCapabilities();
      expect(caps.tools).toBeDefined();
    });
  });

  describe('Tools', () => {
    it('should list all available tools', async () => {
      const tools = await client.listTools();
      expect(tools).toHaveLength(3);
      expect(tools.map(t => t.name)).toEqual(['echo', 'calculate', 'search']);
    });

    it('should execute tools successfully', async () => {
      const result = await client.callTool('echo', { message: 'test' });
      expect(result.content[0]?.text).toBe('test');
    });

    it('should handle tool errors gracefully', async () => {
      const error = await client.expectToolCallError('calculate', { invalid: 'params' });
      expect(error.message).toContain('Invalid parameters');
    });

    it('should have stable tool schemas', async () => {
      const tools = await client.listTools();
      expect(tools).toMatchToolListSnapshot();
    });
  });

  describe('Resources', () => {
    it('should list available resources', async () => {
      await expect(client).toHaveResource('config://app.json');
    });

    it('should read resource content', async () => {
      const content = await client.readResource('config://app.json');
      expect(content.contents[0]?.text).toContain('version');
    });
  });

  describe('Prompts', () => {
    it('should provide defined prompts', async () => {
      await expect(client).toHavePrompt('greeting');
    });

    it('should render prompts with arguments', async () => {
      const prompt = await client.getPrompt('greeting', { name: 'Alice' });
      expect(prompt.messages[0]?.content.text).toContain('Alice');
    });
  });
});

Testing Best Practices

✅ DO:

  1. Test all MCP capabilities - Tools, resources, prompts
  2. Use descriptive test names - Clearly state what's being tested
  3. Combine matchers and snapshots - Explicit assertions + structure validation
  4. Test error cases - Don't just test happy paths
  5. Clean up resources - Always disconnect client in afterAll
  6. Use timeouts appropriately - Set reasonable timeouts for slow operations
  7. Test server lifecycle - Test initialization and shutdown

❌ DON'T:

  1. Don't share client state - Each test suite should have its own client
  2. Don't skip error testing - Error handling is critical
  3. Don't test implementation details - Test public API only
  4. Don't create flaky tests - Avoid timing-dependent assertions
  5. Don't ignore snapshots - Review snapshot changes carefully
  6. Don't hardcode system-specific paths - Use relative paths or env vars

Error Testing

Always test error conditions:

it('should validate tool parameters', async () => {
  const error = await client.expectToolCallError('calculate', {

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [gnana997](https://github.com/gnana997)
- **Source:** [gnana997/mcp-dev-kit](https://github.com/gnana997/mcp-dev-kit)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.