새소식

300x250
AI/MCP(2026) vs CLI

개발자를 위한 MCP 추천(3-2) - Playwright CLI와 MCP 비교 분석 해보기

  • -
728x90

2026년 3월 · 개발자를 위한 MCP 추천 시리즈

Playwright MCP vs playwright-cli — 비교

MCP를 설치하지 않고도 Microsoft의 playwright-cli로 동일한 작업을 할 수 있다.
~22개 Core Tool vs 50+ 명령어, 토큰 효율 차이 — 실제로 무엇이 더 나은지 비교해보려 한다.

이 글을 쓰게 된 이유

지난번 Playwright MCP 설치 및 활용 가이드를 작성하면서 문득 의문이 들었다. Microsoft가 별도로 제공하는 playwright-cli 패키지가 있다. 그렇다면 MCP를 따로 설치하는 것이 의미가 있는가? 아니면 그냥 playwright-cli 조합이 더 낫지 않을까?

여러 시나리오를 직접 테스트해보고 심층 분석을 진행했으며, 결론은 꽤 명확하게 나왔다. playwright-cli가 기능적으로는 MCP의 상위 호환(superset)에 가깝다. 다만 MCP만이 줄 수 있는 고유한 가치도 분명 존재한다. 균형 잡힌 시각으로 두 접근법을 정면 비교해보겠다.

 

안녕하세요! 갓대희입니다.

오늘은 Playwright MCPMicrosoft의 playwright-cli를 직접 비교해보랴 힌다.

해당 글에서 MCPCLI비교를 주로 하고있기 때문에, MCP CLI비교시에는 대비되는 색으로 대부분 구분 해 두었다.

이번글은 실습이라기 보단 논리에 근거한 글이니 재미삼아 조금 지루하고 어려운 부분은 빠르게 넘겨가면서 봐도 좋을 것 같다.

그리고 계속 변경되고 있어서 할루시 네이션이 현시점에도 있거나, 생길수 있는 부분은 확인되시는 경우 말씀 주시면 그떄 그때 수정해 두도록 하겠습니다! 

 

한눈에 보는 결론

  • 도구 수: MCP ~22개 Core Tool (opt-in 포함 시 35+) vs playwright-cli 50+ 명령어 → playwright-cli 우위
  • 토큰 효율: MCP가 상대적으로 더 많은 토큰 소모 (MCP는 접근성 트리를 매번 컨텍스트에 포함)
  • Vision 모드 (Canvas/WebGL): MCP 전용 기능 → MCP 고유 우위
  • Claude Desktop 호환: MCP만 가능 → MCP 고유 우위
  • 네트워크 모킹, 세션 저장, 키보드 조합키: playwright-cli 우위
  • 결론: 기본값은 playwright-cli, Vision 모드가 필요할 때만 MCP를 추가로 활용

목차

  1. 비교의 배경 — "playwright-cli란 무엇인가?"
  2. MCP 스펙 이해하기 — Playwright MCP는 어떤 규격을 따르나?
  3. 한눈에 보는 전체 비교표
  4. 기능별 상세 비교
  5. 토큰 효율성 비교
  6. 워크플로우 시나리오 비교
  7. Skills + CLI 조합: 실전 추천 스택
  8. MCP만 가능한 것 vs playwright-cli만 가능한 것
  9. 소스 코드로 보는 내부 구조 — 개발자 심화
  10. 실전 선택 가이드 & 결론
  11. 참고 자료

1. 비교의 배경 — "playwright-cli란 무엇인가?"

먼저 비교 대상을 명확히 정의해두는 것이 중요하다. 이 글에서 비교하는 두 접근법은 다음과 같다.

구분 Playwright MCP playwright-cli
정의 Microsoft 공식 @playwright/mcp MCP 서버 Microsoft 공식 @playwright/cli 에이전트용 CLI 도구
설치 별도 MCP 서버 설치 필요 npm install -g @playwright/cli@latest
호출 방식 MCP 프로토콜을 통해 Tool 호출 playwright-cli [command]
호환 환경 Claude Code, Claude Desktop Claude Code (Bash를 통해 실행 가능한 환경)
주의: playwright-cli는 npx playwright와 다르다
npx playwright@playwright/test 패키지의 테스트 실행용 CLI다 (npx playwright test, npx playwright codegen 등). 반면 이 글에서 비교하는 playwright-cli@playwright/cli로 별도 설치가 필요한 에이전트 전용 CLI다. 호출 방식도 playwright-cli [command]로 다르다. Claude Code가 내부적으로 Skills를 통해 이 명령어들을 구성하므로, 사용자는 자연어로 요청하면 된다.

2025년 말부터 "MCP가 죽었다"는 논쟁이 지속되고 있다.

Eric Holmes를 비롯한 여러 개발자들이 LLM은 이미 CLI에 능숙하기 때문에 별도의 MCP 추상 계층이 불필요할 수 있다고 주장한다.

실제로 많은 MCP 서버의 기능이 CLI로도 충분히 대체된다.

그러나 모든 MCP가 그런 것은 아니다.

Playwright MCP의 경우 Vision 모드처럼 CLI로는 재현하기 어려운 고유 기능이 존재한다.

이 글은 그 경계를 명확히 그어보는 시도다.

 

2. MCP 스펙 이해하기 — Playwright MCP는 어떤 규격을 따르나?

MCP(Model Context Protocol)는 Anthropic이 2024년 말 오픈소스로 공개한 프로토콜이다.

