
Claude Code나 Cursor 같은 AI 코딩 에이전트를 WSL2에서 쓰다 보면, 브라우저를 자동으로 열어서 페이지를 확인하거나 스크린샷을 찍는 기능이 필요할 때가 있습니다. 이때 사용하는 게 브라우저 MCP인데, WSL2 환경에서는 Playwright MCP와 Chrome DevTools MCP 두 가지 선택지가 있습니다.
Chrome DevTools MCP는 CDP(Chrome DevTools Protocol)라는 걸 사용합니다. CDP는 Chrome이 제공하는 원격 제어 인터페이스인데, 디버그 모드로 실행한 Chrome에 네트워크로 연결해서 페이지 탐색, 스크린샷, DOM 조작 등을 할 수 있게 해줍니다. 개발자 도구(F12)가 내부적으로 쓰는 것과 같은 프로토콜입니다.
저도 처음에는 이미 쓰고 있는 Windows Chrome을 CDP로 연결하면 편하겠다 싶어서 Chrome DevTools MCP부터 시도했습니다. 그런데 WSL2의 네트워크 구조 때문에 결국 안 되더라고요. Playwright MCP가 WSL2에서는 가장 간편한 선택지였습니다. CDP 방식도 relay(중간에서 네트워크 요청을 받아서 다른 곳으로 전달해주는 중계 서버)를 하나 끼우면 우회할 수 있긴 한데, 설정이 좀 더 필요합니다.
이 글에서는 두 MCP의 차이, Playwright 설정법, 그리고 CDP를 WSL2에서도 쓸 수 있는 우회법까지 정리해봤습니다.
Playwright MCP와 Chrome DevTools MCP의 차이

둘 다 브라우저를 제어하는 MCP인데, 작동 방식이 완전히 다릅니다.
Playwright MCP는 자체적으로 Chromium 바이너리를 들고 있어서 MCP가 직접 브라우저를 실행합니다. 외부에 아무것도 미리 띄워놓을 필요 없이, 브라우저 실행부터 종료까지 MCP가 전부 관리합니다. 실행되는 Chromium은 Linux 바이너리입니다.
Chrome DevTools MCP는 반대입니다. 이미 실행 중인 Chrome에 CDP(Chrome DevTools Protocol)로 연결하는 방식입니다. Windows에서 Chrome을 --remote-debugging-port=9222 옵션으로 미리 열어놔야 하고, MCP는 브라우저를 실행하지 않고 연결만 합니다. 대신 기존 Chrome의 확장 프로그램이나 로그인 상태를 그대로 쓸 수 있다는 장점이 있습니다.
| 항목 | Playwright MCP | Chrome DevTools MCP |
|---|---|---|
| 브라우저 실행 | MCP가 직접 실행 | 사용자가 수동으로 미리 실행 |
| 사용 브라우저 | Linux Chromium (내장) | Windows Chrome (외부) |
| 사전 준비 | 없음 | Chrome 디버그 모드 실행 필요 |
| WSL2 호환 | 가능 (WSLg) | 불가 (네트워크 격리) |
| 장점 | 설정 간단, 자동화 완전 | Windows Chrome 그대로 사용, 확장/로그인 유지 |
Windows나 Mac에서 네이티브로 쓸 때는 둘 다 잘 됩니다. 문제는 WSL2 환경입니다.
WSL2에서 Chrome DevTools MCP가 안 되는 이유
WSL2는 WSL1과 달리 경량 VM입니다. 독립된 네트워크 스택을 가지고 있어서, WSL2 안에서 localhost를 치면 Windows가 아니라 WSL2 VM 자체를 가리킵니다.

Windows에서 Chrome을 디버그 모드로 띄워놓으면 localhost:9222에 포트가 열립니다. 그런데 WSL2에서 curl localhost:9222를 날리면 이게 Windows의 9222가 아니라 WSL2 VM 안의 9222로 갑니다. 당연히 아무것도 없으니 connection refused가 뜹니다.
그러면 Windows Host IP로 접근하면 되지 않느냐고 할 수 있는데, Chrome이 기본적으로 127.0.0.1에만 디버그 포트를 바인딩하기 때문에 외부(WSL2 VM 포함)에서는 접근이 안 됩니다.
실제로 테스트해 보면 이렇습니다.

