Skip to main content
Complete API documentation for all @frontmcp/testing exports, types, and methods.

Test Function

test

The main test function with fixture injection.
import { test } from '@frontmcp/testing';

test('description', async ({ mcp, auth, server }) => {
  // Test implementation
});

// Describe blocks
test.describe('group name', () => {
  test('test 1', async ({ mcp }) => {});
  test('test 2', async ({ mcp }) => {});
});

// Skip tests
test.skip('skipped test', async ({ mcp }) => {});

// Only run this test
test.only('focused test', async ({ mcp }) => {});

test.use

Configure fixtures for a test file.
test.use(options: TestOptions): void
OptionTypeDefaultDescription
serverstringPath to server entry file (required)
portnumberAutoPort to run server on
transport'sse' | 'streamable-http''streamable-http'Transport protocol
authAuthOptionsAuthentication configuration
logLevel'debug' | 'info' | 'warn' | 'error''warn'Server log level
envRecord<string, string>Environment variables
startupTimeoutnumber30000Startup timeout in ms
baseUrlstringConnect to existing server

McpTestClient

The primary fixture for testing MCP servers.

Tools API

tools.list

List all available tools.
mcp.tools.list(): Promise<Tool[]>
Returns: Array of tool definitions with name, description, and inputSchema.

tools.call

Call a tool with arguments.
mcp.tools.call(name: string, args: Record<string, unknown>): Promise<ToolResult>
ParameterTypeDescription
namestringTool name
argsRecord<string, unknown>Tool arguments
Returns: ToolResult with methods:
interface ToolResult {
  // Status checks
  isSuccess: boolean;
  isError: boolean;

  // Content accessors
  text(): string;                    // Get text content
  json<T = unknown>(): T;            // Parse JSON content
  image(): { data: string; mimeType: string };

  // Raw access
  raw: CallToolResult;               // Raw MCP response
  content: Content[];                // Content array

  // Error info (if isError)
  error?: { code: number; message: string };
}

Resources API

resources.list

List static resources.
mcp.resources.list(): Promise<Resource[]>
Returns: Array of resources with uri, name, description, and mimeType.

resources.listTemplates

List resource templates.
mcp.resources.listTemplates(): Promise<ResourceTemplate[]>
Returns: Array of templates with uriTemplate, name, and description.

resources.read

Read a resource by URI.
mcp.resources.read(uri: string): Promise<ResourceContent>
Returns: ResourceContent with methods:
interface ResourceContent {
  text(): string;                    // Get text content
  json<T = unknown>(): T;            // Parse JSON content
  blob(): Uint8Array;                // Get binary content
  mimeType: string;                  // Content MIME type
  uri: string;                       // Resource URI
  raw: ReadResourceResult;           // Raw MCP response
}

Prompts API

prompts.list

List available prompts.
mcp.prompts.list(): Promise<Prompt[]>
Returns: Array of prompts with name, description, and arguments.

prompts.get

Get a prompt with arguments.
mcp.prompts.get(name: string, args?: Record<string, string>): Promise<PromptResult>
Returns: PromptResult with:
interface PromptResult {
  messages: PromptMessage[];         // Array of messages
  description?: string;              // Optional description
}

interface PromptMessage {
  role: 'user' | 'assistant';
  content: TextContent | ImageContent | EmbeddedResource;
}

Session & Connection

isConnected

Check connection status.
mcp.isConnected(): boolean

sessionId

Get the current session ID.
mcp.sessionId: string | undefined

serverInfo

Get server information.
mcp.serverInfo: {
  name: string;
  version: string;
}

protocolVersion

Get the MCP protocol version.
mcp.protocolVersion: string

capabilities

Get server capabilities.
mcp.capabilities: ServerCapabilities

hasCapability

Check for a specific capability.
mcp.hasCapability(name: 'tools' | 'resources' | 'prompts'): boolean

authenticate

Authenticate the client with a JWT token.
mcp.authenticate(token: string): Promise<void>

disconnect

Disconnect from the server.
mcp.disconnect(): Promise<void>

Raw Protocol API

raw.request

Send a raw JSON-RPC request.
mcp.raw.request(request: JsonRpcRequest): Promise<JsonRpcResponse>
interface JsonRpcRequest {
  jsonrpc: '2.0';
  id: number | string;
  method: string;
  params?: unknown;
}