기존에는 LLM 벤더마다 도구 호출 방식이 제각각이었는데(OpenAI function calling, Anthropic tool use 등), MCP는 이를 하나의 표준 인터페이스로 통합하려는 시도이다.

Playwright MCP 역시 이 규격 위에서 작동한다.

두 접근법의 차이를 제대로 이해하려면, MCP가 어떤 스펙인지 먼저 아는 것이 도움이 된다.

 

2-1. 기반 프로토콜: JSON-RPC 2.0

MCP는 JSON-RPC 2.0 메시지 포맷 위에 세션 개념을 추가한 Stateful 프로토콜이다.

Claude(클라이언트)와 MCP 서버가 연결되면 다음 순서로 동작한다.

# MCP 통신 플로우: 클라이언트(Claude) ↔ 서버(@playwright/mcp) # ※ 아래는 흐름 설명용 단순 표기. 실제 JSON-RPC 요청은 jsonrpc, id 필드를 포함한다.
// 1. 연결 초기화 (접속 시 1회)
Client → Server: initialize  (프로토콜 버전, 클라이언트 정보 전달)
Server → Client: {"capabilities": {"tools": {"listChanged": true}}, ...}
                 // listChanged는 optional — 미지원 서버는 tools: {} 로 선언
Client → Server: notifications/initialized  (준비 완료)

// 2. 도구 목록 조회 (LLM이 어떤 도구가 있는지 파악)
Client → Server: {"method": "tools/list"}
Server → Client: {"result": {"tools": [{name, description, inputSchema}, ...]}}
   → LLM은 이 스키마를 읽고 어떤 파라미터로 호출할지 자율 판단

// 3. 도구 실행 (LLM이 필요할 때마다 호출)
Client → Server: {"method": "tools/call",
                  "params": {"name": "browser_navigate",
                             "arguments": {"url": "https://example.com"}}}
Server → Client: {"result": {"content": [{"type": "text", "text": "...스냅샷..."}],
                              "isError": false}}
                 // isError: true → 도구 실행 오류 (HTTP는 200이어도 도구는 실패)

 

2-2. MCP 3대 Primitive — 서버가 클라이언트에게 노출하는 것

MCP 스펙은 서버가 클라이언트에게 노출할 수 있는 세 가지 핵심 개념(primitive)을 정의한다. 각각의 제어 주체가 다르다는 점이 중요하다.

Primitive 제어 주체 역할 Playwright MCP 사용 여부
Tools LLM (모델) LLM이 자율적으로 호출하는 실행 가능한 함수. 브라우저 조작·API 호출 등에 사용 사용
Resources 호스트 앱
(Claude Desktop, IDE 등)
URI로 식별되는 데이터 소스(파일, DB 등). 호스트 앱이 어떤 리소스를 컨텍스트에 포함할지 결정 (application-driven) 미사용
Prompts 사용자 사용자가 명시적으로 선택하는 재사용 가능한 프롬프트 템플릿 (슬래시 커맨드 등) 미사용
Playwright MCP = Tools만 구현한 MCP 서버
Playwright MCP는 공개된 README 및 문서 기준으로 Tools만 사용한다. 브라우저 자동화 동작 전체를 Tool로 정의하고, LLM이 자율적으로 tools/call로 호출하는 구조다. Resources나 Prompts는 문서상 언급되지 않는다.

MCP 스펙상 서버는 tools 외에도 logging, resources, prompts 등을 capability로 복수 선언할 수 있다. listChanged는 서버가 tool 목록 변경 알림을 지원할 때 선언하는 optional 필드다. 예: {"capabilities": {"tools": {"listChanged": true}}}

참고: MCP 스펙에는 Sampling, Roots, Elicitation 등 추가 기능도 정의되어 있으나, Playwright MCP는 이를 사용하지 않으므로 이 글에서는 다루지 않는다.

(출처: MCP 공식 스펙 — Tools / @playwright/mcp npm 패키지)

 

2-3. Tool Schema 구조 — LLM이 어떻게 도구를 이해하는가

MCP 스펙에서 Tool은 name, description, inputSchema로 구성된다. LLM은 이 스키마를 읽고 어떤 파라미터로 호출할지 자율 판단한다. Playwright MCP의 실제 Tool 정의 예시:

browser_navigate (탐색 Tool)
{ "name": "browser_navigate", "description": "Navigate to a URL", "inputSchema": { "type": "object", "properties": { "url": { "type": "string" } }, "required": ["url"] }, "annotations": { "readOnlyHint": false } }
browser_click (클릭 Tool)
{ "name": "browser_click", "description": "Click on a web page element", "inputSchema": { "type": "object", "properties": { "element": { "type": "string" }, "ref": { "type": "string" }, "button": { "type": "string", "enum": ["left","right","middle"] }, "doubleClick": { "type": "boolean" }, "modifiers": { "type": "array", "items": { "type": "string" } } }, "required": ["ref"] } }
ref란 무엇인가?
browser_clickref는 접근성 트리에서 각 요소에 부여되는 고유 식별자다 (예: e5, e12). browser_snapshot을 먼저 호출해서 트리를 받은 후, LLM이 그 안에서 원하는 요소의 ref를 확인하고 클릭에 사용한다. playwright-cli의 snapshot → click e5 흐름과 동일한 개념이지만, MCP는 이 과정이 JSON-RPC 메시지 교환으로 이루어진다.

2-4. Transport — 어떻게 연결되고, 왜 토큰이 더 소모되는가

MCP 스펙은 두 가지 공식 Transport를 정의한다. Playwright MCP는 기본적으로 stdio를 사용하며, 이 방식이 토큰 소모 차이의 근본 원인이 된다.

