WebMCP: 웹사이트를 AI 에이전트에게 열어주는 브라우저 표준

AI 에이전트가 웹사이트에서 항공권을 검색하거나 장바구니에 상품을 담는 모습을 상상해보신 적 있나요? 지금까지 AI 에이전트가 웹사이트를 다루려면 사람처럼 DOM 요소를 찾아서 클릭하고 텍스트를 입력해야 했습니다. Playwright MCP나 agent-browser처럼 브라우저 자동화 도구를 쓰는 방법도 있었지만 웹 페이지 구조가 바뀌면 에이전트가 길을 잃기 십상이었죠.
그래서 마이크로소프트와 구글의 브라우저 엔지니어들이 완전히 다른 접근법을 내놓았습니다. 웹사이트가 직접 “나한테는 이런 도구들이 있어”라고 AI 에이전트에게 알려주게 하자는 건데요. 이게 바로 WebMCP입니다.
2026년 3월에 이 글을 처음 쓸 때만 해도 Chrome Canary에서 플래그를 켜야 겨우 만져볼 수 있는 실험이었는데요. 반년 사이에 Chrome 오리진 트라이얼(Origin Trial)이 시작됐고 ChatGPT 데스크톱 앱까지 WebMCP 도구를 쓰기 시작했습니다. API 모양도 꽤 많이 바뀌어서 그 사이의 변화를 모두 반영해 글을 다시 정리했습니다.
이 글에서는 WebMCP가 왜 필요한지, 어떻게 작동하는지, 실제 코드는 어떻게 생겼는지 살펴보겠습니다.
WebMCP란?
WebMCP는 웹사이트가 AI 에이전트에게 도구(tool)를 직접 내보낼 수 있게 해주는 브라우저 API입니다. 2025년 8월에 마이크로소프트의 Brandon Walderman과 구글의 Khushal Sagar 등이 제안서를 냈고 지금은 W3C Web Machine Learning 커뮤니티 그룹에서 초안 보고서(Draft Community Group Report)로 다듬고 있습니다.
이름에서 눈치채셨겠지만 MCP(Model Context Protocol)와 밀접한 관련이 있습니다. MCP가 AI 모델과 백엔드 서비스를 잇는 표준이라면 WebMCP는 AI 에이전트와 브라우저 속 웹사이트를 잇는 표준입니다. WebMCP 도구의 구조도 MCP 도구와 같은 형태(name, description, inputSchema)를 따르고요. 웹 페이지가 브라우저에 도구를 등록해두면 브라우저가 이를 에이전트에게 넘겨주고, 에이전트가 도구를 호출하면 브라우저가 다시 페이지의 콜백을 실행해서 결과를 돌려주는 식입니다.
sequenceDiagram
accTitle: WebMCP 도구 호출 흐름
accDescr: 웹 페이지가 브라우저에 도구를 등록하면 브라우저가 에이전트에게 도구 목록을 넘기고, 에이전트가 도구를 호출하면 브라우저가 페이지의 execute 콜백을 실행해 결과를 에이전트에게 돌려준다.
autonumber
participant P as 웹 페이지
participant B as 브라우저
participant A as AI 에이전트
P->>B: registerTool()
B->>A: 도구 목록 전달
A->>B: 도구 호출
B->>P: execute() 실행
P-->>B: 결과 반환
B-->>A: 결과 전달
그래서 뭐가 좋은 걸까요?
에이전트가 더 이상 화면의 버튼을 더듬어 클릭하지 않아도 됩니다. 웹사이트가 “상품 검색”, “장바구니 담기” 같은 도구를 선언해두면 에이전트는 DOM을 뒤지지 않고 바로 도구를 호출할 수 있거든요.
UI가 바뀌어도 끄떡없다는 것도 큰 장점입니다. WebMCP 도구는 HTML 구조가 아니라 애플리케이션 로직에 묶여 있기 때문에 사이트를 리디자인해도 에이전트 동작에는 영향이 없어요. 게다가 브라우저 내부 시스템을 직접 쓰기 때문에 원격 서버 왕복이 없어 응답도 빠릅니다.
무엇보다 통제권이 운영자한테 있다는 점이 다릅니다. 에이전트가 제멋대로 클릭하는 게 아니라 사이트 측에서 “에이전트는 이렇게 상호작용해라”를 명확하게 정의하는 거예요.
선언적 API
WebMCP는 두 가지 API를 제공하는데요. 먼저 HTML 폼 기반의 선언적(declarative) API부터 살펴보겠습니다.
기존 HTML <form> 요소에 몇 가지 속성만 추가하면 자바스크립트 한 줄 없이도 AI 에이전트가 사용할 수 있는 도구로 만들 수 있습니다.
<form
action="/search"
method="GET"
toolname="search_products"
tooldescription="키워드, 카테고리, 가격으로 상품 카탈로그를 검색합니다"
>
<label for="query">검색어</label>
<input id="query" name="query" type="text" required />
<select
name="category"
toolparamdescription="검색 결과를 필터링할 상품 카테고리"
>
<option value="all">전체</option>
<option value="electronics">전자제품</option>
<option value="clothing">의류</option>
</select>
<input name="max_price" type="number" toolparamdescription="최대 가격 필터" />
<button type="submit">검색</button>
</form>
새로 등장한 속성을 하나씩 뜯어보겠습니다.
toolname은 에이전트가 이 도구를 식별할 때 쓰는 이름입니다.
MCP 도구의 name 필드와 같은 역할이에요.
tooldescription은 도구가 뭘 하는지 자연어로 적어둔 설명입니다.
AI 모델이 이 문장을 읽고 “아, 이 도구는 상품 검색용이구나” 하고 판단하게 되죠.
이 두 속성 중 하나라도 빠지면 도구로 등록되지 않습니다.
각 입력 필드에 붙는 toolparamdescription은 파라미터별 설명입니다.
붙이지 않으면 브라우저가 연결된 <label>의 텍스트를 대신 쓰고, 그것도 없으면 aria-description을 참고합니다.
위 예제의 검색어 필드처럼 레이블이 이미 있다면 설명을 중복해서 달 필요가 없다는 뜻이죠.
브라우저는 폼의 필드 정보를 자동으로 JSON Schema로 변환해서 에이전트에게 넘깁니다.
required 속성이 붙은 필드는 스키마의 required 배열에 들어가고 <select>의 <option> 목록은 enum으로 바뀝니다.
웹 개발자 입장에서는 기존 HTML 폼에 속성 몇 개만 추가하면 끝이고 스키마 변환이니 API 설계니 하는 건 브라우저가 다 처리해줍니다.
에이전트가 이 도구를 호출하면 브라우저가 폼으로 포커스를 옮기고 필드를 채워 넣습니다.
폼은 사용자 눈에 그대로 보이고요.
기본적으로는 사용자가 직접 제출 버튼을 눌러야 하는데, toolautosubmit 속성을 붙이면 에이전트가 폼을 채운 뒤 알아서 제출까지 합니다.
폼이 제출될 때 발생하는 SubmitEvent에는 agentInvoked 속성이 추가돼서 사람이 제출한 건지 에이전트가 제출한 건지 구분됩니다.
게다가 respondWith() 메서드로 도구의 실행 결과를 에이전트에게 직접 돌려줄 수도 있어요.
페이지 이동 없이 검색 결과를 받아와서 에이전트에게 넘기고 싶을 때 유용합니다.
document.querySelector("form").addEventListener("submit", (event) => {
if (!event.agentInvoked) return; // 사람이 제출한 경우는 기본 동작 유지
event.preventDefault();
const params = new URLSearchParams(new FormData(event.target));
event.respondWith(fetch(`/api/search?${params}`).then((res) => res.json()));
});
에이전트가 폼을 채우는 순간에는 window에서 toolactivated 이벤트가, 사용자가 취소하거나 폼을 리셋하면 toolcancel 이벤트가 발생합니다.
CSS에서는 :tool-form-active와 :tool-submit-active 의사 클래스(pseudo-class)로 에이전트가 채운 폼과 제출 버튼을 강조할 수 있어서 사용자에게 “지금 에이전트가 여기를 만지고 있다”는 걸 시각적으로 알려줄 수 있죠.
명령적 API
단순한 폼 제출로는 처리하기 어려운 복잡한 상호작용도 있겠죠. SPA(Single Page Application)에서 동적으로 변하는 UI를 다루거나 장바구니 담기처럼 페이지 이동 없이 처리해야 하는 작업이 대표적입니다.
이런 경우에는 자바스크립트 기반의 명령적(imperative) API를 사용합니다.
document.modelContext 객체의 registerTool() 메서드로 도구를 등록합니다.
const controller = new AbortController();
await document.modelContext.registerTool(
{
name: "add_to_cart",
description: "상품을 장바구니에 추가합니다",
inputSchema: {
type: "object",
properties: {
product_id: { type: "string", description: "추가할 상품의 ID" },
quantity: { type: "number", description: "수량 (기본값: 1)" },
},
required: ["product_id"],
},
annotations: { readOnlyHint: false, consequentialHint: false },
execute: async ({ product_id, quantity = 1 }, { signal }) => {
// 기존 장바구니 로직을 그대로 재사용
await cart.add(product_id, quantity, { signal });
return `${product_id} ${quantity}개를 장바구니에 담았습니다`;
},
},
{ signal: controller.signal },
);
name, description, inputSchema로 도구를 정의하고 execute 콜백에서 실제 로직을 수행하는 구조는 MCP 도구와 같습니다.
MCP를 써본 분이라면 낯익은 형태일 거예요.
execute가 반환한 값은 브라우저가 JSON 문자열로 직렬화해서 에이전트에게 전달합니다.
문자열을 반환해도 되고 객체를 반환해도 됩니다.
이 글의 첫 버전에서는 MCP처럼 { content: [{ type: "text", text: "..." }] } 형태로 감싸서 반환했는데 지금은 그럴 필요가 없습니다.
Chrome 팀은 에이전트의 컨텍스트 창을 아끼기 위해 도구 출력 하나당 1,500자 이내로 간결하게 유지하라고 권장합니다.
execute의 두 번째 인자로 넘어오는 signal은 AbortSignal입니다.
사용자가 에이전트 UI에서 중지 버튼을 누르면 이 시그널이 취소되니 fetch() 같은 비동기 작업에 그대로 넘겨두면 불필요한 작업을 바로 멈출 수 있어요.
주목할 부분은 등록 해제 방식입니다.
처음 제안에는 unregisterTool(), provideContext(), clearContext() 같은 메서드가 있었지만 2026년 3월에 모두 스펙에서 빠졌습니다.
대신 registerTool()의 두 번째 인자로 AbortSignal을 넘기고 나중에 controller.abort()를 호출하면 도구가 해제됩니다.
fetch()나 addEventListener()에서 이미 익숙한 웹 플랫폼의 관용구를 그대로 따른 거죠.
컴포넌트가 마운트될 때 등록하고 언마운트될 때 해제하는 패턴과 잘 맞고, Chrome 153부터는 해제하더라도 이미 실행 중인 도구 호출은 끊기지 않습니다.
annotations 필드도 새로 생겼습니다.
도구의 성격을 에이전트와 브라우저에게 알려주는 힌트인데요.
readOnlyHint는 상태를 바꾸지 않는 조회용 도구라는 뜻이고, untrustedContentHint는 반환값에 사용자 생성 콘텐츠처럼 신뢰할 수 없는 데이터가 섞여 있으니 프롬프트 인젝션을 경계하라는 표시입니다.
consequentialHint는 항공권 예매나 송금처럼 되돌리기 어려운 작업이라는 뜻이라 브라우저나 에이전트가 실행 전에 사용자 확인을 받을 수 있게 해줍니다.
세 값 모두 기본값은 false입니다.
아직 브라우저 지원이 고르지 않으니 기능 감지(feature detection)를 거쳐 등록하는 게 안전합니다. API 위치가 한 번 바뀐 전력이 있는 만큼 더욱 그렇고요.
if (typeof document.modelContext?.registerTool === "function") {
await document.modelContext.registerTool(addToCartTool, { signal });
}
TypeScript를 쓴다면 webmcp-types 패키지로 document.modelContext 타입을 받을 수 있고, React에서는 usewebmcp 패키지의 useWebMCP 훅으로 컴포넌트 생명주기에 맞춰 도구를 등록하고 해제할 수 있습니다.
Angular도 Signal Forms를 WebMCP 도구로 바꿔주는 실험적 지원을 시작했습니다.
페이지 안에서 도구 찾아 쓰기
여기까지는 브라우저에 내장된 에이전트가 도구를 쓰는 시나리오였는데요. WebMCP는 웹 페이지 안에서 자바스크립트로 돌아가는 에이전트도 지원합니다. 사이트에 직접 심어둔 챗봇 위젯이 같은 페이지의 도구를 호출하는 상황을 생각하면 됩니다.
getTools()로 현재 문서에서 접근 가능한 도구 목록을 얻고 executeTool()로 실행합니다.
const tools = await document.modelContext.getTools();
const addToCart = tools.find((tool) => tool.name === "add_to_cart");
const result = await document.modelContext.executeTool(addToCart, {
product_id: "monitor-4k-27",
quantity: 2,
});
console.log(result); // 'monitor-4k-27 2개를 장바구니에 담았습니다'
getTools()가 돌려주는 각 도구에는 name, description, inputSchema 외에 도구를 등록한 origin과 window도 들어 있어서 어느 프레임의 도구인지 알 수 있습니다.
도구 목록이 바뀌면 document.modelContext에서 toolchange 이벤트가 발생합니다.
SPA에서 페이지가 전환되며 도구가 등록되거나 해제될 때 페이지 안의 에이전트가 이 이벤트를 듣고 도구 목록을 갱신하면 됩니다.
document.modelContext.addEventListener("toolchange", async () => {
const tools = await document.modelContext.getTools();
agent.updateTools(tools);
});
활용 시나리오
실제로 어디에 쓸 수 있을까요? 기존 방식과 비교하면 차이가 확 느껴집니다.
고객 지원부터 보죠.
지금까지 AI 에이전트가 고객 지원 사이트에서 문의를 접수하려면 카테고리 드롭다운을 찾고 텍스트 필드를 채우고 제출 버튼을 클릭하는 과정을 UI에서 하나씩 추론해야 했습니다.
WebMCP를 적용하면 사용자가 “네트워크 연결이 안 됩니다”라고 에이전트에게 말하면 에이전트가 create_ticket 도구를 호출해서 카테고리, 심각도, 설명을 한 번에 채워 넣습니다.
UI를 추측하는 게 아니라 명시적으로 정의된 도구를 호출하니까 사이트 디자인이 바뀌어도 깨지지 않죠.
이커머스 쇼핑도 재밌는 사례입니다.
“예산 50만원 이내에서 4K 모니터 추천해줘”라고 하면 에이전트가 search_products 도구로 조건에 맞는 상품을 찾고 비교한 뒤 add_to_cart 도구로 고른 상품을 장바구니에 넣을 수 있어요.
이때 에이전트는 사용자가 지금 보고 있는 페이지 맥락(로그인 세션, 이전 검색 기록 등)을 브라우저를 거쳐 자연스럽게 활용할 수 있습니다.
여행 예약 쪽은 좀 더 직관적입니다.
“다음 주 금요일 서울에서 제주 가는 오전 비행기 알아봐줘”라고 하면 에이전트가 항공사 사이트의 search_flights 도구를 써서 조건에 맞는 편을 정리해주고 가격 비교까지 해줄 수 있어요.
호텔 사이트에서도 비슷한 도구가 있다면 항공편과 숙소를 한 번에 잡는 시나리오도 가능하겠죠.
보안 모델
웹사이트에서 AI 에이전트가 마음대로 뭔가를 한다고 하면 보안이 신경 쓰일 수밖에 없습니다. WebMCP는 이 부분을 꽤 신경 써서 설계했습니다.
기본적으로 동일 출처 정책(Same-Origin Policy)을 따릅니다.
WebMCP 도구는 해당 웹사이트의 출처(origin) 보안 경계를 그대로 물려받고 HTTPS 같은 보안 컨텍스트(secure context)에서만 쓸 수 있습니다.
출처가 격리된 문서에서만 동작하기 때문에 document.domain으로 출처를 느슨하게 만든 페이지에서는 API 자체가 꺼집니다.
여기에 더해 권한 정책(Permissions Policy)으로 더 세밀한 제어도 가능합니다.
WebMCP 도구는 tools라는 권한 정책으로 게이트되어 있어요.
기본값은 self라서 동일 출처에서만 도구를 등록할 수 있고 크로스 오리진 iframe에서 도구를 노출하려면 부모 페이지에서 allow="tools" 속성을 명시해야 합니다.
권한이 없는 곳에서 registerTool()을 부르면 NotAllowedError로 거부되고요.
광고 슬롯이나 외부 위젯이 사용자 모르게 에이전트에게 도구를 등록하는 상황을 막아주는 장치죠.
크로스 오리진 사이에 도구를 나눠 쓰려면 양쪽이 모두 동의해야 합니다.
도구를 등록하는 쪽은 exposedTo 옵션에 허용할 출처를 적고, 가져다 쓰는 쪽은 getTools()의 fromOrigins 옵션에 그 출처를 명시해야 합니다.
한쪽만 열어두면 도구가 보이지 않아요.
// https://partner.example 에서 실행
await document.modelContext.registerTool(
{ name: "get_recommendations" /* ... */ },
{ exposedTo: ["https://shop.example"] },
);
// https://shop.example 에서 실행
const tools = await document.modelContext.getTools({
fromOrigins: ["https://partner.example"],
});
사람이 중간에서 확인하는 것도 빠질 수 없죠.
앞서 본 consequentialHint가 바로 이 용도입니다.
브라우저가 카메라나 위치 권한을 요청하듯이 되돌리기 어려운 작업 전에 사용자 동의를 구할 수 있게 해주거든요.
도구 안에서 사용자에게 직접 확인을 요청하는 API도 논의 중이지만, 이 글의 첫 버전에서 소개했던 requestUserInteraction()은 2026년 6월에 스펙에서 일단 빠진 상태입니다.
Chrome 팀은 도구 설명과 출력의 길이 제한도 권장합니다. 도구 설명은 500자, 파라미터 설명은 150자, 도구 이름과 파라미터 이름은 30자, 도구 출력은 1,500자 이내로 쓰라는 건데요. 에이전트의 가드레일에 걸리지 않고 컨텍스트 창을 아끼기 위한 기준입니다.
다만 아직 풀어야 할 숙제도 있습니다. 프롬프트 인젝션(도구 설명에 악의적인 지시를 숨기는 공격)이나 출력 인젝션(오염된 반환값으로 에이전트를 속이는 공격) 같은 위협은 스펙에서도 인정하고 있습니다. 사이트가 사용자에게 보이는 UI와 다르게 동작하는 도구를 등록해 에이전트를 속이는 의도 왜곡(misrepresentation of intent)이나, 필요 이상으로 많은 파라미터를 요구해 사용자 정보를 긁어가는 과잉 파라미터화(over-parameterization) 위험도 스펙의 보안 섹션에 새로 정리됐습니다.
MCP와의 관계
MCP를 알고 계신 분이라면 “WebMCP가 MCP를 대체하는 건가?”라는 의문이 들 수 있습니다. Chrome 팀의 공식 문서에서도 이 질문을 정면으로 다루는데요, 결론부터 말하면 둘은 경쟁이 아니라 보완 관계입니다.
좋은 비유가 있어요. MCP는 어디서든 전화 한 통이면 연결되는 콜센터에 가깝습니다. 플랫폼에 상관없이 항상 접근할 수 있고 데이터를 끌어오거나 핵심 작업을 처리하죠. 반면 WebMCP는 매장에 직접 방문했을 때만 만날 수 있는 매장 전문가입니다. 사용자가 웹사이트를 열어둔 그 순간에만 존재하지만 현장 맥락을 정확히 파악하고 있어요.
기술적으로 보면 MCP는 JSON-RPC 기반으로 AI 에이전트와 백엔드 서비스를 연결하고 WebMCP는 브라우저가 중간에서 웹 페이지와 에이전트 사이를 중재합니다. 그런데 스펙은 브라우저가 에이전트에게 도구를 어떤 형식으로 넘길지 정해두지 않았습니다. MCP 형식으로 변환해도 되고 모델 고유의 함수 호출(function calling) 형식을 써도 됩니다. 이름은 WebMCP지만 MCP의 자바스크립트 구현이 아니라 브라우저 환경에 맞게 새로 설계한 “MCP에서 영감을 받은(MCP-inspired)” API라서 MCP의 리소스(resources) 같은 서버 측 개념도 없어요.
둘의 차이를 한눈에 정리하면 이렇습니다.
| MCP | WebMCP | |
|---|---|---|
| 목적 | 언제 어디서든 데이터와 작업을 에이전트에게 제공 | 사용자가 사이트를 방문 중일 때 즉각적인 상호작용 |
| 수명 | 영구적 (서버/데몬) | 일시적 (탭에 종속) |
| 연결 범위 | 글로벌 (데스크톱, 모바일, 클라우드, 웹) | 브라우저 에이전트 전용 |
| UI 상호작용 | 헤드리스, 외부 | 브라우저 통합, DOM 인식 |
| 도구 발견 | 에이전트별 등록 흐름 | 웹 페이지 방문 시 등록 |
| 주요 용도 | 백그라운드 API 작업 수행 | 라이브 웹 UI 탐색 및 조작 |
여기서 눈여겨볼 점은 UI 소유권입니다. MCP 앱은 에이전트의 UI 안에서 애플리케이션 인터페이스를 렌더링합니다. 반면 WebMCP에서는 에이전트가 여러분의 웹사이트에 “손님”으로 들어옵니다. 라이브 세션 데이터, 쿠키, DOM 요소에 접근할 수 있지만 탭을 닫거나 사이트를 떠나면 에이전트도 더 이상 접근할 수 없죠.
재밌는 건 도구 형태가 똑같다는 점입니다.
둘 다 name, description, inputSchema로 정의하고 readOnlyHint 같은 어노테이션(annotations)도 MCP에서 가져왔어요.
MCP 생태계에 이미 발을 담근 개발자라면 WebMCP도 무리 없이 시작할 수 있을 겁니다.
함께 쓰면 더 강력하다
Chrome 팀은 가장 효과적인 에이전트 애플리케이션은 MCP와 WebMCP를 함께 사용하는 것이라고 강조합니다.
예를 들어 이커머스 서비스를 만든다고 해보죠. MCP 서버는 뒤에서 돌아가는 주요 로직, 그러니까 상품 조회, 재고 확인, 결제 처리 같은 걸 플랫폼에 관계없이 제공합니다.
그 위에 WebMCP가 브라우저 맥락을 입힙니다. 사용자가 쇼핑몰에 접속해 있는 그 순간, 에이전트가 현재 페이지 정보를 읽고 장바구니에 담고 위시리스트에 추가하는 일을 할 수 있게 되는 거죠.
MCP가 기반을 깔고 WebMCP가 현장 연결 고리를 만들면 에이전트 입장에서는 백엔드도 프론트엔드도 다 열리는 겁니다.
도구 발견 메커니즘
WebMCP 도구는 본질적으로 일시적(ephemeral)입니다. 웹 페이지가 브라우저 탭에 열려 있을 때만 존재하고 사용자가 사이트를 떠나거나 탭을 닫으면 에이전트도 더 이상 접근할 수 없어요. 보안 관점에서는 장점이지만 도구 발견 측면에서는 제약이기도 합니다. 에이전트가 어떤 사이트에 어떤 도구가 있는지 미리 알 수 없고 직접 방문해야 발견할 수 있거든요. Chrome 공식 문서도 이 점을 WebMCP의 한계로 명시하고 있습니다.
그렇다고 정적인 매니페스트 파일에 도구 목록을 적어두는 방식을 택하지도 않았습니다. 설계 과정에서 검토는 했지만 매니페스트로는 로그인 상태나 현재 페이지에 따라 도구를 동적으로 바꿀 수 없고 실행 코드를 담을 수도 없어서 보류됐거든요. 나중에 동적 등록 위에 정적 선언을 얹는 식으로 추가될 여지는 남겨두었습니다.
지금 진지하게 논의 중인 방향은 서비스 워커(Service Worker)입니다.
서비스 워커 안에도 modelContext 객체를 두어서 탭이 열려 있지 않아도 백그라운드에서 도구 호출을 처리하자는 제안인데요.
지도 앱을 보면서 캠핑장 예약 사이트의 도구를 호출하는 식의 시나리오가 가능해집니다.
서비스 워커 설치는 웹 앱 매니페스트의 serviceworker 필드로 사이트를 방문하지 않고도 할 수 있게 하고, 어떤 사이트에 어떤 도구가 있는지 찾는 검색 계층은 아직 열린 문제로 남겨두었습니다.
MCP Registry가 서버 측 MCP 도구의 검색과 배포를 맡는 것처럼 WebMCP 쪽도 발견 체계를 갖춰나가는 중이죠.
브라우저와 에이전트 지원 현황
2026년 2월 10일 Chrome 146 Canary에 첫 구현이 플래그 뒤로 실린 이후 상황이 빠르게 움직였습니다.
Chrome은 2026년 5월 Google I/O에서 오리진 트라이얼을 예고했고 6월에 정식 출시된 Chrome 149부터 트라이얼이 진행 중입니다.
Chrome 156까지 이어질 예정이라 사이트 운영자가 토큰을 등록하면 사용자가 플래그를 켜지 않아도 자기 사이트에서 WebMCP를 실서비스 트래픽으로 실험해볼 수 있습니다.
로컬 개발이라면 여전히 chrome://flags/#enable-webmcp-testing 플래그를 켜면 되고요.
같은 Chromium 기반인 Edge도 Edge 150부터 자체 오리진 트라이얼을 열었고 Brave는 Leo AI 챗에 실험적으로 붙였습니다.
브라우저별 현황은 WebMCP 저장소의 구현 현황 문서에서 계속 갱신됩니다.
에이전트 쪽에서 가장 큰 소식은 ChatGPT입니다. 2026년 8월 말 OpenAI가 ChatGPT 데스크톱 앱의 내장 브라우저에서 WebMCP 도구를 사이트 도구(site tools)라는 이름으로 지원하기 시작했거든요. 주소창의 사이트 도구 메뉴를 열면 현재 페이지가 제공하는 도구가 보입니다. 다만 아직은 최상위 페이지에서 명령적 API로 등록한 도구만 인식하고 선언적 폼 도구나 iframe 안의 도구는 지원하지 않습니다.
개발 도구도 갖춰졌습니다. Chrome은 WebMCP 전용 DevTools 프로토콜 도메인을 추가해서 등록된 도구를 나열하고 직접 호출하고 에이전트의 호출 기록을 남길 수 있게 했습니다. 선언적 도구에 이름이나 설명이 빠지면 DevTools의 Issues 패널에 경고가 뜨고요. Chrome 팀이 제공하는 Model Context Tool Inspector 확장 프로그램을 설치하면 자연어 프롬프트를 입력해서 에이전트가 도구를 의도대로 고르는지 직접 테스트할 수 있습니다. 실제 에이전트를 붙이기 전에 도구 정의를 다듬는 단계에서 유용합니다.
표준화 쪽은 아직 갈 길이 멉니다. 스펙은 여전히 W3C 커뮤니티 그룹의 초안 보고서라 표준 트랙에 오르지 않았고, 다른 브라우저 벤더의 반응도 엇갈립니다. Mozilla는 2026년 6월 중립(neutral) 입장을 냈고 이후 명령적 API에는 관심을 보이며 API 모양을 다듬는 제안을 이어가고 있습니다. 반면 WebKit은 같은 달 반대(oppose) 입장을 공식화했습니다. 에이전트가 페이지를 다루기 어렵다면 그건 페이지의 시맨틱이 부족한 것이니 HTML과 ARIA 같은 기존 계층을 보강해야지 에이전트 전용 도구 계층을 따로 만들 일이 아니라는 논리인데요. 사용자, 보조 기술, 에이전트가 모두 같은 계층의 혜택을 받아야 한다는 주장이라 곱씹어볼 만합니다.
스펙 차원에서 열려 있는 논의도 많습니다.
반환값의 구조를 정의하는 outputSchema와 스트리밍 입출력, 이미지 같은 멀티모달 입출력이 대표적이고요.
여러 도구를 묶어 사용자 여정을 안내하는 스킬(skills)이나 도구 실행 중 사용자에게 확인을 구하는 방법, 진행 상황 보고 같은 주제도 GitHub 이슈에서 논의되고 있습니다.
마치며
지금까지 웹사이트는 사람이 보고 클릭하는 걸 전제로 만들어졌습니다. WebMCP가 자리를 잡으면 AI 에이전트도 웹의 일급 사용자가 되는 셈이죠.
반년 만에 Chrome 오리진 트라이얼이 열리고 ChatGPT가 도구를 소비하기 시작한 걸 보면 속도가 꽤 빠릅니다.
물론 WebKit이 반대 입장을 낸 것처럼 이 방향이 웹의 정답인지를 둘러싼 논쟁은 진행 중이고 프롬프트 인젝션 같은 보안 과제도 남아 있습니다.
API가 반년 사이에 navigator.modelContext에서 document.modelContext로 옮겨가고 메서드 여럿이 사라진 것처럼 앞으로도 모양이 바뀔 수 있으니 지금 도입한다면 기능 감지를 꼭 곁들이는 게 좋겠습니다.
MCP가 AI 에이전트의 백엔드 통신을 표준화했다면 WebMCP는 프론트엔드 상호작용 쪽 퍼즐 조각입니다. 웹 개발자라면 지금부터 관심을 갖고 지켜볼 만합니다.
더 자세한 내용이 궁금하다면 WebMCP W3C 스펙과 Chrome WebMCP 공식 문서를 참고해보세요.
This work is licensed under CC BY 4.0