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.
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 minh | Puppeteer 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 --isolated | Hồ 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/CF | Giữ đăng nhập | Cờ tự động hóa | Nhiều project song song | Chrome tắt theo MCP |
|---|---|---|---|---|---|
| Mặc định (không cờ), MCP tự mở | Không | Không (hồ sơ chung) | Có | Không | Có |
--isolated, MCP tự mở | Không | Không (xóa khi đóng) | Có | Có | Có |
Chỉ --userDataDir riêng, MCP tự mở | Không | Có | Có | Không | Có |
--autoConnect + --userDataDir riêng, BẠN tự mở Chrome | Có | Có | Không | Có | 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ở Chrome | navigator.webdriver | Đăng nhập được? |
|---|---|---|
--enable-automation (Puppeteer tự thêm khi MCP mở Chrome) | true | Không |
--headless | true | Không |
--remote-debugging-port (kể cả =0) hoặc --remote-debugging-pipe | true | Không |
| Không cờ nào ở trên (Chrome thường) | false | Có |
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=<...>\BLuồng chi tiết:
- Launcher chạy
chrome.exe --user-data-dir="<profiles-root>\<slug>" --no-first-run --no-default-browser-check --remote-debugging-port=0. - Chrome chọn một cổng trống, ghi file
<thư mục>\DevToolsActivePortgồm 2 dòng: số cổng và đường dẫn/devtools/browser/<uuid>. Cổng chỉ nghe trên127.0.0.1. - Có
--autoConnect, MCP đọcDevToolsActivePorttrong đúng thư mục--userDataDir, dựngws://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áoCould not connect to Chrome in <thư mục>và KHÔNG tự mở Chrome. - 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
- Tạo thư mục gốc
<profiles-root>(ví dụ%USERPROFILE%\chrome-mcp-profiles) và đặt launcheropen-chrome-mcp.ps1(mã ở dưới) vào đó. - Chọn
<project-slug>khớp regex^[a-z0-9][a-z0-9-]*$, mỗi project một slug riêng. - Tạo 2 file
.cmdở thư mục gốc của project (mã ở dưới), thay<project-slug>và đường dẫn launcher. - Sửa
.mcp.jsoncủa project: mụcchrome-devtoolstrỏ--autoConnect --userDataDirtới<profiles-root>\<project-slug>. - Đăng nhập (nếu project cần tài khoản): chạy chế độ đăng nhập, đăng nhập, đóng hẳn.
- Mở chế độ làm việc, rồi restart client MCP để nạp
.mcp.jsonmớ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 1Hai 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ào | Là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ệt | Agent 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-debuggingtrê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ứng | Cách xử lý |
|---|---|
Could not connect to Chrome... ENOENT ... DevToolsActivePort | Chrome 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 DevToolsActivePort | File 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ổ launcher | open-chrome-mcp.ps1 bị lưu mất BOM - lưu lại UTF-8 có BOM |
running scripts is disabled on this system | Chạ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.json | Chư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