Transport 방식 사용 환경 Playwright MCP
Stdio 표준 입출력 (stdin/stdout) 로컬 머신 프로세스 간 통신 (Claude Desktop 등) 기본값
Streamable HTTP HTTP POST(요청) + GET(SSE 스트림 수신), 응답은 JSON 또는 SSE 원격 서버, Docker, CI/CD 환경 --port 8931 옵션으로 활성화

MCP (stdio) vs playwright-cli (Bash subprocess) 연결 구조

Playwright MCP (stdio)
LLM (Claude) ↕ JSON-RPC 2.0 / stdio MCP 서버 프로세스 (상주, persistent) → Playwright APIChromium [tool 응답] accessibility snapshotLLM context window에 직접 삽입 → 수천 토큰 소모 (스크린샷은 base64)
playwright-cli (Bash subprocess)
LLM (Claude Code) ↕ Bash tool (shell 명령어) playwright-cli subprocess (호출 단위 독립, stateless) → Playwright API → Chromium [결과] 파일에 저장 → 경로만 반환 → 수십 토큰 소모 → 필요 시에만 파일 Read
이것이 토큰 소모 차이의 근본 원인이다
MCP는 tools/call 응답의 content 필드로 접근성 스냅샷(수천 토큰 분량의 텍스트)이나 스크린샷(base64 이미지)을 LLM context window에 직접 삽입한다. playwright-cli는 결과를 파일로 저장하고 경로 한 줄만 반환하므로 컨텍스트 소모가 최소화된다. 커뮤니티 벤치마크(testcollab.com, 2026-02 기준)에서는 세션당 약 4배 차이가 측정된 사례가 있으나, 정확한 배수는 페이지 복잡도·작업 종류에 따라 다를 수 있다. 이 차이는 MCP 스펙의 구조적 특성에서 비롯된 것이지, 구현의 문제가 아니다.

 

3. 한눈에 보는 전체 비교표

30개 이상의 기능 항목을 직접 비교했다. 우위 컬럼의 색상 배지를 기준으로 빠르게 판단할 수 있다.

기능 Playwright MCP playwright-cli 우위
기본 설정
설치 방법 MCP 서버 별도 설치 npm install -g @playwright/cli 동등
도구/명령어 수 ~22개 Core Tool (opt-in 포함 35+) 50+ 명령어 CLI
Claude Desktop 호환 지원 미지원 MCP
토큰 효율 접근성 트리 매번 컨텍스트 포함 결과를 디스크에 저장, 컨텍스트 최소화 CLI
네비게이션 & 기본 조작
URL 이동 browser_navigate goto 명령 동등
앞으로/뒤로 가기 browser_navigate_back (back만 지원, forward 없음) go-back / go-forward CLI
페이지 새로고침 없음 reload 명령 CLI
스크린샷 browser_take_screenshot (인라인) screenshot (파일 저장) 동등
PDF 저장 browser_pdf_save (--caps=pdf 필요) pdf 명령 동등
상호작용 & 폼 제어
클릭 browser_click click 명령 동등
텍스트 입력 browser_type / browser_fill_form type / fill 명령 동등
드래그 & 드롭 browser_drag (Core 기능) drag 명령 동등
파일 업로드 browser_file_upload (Core 기능) upload 명령 동등
체크박스 제어 없음 check / uncheck CLI
마우스 정밀 제어 (좌표) --caps=vision opt-in 필요: browser_mouse_click_xy 등 mousemove / mousedown / mouseup (기본 지원) CLI
드롭다운 선택 browser_select_option select 명령 동등
고급 기능
네트워크 모킹/인터셉트 미지원 route / unroute CLI
쿠키 관리 미지원 cookie-list / cookie-set / cookie-delete CLI
로컬 스토리지 미지원 localstorage-list / localstorage-set / localstorage-clear CLI
세션 저장/불러오기 --storage-state 플래그 (정적 주입) state-save / state-load (동적) CLI
네임드 세션 미지원 -s=name 옵션 CLI
트레이싱 (trace) --save-trace 플래그 (세션 전체) tracing-start / tracing-stop (구간별) CLI
비디오 녹화 --save-video 플래그 (세션 전체) video-start / video-stop (구간별) CLI
테스트 코드 자동 생성 미지원 npx playwright codegen (@playwright/test) CLI
Vision & 시각적 기능
Vision 모드 (스크린샷 기반 좌표 클릭) --caps vision 미지원 MCP
Canvas / WebGL 앱 조작 Vision 모드로 가능 접근성 트리 없으면 어려움 MCP
접근성 트리 분석 browser_snapshot (자동) snapshot 명령 동등
표 읽는 법
표시는 MCP에서 부분적으로 지원되나 CLI보다 제한적임을 뜻한다 (세션 전체 단위 vs 구간별 제어). 항목 수만 보고 playwright-cli가 무조건 좋다고 판단하지 말자. 자신의 워크플로우에서 실제로 필요한 기능이 무엇인지를 기준으로 판단하는 것이 중요하다.

 

4. 기능별 상세 비교

4-1. 네비게이션 & 기본 조작 — 동등

기본 브라우저 조작은 양쪽 모두 가능하다. 문법만 다를 뿐 결과는 동일하다.

