본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 03. 06:18

WebMCP 채택률이 0%라서, 직접 도구를 생성했습니다.

요약

WebMCP의 낮은 채택률 문제를 해결하기 위해, 웹사이트의 DOM을 분석하여 자동으로 MCP 도구를 생성하는 webmcp-gen을 소개합니다. 이 도구는 LLM의 추측에 의존하는 대신 결정론적인 CSS 셀렉터를 바인딩하여 에이전트가 웹 도구를 안정적으로 호출할 수 있게 합니다.

핵심 포인트

  • WebMCP 표준의 낮은 채택률 문제를 해결하기 위한 자동 생성 도구 개발
  • LLM의 추측 대신 CSS 셀렉터를 활용한 결정론적 타겟 바인딩 방식 채택
  • 브라우저 추출, 분석, MCP 서버 실행의 4단계 파이프라인 구축
  • Claude Desktop, Cline 등 기존 MCP 클라이언트와 즉시 호환 가능

AI 에이전트(AI agents)와 웹에 대해 모두가 말하는 깔끔한 이야기가 있습니다.

에이전트는 구조화된 도구(structured tools)를 호출할 것입니다. 웹사이트는 이러한 도구들을 노출할 것입니다. 모든 것은 타입이 지정되고(typed), 신뢰할 수 있으며, 좋은 의미로 지루할 것입니다. Google은 심지어 Chrome의 플래그(flag) 뒤에 이를 위한 표준인 WebMCP를 출시하기도 했습니다.

그것은 진정으로 좋은 아이디어입니다. 다만 한 가지 문제가 있습니다.

거의 아무도 이를 구현하지 않았습니다. 채택률(Adoption)은 사실상 제로입니다. 그리고 웹 표준은 분기 단위로 채택되지 않습니다. 채택된다 하더라도 수년에 걸쳐 이루어집니다.

그래서 그동안 여러분의 에이전트는 여전히 당혹스러운 일을 하고 있습니다. 페이지를 스크린샷 찍고, DOM을 스크래핑하고, 픽셀 좌표를 클릭하며, 지난 화요일 이후로 레이아웃이 바뀌지 않았기를 조용히 기도하는 일 말입니다.

저는 기다리는 것에 지쳤습니다. 그래서 다른 질문을 던졌습니다.

웹사이트의 허가가 필요 없다면 어떨까?

검색창 — 제출 버튼 옆에 라벨이 붙은 입력창 — 은 이미 search(query) 도구입니다. 명세(spec)는 HTML로 렌더링되어 바로 그곳에 있습니다. 누군가 그것을 읽고 기록하기만 하면 됩니다.

그것이 webmcp-gen의 핵심 아이디어입니다.

