Vũ Văn HảiFull-stack · AI-native
Hướng dẫnBlog
Trao đổi dự án

© 2026 Vũ Văn Hải · Viết từ kinh nghiệm triển khai thật.

Trang chủHướng dẫnBlogRSS
  1. Hướng dẫn
  2. /Công cụ dev
  3. /Chrome riêng cho chrome-devtools-mcp: đăng nhập được và không đụng Chrome chính

Chrome riêng cho chrome-devtools-mcp: đăng nhập được và không đụng Chrome chính

Cấu hình một hồ sơ Chrome riêng cho từng project để chrome-devtools-mcp (Claude Code, Cursor...) điều khiển, vẫn đăng nhập được Google/Cloudflare và giữ phiên, chạy nhiều project song song, không chạm vào Chrome cá nhân của bạn.

Cập nhật: 22 thg 9, 202611 phút đọc
Claude CodeMCPTự động hóa trình duyệtWindows
Mục lục
  • Vấn đề với cấu hình mặc định
  • So sánh các cách khởi động
  • Vì sao Chrome cho phép mở cổng debug trên hồ sơ riêng
  • Vì sao đăng nhập bị chặn, và cách né hợp lệ
  • Cách hoạt động
  • Setup cho một project
  • Mã nguồn
  • Launcher open-chrome-mcp.ps1
  • Hai file bấm đúp của project
  • Mục chrome-devtools trong .mcp.json
  • Dùng hằng ngày
  • Bảo mật
  • Xử lý sự cố
  • Tham khảo

Khi để chrome-devtools-mcp (server MCP điều khiển trình duyệt cho Claude Code, Cursor, VS Code...) tự mở Chrome, bạn gặp ba vấn đề: Google và Cloudflare chặn đăng nhập, hai project mở trình duyệt cùng lúc thì lỗi, và agent có thể nhìn thấy mọi tab trong Chrome cá nhân của bạn. Bài này dựng một hồ sơ Chrome riêng cho từng project để MCP chỉ gắn vào đúng trình duyệt đó, vẫn đăng nhập được và giữ phiên, chạy song song nhiều project.

Trong bài, <profiles-root> là thư mục bạn chứa các hồ sơ (ví dụ %USERPROFILE%\chrome-mcp-profiles), <project-slug> là tên ngắn của một project (chữ thường, số, gạch ngang). Hướng dẫn kiểm chứng trên Windows 11 + Chrome stable 153 + chrome-devtools-mcp 1.9.0; ý tưởng áp dụng được cho các client MCP khác.

Vấn đề với cấu hình mặc định

Khi .mcp.json khai chrome-devtools-mcp không kèm cờ nào, MCP tự mở Chrome bằng Puppeteer với một hồ sơ dùng chung cho mọi project. Bốn hệ quả:

Vấn đềNguyên nhân
Google chặn đăng nhập ("This browser or app may not be secure"), Cloudflare Turnstile báo lỗi xác minhPuppeteer thêm cờ --enable-automation, và bản thân cổng remote-debugging cũng bật navigator.webdriver = true - trang web thấy trình duyệt đang bị điều khiển
Hai project mở trình duyệt cùng lúc: The browser is already running... Use --isolatedHồ sơ mặc định dùng chung; Chrome chỉ cho một tiến trình trên mỗi thư mục dữ liệu
Agent thấy nhầm tab / hồ sơ cá nhân của bạn--autoConnect trơn (không kèm hồ sơ riêng) nối vào cả tiến trình Chrome chính, thấy mọi hồ sơ và mọi tab
Dùng --isolated thì mất đăng nhập mỗi lần đóng--isolated tạo thư mục tạm và xóa khi Chrome đóng

So sánh các cách khởi động

Điểm mấu chốt: MCP tự mở Chrome thì luôn kèm cờ tự động hóa (bị chặn đăng nhập); còn bạn tự mở Chrome rồi MCP chỉ CONNECT vào thì không có cờ đó.

CáchĐăng nhập Google/CFGiữ đăng nhậpCờ tự động hóaNhiều project song songChrome tắt theo MCP
Mặc định (không cờ), MCP tự mởKhôngKhông (hồ sơ chung)CóKhôngCó
--isolated, MCP tự mởKhôngKhông (xóa khi đóng)CóCóCó
Chỉ --userDataDir riêng, MCP tự mởKhôngCóCóKhôngCó
--autoConnect + --userDataDir riêng, BẠN tự mở ChromeCóCóKhôngCóKhông