Playwright MCP
# MCP Tool 호출 browser_navigate({ url: "https://example.com" }) browser_snapshot() browser_click({ ref: "e5" }) browser_type({ ref: "e3", text: "hello" })
playwright-cli (Claude Code 내부 명령어)
# playwright-cli 명령어 (snapshot → ref 기반) playwright-cli goto https://example.com playwright-cli snapshot # 접근성 트리 조회 → ref 번호 확인 playwright-cli click e5 # ref 번호로 클릭 playwright-cli fill e3 "hello" # fill <ref> <value>
결론: 동등 — 기본 네비게이션과 클릭/입력은 양쪽 모두 자연어로 동일하게 요청할 수 있다. MCP와 playwright-cli 모두 접근성 트리의 ref 번호로 요소를 특정한다. playwright-cli는 먼저 snapshot으로 ref를 조회한 후 click e5, fill e3 "text" 형식으로 사용한다. 실제 사용에서는 Claude가 알아서 snapshot → ref 확인 → 실행 순서로 처리해주므로 사용자 경험은 동일하다.

 

4-2. 상호작용 & 폼 제어 — CLI 일부 우위

폼 제어 분야에서 일부 차이가 있다. 드래그/파일업로드는 MCP에도 Core Tool이 있지만, 체크박스 명시적 제어는 playwright-cli에만 있다.

# playwright-cli에서 사용하는 상호작용 명령어들
# 드래그 앤 드롭 (MCP의 browser_drag와 동등, ref 기반)
playwright-cli snapshot           # ref 번호 확인
playwright-cli drag e7 e12        # <startRef> <endRef>

# 파일 업로드 (MCP의 browser_file_upload와 동등)
playwright-cli upload "./document.pdf"   # 현재 포커스된 file input에 업로드

# 체크박스 제어 (playwright-cli 전용 - 멱등성 보장)
playwright-cli check e8           # ref로 지정, 이미 체크 시 변경 없음
playwright-cli uncheck e9         # 이미 미체크 시 변경 없음

# 마우스 정밀 제어 (MCP Vision opt-in과 유사, 기본 지원)
playwright-cli mousemove 450 320  # 먼저 좌표 이동
playwright-cli mousedown          # 현재 위치에서 클릭 다운
playwright-cli mouseup            # 현재 위치에서 클릭 업

 

4-3. 고급 기능 — playwright-cli 독점

네트워크 모킹, 세션 관리, 구간별 트레이싱 등 E2E 테스트에서 핵심적인 고급 기능들은 playwright-cli가 훨씬 더 세밀한 제어를 제공한다.

# playwright-cli 고급 기능 (MCP에서 제한적이거나 미지원)
# 네트워크 모킹 — API 응답을 가로채서 테스트용 데이터로 교체
playwright-cli route "/api/users" --body='[{"id":1,"name":"Test User"}]'
playwright-cli unroute "/api/tracking"  # 특정 요청 차단 해제

# 쿠키 관리 — 인증 상태 직접 설정
playwright-cli cookie-set session abc123 --domain=example.com
playwright-cli cookie-list

# 스토리지 관리
playwright-cli localstorage-set "theme" "dark"
playwright-cli localstorage-list
playwright-cli localstorage-clear

# 세션 저장/복원 — 로그인 상태를 파일로 저장해 재사용
playwright-cli state-save "./auth-state.json"
playwright-cli state-load "./auth-state.json"

# 네임드 세션 — 여러 사용자 동시 테스트
playwright-cli goto "https://app.com/user1" -s=user1
playwright-cli goto "https://app.com/user2" -s=user2

# 구간별 트레이싱 (MCP는 세션 전체 단위만 가능)
playwright-cli tracing-start
playwright-cli goto "https://example.com"
playwright-cli tracing-stop "./trace.zip"

# 구간별 비디오 녹화 (MCP는 세션 전체 단위만 가능)
playwright-cli video-start
playwright-cli video-stop "./test-run.mp4"
MCP의 트레이싱/비디오 vs playwright-cli의 차이
MCP는 서버 시작 시 --save-trace, --save-video=800x600 플래그로 세션 전체를 기록할 수 있다. 반면 playwright-cli는 tracing-start / tracing-stop으로 원하는 구간만 선택적으로 기록할 수 있어 디버깅 목적에 훨씬 유용하다.

 

5. 토큰 효율성 비교

토큰 효율성은 비용과 직결되는 중요한 요소다. 반복 작업이 많은 워크플로우에서 이 차이는 체감된다.

항목 Playwright MCP playwright-cli
스크린샷 처리 base64 이미지를 컨텍스트 인라인 전송 파일 경로만 반환, 디스크에 저장
접근성 트리 데이터 browser_snapshot 호출마다 전체 반환 명시적 요청 시에만 snapshot 반환
상대적 토큰 효율 상대적으로 많음 상대적으로 적음
토큰 수치에 대한 안내
공식적으로 측정된 정확한 수치는 확인하지 못했다. 다만 공식 문서에서는 "CLI는 큰 Tool 스키마와 상세 접근성 트리를 매번 모델 컨텍스트에 로드하지 않아 토큰 효율적"이라고 명시한다. (출처: microsoft/playwright-cli GitHub README) 실제 차이는 페이지 복잡도, 작업 종류, 사용 모델에 따라 다를 수 있다.

토큰 차이가 발생하는 주된 원인은 두 가지다.

원인 1: 스크린샷의 인라인 전송 vs 파일 저장

MCP의 browser_take_screenshot은 스크린샷 이미지를 base64로 인코딩해 Claude 컨텍스트로 직접 전달한다. 이미지 한 장이 수만 토큰을 소모할 수 있다. 반면 playwright-cli의 screenshot 명령은 파일을 디스크에 저장하고 경로만 반환하므로 토큰 소모가 최소화된다.