interface JsonRpcResponse {
  jsonrpc: '2.0';
  id: number | string;
  result?: unknown;
  error?: { code: number; message: string; data?: unknown };
}

raw.notify

Send a JSON-RPC notification (no response expected).
mcp.raw.notify(notification: JsonRpcNotification): Promise<void>

raw.sendRaw

Send raw string data (for testing parse errors).
mcp.raw.sendRaw(data: string): Promise<JsonRpcResponse>

Logging & Tracing

logs.all

Get all captured logs.
mcp.logs.all(): LogEntry[]

logs.filter

Filter logs by level.
mcp.logs.filter(level: 'debug' | 'info' | 'warn' | 'error'): LogEntry[]
Search logs by text.
mcp.logs.search(query: string): LogEntry[]

logs.clear

Clear captured logs.
mcp.logs.clear(): void

trace.all

Get all request traces.
mcp.trace.all(): RequestTrace[]
interface RequestTrace {
  method: string;
  params: unknown;
  response: unknown;
  durationMs: number;
  timestamp: Date;
}

trace.last

Get the last request trace.
mcp.trace.last(): RequestTrace | undefined

trace.clear

Clear request traces.
mcp.trace.clear(): void

Auth Fixture

The auth fixture generates JWT tokens for authentication testing.

createToken

Create a valid JWT token.
auth.createToken(options: TokenOptions): Promise<string>
interface TokenOptions {
  sub: string;                              // Subject (required)
  scopes?: string[];                        // OAuth scopes
  email?: string;                           // Email claim
  name?: string;                            // Name claim
  claims?: Record<string, unknown>;         // Custom claims
  expiresIn?: number;                       // Lifetime in seconds (default: 3600)
}

createExpiredToken

Create an expired token for testing expiration handling.
auth.createExpiredToken(options: Omit<TokenOptions, 'expiresIn'>): Promise<string>

createInvalidToken

Create a token with an invalid signature.
auth.createInvalidToken(options: TokenOptions): string

users

Pre-built test user configurations.
auth.users: {
  admin: { sub: 'test-admin', scopes: ['*'] };
  user: { sub: 'test-user', scopes: ['read', 'write'] };
  readOnly: { sub: 'test-readonly', scopes: ['read'] };
}

getJwks

Get the public JWKS for token verification.
auth.getJwks(): Promise<JsonWebKeySet>

getIssuer

Get the token issuer.
auth.getIssuer(): string

getAudience

Get the token audience.
auth.getAudience(): string

Server Fixture

The server fixture provides server control.

info

Server information.
server.info: {
  baseUrl: string;
  port: number;
  pid: number;
}

createClient

Create an additional MCP client.
server.createClient(options?: ClientOptions): Promise<McpTestClient>
interface ClientOptions {
  transport?: 'sse' | 'streamable-http';
  token?: string;
}

restart

Restart the server.
server.restart(): Promise<void>

getLogs

Get server-side logs.
server.getLogs(): string[]

clearLogs

Clear server logs.
server.clearLogs(): void

MockOAuthServer

A fully-functional mock OAuth 2.0 / OpenID Connect server for testing authentication flows.

Constructor

import { MockOAuthServer, TestTokenFactory } from '@frontmcp/testing';

const tokenFactory = new TestTokenFactory();
const server = new MockOAuthServer(tokenFactory, options?: MockOAuthServerOptions);

MockOAuthServerOptions

interface MockOAuthServerOptions {
  port?: number;                              // Port to listen on (default: auto)
  autoApprove?: boolean;                      // Auto-approve authorization requests
  testUser?: MockTestUser;                    // User info for authorized sessions
  clientId?: string;                          // Expected client_id
  clientSecret?: string;                      // Expected client_secret (optional)
  validRedirectUris?: string[];               // Allowed redirect URIs (supports wildcards)
  accessTokenTtlSeconds?: number;             // Access token lifetime (default: 3600)
  refreshTokenTtlSeconds?: number;            // Refresh token lifetime (default: 2592000)
  debug?: boolean;                            // Enable debug logging
}

MockTestUser

