Skip to content

architecture

2 posts with the tag “architecture”

Why Chrome DevTools MCP Isn't Enough

Chrome DevTools MCP was a great first step. But it doesn’t capture WebSockets, can’t handle distributed apps, breaks on advanced frameworks, and slows down the development cycle it was supposed to accelerate.

Chrome DevTools MCP proved something important: AI agents are dramatically better when they can see the browser. That insight changed how developers think about AI-assisted development.

But the implementation has fundamental limitations that surface quickly in real-world projects. If you’ve tried using DevTools MCP on anything beyond a simple SPA, you’ve probably hit them.

Problem 1: The Debug Port Kills Your Security

Section titled “Problem 1: The Debug Port Kills Your Security”

Chrome DevTools MCP requires launching Chrome with --remote-debugging-port. This flag:

  • Disables Chrome’s security sandboxing. The sandbox is Chrome’s primary defense against malicious websites. Turning it off means any site you visit during development can access more of your system.
  • Exposes a network port. Port 9222 accepts remote connections. On a shared network (office, coffee shop, conference WiFi), that’s an attack surface.
  • Breaks your normal browser. You need a special browser launch. Your extensions, bookmarks, and sessions from your regular Chrome instance aren’t there. You’re working in an unfamiliar environment.

Gasoline uses a standard Chrome extension (Manifest V3). No special launch flags. No exposed ports. Your browser stays secure, and you work in your normal environment with your normal sessions.

Modern applications are real-time. Chat apps, collaborative editors, dashboards, notification systems, trading platforms — they all use WebSockets.

Chrome DevTools MCP doesn’t capture WebSocket messages.

That means your AI can’t see:

  • What the server is pushing to the client
  • Out-of-order messages causing state corruption
  • Payload format mismatches (server sends txt, client expects text)
  • Connection drops and failed reconnections
  • Authentication token expiration on long-lived connections

With Gasoline:

observe({what: "websocket_status"}) // Active connections
observe({what: "websocket_events"}) // Message stream

Every frame, every direction, every connection — captured automatically and queryable by your AI.

Problem 3: Distributed Applications Break It

Section titled “Problem 3: Distributed Applications Break It”

Real applications aren’t one tab. They’re:

  • A customer app that talks to an admin panel that reads from a shared API
  • A web app that authenticates via an OAuth provider and fetches data from a third-party service
  • A frontend that sends events to a message queue that triggers a background worker that updates a dashboard

Chrome DevTools MCP gives you one browser tab’s console output. It has no concept of cross-tab workflows, multi-service architectures, or the network calls that tie them together.

Gasoline captures the full picture:

  • Network bodies show exactly what your app sent and what the API returned
  • WebSocket events show real-time communication between services
  • Multi-tab awareness means you can observe activity across tabs
  • Timeline interleaves all events chronologically, so you see the full distributed flow

When your AI can see that Tab A’s API call returned a stale token, which caused Tab B’s WebSocket to disconnect, which triggered the error the user reported — that’s when debugging gets fast.

Problem 4: It Fails on Constantly Changing UIs

Section titled “Problem 4: It Fails on Constantly Changing UIs”

Development moves fast. The UI changes every sprint — new components, renamed classes, restructured layouts. DevTools MCP gives your AI console logs and a DOM snapshot. The AI has to ask you what changed and guess at selectors.

Gasoline’s interact tool uses semantic selectors that adapt:

interact({action: "click", selector: "text=Submit"})
interact({action: "type", selector: "label=Email", text: "user@example.com"})
interact({action: "list_interactive"}) // Discover all elements

When the UI changes, text=Submit still finds the submit button. label=Email still finds the email field. And if the AI is unsure, it calls list_interactive to get a full inventory of every clickable and typeable element on the page.

DevTools MCP can’t interact with the page at all. Gasoline lets the AI click, type, navigate, and verify — the full development cycle in one tool.

Problem 5: It Doesn’t Actually Accelerate Development

Section titled “Problem 5: It Doesn’t Actually Accelerate Development”

