@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.
Fixture-Based Playwright-inspired fixtures inject ready-to-use test clients
Full Protocol Test tools, resources, prompts, and raw JSON-RPC
Offline Testing Mock HTTP calls for fully offline test suites
Installation
npm install -D @frontmcp/testing
@frontmcp/testing requires @frontmcp/sdk as a peer dependency and uses Jest as the test runner.
Quick Start
Create or update your jest.e2e.config.ts:
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
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
# 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 mcpAuto-connected MCP client for making requests serverServer control (restart, logs, create additional clients) authToken factory for authentication testing
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:
// 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:
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:
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():
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
});
Use port: 0 to automatically select an available port. This prevents conflicts when running multiple test suites in parallel.
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.
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.
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.
apps/e2e/demo-e2e-public/e2e/public-auth.e2e.test.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 ' );
});
});
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.
Next Steps