Google Chrome의 WebMCP 회고 — 웹페이지가 AI 에이전트에게 도구를 내주는 방식, 직접 만들어 보고 알게 된 것들
스펙 리뷰가 아니라 사용기입니다. 무엇이 되고, 무엇이 아직 안 되는지.
지난 11월 7일, 말라가에서 열린 BiznagaFest 2026에서 Google Chrome 팀이 이끄는 WebMCP를 처음 접했다. 읽기만 해서는 감이 오지 않아서, 스펙을 직접 써볼 작은 실험으로 “에이전트가 내 일정과 작업물을 신문처럼 채워주는 페이지”를 만들었고 결과물은 GitHub에 올려두었다. 신문은 어디까지나 실험 도구고, 이 글의 주제는 WebMCP 자체다. WebMCP를 처음 들어보는 분도 따라올 수 있도록 개념부터 풀어 썼고, 만들어 보고 알게 된 것과 지금 어디까지 되는지를 회고로 정리했다.
English version of this post is here.
1. WebMCP, 쉽게 말하면
먼저 MCP부터
AI 에이전트(나 대신 검색하고, 예약하고, 일정을 넣어주는 AI)가 실제로 일을 하려면 바깥 서비스의 기능을 쓸 수 있어야 한다. MCP(Model Context Protocol)는 그 연결 방식을 정한 공통 규격이다. 서비스가 “저는 ‘항공권 검색’, ‘일정 추가’ 같은 기능(도구)이 있어요”라고 목록을 내놓으면, 에이전트가 그 목록을 보고 필요한 것을 골라 호출한다. 스마트폰 충전 단자가 USB-C로 통일돼 아무 충전기나 꽂을 수 있게 된 것과 비슷한 발상이다.
기존 MCP에서 이 도구 목록을 내놓는 쪽은 서버(백엔드)다. 여기서 불편이 생긴다. 에이전트는 서버와 직접 대화할 뿐, 내가 지금 브라우저에서 보고 있는 화면은 모른다. 개발자도 로그인 정보와 화면 상태를 서버에 따로 복사해 두어야 한다.
WebMCP는 도구를 내놓는 주체를 바꾼다
BiznagaFest에서 Raúl Tovar(The Workshop)가 “Construyendo la Web Agéntica(에이전틱 웹 만들기)” 세션에서 소개한 WebMCP를 한 줄로 줄이면 이렇다.
MCP는 서버가 에이전트에게 도구를 준다. WebMCP는 웹페이지가 에이전트에게 도구를 준다.
식당으로 비유해 보자. MCP는 주방에 전화로 주문하는 것과 같다. 주문은 되지만, 손님이 테이블에서 무엇을 보고 있는지 주방은 모른다. WebMCP는 테이블 위의 태블릿 메뉴판이다. 손님(나)과 에이전트가 같은 화면을 보고, 화면이 내놓은 버튼(도구)으로 주문한다.
지금까지 에이전트가 웹을 쓰던 방식과도 다르다
브라우저를 쓰는 에이전트는 보통 화면(HTML이나 스크린샷)을 읽고 사람처럼 클릭한다. 버튼 위치나 이름이 바뀌면 곧잘 깨진다. WebMCP는 페이지가 “클릭하지 말고 이 함수를 부르세요”라며 공식 사용설명서를 건네는 방식이다.
네 가지 차이로 정리하면:
- 도구를 등록하는 주체: MCP는 백엔드 서버, WebMCP는 브라우저 안의 웹페이지
- 에이전트가 만나는 곳: MCP는 API 서버(페이지를 우회), WebMCP는 유저가 열어둔 바로 그 탭
- 상태·인증: MCP는 서버에 따로 복제해야 하지만, WebMCP는 페이지가 이미 가진 로그인 상태와 데이터를 그대로 쓴다
- 화면(UI): MCP에서는 에이전트가 화면을 못 보지만, WebMCP에서는 유저와 에이전트가 같은 화면을 본다(shared context)
코드로 보면
페이지가 JavaScript로 도구를 등록한다. 실제로 쓴 코드를 줄여 옮기면 이런 모양이다.
1
2
3
4
5
6
7
8
9
10
11
12
// 최신 위치는 document, 구버전 Chrome은 navigator로 폴백
const mc = document.modelContext ?? navigator.modelContext;
mc?.registerTool({
name: "add_headline", // 도구 이름
description: "Add one main headline to the newspaper", // 에이전트가 읽는 설명
inputSchema: { // 받을 인자의 형식
type: "object",
properties: { title: { type: "string" }, url: { type: "string" } },
},
execute: async (args) => { render(args); return { ok: true }; }, // 실제 동작
});
읽는 법은 간단하다. name과 description은 도구의 이름표와 설명서고, inputSchema는 “제목은 문자열, 링크는 문자열”처럼 받을 값의 형식을 정해 에이전트가 엉뚱한 값을 넣지 못하게 한다. execute는 호출됐을 때 페이지가 실제로 하는 일이다. 에이전트는 DOM을 뒤지는 대신 이 “계약”을 읽고 add_headline을 제목·링크와 함께 부르기만 한다. 화면을 그리는 코드는 전부 페이지 안에 있으니, 레이아웃을 바꿔도 도구 시그니처만 같으면 호출은 깨지지 않는다.
지금 어디까지 왔나
스펙은 W3C Community Group의 드래프트 단계이고, GitHub(webmachinelearning/webmcp)에는 Google Chrome과 Microsoft 엔지니어들이 공동 저자로 올라 있다. Chrome 146 Canary에서 플래그 뒤 프리뷰로 시작했고, Chrome 149부터 오리진 트라이얼(특정 사이트가 토큰을 받아 미리 켜볼 수 있는 시험 기간)이 열렸다. 아직 확정된 표준은 아니다.
2. 어디에 쓰이고, 무엇이 좋고 나쁜가
동작 흐름
- 유저가 WebMCP를 지원하는 페이지를 연다
- 에이전트가 그 탭에 등록된 도구 목록을 발견한다(discovery)
- 에이전트가 도구를 인자와 함께 호출한다
- 페이지가
execute()를 실행해 화면에 반영한다. 이 과정은 브라우저가 매개(mediate)한다
잘 맞는 용도: 이름·주소가 분리된 복잡한 신청서, 여러 구간으로 이뤄진 예약 플로우, 설정 페이지 깊숙이 숨은 진단 기능.
장점
- 백엔드 없이 클라이언트 JS만으로 에이전트 접점이 생긴다
- 페이지 상태와 에이전트 작업이 같은 탭에서 일어나 맥락이 끊기지 않는다
- DOM 스크래핑과 달리 레이아웃이 바뀌어도 깨지지 않는다
단점
- 도구의 수명이 탭에 묶인다. 탭이 열려 있는 동안만 존재하므로 백그라운드 배치 작업은 영역 밖이다.
- 클라이언트 생태계가 어리다. WebMCP 클라이언트로 동작하는 에이전트가 드물다. 페이지 쪽 준비는 됐는데 받아줄 에이전트가 없는 것, 이게 사실상 최대 병목이다.
- 스펙이 아직 움직인다. 2026년 7월 드래프트에서 API가
navigator.modelContext에서document.modelContext로 이동했고, Chrome 150에서 앞의 것을 deprecate했다. 두 위치를 모두 확인하는 코드가 필수다. - 리팩터링 부담이 있다. 도구로 노출하려면 렌더 로직을 컴포넌트에서 분리해
execute()로 옮겨야 한다. 기존 React 앱이면 손이 꽤 간다.
3. 실험 프로젝트 — 에이전트가 채우는 나의 신문
WebMCP를 직접 써보려고 아이디어를 하나 골랐다. 에이전트가 매일 내 일정·작업물·관심 뉴스를 수집해서 신문 1면처럼 채워주는 페이지. 서버 없이 페이지 하나로 에이전트 접점이 생기는지 확인하기에 딱 좋은 크기였다.
설계 원칙은 하나, 서버리스다. 백엔드도, 서버 쪽 유저 데이터도 없다. 뉴스와 일정은 채우는 시점에 에이전트가 수집하는 일회성 스트림이고, 새로고침하면 백지가 된다. 데이터는 열려 있는 그 탭의 메모리에만 있다. 배포는 정적 파일 호스팅이 전부라서, 방문자마다 자기 브라우저에서 자기 에이전트가 자기 신문을 채운다. 서버가 공유하는 상태가 없으니 사용자별로 완전히 독립된 인스턴스가 되고, 멀티유저는 아키텍처의 부산물로 따라왔다.
스택은 Next.js(App Router) + Tailwind + shadcn/ui. 도구는 set_date, add_headline, add_story, add_task, clear_paper 다섯 개다.
4. 만들면서 배운 것들
(1) 도구를 한 곳에서 정의한다
도구 정의(이름·스키마·execute), 상태 스토어, UI 컴포넌트를 세 겹으로 나눴다. 나중에 신문 레이아웃을 갈아엎어도 “계약”은 건드리지 않기 위해서다. 렌더링은 전부 execute() 안에 두고, 에이전트에게 DOM API를 노출하지 않는 것이 핵심이다.
(2) 지금 당장 되는 경로: 미러 레지스트리
네이티브 WebMCP 클라이언트가 드물기 때문에, 페이지는 두 가지를 동시에 한다.
document.modelContext(구버전은navigator.modelContext)에 정식으로 등록한다. 지원하는 브라우저에서는 바로 네이티브 경로로 전환된다.- 같은 도구 객체를
window.__NEWSPAPER_TOOLS__에도 미러링한다. 에이전트는 CDP(Chrome DevTools Protocol, 개발자 도구가 브라우저를 원격 조종하는 통로)로 탭에 붙어tool.execute(args)를 탭 안에서 직접 실행한다. 브라우저의 매개 없이 같은 계약을 지금 바로 통과시키는 파이프다.
1
2
3
4
5
에이전트 ──CDP──▶ 탭 안의 window.__NEWSPAPER_TOOLS__ ──▶ execute(args) ──▶ 렌더
(지금)
에이전트 ──WebMCP 클라이언트──▶ document.modelContext ──▶ execute(args) ──▶ 렌더
(나중) ↑ 바뀌는 건 이 파이프뿐, 계약은 그대로
(3) 보안 — “에이전트의 인자도 믿으면 안 된다”
내 에이전트가 보낸 값이라도 검증 없이 화면에 그리면 그대로 취약점이 된다. 공격용 입력으로 테스트해 확인한 것들이다.
javascript:로 시작하는 링크가 뉴스 URL로 들어오면 클릭 한 번에 악성 스크립트가 실행된다(XSS).http/https만 허용하는 스킴 화이트리스트로 막았다.- 제어문자(개행·탭)가 헤드라인 레이아웃을 깨뜨린다. 제거하고 필드별 길이 상한을 뒀다.
- 브리지가 탭을 고를 때
url.startsWith()같은 앞부분 일치 비교를 쓰면, 형제 경로(<url>-evil)가 도구 채널을 가로챌 수 있다. origin + pathname을 엄격히 비교해야 한다. - 디버그 포트로 테스트할 때는 메인 크롬 프로필을 절대 쓰지 않는다. 전용
--user-data-dir을 쓴다.
정리하면 페이지 경계에서 입력을 걸러내고(sanitize), 브리지 경계에서 엄격하게 매칭하고, 테스트는 DOM 상태로 검증하는 것이다. 도구가 {ok:true}를 돌려줘도 실제로 렌더된 DOM을 읽어봐야 안다.
(4) 전환을 미리 설계한다
브리지에서 네이티브로 넘어갈 때 바뀌는 건 파이프뿐이다. 도구 발견, 데이터 수집, execute 호출이라는 흐름은 같다. 언젠가 Chrome이 표준화하고 에이전트가 네이티브 클라이언트가 되면 중간 매개자만 교체하면 된다. “계약을 먼저 배송하고, 파이프는 나중에 온다”는 설계다.
5. 현재의 한계 — 솔직한 버전
- 지금까지의 모든 채움은 우회 경로로 이뤄졌다. 네이티브 WebMCP 클라이언트가 아직 주류가 아니라서, 브라우저의 동의 UI를 거치는 매개 없이 CDP로 붙는 파이프를 썼다. 표준이 목표하는 “브라우저가 매개하는” 모델과는 다르다. 페이지 쪽 계약은 진짜 WebMCP지만 클라이언트 쪽 파이프는 아직 아니라는 뜻이다. 실패가 아니라 전환 경로로 설계한 것이지만, 이 구분은 분명히 해두고 싶다.
- 도구가 영구적이지 않다. 탭을 닫으면 도구도 사라진다. 정기적인 백그라운드 작업은 Service Worker 통합 논의가 진전될 때까지 기다려야 한다.
- 기기 간 동기화가 없다. localStorage도 기본적으로 쓰지 않아서, 기기가 여러 대면 각자 독립된 신문이다. 서버를 넣지 않기로 한 대가이고, 나는 이 대가를 치르기로 했다.
6. 회고 — 정리
- MCP는 서버가 도구를 주고, WebMCP는 페이지가 준다. 에이전트가 웹을 긁어가는 게 아니라, 페이지가 에이전트에게 공식 계약서를 내주는 방향이다.
- 페이지 쪽은 오늘 배송할 수 있다. 등록 코드 몇십 줄이면 계약이 성립하고, 레이아웃이 바뀌어도 깨지지 않는다.
- 하지만 진짜 병목은 페이지가 아니라 클라이언트 생태계다. WebMCP를 소비하는 에이전트가 늘어야 이 표준이 자리 잡는다.
- 에이전트의 인자도 공격 표면이다. 페이지 경계에서 입력을 걸러내는 일은 프론트엔드 개발자의 새 일거리다.
Google Chrome이 밀고 있는 이 표준이 자리 잡을지는 아직 모른다. 다만 페이지가 에이전트에게 공식 계약서를 내주는 방향은 설득력이 있다. 내 작은 신문은 그 가능성과 한계를 동시에 보여준 실험이었다. 에이전트가 신문을 채우고, 나는 그걸 읽는다. 페이지를 호스팅하는 서버는 오늘도 아무것도 모른다.
레포: github.com/Lajancia/newspaper-web-mcp (Next.js + shadcn/ui, 도구 등록 / 브리지 / sanitize 포함)