The promise of browser MCP tools is faster development cycles. But DevTools MCP only gives the AI some of the data. The developer still has to:

  1. Copy-paste error details the AI can’t see
  2. Describe the visual state (“the button is greyed out”)
  3. Manually check network responses
  4. Explain the WebSocket behavior
  5. Reproduce the issue step by step

You’re still the bottleneck. You’re still shuttling context between the browser and the AI.

Gasoline gives the AI everything:

DataDevTools MCPGasoline
Console errorsYesYes, with deduplication and clustering
Network requestsPartialFull bodies, filtered by URL/status
WebSocket messagesNoFull capture with filtering
ScreenshotsNoYes
User actionsNoRecorded automatically
Web VitalsNoLCP, CLS, INP, FCP with regression detection
AccessibilityNoWCAG audits
API schemasNoAuto-inferred from traffic
Page interactionNoClick, type, navigate, verify

When the AI has the full picture, it doesn’t need you to be the intermediary. It observes, diagnoses, and fixes — at the speed of API calls, not the speed of copy-paste.

Problem 6: Production Dependencies and Supply Chain Risk

Section titled “Problem 6: Production Dependencies and Supply Chain Risk”

Chrome DevTools MCP and BrowserTools MCP require Node.js and npm packages. That’s:

  • A runtime dependency (Node.js must be installed)
  • Package manager overhead (npm/yarn, lock files, version conflicts)
  • Supply chain exposure (every dependency is a potential vulnerability)

Gasoline is a single Go binary. Zero production dependencies. No node_modules. No supply chain risk.

Terminal window
npx gasoline-mcp # Downloads single binary, runs it

The Real Problem DevTools MCP Doesn’t Solve

Section titled “The Real Problem DevTools MCP Doesn’t Solve”

The bottleneck in modern development isn’t “the AI can’t see console errors.” It’s “the AI can’t see enough to work autonomously.”

DevTools MCP gives the AI a partial view — console output and DOM snapshots. That’s better than nothing, but it still leaves the developer as the primary context provider.

Gasoline gives the AI a complete view — errors, network, WebSockets, performance, accessibility, visual state, and browser control. The AI becomes a full participant in the development cycle: observe the bug, understand the context, interact with the app, verify the fix.

That’s the difference between “AI that helps you debug” and “AI that debugs.”

Chrome DevTools MCPGasoline MCP
Setup--remote-debugging-port flagStandard extension
SecuritySandbox disabledFull sandbox preserved
Console errorsYesYes + dedup + clustering + bundles
Network bodiesNoFull request/response capture
WebSocketNoFull capture and filtering
Browser controlNoClick, type, navigate, verify
ScreenshotsNoYes
Web VitalsNoLCP, CLS, INP, FCP
AccessibilityNoWCAG audits + SARIF export
Test generationNoPlaywright tests from sessions
Multi-clientSingle connectionUnlimited concurrent clients
DependenciesNode.js + npmZero (single Go binary)
PrivacyLocalLocal, 127.0.0.1 only
Overhead~5ms per intercept< 0.1ms per intercept

Chrome DevTools MCP was the right idea at the right time. Gasoline is what comes next.

Why Gasoline Is Written in Go

Go was chosen for Gasoline’s MCP server because it compiles to a single binary, has zero runtime dependencies, and doesn’t rot. Here’s why that matters for a developer tool you depend on daily.

You clone a Node.js project from last year. You run npm install. It fails. A dependency broke. You update it. Now another dependency is incompatible. You spend an hour fixing a project that worked perfectly 12 months ago.

This is code rot — software that degrades not because its logic changed, but because the ecosystem around it shifted.

In the JavaScript ecosystem, code rot is constant. The average npm package has 79 transitive dependencies. Each one is a ticking clock — an author who might yank the package, a breaking change in a minor version, a deprecated API, a CVE that forces an urgent update.

Gasoline doesn’t have this problem. It has zero production dependencies.

Gasoline’s Go server imports nothing outside the Go standard library. No HTTP frameworks. No logging libraries. No JSON-RPC packages. No ORMs.

import (
"encoding/json"
"fmt"
"net/http"
"os"
"sync"
)