원인 2: 접근성 트리의 암묵적 포함

MCP의 browser_snapshot은 호출마다 전체 접근성 트리를 반환한다. 복잡한 페이지의 경우 이 데이터만 수천 토큰에 달한다. playwright-cli는 명시적으로 snapshot을 요청하지 않으면 이 데이터를 포함하지 않는다.

 

6. 워크플로우 시나리오 비교

실제 개발 시나리오 3가지를 통해 두 접근법의 체감 차이를 살펴본다.

 

시나리오 1: 페이지 접속 & 스크린샷

가장 기본적인 작업. 양쪽 모두 가능하다. playwright-cli가 토큰을 절약한다.

사용자 요청: https://example.com 에 접속해서 스크린샷 찍어줘

MCP 처리 방식
1. browser_navigate 호출
2. browser_snapshot 호출 (트리 전체 반환)
3. browser_take_screenshot 호출 (이미지 인라인)
스크린샷이 컨텍스트에 인라인 포함됨
playwright-cli 처리 방식
1. playwright-cli goto "https://example.com"
2. playwright-cli screenshot --filename=shot.png
파일 경로만 반환, 토큰 절약

 

시나리오 2: 폼 입력 & 로그인 테스트

양쪽 모두 가능하다. playwright-cli는 세션 저장으로 다음 테스트에서 재사용이 가능하다.

사용자 요청: localhost:3000에서 admin@test.com / pass123으로 로그인하고, 성공하면 인증 상태를 저장해줘

MCP Claude 응답:

browser_navigate → browser_snapshot → browser_type (이메일) → browser_type (비밀번호) → browser_click (로그인 버튼) → browser_snapshot (결과 확인)

동적 세션 저장은 불가능합니다. MCP 서버 시작 시 --storage-state로 미리 준비된 상태를 주입하는 것은 가능하지만, 현재 세션을 파일로 저장하는 것은 지원되지 않습니다. 다음 테스트 시 로그인 과정을 반복해야 합니다.

playwright-cli Claude 응답:

playwright-cli goto → playwright-cli type → playwright-cli type → playwright-cli click → playwright-cli screenshot (로그인 성공 확인)

playwright-cli state-save "./auth-state.json" 실행 완료. 다음 테스트에서 state-load로 즉시 로그인 상태를 복원할 수 있습니다.

 

시나리오 3: 네트워크 모킹 & 에러 처리 테스트

playwright-cli만 가능하다. MCP로는 불가능한 시나리오다.

사용자 요청: /api/products 요청을 가로채서 500 에러를 반환하도록 모킹하고, 앱이 에러를 올바르게 표시하는지 테스트해줘

MCP Claude 응답:

죄송합니다. Playwright MCP는 현재 네트워크 요청 인터셉트(route) 기능을 Tool로 제공하지 않습니다. 이 요청은 MCP만으로는 처리할 수 없습니다.

playwright-cli Claude 응답:

# 네트워크 모킹 설정
playwright-cli route "/api/products" \
  --status=500 \
  --body='{"error":"Internal Server Error"}'

# 페이지 접속 및 에러 표시 확인
playwright-cli goto "http://localhost:3000/products"
playwright-cli screenshot --filename=error-test.png
playwright-cli snapshot

/api/products 요청이 500 응답으로 모킹되었습니다. 스크린샷 확인 결과 에러 메시지 "상품을 불러올 수 없습니다"가 정상적으로 표시됩니다.

 

7. Skills + CLI 조합: 실전 추천 스택

여기서 잠깐 — 단순히 "MCP vs CLI"로만 비교하면 중요한 관점이 빠집니다. Claude Code에는 playwright 관련 Skills가 내장되어 있어, CLI와 조합하면 훨씬 강력한 워크플로우를 구성할 수 있습니다.

 

Claude Code 내장 Playwright Skills 3종

스킬 역할 인터페이스 주요 기능
playwright-cli 대화형 브라우저 자동화 Bash (playwright-cli 명령어) snapshot 기반 상호작용, 세션/네트워크/트레이싱 모범 사례, run-code로 고급 API 직접 실행
playwright-expert 프로덕션 E2E 테스트 TypeScript (Page Object Model) POM 패턴, Fixtures, CI/CD 통합, Flaky 테스트 방지 전략
browser-automation 패턴 가이드 & 아키텍처 지식/가이드 Playwright vs Puppeteer 선택, 안티패턴 탐지, 신뢰성 설계 원칙

 

playwright-cli Skill이 CLI를 완성한다

이 블로그의 비교에서 "CLI" 방식은 단순히 명령어를 직접 입력하는 것이 아닙니다. playwright-cli Skill이 활성화되면 Claude Code는 CLI 도구를 훨씬 지능적으로 활용합니다:

playwright-cli Skill이 제공하는 것

단순 CLI 명령어를 넘어, Skill은 내장 참조 가이드(references)를 통해 다음을 자동으로 적용합니다:

snapshot 기반 상호작용: YAML 스냅샷 → ref ID (e1, e2...) → 안정적인 요소 선택
request-mocking.md: 네트워크 요청 모킹 모범 사례
storage-state.md: 쿠키/localStorage 관리 패턴
session-management.md: 멀티 세션 관리 전략
tracing.md: 디버깅을 위한 트레이싱 활용법
test-generation.md: 테스트 코드 자동 생성
video-recording.md: 비디오 녹화 설정

 

Skills를 활용한 3-Layer 워크플로우

