> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing

> End-to-end testing framework for FrontMCP servers

`@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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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

Create or update your `jest.e2e.config.ts`:

```ts title="jest.e2e.config.ts" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
import type { Config } from 'jest';

const config: Config = {
  displayName: 'e2e',
  preset: '@frontmcp/testing/jest-preset',
  testMatch: ['**/*.e2e.ts'],
  testTimeout: 30000,
};

export default config;
```

### 2. Write Your First Test

```ts title="server.e2e.ts" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
# Using jest directly
npx jest --config jest.e2e.config.ts

# 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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
// 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 made by your tools for offline testing:

```ts theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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 theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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' | 'orchestrated'
    type: 'local',             // '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.test.ts" theme={"theme":{"light":"snazzy-light","dark":"dark-plus"}}
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.test.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>