Cách cuối là mục tiêu của bài. Bạn mở Chrome bằng một launcher (không cờ tự động hóa), MCP chỉ đọc cổng debug của đúng thư mục đó và gắn vào.

Vì sao Chrome cho phép mở cổng debug trên hồ sơ riêng

Từ Chrome 136, cờ --remote-debugging-port và --remote-debugging-pipe bị bỏ qua trên thư mục dữ liệu mặc định; muốn dùng thì phải kèm --user-data-dir trỏ tới một thư mục khác. Lý do: kể từ khi bật App-Bound Encryption, kẻ tấn công lợi dụng remote-debugging để rút cookie, nên Chrome khóa đường này trên hồ sơ mặc định.

Nhờ thay đổi này, Chrome cá nhân của bạn (hồ sơ mặc định) không thể bị mở cổng debug bằng cờ dòng lệnh. Chỉ thư mục dữ liệu RIÊNG mới bật được cổng - đúng cái ta cần.

Vì sao đăng nhập bị chặn, và cách né hợp lệ

Google/Cloudflare chặn khi thấy navigator.webdriver === true. Thuộc tính này bật true khi có bất kỳ dấu hiệu điều khiển nào:

Yếu tố khi mở Chromenavigator.webdriverĐăng nhập được?
--enable-automation (Puppeteer tự thêm khi MCP mở Chrome)trueKhông
--headlesstrueKhông
--remote-debugging-port (kể cả =0) hoặc --remote-debugging-pipetrueKhông
Không cờ nào ở trên (Chrome thường)falseCó

Hệ quả: không thể đăng nhập trong lúc cổng debug đang mở. Cách né hợp lệ (không dùng mẹo giả mạo) là tách hai chế độ trên cùng một thư mục dữ liệu:

  • Chế độ đăng nhập: mở Chrome KHÔNG cổng debug, không cờ tự động hóa. Bạn đăng nhập Google/Cloudflare như trình duyệt thường. Cookie lưu vào thư mục hồ sơ.
  • Chế độ làm việc: đóng hẳn Chrome trên, mở lại VỚI --remote-debugging-port=0. MCP gắn vào. Cookie từ lần đăng nhập vẫn còn, nên các trang vẫn nhận phiên - mà lúc này không cần đăng nhập lại nữa.

Đừng dùng stealth plugin hay sửa navigator.webdriver để "qua mặt" Google/Cloudflare. Đó là mẹo vượt cơ chế chống bot. Cách tách hai chế độ ở trên đăng nhập bằng một phiên trình duyệt SẠCH (không điều khiển), hoàn toàn hợp lệ.

Cách hoạt động

Chrome chính của bạn            Chrome riêng project A            Chrome riêng project B
(hồ sơ mặc định, không cổng)    <profiles-root>\A                 <profiles-root>\B
        ^                       --remote-debugging-port=0         --remote-debugging-port=0
        |                              | ghi                             | ghi
  không MCP nào nối vào         A\DevToolsActivePort (cổng ngẫu nhiên)   B\DevToolsActivePort
                                       ^ đọc                            ^ đọc
                               MCP project A                     MCP project B
                               --autoConnect                     --autoConnect
                               --userDataDir=<...>\A             --userDataDir=<...>\B

Luồng chi tiết:

  1. Launcher chạy chrome.exe --user-data-dir="<profiles-root>\<slug>" --no-first-run --no-default-browser-check --remote-debugging-port=0.
  2. Chrome chọn một cổng trống, ghi file <thư mục>\DevToolsActivePort gồm 2 dòng: số cổng và đường dẫn /devtools/browser/<uuid>. Cổng chỉ nghe trên 127.0.0.1.
  3. Có --autoConnect, MCP đọc DevToolsActivePort trong đúng thư mục --userDataDir, dựng ws://127.0.0.1:<port><path> rồi kết nối. Không có file hoặc cổng không trả lời thì MCP báo Could not connect to Chrome in <thư mục> và KHÔNG tự mở Chrome.
  4. Khi phiên MCP kết thúc, MCP chỉ ngắt kết nối - Chrome vẫn mở.

