ChromeDevTools / ChromeDevTools/chrome-devtools-mcp

Long-lived server can retain active page indefinitely and keep consuming CPU after client activity stops

Open
#2,599 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

collecting-feedback
Dominant language
TypeScript
Stars
52.3k
Forks
4.3k
Avg merge
2d 7h
Merged PRs (30d)
83

Description

Summary

On a long-lived self-hosted chrome-devtools-mcp 1.7.0 deployment, a page left open after an agent finishes can continue consuming substantial CPU indefinitely even though there are no MCP tool calls in flight.

This appears distinct from the 1.6.0 memory/source-map issues in #2431 / #2456, which are marked fixed in 1.7.0. The problem here is lifecycle: an active page remains live forever unless the client explicitly navigates it away/closes it or the server/browser process is recycled.

Environment
  • chrome-devtools-mcp 1.7.0
  • Linux x86_64
  • Headless Chrome launched by the MCP server
  • Persistent, long-lived MCP gateway/server
  • Docker container with a 2 GiB memory limit
  • Real-world, script-heavy SPA as the target
Observed behaviour

A stale page left by a completed investigation held roughly 28–30% CPU continuously for hours on a 4-core host.

Without restarting the container or MCP gateway, simply closing/navigating the stale page away and leaving only about:blank dropped container CPU to roughly 0.03%, then effectively 0%.

The relevant Chrome launch configuration disables background throttling for debugging accuracy, so a page that remains open can legitimately keep timers/rendering/network activity alive in the background. That behaviour is useful while an investigation is active, but there is currently no lifecycle boundary once the client disappears or stops making calls.

Why this is operationally awkward

For a persistent remote MCP service, persistence currently means browser/page state can survive indefinitely. If a client vanishes without cleanup, the server has no way to distinguish "active investigation" from "abandoned live page".

This is particularly noticeable on dynamic SPAs where background timers, polling, rendering or other work continue after the agent is gone.

Production workaround tested successfully

I added an external gateway lifecycle around the upstream 1.7.0 server with two idle stages:

  1. Park after a shorter idle period

    • retain one page
    • close other stale pages
    • select the retained page
    • navigate it to about:blank
  2. Recycle after a longer idle period

    • stop and recreate only the internal chrome-devtools-mcp child
    • keep the public gateway/container alive
    • release retained V8/performance/browser state

The production thresholds I tested were:

  • park: 20 minutes idle
  • recycle: 60 minutes idle
  • lifecycle check: 10 seconds

Long-running manual operations such as a performance trace or screencast hold an activity lease so lifecycle maintenance does not interrupt legitimate work.

Acceptance evidence from the lifecycle implementation

In isolated testing:

  • a live test page was automatically parked to about:blank
  • post-park CPU fell to about 0.13%
  • a manual performance-trace lease prevented both park and recycle while the trace was active
  • after the trace stopped, one park and one internal recycle occurred
  • child PID changed while the Docker container remained running
  • working set fell from roughly 327 MiB to 139 MiB
  • CPU fell to about 0.02%
  • Docker restart count remained zero
  • the MCP tool surface still worked after recycle

In production, the same approach removed a stale-page case that had been burning roughly 28–30% CPU for hours.

Suggested upstream direction

Would you be open to an upstream idle lifecycle for persistent server usage, for example:

  • track external MCP tool activity
  • park stale pages after configurable idle time
  • optionally recycle/recreate internal browser/server state after a longer idle period
  • protect manual traces/screencasts or other long-running operations with an explicit activity lease

I have a tested implementation in a persistent gateway wrapper and can adapt the concept into an upstream PR if this is a direction the project would accept.

I am deliberately filing this separately from the previous memory issues because 1.7.0 fixed those specific regressions, while this stale-page CPU/lifecycle behaviour is still reproducible on 1.7.0.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No repository file or test is named. Start by reproducing the stale-page case on a persistent 1.7.0 server and trace MCP activity, page cleanup, and performance-trace or screencast lifetimes; compare the proposed park/recycle behavior and activity leases against the reported acceptance evidence.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, devtools
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.