Chrome WebMCP: 웹사이트가 AI 에이전트의 도구가 되는 시대

AI 에이전트는 지금 웹을 어떻게 쓰고 있나
AI 에이전트가 웹사이트를 "사용"하는 방식을 보면 좀 답답하다.
Playwright나 Puppeteer로 브라우저를 띄워서 DOM을 긁어오거나, 스크린샷을 찍어서 비전 모델에 넘기거나. 결국 사람 눈에 맞춰 만든 화면을 기계가 억지로 해석하는 방식이다.
AI 에이전트가 웹을 쓰는 현재 방식: 에이전트 → Playwright → 브라우저 → 페이지 렌더링 ↓ DOM 파싱 / 스크린샷 ↓ "이 버튼이 검색인가...?" ↓ CSS 셀렉터로 클릭 시도
잘 돌아가면 좋겠는데, 문제가 많다. CSS 클래스명이 바뀌면 셀렉터가 깨진다. 레이아웃이 달라지면 스크린샷 분석이 틀린다. A/B 테스트로 UI가 바뀌어도 깨진다. 매번 페이지 전체를 렌더링하고 분석해야 하니 느리고, 토큰 비용도 높다.
웹사이트는 에이전트가 쓰라고 만든 게 아니다. 사람이 눈으로 보고 마우스로 클릭하라고 만든 걸, 에이전트가 바깥에서 몰래 들여다보는 거다.
WebMCP: 메뉴판을 내미는 방식
2월 10일, Chrome 146(현재 Canary)에서 WebMCP라는 웹 표준의 early preview가 나왔다. W3C Web Machine Learning Community Group에서 Microsoft와 Google 엔지니어가 같이 만들고 있다.
개념은 간단하다. 웹사이트가 에이전트에게 "나한테 이런 기능이 있어"라고 직접 알려주는 것.
기존 방식 (DOM 스크래핑): 에이전트: (주방 안을 몰래 들여다보며) "저기 빨간 버튼을 누르면... 피자가 나오려나?" WebMCP 방식: 웹사이트: "여기 메뉴판이요." ┌─────────────────────────────┐ │ 1. search_flights │ │ - origin: 출발지 │ │ - destination: 도착지 │ │ - date: 날짜 │ │ │ │ 2. book_seat │ │ - flightId: 항공편 ID │ │ - seatClass: 좌석 등급 │ └─────────────────────────────┘ 에이전트: "search_flights 호출할게요. origin=ICN, destination=NRT, date=2026-03-01"
에이전트가 DOM을 뒤질 필요가 없다. 웹사이트가 구조화된 도구(tool) 목록을 제공하고, 에이전트는 그걸 호출한다. MCP(Model Context Protocol)를 아는 사람이라면 익숙할 텐데, 웹사이트 자체가 MCP 서버가 된다고 보면 된다.
그리고 모델을 안 가린다. Gemini든 Claude든 GPT든 오픈소스든, 브라우저를 통해 접속하는 에이전트라면 어떤 것이든 이 도구를 쓸 수 있다. 브라우저 레벨의 표준이지 특정 모델에 묶인 게 아니다.
두 가지 API: 선언적 vs 명령적
도구를 등록하는 방법이 두 가지 있다.
선언적(Declarative): HTML form 확장
기존 HTML form에 속성 두 개만 추가하면 된다.
<form toolname="search_flights" tooldescription="출발지, 도착지, 날짜로 항공편 검색"> <input name="origin" type="text" /> <input name="destination" type="text" /> <input name="date" type="date" /> <button type="submit">검색</button> </form>
toolname과 tooldescription을 붙인 것뿐이다. 에이전트는 이 form을 도구로 인식하고, 각 input의 name/type을 파라미터로 이해한다. 레거시 사이트도 속성 몇 개만 추가하면 에이전트 대응이 된다는 뜻이다.
재밌는 건 toolautosubmit 속성이다. 이게 없으면 에이전트가 값을 채워 넣기만 하고, 실제 제출은 사람이 한다. 결제 form에서 "에이전트가 입력은 해주되, 마지막 확인은 내가 한다" 같은 흐름이 가능하다.
서버 쪽에서는 SubmitEvent.agentInvoked로 에이전트가 보낸 건지 사람이 보낸 건지 구분할 수 있다. 에이전트 제출에만 추가 검증을 거는 식의 분기도 가능하다.
명령적(Imperative): JavaScript API
비즈니스 로직이 복잡하거나 form으로 표현하기 어려운 경우에는 JavaScript로 직접 등록한다.
navigator.modelContext.registerTool({ name: 'add_to_cart', description: '상품을 장바구니에 추가', inputSchema: { type: 'object', properties: { productId: { type: 'string' }, quantity: { type: 'number', default: 1 } }, required: ['productId'] }, handler: async ({ productId, quantity }) => { const result = await addToCartAPI(productId, quantity); return { success: true, cartTotal: result.total }; } });
MCP의 tool 정의 형식과 거의 같다. inputSchema는 JSON Schema, handler는 실제 로직. SPA에서 이미 API 호출 함수가 분리되어 있다면, 그 함수를 handler에 연결하면 된다.
두 방식의 차이:
| 구분 | 선언적 (form) | 명령적 (JS API) |
|---|---|---|
| 적합한 경우 | 기존 form이 있는 사이트 | SPA, 복잡한 로직 |
| 구현 난이도 | 속성 2개 추가 | JS 코드 작성 |
| 자동 제출 | toolautosubmit 옵션 | handler가 직접 처리 |
| 동적 도구 | 어려움 | 런타임에 등록/해제 가능 |
| 레거시 호환 | 높음 | 리팩토링 필요할 수 있음 |
한 가지 더. 페이지가 곧 MCP 서버이기 때문에, 별도의 Python이나 Node.js 서버가 필요 없다. 프론트엔드 코드 안에서 도구가 정의되고 실행된다.
보안은 어떻게 하나
에이전트가 웹사이트의 도구를 마음대로 호출하면 큰일이다. WebMCP는 브라우저를 중개자로 세워서 이 문제를 다룬다.
┌──────────┐ ┌──────────────────┐ ┌──────────────┐ │ │ │ 브라우저 │ │ 웹사이트 │ │ AI 에이전트│───→│ (중개 + 권한 관리) │───→│ (도구 제공) │ │ │←───│ │←───│ │ └──────────┘ └──────────────────┘ └──────────────┘ │ ▼ ┌──────────────┐ │ 사용자 동의 │ │ "Claude가 Gmail│ │ 도구를 사용 │ │ 하려 합니다" │ └──────────────┘
에이전트는 페이지에 직접 접근하지 않고, 브라우저를 거쳐서만 도구를 호출한다. "Claude + Gmail" 같은 특정 에이전트-사이트 쌍에 대해 사용자가 한 번 승인하면 그 조합만 허용되는 방식이다. OAuth 동의 화면과 비슷하다.
결제나 삭제 같은 민감한 작업에서는 requestUserInteraction()으로 중간에 사용자 확인을 받을 수 있다. 에이전트가 "구매할게요"라고 할 때 사용자에게 "정말?" 하고 물어보는 단계다.
에이전트가 한 페이지에서 동시에 여러 도구를 호출하는 것도 막혀 있다. 순차 실행만 가능하다.
다만 솔직히 아직 풀리지 않은 부분이 있다. 프롬프트 인젝션으로 에이전트 입력을 조작하거나, 이메일을 읽는 도구로 민감한 내용을 빼내서 외부로 보내는 공격 시나리오가 거론되고 있는데, 스펙에서 이걸 완전히 막는 방법은 아직 나오지 않았다.
Playwright/Puppeteer와 뭐가 다른가
| 항목 | Playwright/Puppeteer | WebMCP |
|---|---|---|
| 원리 | DOM 스크래핑 + 셀렉터 | 구조화된 도구 호출 |
| UI 변경 시 | 셀렉터 깨짐 | 도구 인터페이스 유지되면 OK |
| 작업 정확도 | UI 구조에 의존 | ~98% (early 벤치마크) |
| 연산 비용 | 페이지 렌더링 + 분석 | ~67% 오버헤드 감소 |
| 사이트 협조 | 불필요 (외부에서 접근) | 사이트가 도구 등록해야 함 |
| 보안 | 사이트 통제 불가 | 브라우저 중개, 사용자 동의 |
| 헤드리스 | 지원 | 미지원 (현재) |
가장 큰 차이는 협조 모델이 바뀐다는 거다. 기존에는 사이트 동의 없이 바깥에서 긁어가는 방식이었고, WebMCP는 사이트가 직접 도구를 내어주는 방식이다.
검색 엔진 크롤러가 아무 페이지나 긁어가던 시절에서 robots.txt로 "여기는 돼, 여기는 안 돼"를 명시하게 된 것과 비슷한 전환이라고 보면 된다.
Tool SEO라는 것
검색 엔진에 잘 노출되려면 SEO를 신경 써야 하듯이, 에이전트한테 잘 선택되려면 도구의 이름과 설명을 잘 써야 한다. 이걸 "Tool SEO"라고 부르는 사람들이 생기고 있다.
사용자: "서울에서 도쿄 3월 1일 항공편 찾아줘" 에이전트가 발견한 도구들: ┌────────────────────────────────────────────┐ │ [A 사이트] │ │ name: "search" │ │ desc: "Search for items" │ │ → 뭘 검색하는 건지 모호 │ │ │ │ [B 사이트] │ │ name: "search_flights" │ │ desc: "출발지/도착지/날짜로 항공편 검색. │ │ 편도/왕복 모두 지원, 가격순 정렬 가능" │ │ → 명확하고 구체적 │ └────────────────────────────────────────────┘ 에이전트 선택 → B 사이트
도구 이름을 search로 할지 search_flights로 할지, 설명에 어떤 정보를 넣을지가 에이전트의 선택에 직접 영향을 준다. title 태그와 meta description을 잘 쓰는 것과 같은 맥락이다.
robots.txt나 sitemap.xml처럼 .well-known/webmcp 매니페스트를 표준으로 만들자는 이야기도 나오고 있다. 에이전트가 페이지를 열기 전에 그 사이트가 어떤 도구를 제공하는지 미리 알 수 있게 하는 거다. 이게 되면 에이전트용 "검색 인덱스"가 생기는 셈이다.
자꾸 이런 생각이 드는데, 에이전트 트래픽이 일정 비율을 넘어가는 시점에 WebMCP를 안 쓰는 사이트는 에이전트한테 메뉴판 없는 식당이 된다. 들어는 올 수 있지만, 주문하기가 너무 어렵다.
지금 상태
Chrome 146 Canary에서 chrome://flags → "WebMCP for testing" 플래그를 켜면 써볼 수 있다. Chrome 146 stable은 3월쯤 나올 거라고 한다. Firefox, Safari는 W3C 논의에 참여 중이지만 구현체는 아직 없다.
프로덕션에 쓰기엔 아직 이르다.
| 한계 | 상세 |
|---|---|
| 도구 디스커버리 | 페이지를 열어야 도구를 발견함. .well-known/webmcp 논의 중 |
| 헤드리스 미지원 | 서버에서 돌리는 에이전트가 사용 불가 |
| SPA 리팩토링 | 비즈니스 로직이 UI 컴포넌트에 결합돼 있으면 분리 필요 |
| 보안 미해결 | 프롬프트 인젝션, 데이터 유출 시나리오 연구 중 |
| 도구 수 제한 | 페이지당 50개 미만 권장 |
| 브라우저 한정 | Chrome만. 크로스 브라우저 표준화 미정 |
헤드리스 미지원이 실무에서 좀 아프다. 서버에서 돌아가는 에이전트가 WebMCP를 쓰려면 결국 브라우저 인스턴스를 띄워야 하는데, 그러면 Playwright 쓰는 것과 인프라 비용이 크게 다르지 않다.
지금 할 수 있는 것
당장 적용할 단계는 아니지만, 무시하기엔 움직임이 구체적이다. Google과 Microsoft가 같이 코드를 쓰고, W3C가 구조를 잡고 있고, Chrome 146에 이미 구현체가 올라가 있다.
지금 준비할 수 있는 건 이 정도다.
비즈니스 로직을 UI에서 분리해두면 WebMCP가 오든 안 오든 좋은 구조다.
Before: <Button onClick={() => { validate(); calculate(); callAPI(); updateUI(); }}> After: // usecase/addToCart.ts export async function addToCart(productId, qty) { ... } // 컴포넌트에서는 호출만 <Button onClick={() => addToCart(id, 1)}> // WebMCP handler에서도 그대로 handler: ({ productId, qty }) => addToCart(productId, qty)
form의 name, label, aria-* 속성을 정확하게 작성하는 습관도 도움이 된다. toolname, tooldescription이 아니더라도, 시맨틱한 form은 WebMCP 전환 시 그대로 쓸 수 있다. 접근성(a11y)과 방향이 같다.
참고 자료
- WebMCP is available for early preview - Chrome 공식 블로그
- Chrome WebMCP: The Complete 2026 Guide - 기술 가이드
- Chrome Just Dropped Web MCP - 개발자 관점 분석
- WebMCP just landed in Chrome 146 - 구현 가이드
- WebMCP: Making the web AI-agent ready - 아키텍처 분석
- What is WebMCP? - 개념 설명
- WebMCP – DEJAN - SEO/비즈니스 관점






댓글
댓글을 작성하려면 이 필요합니다.