netsh 포트포워딩이나 socat 터널 같은 방법이 있긴 한데, 재시작하면 초기화되거나 설정이 번거롭습니다. Chrome/Edge 자체가 0.0.0.0 바인딩을 지원하지 않아서 직접 연결은 안 됩니다.
다만 Node.js relay를 하나 끼우면 꽤 깔끔하게 우회할 수 있는데, 이건 뒤에서 자세히 다루겠습니다.
WSLg가 뭔지부터 알아야 합니다
여기서 의문이 생길 수 있습니다. WSL2가 VM이면 Playwright가 실행한 Linux Chromium은 어떻게 화면에 보이는 건가?
답은 WSLg입니다. Windows 11부터 WSL2에 내장된 GUI 지원 기능인데, 별도로 X 서버를 설치할 필요 없이 Linux GUI 앱이 Windows 바탕화면에 네이티브 창처럼 표시됩니다. 작업표시줄에도 별도 아이콘으로 나타나고, GPU 가속까지 됩니다.
Windows 10 시절에는 VcXsrv 같은 X 서버를 따로 설치하고, DISPLAY 환경변수를 잡아주고, 방화벽 규칙도 추가해야 했습니다. WSLg가 이런 번거로운 과정을 전부 없애줬습니다.
Playwright가 headless=false로 Chromium을 실행하면, Chromium이 DISPLAY=:0(WSLg의 X 서버)에 화면을 렌더링 하고, WSLg가 이걸 받아서 Windows 바탕화면에 네이티브 창으로 띄워줍니다. WSL2 안에서 실행된 브라우저가 Windows 바탕화면에 그냥 뜨는 겁니다.

WSLg가 정상 동작하는지는 간단하게 확인할 수 있습니다.
Playwright MCP 설정 방법
사전 준비
# Playwright 브라우저 설치 (한 번만)
npx -y @playwright/mcp@latest
# 설치된 Chromium 경로 확인
ls ~/.cache/ms-playwright/chromium-*/chrome-linux64/chrome
# WSLg 동작 확인
echo $DISPLAY # :0 이어야 함
mcp.json 설정
MCP 설정 파일(mcp.json)에서 playwright 항목을 다음과 같이 설정합니다. Claude Code 기준으로 ~/.claude/settings.json의 mcpServers 항목이고, 다른 도구를 쓴다면 해당 도구의 MCP 설정 파일 경로를 확인해 주세요.
{
"mcpServers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest",
"--headless", "false",
"--executable-path", "/home/shell/.cache/ms-playwright/chromium-1208/chrome-linux64/chrome"
],
"env": {
"DISPLAY": ":0"
},
"disabled": false
}
}
}
--headless false는 실제 브라우저 창을 화면에 띄우겠다는 뜻이고, --executable-path는 설치된 Linux Chromium 경로입니다. 버전 번호(1208)는 설치 시점에 따라 다르니 위의 ls 명령으로 확인한 경로를 넣으면 됩니다. DISPLAY는 WSLg가 정상이면 자동 설정되지만 명시해 두는 게 안전합니다.
Chrome DevTools MCP는 WSL2에서 안 되므로 비활성화해 둡니다.
{
"chrome-devtools": {
"type": "stdio",
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"],
"disabled": true
}
}
설정을 저장한 뒤에는 AI 에이전트를 재시작해야 적용됩니다. 재시작 후 "브라우저로 google.com 열어줘"라고 해서 Windows 바탕화면에 Chromium 창이 뜨면 성공입니다.
자주 발생하는 문제 해결 방법
한글 폰트가 다르게 보이는 경우
Linux Chromium은 Windows 폰트(맑은 고딕 등)가 아니라 Linux 폰트를 사용합니다. 한글이 깨지거나 네모로 표시되면 한글 폰트를 설치해 주면 됩니다.
sudo apt install fonts-noto-cjk fonts-noto-cjk-extra
Windows 폰트를 직접 참조하는 방법도 있습니다.
sudo ln -s /mnt/c/Windows/Fonts /usr/share/fonts/windows
fc-cache -fv
브라우저 창 크기와 콘텐츠 영역이 안 맞는 경우
Playwright가 viewport를 고정 크기로 설정하기 때문에, 창을 늘려도 내부 콘텐츠 영역은 초기 viewport 크기 그대로입니다. mcp.json args에 "--viewport-size", "1920,1080"을 추가하면 해결됩니다.
Chromium 업데이트 시 경로 변경
Playwright를 업데이트하면 Chromium 버전 번호가 바뀌면서 경로가 달라집니다. ls ~/.cache/ms-playwright/chromium-*/chrome-linux64/chrome으로 현재 경로를 확인하고 mcp.json도 같이 수정해야 합니다. --executable-path를 생략하면 Playwright가 자동으로 찾긴 하는데, @playwright/mcp@latest가 매번 최신을 받으면서 Chromium을 재설치할 수 있으므로 경로를 고정하는 게 안정적입니다.
WSLg가 안 되는 경우
echo $DISPLAY가 비어있으면 WSLg가 비활성 상태입니다. Windows 10은 WSLg를 지원하지 않으니 Windows 11인지 먼저 확인하고, Windows 11인데도 안 되면 wsl --update 후 wsl --shutdown으로 재시작해보면 대부분 해결됩니다.
root 유저에서 안 되는 경우
Chromium은 보안상 root에서 실행을 거부합니다. --no-sandbox를 붙이면 돌아가긴 하지만 보안상 좋지 않습니다. WSL을 root가 아닌 일반 유저로 쓰는 게 정답입니다.
# PowerShell에서 WSL 기본 유저 변경
ubuntu config --default-user shell
이게 WSL을 root로 설치하면 브라우저 MCP가 안 되는 핵심 원인이기도 합니다.
전체 mcp.json 예시
WSL2 + WSLg 환경에서 사용하는 최종 설정입니다.
{
"mcpServers": {
"playwright": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@playwright/mcp@latest",
"--headless", "false",
"--executable-path", "/home/shell/.cache/ms-playwright/chromium-1208/chrome-linux64/chrome"
],
"env": {
"DISPLAY": ":0"
},
"disabled": false
},
"chrome-devtools": {
"type": "stdio",
"command": "npx",
"args": ["-y", "chrome-devtools-mcp@latest"],
"disabled": true
}
}
}
그런데 CDP도 쓸 수 있긴 하다
Playwright의 한 가지 아쉬운 점은 새 브라우저라는 겁니다. 로그인 세션이 없어서 Google, GitHub, Reddit 같은 사이트에 접속해도 전부 비로그인 상태입니다. 단순 스크린샷이나 페이지 확인 용도라면 상관없는데, 로그인이 필요한 작업을 자동화하려면 이게 꽤 불편합니다.
이런 경우에는 평소에 쓰던 Edge(또는 Chrome)에 CDP로 연결하는 게 낫습니다. 로그인 상태, 확장 프로그램, 쿠키가 전부 살아있으니까요.

