# MCP Testing

> MCP Testing Strategies with Vitest, Inspector, and Integration Tests Use when this capability is needed.

- Skill: `tomevault-io/mcp-testing` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/mcp-testing`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/mcp-testing/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/mcp-testing

---


# MCP Testing Skill

Modern testing strategies for Model Context Protocol (MCP) servers developed in VS Code using TypeScript, Bun, and Vitest.

## Unit Testing with Vitest & In-Memory Transport

### Setup Minimal Test Environment

```typescript
import { describe, it, expect, beforeEach } from "vitest";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/testing/inMemoryTransport.js";
import { RaindropMCPService } from "../src/services/raindropmcp.service.js";

describe("RaindropMCPService Tools", () => {
  let service: RaindropMCPService;
  let transport: InMemoryTransport;
  let client: Client;

  beforeEach(async () => {
    service = new RaindropMCPService();
    transport = new InMemoryTransport(service.getServer());
    client = new Client(
      {
        name: "test-client",
        version: "1.0.0",
      },
      { capabilities: {} },
    );
    await client.connect(transport);
  });

  it("should list available tools", async () => {
    const tools = await client.listTools();
    expect(tools.tools.length).toBeGreaterThan(0);
    expect(tools.tools.map((t) => t.name)).toContain("collection_list");
  });

  it("should call a tool with valid input", async () => {
    const result = await client.callTool({
      name: "collection_list",
      arguments: {},
    });
    expect(result).toBeDefined();
    expect(result.content).toBeDefined();
  });
});
```

### Key Testing Patterns

1. **In-Memory Transport**: Use for unit tests—no subprocess overhead, direct method invocation
2. **Server Capabilities**: Verify manifest before running tool tests
3. **Mock Context**: Provide mock `RaindropService` for isolated tool testing
4. **Error Handling**: Test both success and error paths with Zod validation

## Integration Testing with MCP Inspector

### Launch Inspector in VS Code

1. **Terminal > Run Task > "Debug HTTP Server with Inspector"** (or STDIO variant)
   - Opens Inspector at `http://localhost:3000` (or via auto-opened browser)
   - Live tool/resource exploration with bidirectional message capture

2. **Manual Inspection Flow**:
   - Call `diagnostics` tool → view server version and enabled tools
   - Call `collection_list` → see resource links to collections
   - Read collection resources by URI → validate dynamic resource handling
   - Test tool inputs directly with Inspector's form interface

3. **Record & Replay**:
   - Inspector logs all requests/responses
   - Copy test cases directly into Vitest from Inspector logs
   - Validate against snapshot tests

## Snapshot Testing for Tool Schemas

```typescript
import { describe, it, expect } from "vitest";
import { RaindropMCPService } from "../src/services/raindropmcp.service.js";

describe("Tool Schema Snapshots", () => {
  let service: RaindropMCPService;

  beforeEach(() => {
    service = new RaindropMCPService();
  });

  it("should maintain consistent tool schemas", async () => {
    const tools = await service.listTools();
    expect(tools).toMatchSnapshot();
  });
});
```

### Why Snapshot Testing?

- Catches unintended schema changes (breaking for LLM clients)
- Auto-generates golden files for schema validation
- Reduces boilerplate when verifying complex schemas

## Running Tests in VS Code

### Run Tests with Coverage

```bash
bun run test:coverage
```

Generates coverage reports showing:

- Line & branch coverage for tools
- Uncovered error paths
- Integration test coverage vs unit test coverage

### Watch Mode During Development

```bash
bun test --watch
```

- Re-runs tests on file changes
- Ideal for TDD workflows
- Vitest provides formatted output in terminal

## Load & Performance Testing

### Stress Test Tools with Concurrency

```typescript
it("should handle concurrent tool calls", async () => {
  const promises = Array.from({ length: 10 }, () =>
    client.callTool({
      name: "collection_list",
      arguments: {},
    }),
  );

  const results = await Promise.all(promises);
  expect(results).toHaveLength(10);
  expect(results.every((r) => r.content)).toBe(true);
});
```

### Measure Tool Latency

```typescript
it("should respond within acceptable latency", async () => {
  const start = performance.now();
  await client.callTool({
    name: "bookmark_search",
    arguments: { search: "test" },
  });
  const duration = performance.now() - start;

  expect(duration).toBeLessThan(5000); // 5s timeout for API calls
});
```

## Resource Testing

### Test Dynamic Resource Resolution

```typescript
it("should fetch and validate collection resources", async () => {
  const resources = await client.listResources();
  const collectionPattern = resources.resources.find((r) =>
    r.uri.includes("mcp://collection/"),
  );

  expect(collectionPattern).toBeDefined();

  // Read a specific collection
  const resourceData = await client.readResource({
    uri: "mcp://collection/12345",
  });

  expect(resourceData).toBeDefined();
  expect(Array.isArray(resourceData)).toBe(true);
  expect(resourceData[0].text).toBeDefined();
});
```

### Test Error Conditions

```typescript
it("should handle invalid resource URIs gracefully", async () => {
  expect(async () => {
    await client.readResource({ uri: "mcp://invalid/xyz" });
  }).rejects.toThrow();
});
```

## Recommended Dev Dependencies

### Testing & Quality

```json
{
  "devDependencies": {
    "vitest": "^4.0.0",
    "@vitest/coverage-v8": "^1.0.0",
    "@vitest/ui": "^1.0.0",
    "happy-dom": "^13.0.0"
  }
}
```

### Code Quality & Linting

```json
{
  "devDependencies": {
    "eslint": "^9.0.0",
    "@typescript-eslint/eslint-plugin": "^8.0.0",
    "@typescript-eslint/parser": "^8.0.0",
    "eslint-config-prettier": "^9.0.0",
    "prettier": "^3.0.0"
  }
}
```

### Debugging & Inspection

```json
{
  "devDependencies": {
    "@modelcontextprotocol/inspector": "^1.0.0"
  }
}
```

## References

- [Vitest Documentation](https://vitest.dev/)
- [MCP Testing Guide](https://modelcontextprotocol.io/)
- [MCP Inspector GitHub](https://github.com/modelcontextprotocol/inspector)

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/adeze) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-11 -->

