exray
exray는 웹 페이지를 렌더링하고 사용자가 자신만의 TypeScript 스크래핑 및 추출 코드를 재사용 가능한 명명된 도구로 등록할 수 있는 원격 MCP 서버입니다.
여기서 exray를 실행하거나 설치하지 않습니다. https://mcp.exray.dev/mcp에서 호스팅되는 서비스입니다. 사용자가 Bearer 토큰을 제공하면 MCP를 통해 도구를 호출합니다.
무엇보다 먼저: 연결되었나요?
exray 도구가 도구 목록에 없다면 MCP 서버가 구성되지 않은 것입니다. 사용자에게 다음을 알리세요:
https://app.exray.dev/sign-in에 가입하세요 —/welcome페이지에서 토큰을 발급합니다 (한 번만 표시됨)- 해당 클라이언트에 서버를 추가하세요 — 구성은 https://docs.exray.dev/docs/mcp-clients에 있습니다
- 클라이언트를 다시 시작하세요 — MCP 구성은 시작 시 읽힙니다
fetch나 셸 도구로 스크래핑하여 연결 부재를 해결하려 하지 마세요. 무엇이 누락되었는지 말하고 중단하세요.
도구 선택하기
| 상황 | 도구 |
|---|---|
| 한 페이지, 내용 필요 | scrape |
| 한 페이지, 특정 필드 필요 | extract (플랫 스키마 사용) |
| 사이트 내 여러 페이지 | crawl, 이후 get_crawl_results |
| 동일한 추출을 반복하거나, 플랫 스키마로 처리하기 복잡한 로직 | define_extractor 작성 |
| 페이지에 클릭/스크롤이 필요하여 렌더링되어야 함 | define_fetcher 작성 |
| 사용자가 결과를 보고 싶어함 | define_handler 작성 (결과 페이지) |
가능하면 scrape / extract를 먼저 사용하세요. 기본 제공 도구가 필요한 작업을 진정으로 표현할 수 없을 때만 코드를 작성하세요 — 등록된 에셋은 사용자가 유지 관리해야 하는 것입니다.
플랫 스키마만 허용
extract는 정확히 네 가지 타입만 허용합니다: string, number, boolean, string[]. 중첩은 허용되지 않습니다.
{ "title": "string", "price": "number", "tags": "string[]" }
중첩되거나 조건부 형태는 대신 define_extractor가 필요합니다.
코드 에셋 작성하기
세 가지 종류가 있으며, 모두 TypeScript이고, 허용되기 전에 정적으로 검증됩니다:
- fetcher — 진입점
fetch(ctx), 브라우저를 구동하고PageSnapshot을 반환합니다. - extractor — 진입점
extract(snapshot, ctx?), 스냅샷을 JSON으로 변환합니다. - handler — 진입점
handle(request, ctx), 공개 웹 페이지를 제공합니다.
엄격한 제약 사항 — 위반하는 코드는 등록 시 거부됩니다:
- 유일하게 허용되는 import는
import typefrom@exray/exray-api입니다. 런타임 import는 금지됩니다. DOM 쿼리가 필요하면snapshot.html에서 문자열 처리를 사용하거나, fetcher 내에서ctx.page.evaluate()를 통해 DOM 작업을 수행하세요. eval/new Function금지, 최상위 수준 부수 효과 금지- 샌드박스 내부에서의 네트워크 접근 금지
등록은 에셋을 draft 상태로 둡니다 — 아직 실행할 수 없습니다. 사용하기 전에 publish_definition을 호출하세요. 이 부분은 자주 실수하므로 define_*만으로 성공을 보고하지 마세요.
결과 페이지 — next_action을 읽고 그에 따라 행동하세요
handler를 게시하면 응답에 site 객체가 포함됩니다. 게시 성공이 페이지에 접근 가능하다는 의미는 아닙니다. 항상 site.next_action을 읽고 사용자에게 아직 누락된 특정 사항을 알리세요:
next_action | 사용자에게 알릴 내용 |
|---|---|
set_username | "app.exray.dev/settings/profile에서 사용자 이름을 설정하세요 — 주소는 <username>-<project>.exray.app입니다." |
enable_site | "페이지가 <site.url>에 있습니다. 활성화하려면 exray site enable 또는 대시보드를 사용하세요." |
shorten_slug | "<username>-<slug>가 63바이트를 초과합니다. 더 짧은 프로젝트 슬러그를 사용하세요." |
contact_support | 서버 측 구성 문제입니다. 그대로 보고하세요. |
null | site.url에서 라이브 상태입니다 — 사용자에게 링크를 알려주세요. |
handler 게시를 마칠 때는 페이지 위치나 차단 원인을 반드시 알려야 합니다. 사용자가 다른 방법으로 알 수 없으며, "게시 성공"은 "완료되었다"고 읽힙니다.
handler가 할 수 있는 것과 없는 것:
- 가능:
ctx.data를 통해 이 프로젝트의 작업 데이터 읽기 (작업 목록 조회, 결과 가져오기), HTML 또는 JSON 반환, 경로별 라우팅 - 불가능: 데이터 저장, 네트워크 접근, 양식 제출 수락, 다른 프로젝트의 데이터 읽기
표현 계층일 뿐, 백엔드가 아닙니다.
스토리지 바인딩
에이전트 코드는 기본적으로 지속성을 가지지 않습니다. 프로젝트에 바인딩이 활성화된 경우, fetcher는 ctx.kv / ctx.db / ctx.storage를 사용할 수 있고, extractor는 ctx.kv만 사용할 수 있으며, handler는 세 가지 모두를 읽기 전용으로 사용할 수 있습니다.
호출 시 binding_not_enabled 오류가 발생하면 바인딩이 활성화되지 않은 것입니다 — 이를 위해서는 관리자 토큰(exray bindings set --kv on)이 필요합니다. 사용자에게 알리세요; 직접 활성화할 수 없습니다.
인지할 만한 오류
| 오류 | 의미 |
|---|---|
403 forbidden | 토큰에 필요한 범위가 없습니다. 실행에는 tools.execute, 등록에는 tools.define, 게시에는 tools.publish, 계정 작업에는 admin이 필요합니다. |
402 | 월별 할당량이 소진되었습니다. 중단하고 사용자에게 알리세요. |
definition_incompatible_api | 에셋이 다른 @exray/exray-api 메이저 버전으로 컴파일되었습니다. 다시 등록하세요. |
extractor_invalid / fetcher_invalid | 정적 검증이 코드를 거부했습니다 — 일반적으로 런타임 import 또는 최상위 수준 부수 효과 때문입니다. |
binding_not_enabled | 위의 스토리지 바인딩을 참조하세요. |
concurrent_exceeded | 너무 많은 호출이 진행 중입니다. 기다리세요; 짧은 루프로 재시도하지 마세요. |
budget_exceeded 또는 402 발생 시 중단하세요. 재시도는 진행 없이 사용자의 할당량을 소모합니다.
범위
첫 스크래핑 워크플로우에는 tools.read + tools.execute만 필요합니다. 등록 및 게시에는 tools.define / tools.publish가 필요합니다. 계정에 관련된 모든 것 — 토큰 발급, 결과 페이지 활성화, 바인딩 전환 — 은 admin이 필요하며 사용자의 작업이지, 여러분의 작업이 아닙니다.
전체 문서
https://docs.exray.dev — 빠른 시작, 클라이언트 구성, CLI 참조, 결과 페이지, 도구 매개변수 및 추출기 계약.