In ChromeDevTools/chrome-devtools-mcp, the response formatting layer is where structural complexity and active development collide hardest: format in src/McpResponse.ts carries a cyclomatic complexity of 58, was touched 10 times in the last 30 days, and ranks first by activity-weighted risk — making it a live regression risk, not a cleanup backlog item. Across 480 total functions, 35 are rated critical, and every one of the top-ranked critical functions sits in the “fire” quadrant, meaning high complexity and high recent activity are happening simultaneously. The entire codebase shows zero debt-quadrant functions and zero dormant functions — this is an actively developed project where structural risk is accumulating in real time.
The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).
Top 5 Hotspots
| Function | File | Risk | CC | ND | FO |
|---|---|---|---|---|---|
format | src/McpResponse.ts | 17.9 | 58 | 4 | 47 |
handle | src/McpResponse.ts | 16.5 | 33 | 4 | 26 |
ensureBrowserConnected | src/browser.ts | 16.1 | 22 | 6 | 12 |
insertExtraNodes | src/TextSnapshot.ts | 14.7 | 13 | 4 | 31 |
generateReference | scripts/generate-docs.ts | 14.3 | 23 | 5 | 19 |
Hotspot Analysis
format — src/McpResponse.ts
Based on its name and file path, format is almost certainly responsible for serializing or structuring MCP responses — likely the central function that decides how any tool result gets shaped before it leaves the server. With a cyclomatic complexity of 58, it contains 58 independent execution paths, every one of which is a required test case and a potential bug surface. A fan-out of 47 means it calls 47 distinct functions, giving it one of the broadest coupling footprints in the codebase; with 10 commits touching it in the last 30 days, this is a live regression risk — each of those 47 callees is a point where an in-flight change could introduce a silent failure in the output contract.
Recommendation: Add a suite of characterization tests that cover the major output shapes before any further changes; then apply extract-method refactoring to decompose the 58-path logic into named sub-functions, each handling a distinct response category, which will also reduce the fan-out by localizing callee dependencies.
handle — src/McpResponse.ts
Also in src/McpResponse.ts, handle likely acts as the dispatcher or entry point that receives incoming tool calls and routes them through the response pipeline — the function that triggers format and its siblings. Its cyclomatic complexity of 33 and fan-out of 26 are significant on their own, but what makes this a fire-quadrant function is that it has been touched 8 times in the last 30 days and was last changed just 2 days ago. The god_function and exit_heavy patterns together suggest it is both doing too much and relying on numerous early-return branches, each of which is a separate test obligation and a place where a fast-moving change could silently alter routing behavior.
Recommendation: Map the exit paths first — with multiple early returns and a CC of 33, a control-flow diagram will reveal which branches are untested; then extract the routing logic and the response-construction logic into separate functions to break the god-function coupling before the next round of commits lands.
ensureBrowserConnected — src/browser.ts
In src/browser.ts, ensureBrowserConnected likely protects the boundary between tool handling and the browser session. Its cyclomatic complexity of 22 is high enough to make connection state hard to reason about, and its max nesting depth of 6 suggests multiple layers of conditional handling around browser startup, reconnection, or error recovery. A fan-out of 12 means the function is not as broadly coupled as format, but it still coordinates enough collaborators that connection behavior can drift when adjacent browser lifecycle code changes.
Recommendation: Add characterization tests for the disconnected, already-connected, reconnecting, and failure paths first; then flatten the nested conditionals by extracting named guards for connection state and recovery decisions.
insertExtraNodes — src/TextSnapshot.ts
In src/TextSnapshot.ts, insertExtraNodes likely enriches a text snapshot with additional nodes before the snapshot is consumed downstream. Its cyclomatic complexity of 13 and nesting depth of 4 are moderate, but the fan-out of 31 is the warning sign: the function depends on a wide set of helpers or node operations, so small changes in snapshot representation can have broad effects. That combination points to a long_function and god_function shape even when the branch count is lower than the response-layer functions.
Recommendation: Split the node-selection, node-construction, and insertion-order rules into separate helpers with focused tests; reducing the fan-out of the outer function will make snapshot changes easier to review.
generateReference — scripts/generate-docs.ts
In scripts/generate-docs.ts, generateReference appears to build generated documentation or reference output from source metadata. A cyclomatic complexity of 23 gives it enough independent paths to justify refactoring, while a nesting depth of 5 suggests some of those paths are embedded inside layered conditionals. Its fan-out of 19 also means documentation generation depends on a fairly broad set of formatting, filesystem, or metadata helpers.
Recommendation: Separate reference data collection from output formatting, then extract the deeply nested branches into named functions for each reference section; this should reduce both CC and nesting depth while preserving the generated output contract.
Patterns Found
Antipatterns detected across the top functions in this snapshot:
| Pattern | Occurrences |
|---|---|
complex_branching | 5 |
god_function | 5 |
long_function | 5 |
exit_heavy | 4 |
deeply_nested | 2 |
These labels belong to two tiers — Tier 1 (structural): complex_branching, deeply_nested, exit_heavy, long_function, god_function. Tier 2 (relational/temporal): hub_function, cyclic_hub, middle_man, neighbor_risk, stale_complex, churn_magnet, shotgun_target, volatile_god.
Key Takeaways
formatin src/McpResponse.ts has a cyclomatic complexity of 58 and was touched 10 times in the last 30 days — write characterization tests immediately to catch regressions before the next commit lands.handlein src/McpResponse.ts shows the god_function and exit_heavy patterns with 26 fan-out and 33 cyclomatic complexity; map its exit paths and extract routing logic before its 8-commit-per-month churn rate embeds more branching.ensureBrowserConnectedin src/browser.ts combines CC 22 with nesting depth 6 — flatten connection-state handling before reconnection logic becomes harder to verify.
Reproduce This Analysis
git clone https://github.com/ChromeDevTools/chrome-devtools-mcp
cd chrome-devtools-mcp
git checkout 3efd8c019416ddc83316fd7c4c8803a7c7367837
hotspots analyze . --mode snapshot --explain-patterns --force
To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.
Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →