ChromeDevTools / ChromeDevTools/chrome-devtools-mcp

Growing memory usage during screencast recording if the host machine is not able to encode video using ffmpeg fast enough

Open
#2,291 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Summary

A long-lived chrome-devtools-mcp server (spawned by an AI coding-agent CLI via npm exec chrome-devtools-mcp@latest) attached to an existing Chrome with --browserUrl steadily grows its JS heap until it hits the default ~4GB V8 heap limit and aborts. The npm exec wrapper process dies alongside it (unhandled-rejection path → uv_kill), so each event leaves a pair of crashed node processes.

This looks distinct from #1192 / #1214: those were --autoConnect-mode collector leaks fixed in March/April — and indeed we saw ~3 months of clean operation after those fixes. The leak reported here reappeared with 1.2.0+ in --browserUrl mode.

Environment

  • chrome-devtools-mcp: crashes observed on 1.2.0 and 1.4.0 (resolved fresh via npm exec chrome-devtools-mcp@latest on each start)
  • Invocation: npm exec chrome-devtools-mcp@latest -- --browserUrl=http://127.0.0.1:<port> --experimentalScreencast
  • node v23.6.0 (Homebrew), macOS 15.7.2 (Apple Silicon)
  • Chrome: current stable, attached via CDP (--browserUrl), long-lived instance

Workload profile

The server runs for hours-to-days under an agent that repeatedly: takes snapshots, runs frequent evaluate_script polling, and records repeated screencast_start / screencast_stop cycles against a canvas/WebGL-heavy page.

Observed behavior

Seven crash events over 19 days (2026-06-13 → 2026-07-01), all with the identical signature. Time-to-crash shrinks as automation load increases — process lifetime went 2.7 days → 12.7 h → 3.9 h across the last three events, consistent with a load-proportional leak rather than a fixed-rate one.

Faulting thread (named chrome-devtools-mcp), from the macOS crash report:

libsystem_c.dylib     abort
node                  node::OOMErrorHandler(char const*, v8::OOMDetails const&)
node                  v8::internal::V8::FatalProcessOutOfMemory(...)
node                  v8::internal::Heap::FatalProcessOutOfMemory(char const*)
node                  v8::internal::Heap::CollectGarbage(AllocationSpace, GarbageCollectionReason, ...)
node                  v8::internal::IncrementalMarkingJob::Task::RunInternal()
node                  node::PerIsolatePlatformData::RunForegroundTask(...)
libuv                 uv__async_io → uv__io_poll → uv_run

(Other events show the same FatalProcessOutOfMemory via MinorGCJob / mark-compact — i.e., GC can no longer reclaim; the heap is genuinely retained, not fragmentation.)

Secondary: when the server aborts, the parent npm exec wrapper crashes too, inside PromiseRejectReactionJobnode::Kill/uv_kill — a crash-on-crash in the wrapper's rejection handling that might be worth a defensive fix on its own.

What I've ruled out

  • Not system memory pressure: no jetsam kill; the stack is V8's internal heap-limit abort.
  • Not the screencast temp-file path: frames are written to disk (fs.mkdtemp → mp4), so suspicion falls on CDP session/protocol-object retention under sustained evaluate_script + screencast churn.
  • 1.5.0 changelog contains no related fix, so filing this.

Happy to provide

Full (redacted) .ips crash reports for all seven events, Crashpad minidumps, or a run with --heapsnapshot-near-heap-limit instrumentation if that helps pinpoint the retained objects.

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 source files or tests are named. Start by reproducing the long-running --browserUrl invocation with repeated screencast_start/screencast_stop and evaluate_script calls, then use --heapsnapshot-near-heap-limit to inspect retained objects around the CDP session and screencast lifecycle. Done means identifying and preventing the retention, with stable heap usage under the reported workload.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.