---
title: Testing
sidebarTitle: Overview
slug: testing/overview
icon: flask-vial
description: End-to-end testing framework for FrontMCP servers
keywords: ['frontmcp', 'mcp', 'model context protocol', 'testing', 'tests', 'jest', 'fixtures', 'typescript']
---

`@frontmcp/testing` is the official testing library for FrontMCP, providing a complete toolkit for end-to-end testing of MCP servers. Test your tools, resources, prompts, authentication, plugins, and the full MCP protocol.

<Columns cols={3}>
  <Card title="Fixture-Based" icon="puzzle-piece">
    Playwright-inspired fixtures inject ready-to-use test clients
  </Card>
  <Card title="Full Protocol" icon="code">
    Test tools, resources, prompts, and raw JSON-RPC
  </Card>
  <Card title="Offline Testing" icon="wifi-slash">
    Mock HTTP calls for fully offline test suites
  </Card>
</Columns>

---

## Installation

```bash
npm install -D @frontmcp/testing
```

<Info>
  `@frontmcp/testing` requires `@frontmcp/sdk` as a peer dependency and uses Jest as the test runner.
</Info>

---

## Quick Start

### 1. Configure Jest

The `frontmcp test` command auto-generates the correct Jest/SWC config. No
manual `jest.e2e.config.ts` needed.

By default the injected config discovers:

- Colocated unit specs: `src/**/*.spec.ts` and `src/**/*.spec.tsx`
- `__tests__/**/*.spec.ts(x)`
- E2E specs: `e2e/**/*.e2e.ts(x)` and `e2e/**/*.e2e.spec.ts(x)`

Both `.ts` and `.tsx` files are transformed via SWC with the automatic JSX
runtime, so React component tests work without extra setup.

<Info>
**Bring your own config.** If a `jest.config.{ts,js,mjs,cjs,json}` exists in
your project root, `frontmcp test` delegates to it instead of injecting the
default config. You can also drop a `jest.config.ts` to customise transforms,
projects, setup files, or coverage paths while still running via `frontmcp
test`.
</Info>

### 2. Write Your First Test

Use the `.spec.ts(x)` extension for unit tests colocated with your source
code, and `.e2e.spec.ts(x)` for E2E tests under an `e2e/` directory:

```ts title="server.e2e.spec.ts"
import { test, expect } from '@frontmcp/testing';

// Point to your FrontMCP server entry file
test.use({
  server: './src/main.ts',
  port: 3003,
});

test('server exposes tools', async ({ mcp }) => {
  const tools = await mcp.tools.list();
  expect(tools).toContainTool('my-tool');
});

test('tool execution works', async ({ mcp }) => {
  const result = await mcp.tools.call('my-tool', { input: 'test' });
  expect(result).toBeSuccessful();
  expect(result.json()).toHaveProperty('success', true);
});
```

### 3. Run Tests

```bash
# Recommended: auto-configures Jest/SWC
frontmcp test

# Using nx
nx e2e my-app
```

The library automatically:

- Starts your FrontMCP server on the specified port
- Connects an MCP client using Streamable-HTTP transport
- Runs your tests with injected fixtures
- Cleans up after all tests complete

---

## Key Features

### Fixture System

Tests receive pre-configured fixtures via dependency injection:

| Fixture  | Description                                               |
| -------- | --------------------------------------------------------- |
| `mcp`    | Auto-connected MCP client for making requests             |
| `server` | Server control (restart, logs, create additional clients) |
| `auth`   | Token factory for authentication testing                  |

```ts
test('example with all fixtures', async ({ mcp, server, auth }) => {
  // mcp: ready-to-use MCP client
  const tools = await mcp.tools.list();

  // auth: create test tokens
  const token = await auth.createToken({ sub: 'user-123', scopes: ['read'] });

  // server: create additional clients
  const client2 = await server.createClient({ token });
});
```

### Custom Jest Matchers

MCP-specific matchers for cleaner assertions:

```ts
// Tool matchers
expect(tools).toContainTool('create-note');

// Result matchers
expect(result).toBeSuccessful();
expect(result).toBeError(-32602);

// Content matchers
expect(result).toHaveTextContent();
expect(content).toHaveMimeType('application/json');

// Resource matchers
expect(resources).toContainResource('notes://all');
expect(templates).toContainResourceTemplate('notes://note/{id}');
```