빠른 탐색/스크래핑
   → playwright-cli Skill 활성화
   → playwright-cli goto, snapshot, click, route ...
   → 스냅샷 기반 ref 자동 관리

프로덕션 E2E 테스트
   → playwright-expert Skill 활성화
   → Page Object Model (TypeScript)
   → Fixtures, CI/CD GitHub Actions 자동 생성

아키텍처 결정
   → browser-automation Skill 참고
   → 안티패턴 탐지 (waitForTimeout 금지 등)
   → Playwright vs 다른 도구 선택 기준

 

Skills + CLI vs MCP: 업데이트된 관점

비교 항목 Playwright MCP CLI 단독 Skills + CLI 조합
지능적 상호작용 패턴 MCP 도구 설계에 내장 사용자가 직접 패턴 결정 Skill이 모범 사례 자동 적용
고급 기능 가이드 도구 파라미터에 제한됨 직접 명령어 조합 필요 references 폴더로 즉시 참조
프로덕션 테스트 POM 패턴 미지원 △ 직접 구현 가능하나 복잡 playwright-expert Skill로 완전 지원
run-code 고급 API   △ 가능하나 가이드 없음 Skill 내 running-code.md 참조
Vision 모드 (--caps=vision)    
Claude Desktop 호환      
토큰 효율 상대적 비효율 효율적 효율적 + 패턴 최적화
핵심 결론

Skills + CLI 조합이 실질적으로 MCP의 기능적 상위 호환입니다.
MCP가 도구(tool) 설계에 모범 사례를 내장하는 것처럼, playwright-cli Skill은 CLI 사용에 동일한 구조화된 지식을 제공합니다. Vision 모드와 Claude Desktop이 필요하지 않다면, Skills + CLI가 더 강력하고 효율적인 선택입니다.

 

8. MCP만 가능한 것 vs playwright-cli만 가능한 것

MCP 고유 영역 (대체 불가)

1. Vision 모드 — 스크린샷 기반 좌표 클릭

접근성 트리가 없는 Canvas, WebGL, PDF 뷰어 등의 요소를 조작할 때 유일한 선택지다. MCP를 --caps vision 플래그로 실행하면 스크린샷에서 X/Y 좌표를 직접 지정해 클릭할 수 있다. 게임, 그래프 인터랙션, 커스텀 캔버스 앱 테스트에 필수다.

# Vision 모드 활성화
npx @playwright/mcp@latest --caps vision

# Claude가 내부적으로: 스크린샷 찍고 → 좌표 판단 → 클릭
browser_take_screenshot()
# → Claude: "차트의 막대 그래프가 (450, 320) 위치에 있음"
browser_mouse_click_xy({ x: 450, y: 320 })

2. Claude Desktop 호환성

Claude Desktop에서 브라우저 자동화를 사용하려면 MCP가 유일한 방법이다. playwright-cli 기반 접근은 Claude Code 환경에서만 동작하며, Claude Desktop의 UI에서는 Bash 명령 실행이 불가능하다.

Vision 모드는 대체 불가능한 고유 가치다
접근성 트리가 존재하지 않는 UI는 생각보다 많다. Canvas API로 그린 커스텀 차트, WebGL 3D 뷰어, 일부 PDF.js 기반 뷰어 등이 이에 해당한다. 이런 환경에서 자동화가 필요하다면 Playwright MCP의 Vision 모드가 현실적으로 유일한 선택지다.

 

playwright-cli 우위 영역 (MCP에서 제한적)

다음 기능들은 playwright-cli가 MCP보다 훨씬 세밀한 제어를 제공한다:

  • 네트워크 모킹 — route / unroute (MCP 미지원)
  • 쿠키 관리 — cookie-list / cookie-get / cookie-set / cookie-delete / cookie-clear (MCP 미지원)
  • 스토리지 세밀 제어 — localstorage-list/get/set/delete/clear, sessionstorage-* (MCP 미지원)
  • 동적 세션 저장/복원 — state-save / state-load (MCP는 --storage-state 정적 주입만 가능)
  • 네임드 세션 — -s=name 옵션 (복수 사용자 병렬 테스트, MCP 미지원)
  • 구간별 트레이싱 — tracing-start / tracing-stop (MCP는 세션 전체 --save-trace만 가능)
  • 구간별 비디오 녹화 — video-start / video-stop (MCP는 세션 전체 --save-video만 가능)
  • 체크박스 명시적 제어 — check / uncheck (MCP 미지원)
  • 키보드 조합키 — press "Control+A", press "Shift+Enter" 등 (MCP: browser_press_key와 동등)
  • 페이지 새로고침 — reload 명령 (MCP 미지원)
  • 테스트 코드 생성 — npx playwright codegen (@playwright/test 패키지)

 

8. 소스 코드로 보는 내부 구조 — 개발자 심화

Playwright MCP의 실제 구현이 얼마나 간단한지 궁금할 수 있다. 결론부터 말하면 놀라울 정도로 단순하고 읽기 쉽다. 한 도구의 전체 구현이 보통 30~60줄이다.

소스 위치 주의
Playwright MCP의 실제 TypeScript 소스는 microsoft/playwright-mcp 저장소에 없다. 실제 구현은 Playwright 모노레포 안에 있다.
microsoft/playwrightpackages/playwright-core/src/tools/ (도구 구현)
microsoft/playwrightpackages/playwright-core/src/mcp/ (MCP 서버 인프라)

 

8-1. 전체 아키텍처

코드베이스는 크게 두 레이어로 나뉜다.