Setup cho một project

  1. Tạo thư mục gốc <profiles-root> (ví dụ %USERPROFILE%\chrome-mcp-profiles) và đặt launcher open-chrome-mcp.ps1 (mã ở dưới) vào đó.
  2. Chọn <project-slug> khớp regex ^[a-z0-9][a-z0-9-]*$, mỗi project một slug riêng.
  3. Tạo 2 file .cmd ở thư mục gốc của project (mã ở dưới), thay <project-slug> và đường dẫn launcher.
  4. Sửa .mcp.json của project: mục chrome-devtools trỏ --autoConnect --userDataDir tới <profiles-root>\<project-slug>.
  5. Đăng nhập (nếu project cần tài khoản): chạy chế độ đăng nhập, đăng nhập, đóng hẳn.
  6. Mở chế độ làm việc, rồi restart client MCP để nạp .mcp.json mới.

Mã nguồn

Launcher open-chrome-mcp.ps1

Đặt ở <profiles-root>. Lưu UTF-8 có BOM (PowerShell 5.1 đọc file không BOM theo ANSI, chữ tiếng Việt sẽ lỗi). Script tự định vị thư mục hồ sơ theo vị trí của chính nó, nên không chứa đường dẫn tuyệt đối.

param(
    [Parameter(Mandatory = $true)]
    [ValidatePattern('^[a-z0-9][a-z0-9-]*$')]
    [string]$Project,
    [switch]$Login
)

$ErrorActionPreference = 'Stop'
$profileDir = Join-Path $PSScriptRoot $Project     # <profiles-root>\<Project>
$portFile   = Join-Path $profileDir 'DevToolsActivePort'

$chrome = @(
    "$env:ProgramFiles\Google\Chrome\Application\chrome.exe",
    "${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
    "$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe"
) | Where-Object { Test-Path $_ } | Select-Object -First 1
if (-not $chrome) { Write-Host 'Không tìm thấy Google Chrome.' -ForegroundColor Red; exit 1 }