### HTTP Mocking

Mock external HTTP calls for offline testing.

> **Important:** `httpMock` intercepts HTTP in the **test process** only, NOT in the MCP server subprocess. Do not use httpMock to intercept server-to-API calls — those happen in the child process. Use httpMock for verifying client-to-server request shapes or mocking external APIs called from the test itself.

```ts
import { httpMock } from '@frontmcp/testing';

test('tool with external API', async ({ mcp }) => {
  const interceptor = httpMock.interceptor();

  interceptor.get('https://api.example.com/users', {
    body: [{ id: 1, name: 'John' }],
  });

  const result = await mcp.tools.call('fetch-users', {});
  expect(result).toBeSuccessful();

  interceptor.restore();
});
```

### MCP Request Interception

Mock or modify MCP protocol requests:

```ts
test('mock tool response', async ({ mcp }) => {
  mcp.mock.tool('expensive-tool', { cached: true });

  const result = await mcp.tools.call('expensive-tool', {});
  expect(result.json()).toEqual({ cached: true });
});
```

---

## Test Configuration

Configure tests using `test.use()`:

```ts
test.use({
  // Server configuration
  server: './src/main.ts',    // Entry file path
  port: 3003,                  // Port (default: auto-select)
  startupTimeout: 30000,       // Startup timeout in ms

  // Transport
  transport: 'streamable-http', // 'sse' | 'streamable-http'

  // Authentication
  auth: {
    mode: 'public',            // 'public' | 'local' | 'remote'
  },

  // Debugging
  logLevel: 'debug',           // 'debug' | 'info' | 'warn' | 'error'
  env: { API_KEY: 'test' },    // Environment variables
});
```

<Tip>
  Use `port: 0` to automatically select an available port. This prevents conflicts when running multiple test suites in parallel.
</Tip>

---

## Demo E2E reference suites

The repository ships scenario-focused Nx projects under `apps/e2e/**`. Each server mirrors a real deployment surface (auth modes, caching, CodeCall, OpenAPI ingestion, notifications) and already includes Jest suites wired to `@frontmcp/testing`.

<Note>
  Source layout: server code lives in `apps/e2e/<project>/src`, with matching tests in `apps/e2e/<project>/e2e`. Copy a project into your workspace or point `TestServer` at it during CI runs.
</Note>

- `demo-e2e-public` – minimal Notes + Tasks server that enforces public auth defaults and anonymous scopes.
- `demo-e2e-codecall` – CRM sample that groups eight CRUD tools behind the CodeCall plugin and the new `crm.store.ts`.
- `demo-e2e-openapi` – OpenAPI adapter smoke tests with built-in HTTP mocking examples.
- `demo-e2e-cache` – Cache plugin playground for validating cache hits/misses plus execution tracking resources.

```ts title="apps/e2e/demo-e2e-public/e2e/public-auth.e2e.spec.ts"
test.use({
  server: 'apps/e2e/demo-e2e-public/src/main.ts',
  publicMode: true,
});

test.describe('Public Auth Mode E2E', () => {
  test('lists all tools without auth', async ({ mcp }) => {
    const tools = await mcp.tools.list();
    expect(tools).toContainTool('create-note');
  });
});
```

<Tip>
  Pair `apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.spec.ts` with `httpMock.interceptor()` to keep tests offline: stub Beeceptor endpoints, allow passthrough for the OpenAPI spec, then call `interceptor.restore()` in `finally`.
</Tip>

---

## Next Steps

<Columns cols={2}>
  <Card title="Test Fixtures" icon="puzzle-piece" href="/frontmcp/testing/fixtures">
    Deep dive into the fixture system and available APIs
  </Card>
  <Card title="Custom Matchers" icon="check-double" href="/frontmcp/testing/matchers">
    Full reference for all MCP-specific Jest matchers
  </Card>
  <Card title="Auth Testing" icon="key" href="/frontmcp/testing/authentication">
    Test authentication flows with token generation
  </Card>
  <Card title="HTTP Mocking" icon="globe" href="/frontmcp/testing/http-mocking">
    Mock external API calls for offline testing
  </Card>
</Columns>