앞에서 WSL2의 네트워크 격리 때문에 CDP가 안 된다고 했는데, Node.js relay를 하나 끼우면 우회할 수 있습니다. 원리는 간단합니다. Windows에서 0.0.0.0:9223으로 리슨하는 relay 서버를 띄워서, WSL2에서 오는 요청을 127.0.0.1:9222(Edge의 디버그 포트)로 전달하는 겁니다.
relay 스크립트 만들기
Windows 쪽에 cdp-relay.js 파일을 하나 만들어둡니다.
const net = require('net');
const server = net.createServer(client => {
const target = net.connect(9222, '127.0.0.1', () => {
client.pipe(target);
target.pipe(client);
});
target.on('error', () => client.destroy());
client.on('error', () => target.destroy());
});
server.listen(9223, '0.0.0.0', () => {
console.log('Relay 0.0.0.0:9223 -> 127.0.0.1:9222');
});
순수 Node.js라 별도 패키지 설치도 필요 없습니다. TCP 연결을 그대로 포워딩하는 게 전부입니다.
Edge를 디버그 모드로 실행
중요한 건 기존 Edge를 완전히 종료하고 나서 디버그 모드로 다시 열어야 한다는 겁니다. Edge가 이미 실행 중이면 --remote-debugging-port 플래그가 무시됩니다.
# 기존 Edge 종료
cmd.exe /C "taskkill /F /IM msedge.exe"
sleep 3
# 디버그 모드로 재시작
"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe" \
--remote-debugging-port=9222 \
--remote-allow-origins=* \
--no-first-run \
"https://google.com" &
sleep 5
# relay 시작
cmd.exe /C "start /B node C:\\Users\\root\\cdp-relay.js" &
sleep 2
WSL2에서 연결 확인
GATEWAY=$(ip route show default | awk '{print $3}')
curl -s http://$GATEWAY:9223/json/version
{"Browser":"Edg/..."} 같은 JSON 응답이 오면 성공입니다.

위 스크린샷을 보면 우측 상단에 프로필 아이콘이 보입니다. Playwright의 새 Chromium과 달리, 평소에 쓰던 Edge 그대로라서 로그인 상태가 유지되어 있습니다.
CDP 방식의 단점
편한 만큼 제약도 있습니다. 매 세션마다 Edge를 종료하고 디버그 모드로 재시작한 뒤 relay를 띄워야 하고, 그 사이에 일반적인 Edge 사용이 불편해집니다. 파일 업로드 자동화도 안 되고, relay는 반드시 Windows의 Node.js로 실행해야 합니다. 그래서 상시 사용보다는 로그인이 필요한 특정 작업에만 꺼내 쓰는 게 현실적입니다.
정리
WSL2에서 브라우저 MCP를 쓴다면, 기본적으로는 Playwright가 가장 간편합니다. 설정 세 줄이면 끝나고, WSLg 덕분에 Linux Chromium이 Windows 바탕화면에 네이티브 창으로 뜨니까 사용 경험도 나쁘지 않습니다.
로그인 세션이 필요한 작업이라면 Edge CDP + relay 조합도 고려해볼 만합니다. 설정이 좀 더 번거롭고 매번 Edge를 디버그 모드로 재시작해야 하는 불편함이 있지만, 기존 브라우저의 로그인 상태를 그대로 쓸 수 있다는 건 꽤 큰 장점입니다.
- 단순 브라우저 자동화, 스크린샷, 페이지 확인 → Playwright MCP
- 로그인된 상태에서 작업해야 하는 경우 → Edge CDP + relay
둘 다 WSL2에서 돌아가니까, 상황에 맞는 걸 고르면 됩니다. root 유저에서는 Chromium이 실행을 거부하니까, WSL을 일반 유저로 쓰고 있는지만 확인하면 됩니다.