packages/playwright-core/src/
├── mcp/                         # MCP 서버 인프라
│   ├── index.ts                 # createConnection() 진입점
│   ├── sdk/
│   │   ├── server.ts            # MCP 프로토콜 핸들러, BackendManager
│   │   └── tool.ts              # ToolSchema → MCP Tool 변환 (zod → JSON Schema)
│   └── config.ts                # --caps, --vision 등 설정 처리
└── tools/                       # 개별 도구 구현 (파일당 1~N개 도구)
    ├── tool.ts                  # defineTool() / defineTabTool() 헬퍼
    ├── navigate.ts              # browser_navigate, browser_navigate_back …
    ├── screenshot.ts            # browser_take_screenshot
    ├── snapshot.ts              # browser_snapshot (접근성 트리)
    ├── keyboard.ts              # browser_press_key, browser_type
    ├── mouse.ts                 # browser_mouse_move, browser_mouse_click_xy
    ├── network.ts               # browser_network_requests
    ├── tabs.ts                  # browser_tab_new, browser_tab_list …
    └── … (30개 이상 파일)

 

8-2. defineTool() — 놀랍도록 단순한 헬퍼

defineTool()은 복잡한 미들웨어처럼 보이지만 실제로는 단 한 줄이다. TypeScript 제네릭 타입 추론을 위한 헬퍼일 뿐이다.

// packages/playwright-core/src/tools/tool.ts

export type ToolCapability =
  'config' | 'core' | 'core-navigation' | 'core-tabs' | 'core-input'
  | 'network' | 'pdf' | 'storage' | 'testing' | 'vision' | 'devtools';

export type Tool<Input extends z.Schema = z.Schema> = {
  capability: ToolCapability;
  skillOnly?: boolean;             // true면 --caps에서 제외, Skills 전용
  schema: {
    name: string;
    title: string;
    description: string;
    inputSchema: Input;            // Zod 스키마 → 자동으로 JSON Schema 변환
    type: 'input' | 'assertion' | 'action' | 'readOnly';
  };
  handle: (context: Context, params: z.output<Input>, response: Response) => Promise<void>;
};

// 이게 전부다. 타입 추론 헬퍼일 뿐, 내부 로직 없음
export function defineTool<Input extends z.Schema>(tool: Tool<Input>): Tool<Input> {
  return tool;  // ← 진짜로 이게 전부
}
type 필드와 MCP annotations 매핑
type: 'readOnly' 또는 'assertion'readOnlyHint: true, destructiveHint: false
type: 'action' 또는 'input'readOnlyHint: false, destructiveHint: true
이 annotations를 MCP 클라이언트(Claude)가 읽고 도구 호출 여부를 판단한다.

 

8-3. browser_navigate 전체 구현 — 46줄

MCP 도구 하나의 전체 구현이 어떤 모습인지 보자. browser_navigate는 가장 기본적인 도구이면서 전형적인 패턴을 보여준다.

// packages/playwright-core/src/tools/navigate.ts (발췌)
import { z } from '../mcpBundle';
import { defineTool } from './tool';

const navigate = defineTool({
  capability: 'core-navigation',  // --caps 필터링 기준

  schema: {
    name: 'browser_navigate',
    title: 'Navigate to a URL',
    description: 'Navigate to a URL',
    inputSchema: z.object({
      url: z.string().describe('The URL to navigate to'),
    }),
    type: 'action',            // destructiveHint: true
  },

  handle: async (context, params, response) => {
    const tab = await context.ensureTab();
    let url = params.url;

    // URL 정규화: 스킴 없으면 자동 추가
    try {
      new URL(url);
    } catch (e) {
      if (url.startsWith('localhost'))
        url = 'http://' + url;
      else
        url = 'https://' + url;
    }

    await tab.navigate(url);

    response.setIncludeSnapshot();            // 실행 후 접근성 트리 자동 포함
    response.addCode(`await page.goto('${url}');`); // Playwright 코드 생성
  },
});

주목할 점 두 가지:

  • response.setIncludeSnapshot() — 도구 실행 결과에 접근성 트리가 자동으로 붙는 이유가 여기 있다. LLM이 다음 행동을 결정할 수 있도록 현재 페이지 상태를 함께 반환한다.
  • response.addCode(...) — MCP가 실행하는 동시에 해당 동작의 Playwright 코드를 생성한다. 테스트 자동화 코드 생성의 기반이 바로 이 패턴이다.

 

8-4. capability 시스템 — --caps 플래그의 정체

--caps=vision이나 --caps=pdf가 어떻게 동작하는지 궁금했다면, 답은 간단하다. 각 도구가 선언한 capability 필드로 필터링이 이루어진다.

capability 값 해당 도구 예시 활성화 방법
core, core-navigation, core-input, core-tabs browser_navigate, browser_click, browser_type … 기본 활성화 (항상 포함)
vision browser_mouse_click_xy, browser_mouse_move … --caps=vision
pdf browser_pdf_save --caps=pdf
network browser_network_requests --caps=network
storage browser_get_cookies, browser_get_local_storage … --caps=storage
devtools browser_console_messages, browser_evaluate … --caps=devtools
testing 테스트 관련 도구 (skillOnly 포함) --caps=testing
skillOnly: true 플래그의 의미
일부 도구는 skillOnly: true로 선언된다. 이 도구들은 --caps로 활성화해도 MCP 도구 목록에 나타나지 않고, Skills 모드에서만 사용 가능하다. browser_navigate_forward가 대표적인 예다. Skills가 단순한 명칭이 아니라 별도의 도구 활성화 레이어임을 소스에서 확인할 수 있다.

 