# Chrome chỉ cho một tiến trình trên mỗi thư mục dữ liệu. Nếu đã có Chrome chạy trên thư
# mục này, lần mở mới BỎ QUA các cờ truyền vào -> phải kiểm tra trước để không mở nhầm chế độ.
function Test-ProfileChromeRunning {
    $needle = "--user-data-dir=`"$profileDir`"".ToLowerInvariant()
    [bool](Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" |
        Where-Object { $_.CommandLine -and $_.CommandLine.ToLowerInvariant().Contains($needle) })
}

# Trả về số cổng nếu cổng debug trong DevToolsActivePort đang trả lời, ngược lại $null.
function Get-LiveDebugPort {
    try {
        if (-not (Test-Path $portFile)) { return $null }
        $port = (Get-Content $portFile -TotalCount 1).Trim()
        if (-not $port) { return $null }
        Invoke-RestMethod "http://127.0.0.1:$port/json/version" -TimeoutSec 2 | Out-Null
        return $port
    } catch { return $null }
}

if (Test-ProfileChromeRunning) {
    $port = Get-LiveDebugPort
    if ($Login) {
        if ($port) { Write-Host "Đang mở ở chế độ làm việc (cổng $port). Đóng hẳn rồi chạy lại." -ForegroundColor Yellow; exit 1 }
        Write-Host 'Đang mở ở chế độ đăng nhập rồi.' -ForegroundColor Green; exit 0
    }
    if ($port) { Write-Host "Đã sẵn sàng cho MCP (cổng $port)." -ForegroundColor Green; exit 0 }
    Write-Host 'Đang mở nhưng không có cổng debug (chế độ đăng nhập). Đóng hẳn rồi chạy lại.' -ForegroundColor Yellow
    exit 1
}

New-Item -ItemType Directory -Force $profileDir | Out-Null
$chromeArgs = @("--user-data-dir=`"$profileDir`"", '--no-first-run', '--no-default-browser-check')
if (-not $Login) {
    Remove-Item $portFile -Force -ErrorAction SilentlyContinue  # xóa cổng cũ của lần chạy trước
    $chromeArgs += '--remote-debugging-port=0'
}
Start-Process -FilePath $chrome -ArgumentList $chromeArgs

if ($Login) {
    Write-Host 'Đã mở ở chế độ đăng nhập. Đăng nhập xong thì đóng hẳn, rồi mở lại chế độ làm việc.' -ForegroundColor Green
    exit 0
}

for ($i = 0; $i -lt 40; $i++) {
    $port = Get-LiveDebugPort
    if ($port) { Write-Host "Đã mở cho MCP (cổng $port, chỉ trong máy)." -ForegroundColor Green; exit 0 }
    Start-Sleep -Milliseconds 250
}
Write-Host 'Đã mở nhưng sau 10 giây chưa thấy cổng debug.' -ForegroundColor Red
exit 1

Hai file bấm đúp của project

Đặt ở thư mục gốc project, giữ nội dung ASCII (cmd đọc file batch theo bảng mã OEM). Thay <project-slug> và đường dẫn launcher.

open-chrome-for-mcp.cmd (chế độ làm việc):

@echo off
rem Mo Chrome rieng cua project o che do lam viec (co cong remote-debugging ngau nhien)
rem de chrome-devtools-mcp (--autoConnect --userDataDir) gan vao.
powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\chrome-mcp-profiles\open-chrome-mcp.ps1" -Project <project-slug>
if errorlevel 1 (pause) else (timeout /t 4 >nul)

open-chrome-for-mcp-login.cmd (chế độ đăng nhập):

@echo off
rem Mo Chrome rieng o che do dang nhap (KHONG cong debug) de Google / Cloudflare dang nhap
rem nhu trinh duyet thuong. Dang nhap, dong han Chrome do, roi chay open-chrome-for-mcp.cmd.
powershell -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\chrome-mcp-profiles\open-chrome-mcp.ps1" -Project <project-slug> -Login
if errorlevel 1 (pause) else (timeout /t 6 >nul)

-ExecutionPolicy Bypass chỉ áp cho đúng tiến trình PowerShell đó, không đổi cài đặt hệ thống.

Mục chrome-devtools trong .mcp.json

JSON không giãn biến môi trường, nên điền đường dẫn tuyệt đối. Trong JSON, \ viết \\.

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "cmd",
      "args": [
        "/c", "npx", "-y", "[email protected]",
        "--autoConnect",
        "--userDataDir=<profiles-root>\\<project-slug>"
      ]
    }
  }
}

cmd /c là bắt buộc trên Windows vì npx là file .cmd. Ghim version (không @latest) để tránh tự tải bản vừa publish - một lớp phòng tấn công chuỗi cung ứng npm. Đừng thêm --isolated (xung đột với --autoConnect lẫn --userDataDir), --browserUrl hay --executablePath.

Dùng hằng ngày

Khi nàoLàm gì
Lần đầu, hoặc khi trang bắt đăng nhập lạiĐóng Chrome riêng, chạy chế độ đăng nhập, đăng nhập, đóng hẳn
Muốn agent làm việc trên trình duyệtAgent tự mở khi cần; hoặc bấm đúp file chế độ làm việc
Xong việcĐóng cửa sổ Chrome riêng - đăng nhập vẫn được giữ
Muốn xóa sạch dữ liệu projectĐóng Chrome riêng, xóa thư mục <profiles-root>\<slug> (mất hết đăng nhập)

Trong lúc agent làm việc, bạn vẫn dùng Chrome chính bình thường. Nên chọn một màu theme riêng cho Chrome này để dễ phân biệt.

Bảo mật

  • Khi Chrome riêng mở ở chế độ làm việc, mọi chương trình trên máy đều nối được vào cổng debug (cổng chỉ nghe 127.0.0.1, không lộ ra mạng) và điều khiển Chrome đó, kể cả đọc cookie. Vì vậy: chỉ đăng nhập các tài khoản thật sự cần; xong việc thì đóng Chrome riêng.
  • Giữ TẮT chrome://inspect/#remote-debugging trên Chrome chính - đó là đường duy nhất còn lại để mở cổng debug trên hồ sơ mặc định.
  • Thư mục <profiles-root>\<slug> chứa cookie đăng nhập. Không commit, không đồng bộ cloud, không chia sẻ.
  • Cân nhắc thêm cờ: --redactNetworkHeaders (ẩn header nhạy cảm khi đọc network), --allowedUrlPattern / --blockedUrlPattern (giới hạn trang MCP được vào).

