Skip to content

Mcp

Model Context Protocol (MCP) server for CodeceptJS enables AI agents (like Claude) to interact with and control CodeceptJS tests programmatically.

The MCP server provides AI agents with tools to:

  • List all tests in a CodeceptJS project
  • List all available CodeceptJS actions (I.* methods)
  • Run arbitrary CodeceptJS code with artifacts capture, return value, and console.log capture
  • Run specific tests with detailed output
  • Run tests step by step for detailed analysis
  • Capture a point-in-time snapshot of the browser without any action
  • Start and stop browser sessions
  • Capture screenshots, ARIA snapshots, formatted HTML, browser console logs, and storage state (cookies + localStorage)

Install the MCP SDK dependency:

Terminal window
npm install @modelcontextprotocol/sdk

The MCP server binary is available at bin/mcp-server.js.

Configure the MCP server in your Claude Desktop or MCP-compatible client configuration:

{
"mcpServers": {
"codeceptjs": {
"command": "node",
"args": ["path/to/codeceptjs/bin/mcp-server.js"]
}
}
}

With basic configuration, the server looks for codecept.conf.js in the current working directory.

Use environment variables to specify the CodeceptJS project directory and config file:

{
"mcpServers": {
"codeceptjs": {
"command": "node",
"args": ["path/to/codeceptjs/bin/mcp-server.js"],
"env": {
"CODECEPTJS_CONFIG": "/path/to/your/codecept.conf.js",
"CODECEPTJS_PROJECT_DIR": "/path/to/your/project"
}
}
}
}

Environment Variables:

VariableDescription
CODECEPTJS_CONFIGAbsolute path to the CodeceptJS configuration file
CODECEPTJS_PROJECT_DIRAbsolute path to the project root directory

Example: Full Claude Desktop Configuration

Section titled “Example: Full Claude Desktop Configuration”
{
"mcpServers": {
"codeceptjs-mcp": {
"command": "node",
"args": ["D:/projects/my-project/node_modules/codeceptjs/bin/mcp-server.js"],
"env": {
"CODECEPTJS_CONFIG": "D:/projects/my-project/codecept.conf.js",
"CODECEPTJS_PROJECT_DIR": "D:/projects/my-project"
}
}
}
}

List all tests in the CodeceptJS project.

Parameters:

  • config (optional): Path to codecept.conf.js (default: codecept.conf.js)

Returns:

{
"count": 5,
"tests": [
{
"file": "/full/path/to/test/file.js",
"relativePath": "tests/example_test.js"
}
]
}

Example:

{
"name": "list_tests",
"arguments": {
"config": "/path/to/codecept.conf.js"
}
}

List all available CodeceptJS actions (I.* methods) from enabled helpers and support objects.

Parameters:

  • config (optional): Path to codecept.conf.js

Returns:

{
"count": 120,
"actions": [
{
"helper": "Playwright",
"action": "amOnPage",
"signature": "I.amOnPage(url)"
},
{
"helper": "Playwright",
"action": "click",
"signature": "I.click(locator, context)"
}
]
}

Run arbitrary CodeceptJS code. The tool captures the value the code returns, every I.* step it runs, anything written to console.log / console.info / console.warn / console.error / console.debug, plus a final-state snapshot of the page.

Parameters:

  • code (required): CodeceptJS code to execute. May return a value and use console.* for debugging.
  • timeout (optional): Timeout in milliseconds (default: 60000)
  • config (optional): Path to codecept.conf.js
  • saveArtifacts (optional): Save final-state artifacts to disk (default: true)

Returns:

{
"status": "success",
"output": "Code executed successfully",
"error": null,
"commands": [
"I.amOnPage(\"/\")",
"I.grabTextFrom(\"h1\")"
],
"logs": [
{ "level": "log", "message": "headline Welcome", "t": 47 }
],
"returnValue": "{\n \"url\": \"http://localhost:8000/\",\n \"text\": \"Welcome\"\n}",
"artifacts": {
"url": "http://localhost:8000/",
"html": "file:///output/trace_run_code_.../mcp_page.html",
"aria": "file:///output/trace_run_code_.../mcp_aria.txt",
"screenshot": "file:///output/trace_run_code_.../mcp_screenshot.png",
"console": "file:///output/trace_run_code_.../mcp_console.json",
"storage": "file:///output/trace_run_code_.../mcp_storage.json",
"cookieCount": 3,
"localStorageCount": 5
},
"dir": "/output/trace_run_code_...",
"traceFile": "file:///output/trace_run_code_.../trace.md"
}

