Back to list
adeze

mcp-testing

by adeze

Raindrop MCP Server

108🍴 19📅 Jan 23, 2026

SKILL.md


name: mcp-testing description: MCP Testing Strategies with Vitest, Inspector, and Integration Tests keywords: [mcp, testing, vitest, inspector, unit-tests, integration-tests, ci-cd]

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

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

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

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

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

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

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

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

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

Testing & Quality

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

Code Quality & Linting

{
  "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

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

References

Score

Total Score

75/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

+5
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

+5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon