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

# MCP server

> Let your coding agent use your app and check its own work.

`e2e mcp` gives a coding agent such as Claude Code, Codex, or Cursor a live
session on your app, on web, iOS, or Android. The agent sees the screen,
acts on it, and checks its work.

## Why it matters

| Task | Without `e2e mcp` | With `e2e mcp` |
| --- | --- | --- |
| Write a test | Guesses locators, runs, fails, guesses again | Writes the test as it walks the flow, from checked test lines and lines it ran with `run_code` |
| Change the UI | Done when it compiles | Opens the page and checks the result |
| Reproduce a bug | Guesses from the code | Follows the steps in the app |
| Fix a failing test | Clicks through the flow again | Runs the test and stops on the failure |
| Run the suite | Needs a shell for `e2e run` | Runs it with `run_tests` |
| Show a change in a PR | Describes it | Records a video |

The server needs no model. A test it runs needs one only for an agent
step with no recording.

## Set it up

`e2e init` offers to register the server in `.mcp.json` (Claude Code) and
`.cursor/mcp.json` (Cursor). By hand:

<Tabs>
  <Tab title="Claude Code">
    <CodeGroup>
    ```bash npm
    claude mcp add --scope project e2e -- npx e2e mcp
    ```

    ```bash pnpm
    claude mcp add --scope project e2e -- pnpm exec e2e mcp
    ```

    ```bash bun
    claude mcp add --scope project e2e -- bunx e2e mcp
    ```
    </CodeGroup>
  </Tab>
  <Tab title="Codex">
    Add the server to `.codex/config.toml`, trust the project, and start a
    new session:

    ```toml title=".codex/config.toml"
    [mcp_servers.e2e]
    command = "npx"
    args = ["e2e", "mcp"]
    ```
  </Tab>
  <Tab title="Cursor">
    Add the server to `.cursor/mcp.json`. Other clients that read an
    `mcpServers` map take the same block.

    ```json title=".cursor/mcp.json"
    {
      "mcpServers": {
        "e2e": { "command": "npx", "args": ["e2e", "mcp"] }
      }
    }
    ```
  </Tab>
</Tabs>

A session starts the target's app command, if it has one, and names it
with its URL and port. The config reads the server's environment, not the
agent's shell.

## Ask the agent

- "Add a Remember me checkbox to the login form. Check it in the app with e2e."
- "Write a test for checkout while you walk it in the app."
- "Reproduce issue #123 in the app and record a video."

Add "headed" to watch a local browser or simulator.

## How it writes a test line

Each action in a session answers with the test line that repeats it. The
line's locator matched that control alone on the live screen:

```text wrap
Tapped #n31.
Test line: await screen.getByRole("button", "Sign in").tap();
```

The agent copies the lines it needs into the test as it walks the flow.
`test_lines` returns every line so far, in order, as a draft test body. See
[`test_lines`](https://e2e.tester.army/docs/reference/mcp#test_lines) for how a line is built.

## How it checks a locator

For a line no action printed, such as an assertion, the agent tries the
locator in the session first. A wrong guess fails there, not in a test run:

```text wrap
0 nodes match getByLabel("Email").
A test using this locator would fail with LOCATOR_NOT_FOUND. ...

1 node matches getByRole("button", name: "Sign in").
Use: screen.getByRole("button", "Sign in")
```

## How it runs a test line

The agent runs the lines no action printed, such as assertions, with
`run_code` in the open session. The ones that pass join the `test_lines`
draft. A wrong line fails in seconds, without a test run:

```text wrap
Statement 2 of 2 failed; the one before it passed. Each statement waited at most 5000 ms. ...
1. passed: await screen.getByLabel('Full name').fill('Grace Hopper');
2. failed: await screen.getByRole('button', 'Save').tap();
   LOCATOR_NOT_FOUND: locator matched no nodes within getByRole("button", name: "Save")
```

The server parses the lines and never evaluates them as JavaScript. See
[`run_code`](https://e2e.tester.army/docs/reference/mcp#run_code).

## Fix a failing test

`open_session {test: "tests/checkout.e2e.ts:12"}` runs one test in the
session and stops on the screen where it failed. The agent reads the
failure, checks the screen, and edits the test:

```text wrap
Test "a member checks out" (tests/checkout.e2e.ts:12) failed after 30.25s; 8 steps ran.
LOCATOR_NOT_FOUND: locator matched no nodes within getByLabel("Name")
At tests/checkout.e2e.ts:20:3
On screen, closest to what the locator asked for:
  #n32 textbox "Full name"
```

Each action from that screen prints its
[test line](#how-it-writes-a-test-line), and `run_code` runs a fixed line
there. The agent puts those lines in the test in place of the one that
failed.

To rerun the edited test, the agent closes the session and opens a new one
with the same `test`. Agent steps replay from the cache as in `e2e run`.
See [Running a test](https://e2e.tester.army/docs/reference/mcp#running-a-test) for what runs and the
limits.

## Run tests next to a session

A session writes no test results, and only a test it runs with
`open_session {test}` uses the replay cache. The agent runs suites with
[`run_tests`](https://e2e.tester.army/docs/reference/mcp#run_tests), the same run as `e2e run`, and,
when a run can go beside the session, keeps the session open between runs. After a failed run, it goes to the failing screen in
that session instead of opening a new one.

On web, a run next to a session depends on the target's `app`:

| Target's `app` | A run while a session is open |
| --- | --- |
| No `command` | Both use the app you started. |
| `url` on port [`0`](https://e2e.tester.army/docs/web#let-the-runner-pick-the-port) | Each starts its own copy of the app. A dev server that runs one copy per directory, such as `next dev`, fails the run. |
| `command` with [`reuseExisting: true`](https://e2e.tester.army/docs/web#starting-your-app) | The run uses the app the session started. When the session closes, also during a run, that app stops. |
| `command` on a fixed port, without `reuseExisting` | Fails with `APP_ALREADY_RUNNING`. |

When `CI` is set, e2e ignores `reuseExisting`, and the run fails as on a
fixed port. Close the session before a run that would fail. On mobile, run
on a device no session uses.

## Run several agents

Each agent, subagents included, opens its own session with its own browser
or device, up to four by default. On mobile, give each session its own
target.

## Secrets

`type_secret`, or a `fill` in `run_code`, fills a secret without showing it
to the agent. Screenshots mask secure fields only, so a secret the app
shows anywhere else is in them.

<Warning>
Videos from `start_recording` are not masked.
</Warning>

## Next

<CardGroup cols={2}>
  <Card title="MCP server reference" icon="book" href="/reference/mcp">
    Every tool, flag, session rule, and error code.
  </Card>
  <Card title="Coding agents" icon="robot" href="/coding-agents">
    The skill, running tests, and reading a failure.
  </Card>
</CardGroup>