That’s it. Everything Gasoline does — HTTP serving, JSON-RPC 2.0, ring buffers, cursor pagination, file persistence, rate limiting, multi-client bridging — is built on Go’s standard library.

What this means in practice:

  • No go.sum file to audit. There are no third-party dependencies to check for vulnerabilities.
  • No supply chain attacks. You can’t compromise what doesn’t exist.
  • No version conflicts. No “package X requires Y v2 but Z requires Y v1.”
  • No breaking updates. Go’s compatibility guarantee means code written for Go 1.21 compiles on Go 1.25.

go build produces a single executable. No runtime required. No interpreter. No virtual machine.

When you run npx gasoline-mcp, it downloads a pre-compiled binary for your platform and runs it. There’s no:

  • npm install (no node_modules)
  • pip install (no Python environment)
  • go install (no Go toolchain needed)
  • .jar files (no JVM)

One binary. It runs. That’s the deployment story.

Compare this to tools built on Node.js:

Node.js MCP ServerGasoline (Go)
Runtime requiredNode.js 18+None
Package managernpm/yarn/pnpmNone
DependenciesDozens to hundredsZero
Install time10-60 seconds< 2 seconds (binary download)
Disk footprint50-200 MB (node_modules)~15 MB (single binary)
Cold start500ms-2s (require/import resolution)300-400ms
CVE exposureEvery dependencyGo stdlib only

Go has a forward compatibility guarantee: code written for Go 1.x compiles on all future 1.x versions. This guarantee has held since Go 1.0 in 2012.

In practice, this means:

  • Code written today compiles in 5 years without changes
  • No “upgrade to the latest framework version” treadmill
  • No deprecation warnings that become errors in the next release
  • No migration guides to follow every 18 months

For a developer tool that people depend on daily, this stability is a feature, not a constraint.

Go compiles to native machine code. There’s no interpreter overhead, no JIT warmup, no garbage collection pauses that matter at Gasoline’s scale.

Gasoline’s performance targets:

MetricTargetWhy Go helps
Console intercept overhead< 0.1msNo runtime startup per request
HTTP endpoint latency< 0.5msnet/http is battle-tested and fast
Cold start< 600msStatic binary, no dependency resolution
Concurrent clients500+Goroutines are cheap (~2KB stack each)
Memory under loadPredictableRing buffers with fixed capacity

Go’s concurrency model (goroutines + channels) makes the multi-client bridge pattern trivial. Each MCP client gets its own goroutine. The ring buffers are protected by sync.RWMutex. No thread pool configuration, no async/await complexity, no callback hell.

Node.js is great for web applications. But for a local system tool like an MCP server, it has drawbacks:

Dependency sprawl. Even a simple HTTP server pulls in Express or Fastify, which pull in dozens of sub-dependencies. Each one needs maintenance.

Runtime requirement. Users need Node.js installed. Version mismatches cause issues. Some users have Node 16, some have 22, and the behaviors differ.

Startup overhead. Node.js resolves and loads modules at startup. For a CLI tool that needs to be ready in milliseconds, this adds latency.

Single-threaded concurrency. Node.js uses an event loop. Under load (500 concurrent MCP clients), this becomes a bottleneck. Go’s goroutines scale to thousands of concurrent operations without additional complexity.

Rust would also work well for Gasoline — single binary, no runtime, excellent performance. The tradeoff is development speed.

Go’s simpler type system and garbage collector mean faster iteration. For a product that ships features weekly and maintains a 140-test suite, developer velocity matters more than squeezing the last nanosecond out of a buffer read.

Go is fast enough. And “fast enough with faster development” beats “fastest possible with slower development” for a tool that’s still rapidly evolving.

Go gives Gasoline:

  • Zero dependencies — nothing to break, nothing to patch, nothing to audit
  • Single binary — download and run, no runtime required
  • Stability — compiles the same way in 5 years
  • Performance — native code, goroutine concurrency, predictable memory
  • Fast development — simple language, fast compilation, easy concurrency

The language choice is a product decision, not just a technical one. When your tool has zero dependencies, it doesn’t rot. When it’s a single binary, it installs in seconds. When it’s stable, users trust it.

That trust compounds over time. And time is the one dependency you can’t pin to a version.