Notes:

  • returnValue is the value the code’s last return statement produced, JSON-stringified with circular-ref handling. Capped at 20 KB; returnValueTruncated: true is set if it was cut.
  • logs is an in-order list of console output captured during execution. Each entry has { level, message, t } where t is ms since the code started. Capped at 100 entries × 2 KB per message; logsTruncated: true is set if hit. console.* writes do not pollute MCP stdio — they’re captured in-memory only.
  • commands is the list of I.* calls observed during execution (via the recorder).
  • artifacts.storage is omitted when both cookies and localStorage are empty.

Example:

{
"name": "run_code",
"arguments": {
"code": "await I.amOnPage('/'); const t = await I.grabTextFrom('h1'); console.log('headline', t); return { url: await I.grabCurrentUrl(), text: t };",
"timeout": 30000
}
}

Capture the current state of the browser without performing any action. Useful for inspecting what’s on the page right now (URL, cookies, localStorage, formatted HTML, ARIA, screenshot, browser console logs) when reasoning between actions.

Parameters:

  • config (optional): Path to codecept.conf.js
  • fullPage (optional): Take a full-page screenshot (default: false)

Returns:

{
"status": "success",
"dir": "/output/snapshot_1700000000000_abcd1234",
"traceFile": "file:///output/snapshot_.../trace.md",
"artifacts": {
"url": "http://localhost:8000/dashboard",
"html": "file:///output/snapshot_.../snapshot_page.html",
"aria": "file:///output/snapshot_.../snapshot_aria.txt",
"screenshot": "file:///output/snapshot_.../snapshot_screenshot.png",
"console": "file:///output/snapshot_.../snapshot_console.json",
"storage": "file:///output/snapshot_.../snapshot_storage.json",
"cookieCount": 3,
"localStorageCount": 5
}
}

Example:

{
"name": "snapshot",
"arguments": { "fullPage": true }
}

Release a paused test (one that called pause() during run_test) and let it run to completion. Returns the final reporter result.

To inspect or manipulate state while the test is paused, use run_code — it operates on the same container the test is using.

Parameters:

  • timeout (optional): ms to wait for the test to finish after continuing (default 60000).

Returns:

{
"status": "completed",
"reporterJson": { "stats": { "tests": 1, "passes": 1, "failures": 0 }, "tests": [...] },
"error": null
}

Example flow:

{ "name": "run_test", "arguments": { "test": "checkout_test" } }
// → { "status": "paused", "file": "...", "note": "..." }
{ "name": "run_code", "arguments": { "code": "return await I.grabCurrentUrl()" } }
// → { "status": "success", "returnValue": "http://...", "artifacts": { ... } }
{ "name": "run_code", "arguments": { "code": "await I.click('Save')" } }
// → { "status": "success", "artifacts": { ... } }
{ "name": "continue", "arguments": {} }
// → { "status": "completed", "reporterJson": { ... } }

Notes:

  • Pause runs in-process: run_code and the test share the same I / browser. There’s no subprocess, no IPC.
  • run_test and continue wrap test execution in the same withSilencedIO helper that run_step_by_step uses, so step output doesn’t interleave with the MCP JSON-RPC stream. Stdout/stderr are restored before each tool call returns.
  • TTY behaviour (npx codeceptjs run --debug at a terminal) is unchanged — pause() opens the readline REPL whenever process.stdin.isTTY is true.

Run a specific test by name or file path. Runs in-process so it shares the same I / browser as run_code and snapshot. If the test calls pause() — or if pauseAt is set and the Nth step completes — this tool returns early and the agent drives the session through run_code and continue.

Parameters:

  • test (required): Test name or file path
  • timeout (optional): Timeout in milliseconds (default: 60000)
  • config (optional): Path to codecept.conf.js
  • pauseAt (optional): 1-based step index. The test pauses after the Nth step completes. Use this as a programmatic breakpoint without editing the test. Discover step indices via the list CLI (--steps) or via run_step_by_step.

Returns (test completed normally):

{
"status": "completed",
"file": "/path/to/test.js",
"reporterJson": { "stats": { "tests": 1, "passes": 1, "failures": 0 }, "tests": [...] },
"error": null
}

Returns (test reached pause() or pauseAt):

{
"status": "paused",
"file": "/path/to/test.js",
"pausedAfter": { "index": 3, "name": "I.click(\"Save\")", "status": "passed" },
"page": { "url": "https://example.com/checkout", "title": "Checkout", "contentSize": 18432 },
"suggestions": [
"Call snapshot to capture URL/HTML/ARIA/screenshot/console/storage at this point",
"Call run_code to inspect or manipulate state (e.g. return await I.grabText(\"h1\"))",
"Call continue to release the pause and let the test finish"
]
}

Features:

  • Automatically resolves test names to file paths
  • Supports partial test name matching
  • Runs in-process; results assembled from CodeceptJS test events
  • Yields on pause() (or pauseAt) so the agent can inspect via run_code and release with continue