8-5. MCP 서버 전체 초기화 흐름

서버가 시작되고 첫 번째 도구 호출이 이루어지기까지의 흐름이다.

// 1. 진입점 (packages/playwright-core/src/mcp/index.ts)
export async function createConnection(userConfig: Config = {}): Promise<Server> {
  const config = await resolveConfig(userConfig);
  const tools = filteredTools(config);  // capability 필터 적용
  return createServer('api', version, backendFactory, false);
}

// 2. 도구 호출 요청 처리 (sdk/server.ts)
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  // 첫 호출 시 브라우저 컨텍스트 생성 (lazy initialization)
  if (!backendPromise)
    backendPromise = initializeServer(server, factory, runHeartbeat);

  const backend = await backendPromise;
  return await backend.callTool(request.params.name, request.params.arguments);
});

// 3. 실제 도구 실행 (tools/browserServerBackend.ts)
async callTool(name: string, args: Arguments) {
  const tool = this._tools.find(t => t.schema.name === name);
  await tool.handle(this._context, args, response); // navigate.ts의 handle() 호출
  return response.build();  // 접근성 트리 + 코드 + 텍스트 결합
}

브라우저는 Lazy 초기화된다. MCP 서버가 시작돼도 브라우저가 바로 뜨지 않고, 첫 번째 도구 호출이 들어올 때 비로소 브라우저 컨텍스트가 생성된다. 이 덕분에 MCP 서버를 등록해두고 필요할 때만 쓰는 패턴이 깔끔하게 동작한다.

직접 도구를 추가하고 싶다면?

구조가 단순하므로 커스텀 도구 추가도 어렵지 않다. defineTool({ capability, schema, handle }) 패턴을 따르면 된다. 다만 소스가 Playwright 모노레포 안에 있어 직접 빌드가 필요하다는 점을 기억하자.

→ 전체 도구 소스 보기 (GitHub)

 

10. 실전 선택 가이드 & 결론

의사결정 플로우차트

Q1. Claude Desktop에서 사용해야 하는가?

→ YES: Playwright MCP 필수

→ NO: 다음 질문으로

Q2. Canvas / WebGL 기반 앱을 조작해야 하는가?

→ YES: Playwright MCP (Vision 모드)

→ NO: 다음 질문으로

Q3. 네트워크 모킹, 쿠키 관리, 세션 동적 저장이 필요한가?

→ YES: playwright-cli 필수

→ NO: 다음 질문으로

Q4. 반복 작업이 많고 토큰 비용이 중요한가?

→ YES: playwright-cli 권장 (토큰 효율 우위)

→ NO: 다음 질문으로

Q5. 기본적인 탐색 & 스크린샷만 필요한가?

→ YES: 양쪽 모두 가능 — 이미 MCP 있으면 유지, 없으면 playwright-cli 사용

 

상황별 추천 요약

상황 추천 이유
E2E 테스트 자동화 (Claude Code) playwright-cli 네트워크 모킹, 세션 관리, 구간별 트레이싱 필요
웹 스크래핑 반복 작업 playwright-cli 토큰 효율 우위, 비용 절감
Canvas/WebGL 앱 시각 검증 MCP Vision 모드가 유일한 선택지
Claude Desktop에서 브라우저 조작 MCP Bash 실행 불가 환경
빠른 탐색 & 스크린샷 둘 다 기능 동등, 있는 것 사용
CI/CD 파이프라인 통합 playwright-cli 별도 MCP 프로세스 관리 불필요, 안정적

 

최종 결론

직접 시나리오를 테스트하고 분석한 결과를 종합하면 결론은 명확하다.

추천 전략: "Skills + CLI 조합을 기본으로, MCP는 Vision 모드가 필요할 때 보조 도구로"

  • Claude Code에서의 대부분의 브라우저 자동화는 playwright-cli Skill + CLI 조합으로 충분하고 더 효율적이다
  • 설치는 npm install -g @playwright/cli@latest 한 번으로 완료된다
  • 토큰 소모가 상대적으로 적어 비용 효율적이고, 고급 기능(모킹, 세션, 트레이싱)도 Skill의 references 가이드와 함께 제공한다
  • 프로덕션 E2E 테스트는 playwright-expert Skill로 POM 패턴 + CI/CD까지 완전 커버된다
  • Canvas/WebGL 앱, Claude Desktop을 사용하는 경우에는 MCP의 Vision 모드가 필수다
  • 세 접근법(MCP, CLI, Skills)은 상호 배타적이지 않다. 상황에 맞게 조합할 수 있다

"MCP가 죽었다"는 주장이 Playwright에 대해서는 절반만 사실이다. 기능 수와 토큰 효율에서는 playwright-cli가 압도적이고, Skills 조합으로 지능적인 워크플로우까지 구성할 수 있다. 다만 Vision 모드라는 고유하고 대체 불가능한 가치를 MCP는 여전히 보유하고 있다. 도구는 목적에 맞게 선택하는 것이 최선이다.

 

11. 참고 자료

공식 문서

Claude Code 내장 Skills

  • playwright-cli Skill — Bash(playwright-cli:*) 기반, snapshot 상호작용 + references 가이드 내장
  • playwright-expert Skill — TypeScript POM 패턴, Fixtures, CI/CD 통합 전문가
  • browser-automation Skill — 패턴 가이드 & 안티패턴 탐지, 도구 선택 기준

이 시리즈 관련 글

300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.

💡 AI 관련 질문이 있나요? 눌러보세요!