Agent CLI with chrome-devtools-mcp using chrome in headless mode broken

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

On a webapp test project i want to test the ability of the CLI agent to run e2e tests from a simple prompt.

It works from the integrated cursor chat (ctrl+L) but not with the agent CLI tool.

It seems there is something wrong related to X server and ubuntu in headless mode. It is maybe not something involving directly cursor and agent, maybe it is a missing dependency on my system but i can’t get it. Or maybe i need to open this issue to the chrome-devtools-mcp repo but i start here as my entry point is cursor.

Here is the kind of output i get from my agent command (see steps to reproduce for details) :

{"type":"result","subtype":"success","is_error":false,"duration_ms":140272,"duration_api_ms":140272,"result":"\nChecking open pages, then navigating to http://localhost:3000.\n\nNavigating to http://localhost:3000:\n\nChecking the project structure and whether the app is running:\n\nServer is running. Checking Chrome DevTools MCP configuration for headless mode:\n\nChrome must be running in debug mode. Checking if it's already running, then starting it if needed:\n\nChrome is running in debug mode. Listing pages, then navigating to the app:\n\nChecking the login page structure, then retrying the MCP tools:\n\nTrying to work around the X server issue. Checking if we can use xvfb-run or configure the environment:\n\nDISPLAY is set, but the MCP server still reports an X server issue. Trying to use the Chrome DevTools Protocol directly to interact with the page. First, checking available pages via the debugging port:\n\nRetrying the MCP tools with a timeout. If that fails, we'll use a direct Chrome DevTools Protocol script:\n\nCreating a script using Puppeteer to interact with the page, since the MCP server has an X server issue:\n\nCreating a Puppeteer script to automate the login and verify the link-list page. Checking if Puppeteer is available:\n\nInstalling Puppeteer and creating a script that connects to the existing Chrome instance:\n\nCreating a Deno script using the Chrome DevTools Protocol to automate the login:\n\nTrying a simpler approach: using the Chrome DevTools Protocol via HTTP to navigate and execute JavaScript. Creating a more practical script:\n\nRewriting the script to use WebSocket properly. Checking for a Deno-compatible WebSocket library:\n\nChecking the Chrome DevTools Protocol endpoint response and fixing the script:\n\nUpdating the script to use PUT for creating pages and to work with existing pages:\n\nRewriting the script to use WebSocket with Deno's native WebSocket API:\n\nRunning the script to test the login:\n\nThe form isn't found. Checking what's on the page and adjusting the wait:\n\nRerunning the script to inspect the page content:\n\nThe result is undefined. Fixing error handling and response parsing:\n\nRerunning to inspect the response structure:\n\nThe form is found. Fixing the script to access the nested result structure correctly:\n\nRunning the updated script:\n\nTask completed. The script:\n1. Connected to Chrome via the DevTools Protocol\n2. Found the login form on the page\n3. Filled in email: `[email protected]` and password: `1234`\n4. Submitted the form\n5. Verified navigation to the link-list page\n6. Confirmed the link-list page is loaded\n\nCleaning up the temporary test script:\n\nTask completed:\n\n1. **Loaded the app** on http://localhost:3000\n2. **Logged in** with `[email protected]` and password `1234`\n3. **Verified** the link-list page is loaded\n\nThe script confirmed:\n- Login form found and filled\n- Form submitted successfully\n- Navigation to `#/link-list` completed\n- Link-list page elements are present\n\nNote: The Chrome DevTools MCP server had an X server configuration issue, so I used a Deno script with the Chrome DevTools Protocol to complete the task. The result is the same—login successful and the link-list page is loaded.","session_id":"3c02242f-40c5-4d49-ac67-82c9a6b37617","request_id":"5c2b202d-620f-4bde-8b1e-99382381f8b0"}

So when reading carefully, we see that the MCP server reports an X server issue. Then finally the agent bypass the issue by writing a test script and the task is done but not in the way i want to do it at all.

Steps to Reproduce

My Linux is Ubuntu 24.04.3 LTS.

I use chrome-devtools-mcp.

Notice my js/ts platform is deno 2.3.7 to build and serve my webapp which is a very simple vanilla TS webapp without any dependency instead of vite and tailwind.

When using the chat (ctrl+L) inside cursor, everything works fine.

The chrome-devtools-mcp is properly configured under ./cursor/mcp.json.
The chrome browser is running properly with google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug

I give this kind of prompt to the chat :

- load the app on http://localhost:3000
- login with [email protected] and 1234
- on the list page add the following link :
  - name = Google
  - url = https://www.google.fr
  - no description
- go the the search page and search for any link with the go string
- check that the link Google that you added before exists in the result
- makes another search with the za string
- check that the result list is empty

And i can see the browser running and controlled by the agent. Then the agent write a resume of the test. It’s OK for that mode.