Example:

{
"name": "run_test",
"arguments": {
"test": "basic_navigation_test",
"timeout": 60000
}
}

Run a test interactively, pausing after every step. Returns a paused payload after the first step completes — the agent then calls continue to advance one step at a time, or run_code / snapshot to inspect state at any pause.

Parameters:

  • test (required): Test name or file path
  • timeout (optional): per-call timeout in milliseconds (default: 60000)
  • config (optional): Path to codecept.conf.js

Returns (after each step):

{
"status": "paused",
"file": "/path/to/test.js",
"pausedAfter": { "index": 1, "name": "I.amOnPage(\"/\")", "status": "passed" },
"page": { "url": "http://localhost:8000/", "title": "Test App", "contentSize": 1832 },
"suggestions": [
"Call snapshot to capture URL/HTML/ARIA/screenshot/console/storage at this point",
"Call run_code to inspect or manipulate state ...",
"Call continue to release the pause and let the test run the next step (or finish)"
]
}

Returns (after the last step):

{ "status": "completed", "file": "...", "reporterJson": { "stats": {...}, "tests": [...] } }

Flow:

{ "name": "run_step_by_step", "arguments": { "test": "checkout_test" } }
// → { "status": "paused", "pausedAfter": { "index": 1, ... } }
{ "name": "snapshot", "arguments": {} }
// → full artifact bundle for step 1
{ "name": "continue", "arguments": {} }
// → { "status": "paused", "pausedAfter": { "index": 2, ... } }
{ "name": "continue", "arguments": {} }
// → ... and so on, until { "status": "completed", "reporterJson": {...} }

For a one-shot breakpoint (pause once at a specific step rather than every step), use run_test with pauseAt: N instead.

For per-step trace artifacts written to disk (HTML / ARIA / screenshot / console / storage per step) without the interactive flow, enable the aiTrace plugin.

Start the browser session (initializes CodeceptJS container).

Parameters:

  • config (optional): Path to codecept.conf.js

Returns:

{
"status": "Browser started successfully"
}

Note: Browser is automatically started on first code execution. This tool is useful for pre-initialization.

Stop the browser session and cleanup resources.

Parameters:

  • None

Returns:

{
"status": "Browser stopped successfully"
}

Note: Useful for releasing resources between long-running sessions.

The MCP server includes a comprehensive test suite:

Terminal window
node test/mcp/mcp_server_test.js

Tests cover:

  • Tool listing and schema validation
  • Test enumeration
  • Action listing
  • Code execution with artifacts
  • Test execution (run_test)
  • Step-by-step execution
  • Browser lifecycle
  • Error handling

Important: Start the test web server first!

The MCP test scenarios require a web server running on port 8000. Start it in a separate terminal:

Terminal window
# Option 1: Using http-server (recommended)
cd test/mcp
npx http-server -p 8000
# Option 2: Using Python
cd test/mcp
python -m http.server 8000
# Option 3: Using PHP
cd test/mcp
php -S localhost:8000

The server will start at http://127.0.0.1:8000

Keep this terminal open while running tests through MCP/Claude.

Once the server is running, you can use Claude to run tests:

"List all tests"
"Run basic navigation test"
"Run form interaction test step by step"

Note: If tests fail with ERR_CONNECTION_REFUSED, make sure the web server is running on port 8000.

When using run_step_by_step, the server generates trace files that provide rich context for AI agents:

output/
└── trace_Test_Name_abc123/
├── 0000_<step>_screenshot.png # Screenshot after step 0
├── 0000_<step>_page.html # Formatted HTML (minified -> trash classes/scripts/styles stripped -> beautified)
├── 0000_<step>_aria.txt # ARIA snapshot after step 0 (Playwright only)
├── 0000_<step>_console.json # Browser console logs (normalized to {type, text})
├── 0001_<step>_screenshot.png
├── 0001_<step>_page.html
├── 0001_<step>_aria.txt
├── 0001_<step>_console.json
├── final_storage.json # Cookies + localStorage at test end (run_step_by_step fallback)
└── trace.md # AI-friendly summary with links to all of the above

For ad-hoc run_code and snapshot() runs, only a single set of artifacts is produced (mcp_* / snapshot_* prefix), since there are no per-step iterations.

The trace.md file provides structured information perfect for AI analysis:

# Test: Login functionality
**Status**: failed
**File**: tests/login_test.js
## Steps
1. **I.amOnPage("/login")** - passed (150ms)
2. **I.fillField("#username", "user")** - passed (80ms)
3. **I.fillField("#password", "pass")** - passed (75ms)
4. **I.click("#login")** - passed (100ms)
5. **I.see("Welcome")** - failed (50ms)
## Error
Element "Welcome" not found
## Artifacts
- Screenshot: 0005_screenshot.png
- HTML: 0005_page.html
- ARIA: 0005_aria.txt