pip install webmcp-gen
webmcp-gen https://news.ycombinator.com --groq
{
  "tools": [{
    "name": "searchStories",
...

이 도구는 실제 브라우저를 구동하고, 사람이 하는 방식대로 페이지를 읽으며, WebMCP 도구 정의를 방출합니다. 그다음 — 이것을 장난감이 아닌 유용한 도구로 만드는 부분인데 — **MCP 서버 (MCP server)**로 실행되므로, Claude Desktop, Cline 또는 어떤 MCP 클라이언트라도 실제 라이브 사이트에서 해당 도구들을 실제로 호출하고 구조화된 결과를 돌려받을 수 있습니다.

파이프라인은 4단계로 구성됩니다:

EXTRACT   실제 브라우저 -> DOM + Shadow DOM + iframes -> 안정적인 CSS 셀렉터 (CSS selectors)
ANALYZE   휴리스틱(heuristic) 또는 LLM -> WebMCP 도구, 각 파라미터는 셀렉터에 바인딩됨
SERVE     MCP 서버 (stdio / SSE / streamable-HTTP)
...

실제로 고민이 들어갔던 두 가지 부분을 보여드리겠습니다.

파트 1: 셀렉터 바인딩 (실제 페이지에서 무너지지 않는 이유)

대부분의 "AI가 브라우저를 사용하게 만드는" 도구들은 모델에게 DOM을 보여주고 무엇을 클릭할지 추측하게 하는 방식으로 작동합니다. 그 추측이야말로 실제의 복잡한 페이지에서 도구들이 무너지는 바로 그 지점입니다. 모델이 잘못된 입력창을 선택하거나, 레이아웃이 변경되어 좌표가 쓸모없게 변해버립니다.

webmcp-gen은 다른 방식을 택합니다: 생성 시점에 단 한 번, 결정론적(deterministically)으로 타겟을 해결합니다. 분석기(analyzer)가 내보내는 모든 파라미터는 이를 채울 정확한 CSS 셀렉터인 _selector를 포함합니다. 에이전트가 보는 도구는 깔끔합니다:

{ "query": { "type": "string", "description": "Search term" } }

하지만 실행기(executor)가 보유한 버전에는 바인딩(binding) 정보가 포함되어 있습니다:

{
  "query": {
    "type": "string",
...

에이전트가 searchStories(query="rust")를 호출할 때, 추측은 필요하지 않습니다. 실행기는 input[name="q"]를 채우고 form#search를 제출합니다. LLM은 사물의 이름을 지정하고 의도를 추론하기 위해 초기에 단 한 번 사용되었을 뿐이며, 검색창이 무엇인지 다시 유도하기 위해 실행 경로(hot path)에서 사용되지 않습니다.

셀렉터 자체는 가장 안정적인 것을 우선순위로 하는 폴백 체인(fallback chain)을 통해 생성됩니다:

function stableSelector(el) {
  if (el.id) return '#' + CSS.escape(el.id);
  if (el.getAttribute('data-testid'))
...

#id가 가장 좋습니다. data-testid는 바로 이러한 목적을 위해 잘 만들어진 프론트엔드들이 제공하는 것입니다. [name=...]은 폼 필드(form fields)에 있어 신뢰할 수 있습니다. 이 모든 것이 실패할 경우에만 구조적 경로(structural path)를 구축하며, 그마저도 다음 배포 시 깨질 수 있는 12단계 깊이의 취약한 셀렉터가 생성되지 않도록 5단계로 제한합니다.

파트 2: form.method를 절대 믿지 말아야 함을 가르쳐준 버그

여기 실전 경험담이 있습니다. 이는 본인의 테스트 페이지가 아니라 수십 개의 실제 사이트를 대상으로 실행해 보았을 때만 마주칠 수 있는 종류의 문제입니다.

특정 사이트에서 추출(extraction) 과정이 충돌(crash)하고 있었습니다. 우아하게 에러를 내는 것이 아니라, 페이지 추출 전체가 충돌하여 도구가 하나도 반환되지 않는 상황이었습니다. 스택 트레이스(stack trace)는 다음과 같이 무해해 보이는 줄을 가리키고 있었습니다:

method: (form.method || 'GET').toUpperCase()

범인은 바로 **DOM 클로버링 (DOM clobbering)**입니다. 만약 폼(form)에 method라는 이름의 입력 필드 — 예를 들어 <input name="method"> — 가 포함되어 있다면

Cloudflare 챌린지(challenges), CAPTCHA, 또는 행동 지문 채취(behavioral fingerprinting)를 통과하기에는 이것만으로는 충분하지 않습니다. 이를 극복한다는 것은 주거용 프록시(residential proxies)와 TLS 스푸핑(TLS-spoofing) 군비 경쟁을 의미하며, 저는 이를 의도적으로 포함하지 않았습니다.

따라서 사이트가 이를 차단하면, webmcp-gen은 다음과 같이 알려줍니다:

{
  "success": false,
  "blocked": true,
...

이 도구는 CAPTCHA 페이지에서 success: true를 절대 거짓으로 꾸며내지 않습니다. 에이전트(agent)에게는 쓰레기 같은 결과가 포함된 가짜 성공이 정직한 "차단되었습니다"라는 응답보다 훨씬 더 위험합니다. 에이전트는 후자의 경우에서 복구할 수 있지만, 전자의 경우에는 기꺼이 그 결과에 따라 행동할 것이기 때문입니다.

실제로 작동하나요?

저장소(repo)에 벤치마크가 있습니다. "X% 성공"이라는 수치는 어떤 사이트인지 말하기 전까지는 의미가 없기 때문에, 난이도별로 그룹화된 실제 사이트들을 대상으로 전체 파이프라인을 실행합니다.

계층 (Tier)의미
sandbox자동화를 위해 구축된 사이트
...

Open 및 sandbox 계층에서는 단순한 연습용 페이지뿐만 아니라 Google, Bing, GitHub, Wikipedia와 같은 이름의 사이트들에 대한 성공적인 라이브 실행을 포함하여 대다수의 사이트에 도달합니다. 차단된 계층(walled tier)에서는 정확하게 blocked라고 보고합니다.

계층을 나눈 이유는 정직함 때문입니다. 하나의 통합된 백분율은 이 도구가 실제로 어떤 사이트들을 처리할 수 있는지 숨기게 됩니다. 전체 스위트(suite)는 소스에 포함되어 있으며, 다음과 같이 다시 실행할 수 있습니다:

webmcp-benchmark --suite full

단일 호출 이상의 기능을 수행합니다

  • 다중 페이지 크롤링 (Multi-page crawl) — 하나의 페이지가 사이트가 할 수 있는 모든 것을 보여주는 경우는 드뭅니다. --crawl은 오리진(origin)을 탐색하고 발견된 모든 페이지의 도구들을 병합합니다.
  • 인증된 세션 (Authenticated sessions) — 접근이 제한된 사이트의 경우, 실제 브라우저에서 한 번 로그인하면(도구가 아닌 사용자가 직접 비밀번호를 입력) 세션을 재사용합니다.
  • 도구 체이닝 워크플로우 (Tool-chaining workflows)검색 -> 결과 열기 -> 실행을 체이닝하여 이전 단계의 결과를 다음 단계로 전달합니다. 단계 사이에 페이지를 다시 읽기 때문에, 상세 페이지에서만 나타나는 "예약" 버튼도 해당 페이지에 도달하면 호출할 수 있게 됩니다.

이 모든 기능은 Groq, OpenAI 또는 로컬 Ollama 모델과 같은 모든 OpenAI 호환 API와 함께 작동하므로, 분석을 완전히 오프라인으로 실행할 수 있습니다.

시도해 보세요

pip install webmcp-gen
playwright install chromium
webmcp-gen https://en.wikipedia.org --groq

이 프로젝트는 MIT 라이선스이며, PyPI에 등록되어 있습니다. README에는 아키텍처 다이어그램 (architecture diagrams)과 솔직한 주의 사항 (caveats)이 명시되어 있습니다.

github.com/Nidhicodes/webmcp-gen

만약 에이전트 (agents)를 구축하면서 정확히 이와 같은 좌절감을 느끼셨다면, 어떤 부분에서 문제가 발생하는지 진심으로 알고 싶습니다. 흥미로운 실패 사례는 제가 아직 보지 못한 것들이니까요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0