Xử lý sự cố

Triệu chứngCách xử lý
Could not connect to Chrome... ENOENT ... DevToolsActivePortChrome riêng chưa mở ở chế độ làm việc - chạy launcher rồi gọi lại công cụ
Could not connect... dù có file DevToolsActivePortFile cổng của lần trước (Chrome đã tắt) hoặc đang ở chế độ đăng nhập - launcher sẽ xóa file cũ khi mở lại
Google "This browser or app may not be secure"Đang đăng nhập lúc có cổng debug / MCP gắn vào - dùng chế độ đăng nhập (không cổng)
Chữ tiếng Việt lỗi trong cửa sổ launcheropen-chrome-mcp.ps1 bị lưu mất BOM - lưu lại UTF-8 có BOM
running scripts is disabled on this systemChạy .ps1 trực tiếp dưới ExecutionPolicy mặc định - chạy qua file .cmd
Launcher báo "đang mở nhưng không có cổng debug" dù đã đóng cửa sổChrome còn chạy nền (cài đặt "chạy ứng dụng nền khi đóng") - thoát từ khay hệ thống rồi chạy lại
Client MCP không thấy công cụ chrome-devtools sau khi sửa .mcp.jsonChưa restart phiên, hoặc server chưa được duyệt - restart client MCP

Tham khảo

  • Chrome for Developers - Changes to remote debugging switches (Chrome 136): https://developer.chrome.com/blog/remote-debugging-port
  • chrome-devtools-mcp - Advanced usage (--autoConnect, --browser-url, cảnh báo bảo mật cổng debug): https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/advanced-usage.md
  • Connect your AI agent to your personal browser with auto-connect (Chrome 144+): https://developer.chrome.com/docs/devtools/agents/use-cases/auto-connect
  • MDN - Navigator: webdriver property: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver
Bài trướcSửa lỗi kết nối Claude Code trên Windows (ECONNREFUSED, Bun crash)

Bài liên quan

  • Kế toán token cho AI agent: hiểu token, cửa sổ ngữ cảnh và cache từ gốc

    Model không có trí nhớ - mọi thứ trông giống trí nhớ đều do code của bạn gửi lại. Hiểu đúng một câu đó là hiểu toàn bộ chuyện token, cửa sổ ngữ cảnh và prompt caching, và vì sao hoá đơn của một agent lại phình lên.

  • Clone database PostgreSQL từ VPS về máy local Windows

    Tạo bản sao đầy đủ (schema lẫn data) của database PostgreSQL trên VPS về máy dev Windows bằng SSH Tunnel, pg_dump và pg_restore, kèm cách đổi port PostgreSQL local để không xung đột.

    Database

    Database
  • Debug và bypass SSL pinning của app Android trên giả lập

    Soi traffic API của một app Android có SSL pinning bằng LDPlayer 9 và HTTP Toolkit: bật root, kết nối ADB, tự động bypass SSL, và xử lý các lớp bảo vệ nâng cao.

    Công cụ dev

    Công cụ dev

Viết bởi Vũ Văn Hải

Tôi là Hải, full-stack developer ở TP. Hồ Chí Minh. Các bài ở đây đúc kết từ những hệ thống tôi tự dựng và vận hành. Cần dựng hoặc gỡ rối một hệ thống tương tự? Cứ nhắn tôi.

Trao đổi dự ánXem thêm hướng dẫn

Thấy sai sót hoặc lệnh không còn chạy? Báo cho tôi

Mục lục

  • Vấn đề với cấu hình mặc định
  • So sánh các cách khởi động
  • Vì sao Chrome cho phép mở cổng debug trên hồ sơ riêng
  • Vì sao đăng nhập bị chặn, và cách né hợp lệ
  • Cách hoạt động
  • Setup cho một project
  • Mã nguồn
  • Launcher open-chrome-mcp.ps1
  • Hai file bấm đúp của project
  • Mục chrome-devtools trong .mcp.json
  • Dùng hằng ngày
  • Bảo mật
  • Xử lý sự cố
  • Tham khảo