AI agents can use these artifacts to:

  • Visualize what the test saw at each step
  • Analyze page structure via ARIA
  • Debug issues using HTML snapshots
  • Identify errors from console logs

Every HTML snapshot saved by the MCP server (and the aiTrace / pageInfo plugins, since they share the same captureSnapshot funnel in lib/utils/captureSnapshot.js) is processed through a three-stage pipeline before being written to disk:

  1. Minify (via html-minifier-terser) — strips comments, collapses whitespace, removes redundant attributes.
  2. Clean — drops <style>, <noscript>, and inline <script> (no src) blocks entirely; preserves <script src="...">; strips trash class names (Tailwind utilities text-*, flex-*, border-*, framework-generated v-*, ember-*, Header__title, hashed classes containing digits, and xl:hidden-style scoped classes); drops style="..." attributes. Semantic attributes (id, aria-*, data-*, role, href, src, alt, title, name) are kept.
  3. Beautify (via js-beautify) — re-indents with 2-space indentation; keeps inline elements like <strong> / <a> on the same line as their text.

The result is a multi-line, low-noise HTML document that’s far cheaper for an LLM to reason about than raw page source.

When a Playwright helper is configured, captureSnapshot calls helper.grabStorageState() to dump cookies + localStorage in one go. For Puppeteer / WebDriver, it falls back to helper.grabCookie() plus an executeScript() call that walks window.localStorage. Both paths produce the same shape ({ cookies: [...], origins: [{ origin, localStorage: [...] }] }) so AI agents see a consistent storage payload regardless of the helper.

Storage capture is disabled per-step in aiTrace (cookies / localStorage rarely change between actions, so per-step files would be noise) and enabled by default for run_code, snapshot, run_step_by_step fallback, and pageInfo.

  1. MCP Client sends JSON-RPC request via stdin/stdout
  2. Server processes request and calls appropriate tool
  3. Tool executes CodeceptJS code or runs tests
  4. Results formatted as JSON and returned
  5. MCP Client receives response
  • Initialization: CodeceptJS container initialized on first request
  • Browser: Started once and reused across requests
  • Locking: run_test uses locking to prevent concurrent test runs
  • Cleanup: stop_browser releases all resources
  • All errors returned as JSON with error message and stack
  • Invalid tools return error response
  • Test failures included in results (not thrown)
  • Timeout protection on all long-running operations
  • Ensure @modelcontextprotocol/sdk is installed
  • Check Node.js version (requires Node.js 16+)
  • Verify the path to mcp-server.js in your MCP client config
  • Check file permissions
  • Set CODECEPTJS_CONFIG environment variable to absolute path of your config file
  • Set CODECEPTJS_PROJECT_DIR environment variable to your project directory
  • Use absolute paths in environment variables (e.g., D:/projects/my-project/codecept.conf.js)
  • Verify config file exists and is valid JavaScript
  • Verify you’re in the correct working directory
  • Check that codecept.conf.js exists
  • Use absolute paths for tests if relative paths don’t work
  • Check test patterns in config file match your test files
  • Ensure browser dependencies are installed (Chromium for Playwright)
  • Check if browser is already running
  • Verify show: false in config (headless mode recommended)
  • Check firewall/proxy settings
  • Increase timeout parameter (default 60s)
  • Check if web server is running (for tests that need it)
  • Disable video recording and other heavy features
  • Use run_test instead of run_step_by_step for faster execution
// In codecept.conf.js
export const config = {
tests: './tests/**/*_test.js',
// ... rest of config
}

For best results with AI agents:

  1. Enable aiTrace plugin in config (automatically enabled for run_step_by_step)
  2. Use descriptive test names for better trace file organization
  3. Keep tests focused - one scenario per test for clearer traces
  4. Add assertions with clear messages - better error reporting
{
"mcpServers": {
"codeceptjs": {
"command": "node",
"args": ["node_modules/codeceptjs/bin/mcp-server.js"],
"env": {
"CODECEPTJS_CONFIG": "/absolute/path/to/codecept.conf.js",
"CODECEPTJS_PROJECT_DIR": "/absolute/path/to/project"
}
}
}
}
  • MCP server runs with same permissions as calling process
  • run_code allows arbitrary CodeceptJS execution - use in trusted environments only
  • Test files should validate input if exposed to external systems
  • Environment variables may contain sensitive paths - secure accordingly

When contributing to MCP server:

  1. Add tests for new tools in test/mcp/mcp_server_test.js
  2. Update this documentation with new tools/parameters
  3. Ensure error handling is consistent
  4. Test with both Playwright and Puppeteer helpers
  5. Verify trace files are generated correctly for run_step_by_step

MIT