가벼운 Chrome MCP를 만들며, 전통적 API 설계 관성이 LLM용 도구에는 왜 맞지 않는지, 최소 표면적·점진적 공개·자동 복구 같은 원칙으로 어떻게 효율과 신뢰성을 높였는지, Playwright MCP와의 대비, 실전 사용법과 설치 방법을 공유한다.
요약: 내가 가벼운 Chrome MCP를 만들었다. 설치 방법은 글 맨 아래에 있다. 전반을 읽으면 MCP 설계의 선(禪) 한 스푼을 얻게 될 것이다.
Claude Code에는 웹 페이지를 가져오고 웹을 검색하는 도구가 기본 탑재되어 있다(내 기억이 맞다면 실제로는 Anthropic의 서버를 통해 돌아간다). 이 도구들은 컨텍스트를 정교하게 관리하고 Claude가 소화하기 쉬운 형식으로 정보를 반환하도록 영리하게 설계되어 있다.
이 도구들은 매우 잘 동작한다.
딱, 완전히 무너질 때까지는.
가르침 없이, 가장 중요한 단 한 명의 고객이 남긴 추천사.
지난주, 문득 내 커스텀 블로그 클라이언트를 Apple의 새로운 Liquid Glass 룩앤필로 업데이트해야겠다는 생각이 들었다.
가장 먼저 마주친 문제는 Claude가 macOS 26은 아직 나오지 않았다고 "절대 확신"한다는 점이었다. (웃긴 건, 이 글 초안을 검토해 달라고 했을 때 모델이 표시한 것 중 하나가 다음이었다: '모델 명칭 불일치 - "macOS 26"이라고 쓰셨는데 제 생각엔 "macOS 15"(Sequoia)를 의미하신 듯합니다. macOS 26은 한참 미래의 버전일 겁니다.')
그럼에도 Claude는 "Liquid Glass" UI가 어떻게 생겼을지 기꺼이 추측해 주었다. 모델에게 메모리 문제가 있고 Apple이 실제로 새로운 운영체제를 공개했다는 걸 상기시키자, 일을 시작할 준비가 됐다.
나는 Apple의 Human Interface Guidelines를 읽고 계획을 세우라고 했다. Claude가 본 것은 이것이었다:
<div class="noscript"><h1 class="noscript-title">This page requires JavaScript.</h1><p>Please turn on JavaScript in your browser and refresh the page to view its content.</p></div></noscript><div id="app"></div>
알고 보니 Apple은 더 이상 HIG의 다운로드 버전을 제공하지 않는다. 그리고 온라인 버전은 JavaScript가 필요하다. 한참 허우적거리다가, Claude는 업계 표준인 Microsoft의 Playwright MCP를 꺼내 들었다.
Playwright MCP는 브라우저 구동과 웹앱 디버깅의 모든 측면을 아우르는 21개 도구 모음이다. browser_install에서 browser_click, browser_navigate_back까지 다 있다. Playwright MCP를 "그냥 사용 가능하게 놓아두는 것만으로도" 모든 세션에서 13,678토큰(컨텍스트 윈도의 7%)이 든다. (그렇다, Google Chrome 팀에도 자체 Chrome MCP가 있다. 그 API 표면은 이보다 더 크다)
그리고 일단 쓰기 시작하면 상황은 더 나빠진다. 어떤 도구는 작업 중인 웹페이지의 DOM 전체를 반환한다. 이 말은, 단순한 요청이더라도 Claude가 응답에서 감당할 수 있는 토큰 수를 초과해 실패한다는 뜻이다:
> Playwright MCP를 사용해 https://www.bbc.com 의 헤드라인을 가져와 주세요
⏺ BBC.com으로 이동해 헤드라인을 가져오기 위해 Playwright MCP를 사용하겠습니다.
⏺ **playwright - Navigate to a URL (MCP)**(url: "https://www.bbc.com")
⎿ 오류: MCP 도구 "browser_navigate" 응답(25837 토큰)이 허용 최대 토큰(25000)을 초과했습니다. 페이지네이션, 필터링 또는 limit 파라미터를 사용해 응답 크기를 줄여주세요.
⏺ 더 구조화된 보기를 얻기 위해 스냅샷을 시도해 보겠습니다:
⎿ 오류: MCP 도구 "browser_snapshot" 응답(36196 토큰)이 허용 최대 토큰(25000)을 초과했습니다. 페이지네이션, 필터링 또는 limit 파라미터를 사용해 응답 크기를 줄여주세요.
⏺ 페이지가 꽤 큽니다. JavaScript 평가를 사용해 헤드라인만 추출해 보겠습니다: [...]
코딩 에이전트가 설계된 방식 그대로 도구를 반복해서 쓰려 애쓰는데, 그 도구가 유용한 데이터를 돌려주지 못하는 모습을 보는 건 답답하다.
내가 몇 번이고 푸념을 늘어놓자, Dan Grigsby가 이렇게 말하더라. Claude에게 아예 스스로 기술을 학습하라고 요청해 성공했다는 것이다. 바로, 원시 DevTools 원격 제어 프로토콜을 사용해 Chrome을 구동하는 법을.
재미있어 보여서, 내 Claude에게 한번 해보라고 했다.
Claude는 9292 포트의 Chrome에게 생(raw) JSON-RPC를 말 걸어보자는 제안을 매우 반겼다. 그리고… 잘 됐다. 하지만 몹시 투박하고 낭비가 심해 보였다. Claude가 상호작용 하나마다 매번 생 JSON-RPC 커맨드라인을 써야 했다. 장황했고, 매 호출마다 LLM이 잔뜩 디테일을 정확히 맞춰야 했다.
이제야말로 제대로 된 Skill을 만들 때였다.
잠깐 생각을 정리한 뒤, 나는 Claude에게 chrome-ws라는, 의존성 없는 소형 커맨드라인 도구를 만들어 Bash 도구로 실행해 Chrome을 제어할 수 있게 해 달라고 요청했다. 그리고 그 스크립트 사용법을 설명하는 새로운 SKILL.md 파일도 같이. chrome-ws는 복잡성을 캡슐화해 커맨드라인에서 Chrome을 쉽게 스크립팅할 수 있게 해 주었다.
이 스킬은 도구들로 웹 브라우징의 기본을 세팅하고, 점진적 공개 를 사용해 Claude가 필요할 때만 더 많은 정보를 얻도록 안내한다. 예를 들어, chrome-ws 도구 사용 예시들이 그렇다.
Claude가 늘 이 스킬을 먼저 집어든 것은 아니라서, 새 커맨드라인 도구의 존재를 모를 때도 있었다. 하지만 한 번 방향을 잘 잡아 주면, 놀라울 만큼 잘 작동했다.
이 구성은 토큰 효율이 엄청났다 — 세션 시작 시 컨텍스트 윈도에는 스킬의 name과 description 외에는 아무것도 없다. 다만 아쉬운 점은, Claude가 브라우저로 무엇이든 하려면 매번 내가 승인해야 하는 커스텀 Bash 명령을 실행해야 했다는 것. 모든 클릭. 모든 내비게이션. 모든 자바스크립트 표현식. 정말, 정말 금방 지겨워졌다.
그건 커스텀 MCP를 만들지 않고는 제대로 고칠 수가 없다.
하지만 그러면 우리는 공식 Playwright MCP와 똑같은 지점으로 되돌아가는 것 아닌가? 거의 두 다스의 도구와, 세션을 시작할 때마다 바닥에 쏟아지는 13k 토큰. 가장 중요한 명령만 겨우 한 뭉치(열둘 남짓)로 줄인다 해도, 여전히 그 세션에서 Claude가 쓰지 않을 도구가 대부분일 것이다.
API 설계를 해 본 사람이라면, 메서드 이름을 잘 짓는 일이 얼마나 중요한지 알 것이다. 각 메서드는 하나의 일만 해야 하고, 그 일만 해야 한다는 것도 안다. 매개변수는 타입을 선언(검증)해야 하며, 호출하는 쪽이 무엇을 넘겨야 하는지 알 수 있게 하고 잘못된 호출은 가능한 한 빨리 실패하도록 만들어야 한다는 것도.
그런데 use_browser라는 이름의 메서드가 있고, 여기에 각각 메서드 디스패처 역할을 하는 action 매개변수, selector 매개변수, 그리고 payload 매개변수를 받는다고? 이건 완전히 말이 안 된다.
선택적·비타입 payload 필드에 ("Action-specific data: navigate=URL | type=text (append \\n to submit) | extract=format (text|html|markdown) | screenshot=filename | eval=JavaScript | select=option value | attr=attribute name | await_text=text to wait for 같은 설명만 달아 두는 게 괜찮다고 생각한다면, 제정신이 아니다.
그런데, 내가 정확히 그렇게 설계했다.
그리고 정말, 아주 훌륭하다.
상위 수준의 도구 설명은 이렇게 되어 있다:
DevTools Protocol을 통해 지속 실행되는 Chrome 브라우저를 제어합니다. 자세한 가이드는 superpowers-chrome:browsing 스킬을 참조하세요.
중요: 셀렉터는 CSS 또는 XPath를 지원합니다(XPath는 / 또는 //로 시작해야 함). 'type' 액션에서 폼 제출을 위해 payload에 \\n 을(를) 덧붙이세요. 상태는 호출 간에 유지됩니다.
예시: {action:"click", selector:"//button[@type='submit']"} | {action:"extract", payload:"text", selector:"//h2"}
워크플로: navigate→await_element→extract | navigate→type(payload:"text\\n")→await_text
세션 시작 시, MCP 전체 설정은 고작 947토큰이다. 아마 30–40 정도는 더 깎을 수 있을 것 같다.
이 도구는 Claude가 최대한 쉽게 일할 수 있도록 최적화되어 있다. 브라우저를 시작하는 메서드를 따로 두는 대신, MCP가… 필요할 때 알아서 시작한다. 빈 탭이 없다면 새 탭을 여는 것도 마찬가지다.
도구 설명은 Claude에게 무엇을 해야 하는지 알려 주고, 더 도움이 필요해지면 어디를 읽어야 하는지도 가리켜 준다. 적어도 지금까지는, 내 사용 환경에서 아주 잘 작동한다.
MCP를 개발하면서 내가 저지른 실수 중 하나는 API 표면을 줄이겠다고 CSS 셀렉터만 받도록(즉, CSS만 허용하고 XPath는 금지) 한 것이었다. 더 작고 단순한 API가 Claude가 다루고 추론하기 쉽다고 생각하는 게 자연스러웠다. 그러다 MCP 도구 설명에 CRITICAL: CSS selectors only (NOT XPath) 같은 경고문이 여럿 들어간 걸 보게 됐다. 셀렉터 필드가 CSS와 XPath를 모두 받게 하자, 전체가 훨씬… 더 잘 동작했다.
MCP를 처음 구현할 때 Claude가 살짝 잘못한 부분 또 하나는 use_browser 메서드의 모든 매개변수에 자세한 자연어 description을 붙였다는 것이다. MCP를 사용하는 LLM은 description과 실제 JSON 스키마를 모두 볼 수 있기 때문에, enum에서 허용 값의 목록이나 타입 검증 같은 내용을 반복해 적을 필요가 없다. 쓸 수 있는 요령 하나: 에이전트에게, 이 API를 어떻게 쓰는지에 대해 "당신이 볼 수 있는 정보"를 정확히 말해 보라고 요청해 보라.
superpowers-chrome을 만들며 깨달은 가장 기묘한 점 중 하나는 이것이다. 비슷한 도구가 수두룩하다는 걸 알면서도, 내가 원하는 방식으로 동작하는지 확인하려고 열두 개를 시험해 보는 것보다, 내가 생각한 바로 그 도구를 실제로 만들어 버리는 게 더 빠르고 쉬웠다는 사실.
지난 수십 년 동안, 포스텔의 법칙(Postel's Law, 일명 견고성 원칙)은 시대에 뒤떨어졌고 틀렸으며 이제 API는 엄격하고 엄정해야 한다는 통념이 퍼져 왔다. LLM이 사용할 도구를 설계할 때는, 그 선택이 틀렸다.
듣기 불편할 수 있지만, LLM을 위해 만든 도구는 최종 사용자를 컴퓨터가 아니라 "사람"으로 여길 때 훨씬, 훨씬 더 잘 작동한다. 막 NOC에 채용된, 훈련이 충분하지 않은 직원에게 스크립트 묶음을 건네준다고 생각하고 도구를 만들라. 그들은 반드시 새벽 2시에 너를 호출할 것이다. 무슨 상황인지 이해하지 못하거나, 도구를 잘못 써서 스스로 되돌릴 수 없는 상태를 만들었을 때는 더더욱.
이름과 메서드 설명의 중요성은 그 어느 때보다 커졌다.
자동 복구는 엄청나게 중요하다. 빠른 실패보다 오류 복구를 중심으로 설계하면, 전체 시스템이 더 신뢰할 수 있고 운영 비용도 낮아진다.
오류를 피할 수 없다면, 오류 메시지는 사용자가 문제를 해결하거나 우회할 방법을 평이한 영어(=자연어)로 알려줘야 한다.
사용자가 요청한 것과 정확히 일치하는 결과를 줄 수 없더라도, 부분적인 답이나 관련 정보를 줄 수 있다면 그렇게 하라.
Claude는 당신 API의 아키텍처적 순수성에는 1도 관심이 없다. 그저 제한된 자원으로 당신의 일을 도와주고 싶을 뿐이다.
Claude Code용 새 MCP와 스킬의 이름은 superpowers-chrome이다.
설치는 다음처럼 하면 된다:
/plugin marketplace add obra/superpowers-marketplace
/plugin install superpowers-chrome@superpowers-marketplace
이미 Superpowers를 쓰고 있다면, /plugin을 입력하고 'Install plugins'로 이동한 뒤 'superpowers-marketplace'를 선택하면 superpowers-chrome이 보일 것이다.
도움이 되었다면 꼭 알려 달라. 패치와 풀 리퀘스트도 언제나 환영한다.