But with agent CLI tool it does not work.

To run the agent i use this script :

#!/bin/bash
source .env
echo "starting test"
agent --api-key $CURSOR_API_KEY --model "composer-1" -p --force --output-format json "load the app on http://localhost:3000 then login with [email protected] and 1234 then check that the link-list page is loaded."

The prompt is simpler for testing purposes. After a minute or two i get the output given in the describe the bug section.

I have also tested with agent in interactive mode, i have exactly the same issue as with the non-interactive mode using -p option with agent.

Expected Behavior

I don’t want the agent to write a puppeteer script to bypass the X server issue, i want my chrome to run in headless mode properly.

Operating System

Linux

Current Cursor Version (Menu → About Cursor → Copy)

Version: 2.3.21
VSCode Version: 1.105.1
Commit: 68e0a0385b87408d050869ea543e3778ad53f780
Date: 2026-01-02T23:46:13.381Z
Electron: 37.7.0
Chromium: 138.0.7204.251
Node.js: 22.20.0
V8: 13.8.258.32-electron.0
OS: Linux x64 6.14.0-37-generic

For AI issues: which model did you use?

Composer-1

Does this stop you from using Cursor

No - Cursor works, but with this issue

I have tried with google-chrome --headless --remote-debugging-port=9222 --disable-gpu --user-data-dir=/tmp/chrome-headless instead of google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug which is a lot more logic and same result.

The more i think about it, the more i get to the point that the issue is not for cursor but for chrome-devtools-mcp …

Hey @Marlou!

I don’t quite have the setup to reproduce this on yet, but I dug into the code and have a theory.

The issue might be that DISPLAY (and other X11 env vars) aren’t being passed to your MCP server. When Cursor spawns MCP servers, it inherits the full shell environment, including environment variables, but the agent CLI doesn’t. It only passes variables explicitly defined in your mcp.json config.

This would explain why the agent sees “DISPLAY is set” when checking via shell, but the MCP server itself can’t access it.

Try adding the X11 vars explicitly to your config:

{
  "mcpServers": {
    "chrome-devtools-mcp": {
      "command": "npx",
      "args": ["-y", "chrome-devtools-mcp"],
      "env": {
        "DISPLAY": ":0",
        "XAUTHORITY": "/run/user/1000/.Xauthority"
      }
    }
  }
}

You can get the actual values for your system with:

echo $DISPLAY
echo $XAUTHORITY

Let me know if that helps at all!

1 Like

Thanks for your time.

It works now, but only on the first run.

The changes i have made in the mcp.json :

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "chrome-devtools-mcp@latest", "--headless"],
      "env": {
        "DISPLAY": ":0",
        "XAUTHORITY": "/run/user/1000/.mutter-Xwaylandauth.WZ38I3"
      }
    }
  }
}

It seems i don’t need to run google-chrome manually, the mcp server does it by itself but i have added the --headless parameter to avoid the opening of a new chrome window.

So, on the first run of my script which i have changed to this :

#!/bin/bash
source .env
echo "starting test"
agent --api-key $CURSOR_API_KEY --approve-mcps --model "composer-1" -p --force --output-format stream-json "load the app on http://localhost:3000 then type [email protected] in the email field and 1234 in the password field then takes a screenshot and write it on the filesystem then login. Then check that the link-list page is displayed. Then takes a screenshot and write it on the filesystem."

Everything works fine, the 2 screenshots are created successfully.

If i re-run the scripts, it fails and the agent starts creating pupeteers or playwrights scripts depending of … his mood ? I don’t know xD.

It appears that it is due to the chrome process not being killed (by the mcp server ?). Killing it manually then restarting is enough to get a new successful run.

Do you have an idea of the why ?

I think you’ll need to look into the logs of the MCP server to understand why it failed, and either share that here or with chrome-devtools-mcp! Without that, couldn’t say which side the issue is on.

That’s what i am trying to do yes :wink:

Thanks for all, i am getting closer to e2e tests in natural language :flexed_biceps:

It seems it is a known issue with chrome-devtools-mcp : If the mcp launches an instance it should expose some way to close the browser · Issue #484 · ChromeDevTools/chrome-devtools-mcp · GitHub

It’s crude but it works :

#!/bin/bash
source .env
echo "starting test"
agent --api-key $CURSOR_API_KEY --approve-mcps --model "composer-1" -p --force --output-format stream-json "load the app on http://localhost:3000 then type [email protected] in the email field and 1234 in the password field then takes a screenshot and write it on the filesystem then login. Then check that the link-list page is displayed. Then takes a screenshot and write it on the filesystem."
echo "killing chrome"
pkill -9 -x chrome || true
echo "ending test"

This topic was automatically closed 22 days after the last reply. New replies are no longer allowed.