An open API service indexing awesome lists of open source software.

https://github.com/mcpland/mock-mcp

Mock MCP Server - AI-driven mock data orchestration with OpenAPI JSON Schema for testing
https://github.com/mcpland/mock-mcp

mcp-server mock mock-data openapi openapi-spec

Last synced: 9 days ago
JSON representation

Mock MCP Server - AI-driven mock data orchestration with OpenAPI JSON Schema for testing

Awesome Lists containing this project

README

          

# mock-mcp

![Node CI](https://github.com/mcpland/mock-mcp/workflows/Node%20CI/badge.svg)
[![npm](https://img.shields.io/npm/v/mock-mcp.svg)](https://www.npmjs.com/package/mock-mcp)
![license](https://img.shields.io/npm/l/mock-mcp)

Mock MCP Server - AI-generated mock data based on your **OpenAPI JSON Schema** definitions. The project uses a **Daemon + Adapter** architecture that enables multiple MCP clients (Cursor, Claude Desktop, etc.) to run simultaneously without port conflicts, while providing robust claim-based concurrency control for mock batch processing.

## Table of Contents

- [Quick Start](#quick-start)
- [Why Mock MCP](#why-mock-mcp)
- [What Mock MCP Does](#what-mock-mcp-does)
- [Architecture](#architecture)
- [Configure MCP Server](#configure-mcp-server)
- [Connect From Tests](#connect-from-tests)
- [Describe Requests with Metadata](#describe-requests-with-metadata)
- [MCP Tools](#mcp-tools)
- [CLI Commands](#cli-commands)
- [Available APIs](#available-apis)
- [Environment Variables](#environment-variables)
- [How It Works](#how-it-works)
- [Use the development scripts](#use-the-development-scripts)
- [License](#license)

## Quick Start

1. **Install the package.** Add mock-mcp as a dev dependency inside your project.

```bash
npm install -D mock-mcp
# or
yarn add -D mock-mcp
# or
pnpm add -D mock-mcp
```

2. **Configure the Model Context Protocol server.** Add mock-mcp to your MCP client configuration (Cursor, Claude Desktop, etc.):

```json
{
"mcpServers": {
"mock-mcp": {
"command": "npx",
"args": ["-y", "mock-mcp@latest", "adapter"]
}
}
}
```

> **Note:** The `adapter` command connects to a shared daemon process that is automatically started when needed. This eliminates port conflicts when running multiple MCP clients simultaneously.

3. **Connect from your tests.** Use `connect` to retrieve a mock client and request data for intercepted calls.

```ts
import { render, screen, fireEvent } from "@testing-library/react";
import { connect } from "mock-mcp";

const userSchema = {
summary: "Fetch the current user",
response: {
type: "object",
required: ["id", "name"],
properties: {
id: { type: "number" },
name: { type: "string" },
},
},
};

it("example", async () => {
const mockClient = await connect();
const metadata = {
schemaUrl: "https://example.com/openapi.json#/paths/~1user/get",
schema: userSchema,
instructions: "Respond with a single user described by the schema.",
};

fetchMock.get("/user", async () => {
const response = await mockClient.requestMock("/user", "GET", { metadata }) // add mock via mock-mcp
return response.data
});

const result = await fetch("/user");
const data = await result.json();
expect(data).toEqual({ id: 1, name: "Jane" });
}, 10 * 60 * 1000); // 10 minute timeout for AI interaction
```

4. **Run with MCP enabled.** Prompt your AI client to run the persistent test command and provide mocks through the tools.

```
Please run the persistent test: `MOCK_MCP=true npm test test/example.test.tsx` and mock fetch data with mock-mcp
```

## Why Mock MCP

### The Problem with Traditional Mock Approaches

Testing modern web applications often feels like preparing for a battle—you need the right weapons (test cases), ammunition (mock data), and strategy (test logic). But creating mock data has always been the most tedious part:

```typescript
// Traditional approach: Manual fixture hell
const mockUsers = [
{ id: 1, name: "Alice", email: "alice@example.com", role: "admin", ... },
{ id: 2, name: "Bob", email: "bob@example.com", role: "user", ... },
// ... 50 more lines of boring manual data entry
];
```

**Common Pain Points:**

| Challenge | Traditional Solutions | Limitations |
| --------------------------- | ------------------------------- | ------------------------------------------- |
| **Creating Realistic Data** | Manual JSON files or faker.js | ❌ Time-consuming, lacks business logic |
| **Complex Scenarios** | Hardcoded edge cases | ❌ Difficult to maintain, brittle |
| **Evolving Requirements** | Update fixtures manually | ❌ High maintenance cost |
| **Learning Curve** | New team members write fixtures | ❌ Steep learning curve for complex domains |
| **CI/CD Integration** | Static fixtures only | ❌ Can't adapt to new scenarios |

### The Mock MCP Innovation

Mock MCP introduces a **paradigm shift**: instead of treating mock data as static artifacts, it makes them **AI-generated, interactive, and evolvable**.

```
Traditional: Write Test → Create Fixtures → Run Test → Maintain Fixtures
↑ ↓
└──────── Pain Loop ───────┘

Mock MCP: Write Test → AI Generates Data (Schema-Compliant) → Run Test → Solidify Code
↑ ↓
└───────────── Evolution ────────────┘
```

### Schema-Driven Accuracy

Unlike "hallucinated" mocks, Mock MCP uses your actual **OpenAPI JSON Schema** definitions to ground the AI. This ensures that generated data not only looks real but strictly adheres to your API contracts, catching integration issues early.

## What Mock MCP Does

Mock MCP uses a **Daemon + Adapter** architecture to move intercepted requests from tests to AI helpers and back again.

- **Schema-aware generation** uses your provided metadata (OpenAPI JSON Schema) to ensure mocks match production behavior.
- **Batch-aware test client** collects every network interception inside a single macrotask and waits for the full response set.
- **Claim-based concurrency** prevents multiple AI clients from racing on the same batch through lease-based locking.
- **Multi-run isolation** supports concurrent test processes with distinct run IDs.
- **IPC-based communication** uses Unix Domain Sockets (macOS/Linux) or Named Pipes (Windows) instead of TCP ports, eliminating port conflicts.
- **Timeouts, TTLs, and cleanup** guard the test runner from stale batches or disconnected clients.

## Architecture

The v0.4.0 release introduces a new **Daemon + Adapter** architecture that fundamentally solves the "multiple MCP clients" problem:

```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Test Process │ │ Daemon │ │ Adapter │
│ (your tests) │────▶│ (per-project) │◀────│ (per MCP client)│
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ WebSocket/IPC │ JSON-RPC/IPC │ MCP stdio
│ │ │
▼ ▼ ▼
BatchMockCollector Mock Bridge Daemon MCP Tools
- Auto-discovers - Manages runs/batches - claim_next_batch
- Sends batches - Claim/lease control - provide_batch_mock_data
- Receives mocks - Multi-client safe - get_status, list_runs
```

**Key Benefits:**

- Single daemon per project (no per-client server instances)
- IPC communication
- Full multi-client support
- Claim-based concurrency (no race conditions)
- Auto-discovery (no manual configuration)

## Configure MCP Server

Add mock-mcp to your MCP client configuration. The adapter automatically discovers or starts the daemon for your project:

```json
{
"mcpServers": {
"mock-mcp": {
"command": "npx",
"args": ["-y", "mock-mcp", "adapter"]
}
}
}
```

**That's it!** The daemon uses IPC (Unix Domain Sockets on macOS/Linux, Named Pipes on Windows) which:

- Eliminates port conflicts between multiple MCP clients
- Automatically shares state between all adapters in the same project
- Requires no manual coordination or environment variables

Restart your MCP client and confirm that the `mock-mcp` server exposes the tools (`get_status`, `claim_next_batch`, `provide_batch_mock_data`, etc.).

## Connect From Tests

Tests call `connect` to spin up a `BatchMockCollector` that automatically discovers and connects to the daemon:

```ts
// tests/mocks.ts
import { connect } from "mock-mcp";

// Auto-discovers daemon via IPC
const mockClient = await connect({
timeout: 60000,
});

await page.route("**/api/users", async (route) => {
const url = new URL(route.request().url());
const { data } = await mockClient.requestMock(
url.pathname,
route.request().method()
);

await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(data),
});
});
```

Batch behaviour stays automatic: additional `requestMock` calls issued in the same macrotask are grouped, forwarded, and resolved together.

Need to pause the test until everything in-flight resolves? Call `waitForPendingRequests` to block on the current set of pending requests (anything started after the call is not included):

```ts
// After routing a few requests
await mockClient.waitForPendingRequests();
// Safe to assert on the results produced by the mocked responses
```

**Multiple test processes** can run concurrently - each gets a unique `runId` and their batches are isolated from each other.

## Describe Requests with Metadata

`requestMock` accepts an optional third argument (`RequestMockOptions`) that is forwarded without modification to the MCP server. The most important field in that object is `metadata`, which lets the test process describe each request with the exact OpenAPI JSON Schema fragment, sample payloads, or test context that the AI client needs to build a response.

When an MCP client calls `get_pending_batches`, every `requests[].metadata` entry from the test run is included in the response. That is the channel the LLM uses to understand the requested endpoint before supplying data through `provide_batch_mock_data`. Metadata is also persisted when batch logging is enabled, so you can audit what was sent to the model.

```ts
const listProductsSchema = {
summary: "List products by popularity",
response: {
type: "array",
items: {
type: "object",
required: ["id", "name", "price"],
properties: {
id: { type: "string" },
name: { type: "string" },
price: { type: "number" },
},
},
},
};

await mockClient.requestMock("/api/products", "GET", {
metadata: {
// Link or embed the authoritative contract for the AI to follow.
schemaUrl:
"https://shop.example.com/openapi.json#/paths/~1api~1products/get",
schema: listProductsSchema,
instructions:
"Return 3 popular products with stable ids so the UI can snapshot them.",
testFile: expect.getState().testPath,
},
});
```

**Tips for useful metadata**

- Embed the OpenAPI/JSON Schema snippet (or a reference URL) that describes the response structure for the intercepted endpoint.
- Include contextual hints such as the test name, scenario, user role, or seed data so the model can mirror your expected fixtures.
- Keep the metadata JSON-serializable and deterministic; large binary blobs or class instances will be dropped.
- Reuse helper functions to centralize schema definitions so each test only supplies the endpoint-specific instructions.

## MCP Tools

The new architecture provides a richer set of tools with claim-based concurrency control:

| Tool | Purpose | Input |
| ------------------------- | ----------------------------------------------- | ------------------------------------------ |
| `get_status` | Get daemon status (runs, pending, claimed) | None |
| `list_runs` | List all active test runs | None |
| `claim_next_batch` | Claim the next pending batch (with lease) | `{ runId?, leaseMs? }` |
| `get_batch` | Get details of a specific batch (read-only) | `{ batchId }` |
| `provide_batch_mock_data` | Provide mock data for a claimed batch | `{ batchId, claimToken, mocks }` |
| `release_batch` | Release a claimed batch without providing mocks | `{ batchId, claimToken, reason? }` |

### Workflow

The new workflow uses **claim → provide** to prevent race conditions:

1. **Claim a batch** - Call `claim_next_batch` to acquire a lease on a pending batch
2. **Receive batch details** - Get `batchId`, `claimToken`, and `requests` array
3. **Generate mocks** - Create mock responses for each request
4. **Provide mocks** - Call `provide_batch_mock_data` with the claim token

```jsonc
// Step 1: Claim
{
"name": "claim_next_batch",
"arguments": { "leaseMs": 30000 }
}
// Returns: { "batchId": "batch:abc:1", "claimToken": "xyz", "requests": [...] }

// Step 2: Provide
{
"name": "provide_batch_mock_data",
"arguments": {
"batchId": "batch:abc:1",
"claimToken": "xyz",
"mocks": [
{ "requestId": "req-1", "data": { "id": 1, "name": "Alice" } }
]
}
}
```

**Lease expiration**: If you don't provide mocks within the lease time (default 30s), the batch is automatically released for another adapter to claim.

## CLI Commands

| Command | Description |
| ------------------- | ----------------------------------------------------- |
| `mock-mcp adapter` | Start the MCP adapter (default, for MCP clients) |
| `mock-mcp daemon` | Start the daemon process (usually auto-started) |
| `mock-mcp status` | Show daemon status for current project |
| `mock-mcp stop` | Stop the daemon for current project |
| `mock-mcp help` | Show help |
| `mock-mcp version` | Show version |

Example usage:

```bash
# Check if daemon is running
mock-mcp status

# Manually stop daemon
mock-mcp stop
```

## Available APIs

The library exports primitives so you can embed the workflow inside bespoke runners or scripts:

### Client APIs

- `connect(options?)` - Creates a `BatchMockCollector` and waits for daemon connection.
- `BatchMockCollector` - Low-level batching client for test environments.
- `BatchMockCollector.requestMock(endpoint, method, options?)` - Request mock data for an endpoint.
- `BatchMockCollector.waitForPendingRequests()` - Wait for pending requests to settle.
- `BatchMockCollector.getRunId()` - Get the unique run ID for this collector.

### Server APIs

- `MockMcpDaemon` - The daemon process that manages runs and batches.
- `runAdapter()` - Start the MCP adapter (stdio transport).
- `DaemonClient` - JSON-RPC client for communicating with the daemon.

### Discovery APIs

- `ensureDaemonRunning(options?)` - Ensure daemon is running, start if needed.
- `resolveProjectRoot(startDir?)` - Find project root by searching for `.git` or `package.json`.
- `computeProjectId(projectRoot)` - Compute stable project ID from path.

Each class accepts logger overrides, timeout tweaks, and other ergonomics.

## Environment Variables

| Variable | Description | Default |
| -------------------- | ------------------------------------------------------------------------ | ------------------ |
| `MOCK_MCP` | Enables the test runner hook so intercepted requests are routed to mock-mcp. | unset |
| `MOCK_MCP_CACHE_DIR` | Override the cache directory for daemon files (registry, socket, lock). | `~/.cache/mock-mcp`|

## How It Works

The new **Daemon + Adapter** architecture uses four collaborating processes:

| Process | Responsibility | Technology | Communication |
| ---------------- | ----------------------------------------------------- | ---------------------------------------- | ------------------------------- |
| **Test Process** | Executes test cases and intercepts HTTP requests | Playwright/Puppeteer + BatchMockCollector| WebSocket over IPC → Daemon |
| **Daemon** | Manages runs, batches, claims with lease control | Node.js + HTTP/WS on Unix socket | IPC ↔ Test & Adapter |
| **Adapter** | Bridges MCP protocol to daemon RPC | Node.js + MCP SDK (stdio) | stdio ↔ MCP Client, RPC → Daemon|
| **MCP Client** | Uses AI to produce mock data via MCP tools | Cursor / Claude Desktop / custom clients | MCP protocol → Adapter |

### Data flow sequence with claim-based concurrency

```
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Test Process │ │ Daemon │ │ Adapter │ │ MCP Client │
│ (Browser Test) │ │ (per-project) │ │ (per MCP client) │ │ (AI) │
└────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘
│ │ │ │
│ 1. Connect via IPC │ │ │
│ HELLO_TEST │ │ │
├════════════════════════►│ │ │
│ │ │ │
│ 2. HELLO_ACK │ │ │
│◄════════════════════════┤ │ │
│ │ │ │
│ 3. BATCH_MOCK_REQUEST │ │ │
│ [req-1, req-2, ...] │ │ │
├════════════════════════►│ │ │
│ │ │ │
│ Test paused... │ 4. Store in pending │ │
│ Awaiting mocks │ queue │ │
│ │ │ │
│ │ │◄────────────────────────┤
│ │ │ 5. claim_next_batch │
│ │ │ │
│ │◄────────────────────────┤ │
│ │ 6. RPC: claimNextBatch │ │
│ │ │ │
│ ├────────────────────────►│ │
│ │ 7. {batch, claimToken} │ │
│ │ │ │
│ │ ├────────────────────────►│
│ │ │ 8. Return batch info │
│ │ │ │
│ │ │ 9. AI generates │
│ │ │ mock data │
│ │ │ │
│ │ │◄────────────────────────┤
│ │ │ 10. provide_batch_ │
│ │ │ mock_data │
│ │ │ │
│ │◄────────────────────────┤ │
│ │ 11. RPC: provideBatch │ │
│ │ + claimToken │ │
│ │ │ │
│ 12. BATCH_MOCK_RESULT │ │ │
│ [mock-1, mock-2] │ │ │
│◄════════════════════════┤ │ │
│ │ │ │
│ 13. Resolve promises │ │ │
│ Test continues │ │ │
▼ ▼ ▼ ▼

Protocol Summary:
─────────────────
- Test Process ←→ Daemon: WebSocket over IPC (Unix socket / Named pipe)
Message types: HELLO_TEST, BATCH_MOCK_REQUEST, BATCH_MOCK_RESULT

- Adapter ←→ Daemon: HTTP JSON-RPC over IPC
Methods: claimNextBatch, provideBatch, getStatus, listRuns

- MCP Client ←→ Adapter: MCP protocol (stdio)
Tools: claim_next_batch, provide_batch_mock_data, get_status, list_runs

Key Features:
──────────────
✓ uses IPC instead of TCP - No port conflicts
✓ Multi-client support - multiple MCP clients can run simultaneously
✓ Claim-based concurrency - prevents race conditions on batches
✓ Lease expiration - auto-recovery if adapter crashes
✓ Multi-run isolation - concurrent test processes are isolated
✓ Auto-discovery - no manual configuration needed
```

## Use the development scripts

```bash
yarn test # runs Vitest suites
yarn test:concurrency # runs concurrency tests specifically
yarn dev # tsx watch mode for the CLI
yarn dev:adapter # tsx watch mode for adapter
yarn lint # eslint --ext .ts
yarn build # compile TypeScript
```

Tests create isolated daemon instances with temporary cache directories, so they can run safely without affecting your development environment.

## License

MIT