interface MockTestUser {
  sub: string;                                // Subject identifier (required)
  email?: string;                             // Email claim
  name?: string;                              // Name claim
  picture?: string;                           // Picture URL claim
  claims?: Record<string, unknown>;           // Additional claims
}

Methods

start

Start the OAuth server.
server.start(): Promise<MockOAuthServerInfo>

stop

Stop the OAuth server.
server.stop(): Promise<void>

setAutoApprove

Enable or disable auto-approval of authorization requests.
server.setAutoApprove(enabled: boolean): void

setTestUser

Set the test user for authorized sessions.
server.setTestUser(user: MockTestUser): void

addValidRedirectUri

Add a valid redirect URI pattern.
server.addValidRedirectUri(uri: string): void

clearStoredTokens

Clear all stored authorization codes and refresh tokens.
server.clearStoredTokens(): void

getTokenFactory

Get the token factory used by this server.
server.getTokenFactory(): TestTokenFactory

Properties

info

Server information (available after start()).
interface MockOAuthServerInfo {
  baseUrl: string;                            // Base URL (e.g., http://localhost:8080)
  port: number;                               // Listening port
  issuer: string;                             // Token issuer URL
  jwksUrl: string;                            // JWKS endpoint URL
}

Supported Endpoints

EndpointDescription
/.well-known/openid-configurationOpenID Connect discovery
/.well-known/oauth-authorization-serverOAuth 2.0 metadata
/.well-known/jwks.jsonJSON Web Key Set
/oauth/authorizeAuthorization endpoint
/oauth/tokenToken endpoint
/userinfoUserInfo endpoint

Supported Grant Types

  • authorization_code - Standard OAuth 2.0 authorization code flow
  • refresh_token - Token refresh
  • anonymous - Issue anonymous tokens (for testing)

Example

import { test } from '@frontmcp/testing';
import { MockOAuthServer, TestTokenFactory } from '@frontmcp/testing';

test.describe('OAuth integration', () => {
  let oauthServer: MockOAuthServer;

  test.beforeAll(async () => {
    const tokenFactory = new TestTokenFactory();
    oauthServer = new MockOAuthServer(tokenFactory, {
      autoApprove: true,
      testUser: { sub: 'user-123', email: 'test@example.com' },
      clientId: 'my-client',
      validRedirectUris: ['http://localhost:*/callback'],
    });
    await oauthServer.start();
  });

  test.afterAll(async () => {
    await oauthServer.stop();
  });

  test('should complete OAuth flow', async () => {
    // Construct endpoints from baseUrl:
    // `${oauthServer.info.baseUrl}/oauth/authorize`
    // `${oauthServer.info.baseUrl}/oauth/token`
  });
});

MockCimdServer

Mock server for CIMD (Client ID Metadata Documents) testing. Serves client metadata documents at configurable paths, allowing testing of OAuth flows with dynamic client registration via CIMD.

Constructor

import { MockCimdServer } from '@frontmcp/testing';

const cimdServer = new MockCimdServer(options?: MockCimdServerOptions);

MockCimdServerOptions

interface MockCimdServerOptions {
  port?: number;                            // Port to listen on (default: random available port)
  debug?: boolean;                          // Enable debug logging
}

MockCimdClientOptions

Options for registering a mock CIMD client.
interface MockCimdClientOptions {
  name: string;                             // Human-readable name (also used for URL path)
  path?: string;                            // Custom path (default: derived from name)
  redirectUris?: string[];                  // Redirect URIs (default: ['http://localhost:3000/callback'])
  tokenEndpointAuthMethod?: 'none' | 'client_secret_basic' | 'client_secret_post' | 'private_key_jwt';
  grantTypes?: string[];                    // OAuth grant types (default: ['authorization_code'])
  responseTypes?: string[];                 // OAuth response types (default: ['code'])
  clientUri?: string;                       // Client home page URL
  logoUri?: string;                         // Client logo URL
  scope?: string;                           // Requested OAuth scopes (space-separated)
  contacts?: string[];                      // Contact emails
}

Methods

start

Start the mock CIMD server.
cimdServer.start(): Promise<MockCimdServerInfo>

stop

Stop the mock CIMD server.
cimdServer.stop(): Promise<void>

registerClient

Register a client and return its client_id URL.
cimdServer.registerClient(options: MockCimdClientOptions): string
Returns the client_id URL to use in OAuth flows (e.g., http://localhost:PORT/clients/test-client/metadata.json).

getClientId

Get the client_id URL for a previously registered client.
cimdServer.getClientId(name: string): string

removeClient

Remove a registered client.
cimdServer.removeClient(name: string): void

clear

Clear all registered clients and custom responses.
cimdServer.clear(): void

registerInvalidDocument

Register an invalid document for error testing.
cimdServer.registerInvalidDocument(path: string, document: unknown): void

registerFetchError

Register a custom error response for a path.
cimdServer.registerFetchError(path: string, statusCode: number, body?: unknown): void

Property

info

Server info (only available after start()).
cimdServer.info: MockCimdServerInfo
interface MockCimdServerInfo {
  baseUrl: string;                          // Base URL of the server
  port: number;                             // Port the server is listening on
}

Example

import { test } from '@frontmcp/testing';
import { MockCimdServer } from '@frontmcp/testing';

test.describe('CIMD integration', () => {
  let cimdServer: MockCimdServer;

  test.beforeAll(async () => {
    cimdServer = new MockCimdServer();
    await cimdServer.start();
  });

  test.afterAll(async () => {
    await cimdServer.stop();
  });

  test('should use CIMD client_id in OAuth flow', async () => {
    // Register a client
    const clientId = cimdServer.registerClient({
      name: 'Test Client',
      redirectUris: ['http://localhost:3000/callback'],
    });

    // clientId is now a URL like:
    // http://localhost:PORT/clients/test-client/metadata.json

    // Use clientId in OAuth flow
    // The OAuth server will fetch the metadata from this URL
  });

  test('should test error handling', async () => {
    // Register an error response
    cimdServer.registerFetchError('/clients/broken/metadata.json', 500);

    // Test how your code handles CIMD fetch failures
  });
});

TestTokenFactory

Factory for creating JWT tokens for testing authentication.

Constructor

import { TestTokenFactory } from '@frontmcp/testing';

const factory = new TestTokenFactory(options?: TokenFactoryOptions);

TokenFactoryOptions

interface TokenFactoryOptions {
  issuer?: string;                            // Token issuer (default: 'https://test-issuer.local')
  audience?: string;                          // Token audience (default: 'test-audience')
  expiresInSeconds?: number;                  // Default token lifetime (default: 3600)
}

Methods

createTestToken

Create a token with custom claims.
factory.createTestToken(options: CreateTokenOptions): Promise<string>
interface CreateTokenOptions {
  sub: string;                                // Subject (required)
  scopes?: string[];                          // OAuth scopes
  email?: string;                             // Email claim
  name?: string;                              // Name claim
  claims?: Record<string, unknown>;           // Custom claims
  expiresIn?: number;                         // Lifetime in seconds
}

createAdminToken

Create a token with admin privileges.
factory.createAdminToken(): Promise<string>
Returns a token with sub: 'test-admin' and scopes: ['*'].

createUserToken

Create a token with standard user privileges.
factory.createUserToken(): Promise<string>
Returns a token with sub: 'test-user' and scopes: ['read', 'write'].

createAnonymousToken

Create an anonymous token.
factory.createAnonymousToken(): Promise<string>
Returns a token with sub: 'anonymous' and no scopes.

createExpiredToken

Create an already-expired token for testing expiration handling.
factory.createExpiredToken(options: Omit<CreateTokenOptions, 'expiresIn'>): Promise<string>

createTokenWithInvalidSignature

Create a token with an invalid signature for testing signature verification.
factory.createTokenWithInvalidSignature(options: CreateTokenOptions): string

getPublicJwks

Get the public JWKS for token verification.
factory.getPublicJwks(): JsonWebKeySet

getIssuer

Get the token issuer.
factory.getIssuer(): string

getAudience

Get the token audience.
factory.getAudience(): string

Example

import { TestTokenFactory } from '@frontmcp/testing';

const factory = new TestTokenFactory({
  issuer: 'https://auth.example.com',
  audience: 'my-api',
});

// Create various token types
const adminToken = await factory.createAdminToken();
const userToken = await factory.createUserToken();
const customToken = await factory.createTestToken({
  sub: 'custom-user',
  scopes: ['read', 'write', 'delete'],
  email: 'custom@example.com',
  claims: { tenant_id: 'tenant-123' },
});

// For testing error cases
const expiredToken = await factory.createExpiredToken({ sub: 'user' });
const invalidToken = factory.createTokenWithInvalidSignature({ sub: 'user' });

// Get JWKS for server configuration
const jwks = factory.getPublicJwks();

Mock Registry

The mcp.mock API for mocking MCP responses.

mock.add

Add a mock definition.
mcp.mock.add(options: MockOptions): MockHandle
interface MockOptions {
  method: string;                           // MCP method to match
  params?: Record<string, unknown>;         // Parameters to match (partial)
  response: JsonRpcResponse;                // Response to return
  times?: number;                           // Match count (default: unlimited)
  delay?: number;                           // Response delay in ms
}

interface MockHandle {
  callCount(): number;
  calls(): MockCall[];
  remove(): void;
}

mock.tool

Convenience method for mocking tool responses.
mcp.mock.tool(name: string, response: unknown): MockHandle

mock.toolError

Mock a tool error.
mcp.mock.toolError(name: string, code: number, message: string): MockHandle

mock.resource

Mock a resource response.
mcp.mock.resource(uri: string, content: string | ResourceContent): MockHandle

mock.clear

Clear all mocks.
mcp.mock.clear(): void

Request Interceptors

The mcp.intercept API for intercepting requests and responses.

intercept.request

Intercept outgoing requests.
mcp.intercept.request(handler: RequestInterceptor): () => void
type RequestInterceptor = (ctx: RequestContext) => InterceptAction;

interface RequestContext {
  request: JsonRpcRequest;
  meta: { sessionId?: string };
}

type InterceptAction =
  | { action: 'passthrough' }
  | { action: 'modify'; request: JsonRpcRequest }
  | { action: 'mock'; response: JsonRpcResponse }
  | { action: 'error'; error: Error };
Returns: Function to remove the interceptor.

intercept.response

Intercept incoming responses.
mcp.intercept.response(handler: ResponseInterceptor): () => void
type ResponseInterceptor = (ctx: ResponseContext) => ResponseAction;

interface ResponseContext {
  request: JsonRpcRequest;
  response: JsonRpcResponse;
  durationMs: number;
}

type ResponseAction =
  | { action: 'passthrough' }
  | { action: 'modify'; response: JsonRpcResponse };

intercept.delay

Add delay to all requests.
mcp.intercept.delay(ms: number): () => void
Returns: Function to remove the delay.

intercept.failMethod

Fail requests to a specific method.
mcp.intercept.failMethod(method: string, message: string): () => void
Returns: Function to remove the failure.

HTTP Mock API

The httpMock module for mocking external HTTP requests.

httpMock.interceptor

Create an HTTP interceptor.
import { httpMock } from '@frontmcp/testing';

const interceptor = httpMock.interceptor();

Interceptor Methods

get, post, put, delete

Create method-specific mocks.
interceptor.get(url: UrlMatcher, response: unknown, options?: MockOptions): MockHandle
interceptor.post(url: UrlMatcher, response: unknown, options?: MockOptions): MockHandle
interceptor.put(url: UrlMatcher, response: unknown, options?: MockOptions): MockHandle
interceptor.delete(url: UrlMatcher, response: unknown, options?: MockOptions): MockHandle
type UrlMatcher = string | RegExp | ((url: string) => boolean);

any

Match any HTTP method.
interceptor.any(url: UrlMatcher, response: unknown, options?: MockOptions): MockHandle

mock

Full mock definition.
interceptor.mock(options: HttpMockOptions): MockHandle
interface HttpMockOptions {
  match: {
    url: UrlMatcher;
    method?: string | string[];
    headers?: Record<string, string | RegExp>;
    body?: unknown | ((body: unknown) => boolean);
  };
  response: HttpResponse;
  times?: number;
}

interface HttpResponse {
  status?: number;
  statusText?: string;
  headers?: Record<string, string>;
  body?: unknown;
  delay?: number;
}

allowPassthrough

Allow unmatched requests to reach the network.
interceptor.allowPassthrough(enabled: boolean): void

assertDone

Assert all one-time mocks were used.
interceptor.assertDone(): void

pending

Get unused mocks.
interceptor.pending(): HttpMockOptions[]

restore

Restore original fetch function.
interceptor.restore(): void

MockHandle

Returned by mock methods.
interface MockHandle {
  callCount(): number;
  calls(): HttpCall[];
  waitForCalls(count: number, timeout?: number): Promise<HttpCall[]>;
}

interface HttpCall {
  url: string;
  method: string;
  headers: Record<string, string>;
  body?: unknown;
}

Response Helpers

httpResponse

Pre-built HTTP response creators.
import { httpResponse } from '@frontmcp/testing';

httpResponse.json(data: unknown): HttpResponse
httpResponse.text(text: string): HttpResponse
httpResponse.html(html: string): HttpResponse
httpResponse.notFound(): HttpResponse
httpResponse.unauthorized(): HttpResponse
httpResponse.forbidden(): HttpResponse
httpResponse.serverError(message?: string): HttpResponse
httpResponse.error(status: number, message: string): HttpResponse
httpResponse.delayed(data: unknown, ms: number): HttpResponse

mockResponse

Pre-built MCP response creators.
import { mockResponse } from '@frontmcp/testing';

mockResponse.success(result: unknown): JsonRpcResponse
mockResponse.toolResult(content: Content[]): JsonRpcResponse
mockResponse.toolsList(tools: Tool[]): JsonRpcResponse
mockResponse.resourcesList(resources: Resource[]): JsonRpcResponse
mockResponse.resourceRead(contents: ResourceContent[]): JsonRpcResponse
mockResponse.error(code: number, message: string): JsonRpcResponse

// Error shortcuts
mockResponse.errors.methodNotFound(method: string): JsonRpcResponse
mockResponse.errors.resourceNotFound(uri: string): JsonRpcResponse
mockResponse.errors.invalidParams(message: string): JsonRpcResponse
mockResponse.errors.unauthorized(): JsonRpcResponse

Custom Matchers

All custom Jest matchers added by @frontmcp/testing.

Tool Matchers

expect(tools).toContainTool(name: string): void

Result Matchers

expect(result).toBeSuccessful(): void
expect(result).toBeError(code?: number): void

Content Matchers

expect(result).toHaveTextContent(text?: string): void
expect(result).toHaveImageContent(): void
expect(result).toHaveResourceContent(): void
expect(content).toHaveMimeType(mimeType: string): void

Resource Matchers

expect(resources).toContainResource(uri: string): void
expect(templates).toContainResourceTemplate(uriTemplate: string): void

Prompt Matchers

expect(prompts).toContainPrompt(name: string): void
expect(result).toHaveMessages(count: number): void
expect(message).toHaveRole(role: 'user' | 'assistant'): void
expect(message).toContainText(text: string): void

JSON-RPC Matchers

expect(response).toBeValidJsonRpc(): void
expect(response).toHaveResult(): void
expect(response).toHaveError(): void
expect(response).toHaveErrorCode(code: number): void

Error Codes

Common MCP error codes for use in tests.
CodeNameDescription
-32700Parse errorInvalid JSON
-32600Invalid requestInvalid JSON-RPC structure
-32601Method not foundUnknown method
-32602Invalid paramsInvalid parameters
-32603Internal errorServer error
-32001UnauthorizedAuthentication required
-32002Resource not foundResource doesn’t exist
-32800Request cancelledRequest was cancelled

Type Exports

All types are exported for TypeScript usage.
import type {
  // Test types
  TestOptions,
  TestFixtures,

  // Client types
  McpTestClient,
  ToolResult,
  ResourceContent,
  PromptResult,

  // Auth types
  AuthFixture,
  TokenOptions,

  // Server types
  ServerFixture,
  ClientOptions,

  // OAuth server types
  MockOAuthServer,
  MockOAuthServerOptions,
  MockOAuthServerInfo,
  MockTestUser,

  // CIMD server types
  MockCimdServer,
  MockCimdServerOptions,
  MockCimdServerInfo,
  MockCimdClientOptions,

  // Token factory types
  TestTokenFactory,
  TokenFactoryOptions,
  CreateTokenOptions,

  // Mock types
  MockOptions,
  MockHandle,
  HttpMockOptions,
  HttpResponse,

  // Interceptor types
  RequestInterceptor,
  ResponseInterceptor,
  InterceptAction,
  ResponseAction,
} from '@frontmcp/testing';