mcp-retrieval
이게 뭔가요
mcp-retrieval은 Go로 작성된 Model Context Protocol 서버입니다. MCP 호환 클라이언트(Claude Desktop, IDE 에이전트, 커스텀 LLM 앱)에 웹 검색 기능을 세 가지 읽기 전용 도구로 노출합니다. 내부적으로는 retrieval-go 라이브러리를 사용해 웹을 검색하고 페이지를 가져오며, 결과를 모델에 바로 전달할 수 있는 깔끔한 Markdown으로 반환합니다.
이 라이브러리는 API 키가 필요 없습니다: 웹 검색은 DuckDuckGo Lite를, 이미지 검색은 Bing Images를 거치며, 페이지 가져오기는 HTML을 readability 추출기에 통과시킨 후 Markdown으로 변환합니다. 봇 보호에 대비해 TLS 수준에서 실제 브라우저를 가장하며 브라우저 지문과 프록시를 모두 순환할 수 있습니다 — 검색 엔진을 참조하세요.
MCP SDK가 지원하는 두 전송 방식 모두 사용할 수 있으며 동일한 도구 세트를 노출합니다:
stdio — 클라이언트가 바이너리를 실행하고 stdin/stdout으로 통신합니다(기본값, 데스크톱 클라이언트에 적합).
http — 장기 실행 스트리밍 HTTP 서버(원격/공유 배포에 유용).
Related MCP server: mcp-web-calc
도구
도구 | 설명 |
| 하나 이상의 쿼리를 병렬로 실행하고 쿼리별로 중복 제거 및 재순위화된 스니펫을 링크와 함께 반환합니다. |
| 하나 이상의 이미지 쿼리를 병렬로 실행하고 쿼리별로 중복 제거된 이미지 결과를 반환합니다. |
| 하나 이상의 페이지를 병렬로 다운로드하고 본문 기사 텍스트를 Markdown으로 반환합니다. |
세 도구 모두 읽기 전용으로 주석 처리되어 있습니다. 각 도구는 출력 스키마와 일치하는 구조화된 JSON 페이로드를 반환합니다. SDK는 structuredContent를 읽지 않는 클라이언트를 위해 동일한 JSON을 텍스트 콘텐츠 블록에도 미러링합니다.
web_search
매개변수 | 타입 | 기본값 | 참고 |
|
| — | 필수. 병렬로 실행됩니다. |
|
|
| 쿼리당 스니펫 수, |
|
|
| 전체 호출 타임아웃, 구성의 |
|
| — | 최신성 필터: |
web_search_images
매개변수 | 타입 | 기본값 | 참고 |
|
| — | 필수. 병렬로 실행됩니다. |
|
|
| 쿼리당 이미지 수, |
|
|
| 전체 호출 타임아웃, 구성의 |
|
| — | 최신성 필터: |
web_scrape
매개변수 | 타입 | 기본값 | 참고 |
|
| — | 필수. 병렬로 다운로드됩니다. |
|
|
| 페이지의 |
|
|
| 전체 호출 타임아웃, 구성의 |
|
|
| 텍스트에서 Markdown 링크를 제거합니다. |
|
|
| 페이지 텍스트를 N자로 자르며, |
queries/urls목록은 모두 호출당max_queries(10)개 항목으로 상한이 적용됩니다. 쿼리는 512자 이하여야 하며, URL은 2048자 이하이고http/https만 허용됩니다.
결과 및 개수
모든 호출은 입력 목록 전체에 걸쳐 분산되며 쿼리/URL당 하나의 항목을 반환하고, 각 항목에는 success, failed, timeout 중 하나의 status가 포함되므로 부분 실패가 발생해도 성공한 항목은 계속 반환됩니다.
count는 실제로 반환된 항목 수이며, 요청한 max_results / max_images보다 낮을 수 있습니다: 단일 쿼리 결과 내의 중복은 상한이 적용되기 전에 제거되며, 업스트림에 제공할 항목이 단순히 더 적을 수도 있습니다. count가 더 작은 것은 정상적인 결과이지 오류가 아닙니다.
중복 제거는 쿼리별로 수행되며 쿼리 간에는 수행되지 않습니다. 각 항목은 자체적으로 중복 제거되므로, 같은 호출의 두 쿼리에서 발견된 링크는 두 항목 모두에 나타납니다 — 필요하다면 직접 합집합에서 중복을 제거하세요.
오류
요청 수준의 실패는 JSON-RPC 오류가 아닌 isError: true와 일반 텍스트 메시지가 포함된 도구 결과로 반환됩니다 — 모델이 메시지를 읽고 호출을 스스로 수정할 수 있습니다. 항목별 실패는 이렇게 처리되지 않으며 페이로드 안에 status: "failed" / "timeout"으로 유지됩니다.
호출이 완전히 실패하는 경우는 입력이 작업 시작 전에 거부되거나, 모든 항목이 실패한 경우뿐입니다:
메시지 | 의미 |
| 인수가 검증을 통과하지 못했습니다. |
| 목록이 |
| 빈 쿼리 또는 빈 |
| 쿼리가 512자를 초과합니다. |
| URL이 잘못되었거나, 2048자를 초과하거나, |
|
|
| 업스트림이 예상치 못한 상태 코드로 응답했습니다. |
| 모든 URL이 실패했습니다. 개별 원인은 |
| 모든 쿼리가 실패했습니다. |
| 분류되지 않은 모든 오류입니다. |
전체 실패 메시지는 의도적으로 타임아웃과 다른 원인을 구분하지 않습니다: 혼합 배치는 여러 이유로 동시에 실패할 수 있으며, 항목별 status가 항목이 하나라도 살아남을 때마다 이미 그 세부 정보를 담고 있기 때문입니다.
알려진 제한 사항
web_scrape는 HTML만 처리합니다. 페이지는 readability 추출기를 통과하며, 이 추출기는 기사 마크업이 필요하므로text/plain응답은 아무것도 생성하지 못하고status: "failed"로 반환됩니다. 원시 파일 호스트가 일반적인 경우입니다:raw.githubusercontent.com,github.com/.../raw/...,cdn.jsdelivr.net. 원시 파일 대신 렌더링된 페이지를 스크래핑하세요.web_search_images의 관련성은 보장되지 않습니다. 일부 쿼리의 경우 Bing Images가 결과 집합이 아닌 페이지를 제공하며, 이를 결과 집합인 것처럼 파싱합니다 — 그러면 도구가 관련 없는 이미지를status: "success"로 반환합니다. 이미지 결과는 최선의 노력(best-effort)으로 간주하고 사용자에게 보여주기 전에 검증하세요.JavaScript가 없습니다. 페이지는 있는 그대로 가져오며, 클라이언트 측에서 렌더링되는 콘텐츠는 추출기에 보이지 않습니다.
빠른 시작
설치
원하는 방식을 선택하세요 — 모두 동일한 서버를 제공합니다.
컨테이너 (Go 툴체인 불필요):
docker pull ghcr.io/role1776/mcp-retrieval:latest사전 빌드된 바이너리 — 최신 릴리스에서 플랫폼에 맞는 아카이브를 받아 압축을 풀고 mcp-retrieval을 PATH에 추가하세요.
MCP 번들 — .mcpb 파일을 설치하는 클라이언트의 경우, 최신 릴리스에서 mcp-retrieval_<version>_<os>_<arch>.mcpb를 다운로드하여 클라이언트로 열면 됩니다. 번들에는 컴파일된 바이너리가 포함되어 있으므로 Docker도 Go도 필요하지 않습니다. OS 및 CPU 아키텍처와 일치하는 파일을 선택하세요: 번들에는 네이티브 바이너리 하나가 들어 있습니다.
소스에서:
go install github.com/Role1776/mcp-retrieval/app/cmd/mcp-retrieval@latest # needs Go 1.25.5+또는 바이너리를 제자리에서 빌드합니다(Go 모듈은 app/에 있습니다):
make build # -> bin/mcp-retrieval실행
# defaults: stdio transport, no configuration needed
./bin/mcp-retrieval
# with an explicit env file
./bin/mcp-retrieval -env /absolute/path/to/.env플래그 하나는 선택 사항입니다:
플래그 | 의미 |
|
|
MCP 클라이언트 연결 (stdio)
클라이언트를 빌드된 바이너리로 지정하세요. Claude Desktop 설정 예시:
{
"mcpServers": {
"retrieval": {
"command": "/absolute/path/to/mcp-retrieval",
"env": {
"MAX_RESULTS": "20"
}
}
}
}env 블록은 선택 사항입니다 — "command"만으로 충분합니다.
MCP 클라이언트 연결 (컨테이너)
stdio로 이미지를 실행하세요. 구성은 여전히 env 블록을 통해 전달되지만, Docker는 각 변수가 프로세스에 도달하려면 -e 플래그로 명령줄에 명시되어야 합니다:
{
"mcpServers": {
"retrieval": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MAX_RESULTS",
"-e", "DEFAULT_TIMEOUT_MS",
"ghcr.io/role1776/mcp-retrieval:latest"
],
"env": {
"MAX_RESULTS": "20",
"DEFAULT_TIMEOUT_MS": "5000"
}
}
}
}-i는 필수입니다 — 없으면 컨테이너가 stdin을 받지 못하고 클라이언트는 서버가 즉시 종료되는 것을 보게 됩니다. MCP 레지스트리에서 설치하는 클라이언트는 이 호출을 직접 구성하고 server.json에 선언된 변수를 입력하라는 메시지를 표시합니다.
HTTP로 실행
MCP_TRANSPORT=http로 설정하면 서버는 MCP_PATH의 SERVER_PORT에서 수신합니다 (기본값 http://localhost:8080/mcp).
구성
모든 것은 환경 변수를 통해 구성되며, 각 값은 시작 전에 검증됩니다: 숫자가 아니거나 양수가 아닌 값은 시작 오류입니다. 한도 간의 관계는 시작 시 확인되지 않습니다 — 한도를 참조하세요. 환경에 이미 존재하는 변수는 .env 파일보다 우선하므로, MCP 클라이언트의 env 블록이 항상 적용됩니다. 모든 필드에는 합리적인 기본값이 있으므로 서버는 구성 없이도 실행됩니다 (stdio 전송).
전체 목록과 기본값은 .env.example을 참조하여 .env로 복사할 수 있습니다.
MCP 서버
환경 변수 | 기본값 | 참고 사항 |
|
|
|
|
| 클라이언트에 광고되는 서버 이름. |
|
| HTTP 경로 (http 전송 전용). |
클라이언트에 광고되는 버전은 구성할 수 없습니다: 빌드 시 git 태그에서 바이너리에 고정됩니다.
HTTP 서버 (http 전송 전용)
환경 변수 | 기본값 |
|
|
|
|
|
|
HTTP 클라이언트 및 프록시
환경 변수 | 기본값 | 참고 사항 |
|
| HTTP 연결 풀링. |
| — | 선택 사항. 설정하면 요청이 세션 순환 프록시를 통해 라우팅됩니다. |
| — |
|
| — |
|
| — |
|
| — |
|
프록시가 구성되면 각 아웃바운드 요청은 로그인에 고유한 세션 ID가 추가되어, 업스트림 제공자가 요청마다 출구 IP를 순환시킵니다.
한도
환경 변수 | 기본값 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
각 값은 개별적으로 검사됩니다 — 0보다 커야 합니다 — 그러나 DEFAULT_*, MIN_* 및 MAX_* 세 쌍은 시작 시 서로 교차 검사되지 않습니다. 일관되지 않은 집합이 서버를 중단시키지는 않습니다. 대신 요청별로 조정됩니다:
호출자가 생략하거나 0 또는 음수로 전달한 값은 해당
DEFAULT_*로 대체됩니다;그 결과는
[MIN_*, MAX_*]범위로 제한되므로,DEFAULT_*가 해당MAX_*보다 크면 단순히MAX_*가 됩니다;MIN_*가MAX_*를 초과하면 최대값이 우선합니다.
따라서 유효 한도는 항상 구성된 최대값 내에 있으며, 잘못된 구성은 시작 실패가 아닌 작동하는 서버로 이어집니다. 단점은 조용히 저하된다는 점입니다: MAX_RESULTS=2처럼 20 대신 오타가 있어도 경고가 발생하지 않고, 단지 응답이 조용히 작아질 뿐입니다. 결과가 잘린 것처럼 보일 때는 이 값을 다시 확인하는 것이 좋습니다.
로깅
환경 변수 | 기본값 | 참고 사항 |
|
|
|
아키텍처
이 프로젝트는 깔끔하고 계층화된 구조를 따릅니다. 의존성은 도메인을 향해 안쪽으로 향하며, 각 계층은 인터페이스를 통해 다음 계층과 통신합니다.
app/ the Go module: sources plus its build files
(Dockerfile, .dockerignore, .goreleaser.yaml)
cmd/mcp-retrieval/main.go entry point: parse flags, load config, run app
internal/
app/ wiring + lifecycle (build server, run, graceful shutdown)
config/ config loading (.env → env vars → validate)
domain/ core types (Query, Link, Document, Snippet, Image) and errors
dto/web/ request/response shapes for the MCP tools
transport/mcp/ MCP layer
router/ registers every tool group on the MCP server
web/ tool handlers
utils/ schema helpers and error → tool-result mapping
usecase/web/ business logic: validation, parallelism, timeouts, dedupe/limit/rerank
adapter/web/ retrieval-go client wiring (search, images, scrape, proxy)
pkg/ reusable building blocks (mcpserver, server, logger, validator)도구 호출의 요청 흐름:
MCP client → transport/mcp/web (handler) → usecase/web → adapter/web → retrieval-go → the web
↑ maps errors ↑ validates, fans out, limits results검색과 스크래핑은 모두 입력 목록 전체에 걸쳐 동시에 분산되며 항목별 결과를 집계하며, 각각 고유한 상태(success, failed, timeout)를 가집니다. 호출이 완전히 실패하는 경우는 해당 호출의 모든 항목이 실패한 경우뿐입니다.
검색 엔진
모든 네트워크 작업은 retrieval-go에 위임되며, app/internal/adapter/web에서 구성됩니다. 알아두면 좋은 사항:
소스. 웹 검색은 DuckDuckGo Lite를 사용합니다; 이미지 검색은 Bing Images를 사용합니다; 페이지 가져오기는 원시 HTML을 readability 추출기를 통해 처리하고 본문 기사를 Markdown으로 변환합니다 (표 포함). 검색 엔진 API 키가 필요하지 않습니다.
브라우저 가장. 어댑터는
WithBrowserRotation()을 활성화하므로 각 요청은 무작위로 선택된 ~11개의 실제 브라우저 프로필 중 하나에서 전송됩니다. 각 프로필은 실제 TLS/JA3 지문(uTLS 사용)과 일치하는User-Agent및 클라이언트 힌트 헤더를 쌍으로 사용합니다 — Chrome 133/131/120 (Windows/macOS/Linux), Edge 131, Firefox 120 (Windows/macOS), Safari 18.4 (macOS), iOS 18.4 Safari. 이렇게 하면 트래픽이 Go HTTP 클라이언트가 아닌 일반 브라우저처럼 보이며, 이것이 무료 소스에 계속 접근할 수 있게 하는 요소입니다.프록시 순환.
PROXY_HOST가 구성되면 어댑터는 모든 요청에서 프록시 사용자 이름에 고유한session-<id>를 추가하는 프록시 팩토리를 설치합니다. 세션 기반 리지덴셜/순환 프록시 제공자를 사용하면 요청마다 새로운 출구 IP가 생성되어 부하를 분산하고 속도 제한을 피할 수 있습니다. 프록시가 없으면 요청은 직접 나갑니다.응답 처리. 응답은 투명하게 압축 해제되며(
gzip,br,zstd,deflate), keep-alive는 비활성화됩니다(WithDisableKeepAlive()) — 풀링된 연결이 요청 간에 단일 지문/IP에 고정되지 않도록 하기 위함입니다.
이 중 어떤 것도 작동하기 위해 구성이 필요하지 않습니다 — 위의 기본값이 자동으로 적용됩니다. 프록시 자격 증명만 선택적 추가 사항입니다.
개발
Go 관련 모든 것은 app/에 있으므로, 저장소 루트의 makefile을 사용하거나 도구 체인에 -C app을 전달하세요:
make build # compile the binary
make test # run tests
go -C app build ./... # compile everything
go -C app test ./... # run tests
go -C app vet ./... # static checks풀 리퀘스트 지침은 CONTRIBUTING.md를 참조하세요.
라이선스
MIT 라이선스로 배포됩니다.
Available Tools
3 toolsweb_scrapeWeb scrapeARead-onlyIdempotent
Downloads pages by their links and returns the main text as markdown. Use this to read a page in full after 'web_search' found it; snippets alone are often not enough. Links are fetched in parallel, up to 10 per call, so batch all links into one call.
Size: 'max_chars' is a per-page character limit (not tokens). A page cut short ends with '[truncated]' and has 'truncated' set; the rest cannot be fetched afterwards.
Results are reported per URL with a 'status' field (success, failed or timeout). A failed URL does not fail the others; the call errors only if every URL fails. Target sites may block or rate-limit the request, which shows up as a failed URL.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | 1-10 absolute http(s) page URLs, fetched in parallel; one malformed URL rejects the whole call | |
| max_chars | No | character limit applied to each page separately, not to the whole response; default and maximum 20000, so it can only lower the limit; a cut page ends with '[truncated]' | |
| robots_txt | No | if true, pages disallowed by the site robots.txt are not fetched; default false | |
| timeout_ms | No | timeout for the whole call in milliseconds, shared by all URLs; default 5000, clamped to 1000-10000; unfinished pages get status 'timeout' | |
| remove_links | No | if true, markdown links are replaced by their text; default false |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | |
| metadata | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (readOnly, idempotent, openWorld, non-destructive), yet the description still adds real substance: per-URL status values, partial-failure semantics ('a failed URL does not fail the others'), all-fail error condition, external blocking/rate-limiting, and the irreversibility of truncation. Minor gap: it doesn't mention the robots_txt opt-in or the call-wide timeout being shared across URLs, both of which affect real call behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the batching rule, then cleanly separated into size and result-reporting sections. Every sentence carries a constraint or a consequence an agent would otherwise get wrong; nothing is padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers the things that actually break an agent's plan: batching limit, per-page truncation, partial failure isolation, and timeouts. An output schema exists, yet the description still summarizes the per-URL status contract, which is a useful addition rather than redundancy.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds interpretive value beyond the schema: 'max_chars' is a per-page limit, not tokens, and a cut page cannot be recovered afterwards. The remaining parameters (robots_txt, timeout_ms, remove_links) are left entirely to the schema, which is acceptable given full coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Downloads pages by their links and returns the main text as markdown') and explicitly positions itself against the sibling 'web_search' by naming the gap in snippets. An agent can distinguish it from web_search and web_search_images without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit sequencing rule ('use this to read a page in full after web_search found it; snippets alone are often not enough') and an operational rule ('batch all links into one call'). The alternative tool is named together with the condition that selects it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
web_searchWeb searchARead-onlyIdempotent
Searches the web for one or more queries and returns snippets with links. Queries run in parallel. IMPORTANT: Always write search queries in English for best results and relevance. Use this to find sources; then call 'web_scrape' to read a full page, or 'web_search_images' when you need pictures (both can be called in the same turn).
Freshness: set the 'date' field to restrict results by recency - 'd' (past day), 'w' (past week), 'm' (past month), 'y' (past year). Use it to prefer the most recent pages when the user asks about news or anything time-sensitive; leave it empty for all time.
Query operators (put them inside the query string itself): 'site:example.com term' limits the search to one site; 'filetype:pdf term' restricts to a file type; double quotes "exact phrase" force an exact match; a leading '-' excludes a word (term -foo); 'intitle:term' requires the word in the page title. Operators can be combined, e.g. 'site:arxiv.org filetype:pdf transformers'.
Results are reported per query with a 'status' field (success, failed or timeout). A failed query does not fail the others; the call errors only if every query fails. The upstream search engines may rate-limit or block requests, which shows up as a failed or timed-out query - retry later or rephrase.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | freshness filter: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time; use only these values | |
| queries | Yes | 1-10 search queries in English, run in parallel; each must be non-empty and at most 512 characters, otherwise the whole call is rejected | |
| timeout_ms | No | timeout for the whole call in milliseconds, shared by all queries; default 5000, clamped to 1000-10000; unfinished queries get status 'timeout' | |
| max_results | No | maximum snippets per query, not in total; default 5, values above 20 are clamped to 20 |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | |
| metadata | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/openWorld/idempotent annotations: it explains per-query status reporting (success/failed/timeout), that a failed query does not fail the others and the call errors only if all queries fail, and that upstream rate-limiting surfaces as failed/timed-out queries requiring retry or rephrasing. That is exactly the operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose before the operational detail, and section labels (Freshness, Query operators) make it scannable. Minor redundancy: the date filter values are spelled out in both the description and the schema's date property description, costing a sentence that adds no new information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers everything an agent needs for a multi-query search tool: batching behavior, partial-failure semantics, timeout/rate-limit handling, query formatting, and result shape at a high level. An output schema exists, so return values need not be enumerated here.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema coverage is 100%, the description adds substantial meaning: it mandates English queries, enumerates the supported query operators (site:, filetype:, quoted phrases, leading '-', intitle:) with a combined example, and explains freshness semantics. This is syntax guidance the schema does not express.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('searches the web') plus scope ('one or more queries', parallel execution, snippets with links). It explicitly distinguishes itself from both siblings by naming web_scrape for full-page reads and web_search_images for pictures.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing ('Use this to find sources; then call web_scrape...') and notes both can be called in the same turn. It also supplies conditional guidance for the date filter ('use it when the user asks about news or anything time-sensitive; leave it empty for all time').
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
web_search_imagesWeb image searchARead-onlyIdempotent
Searches for images by one or more queries, executed in parallel. IMPORTANT: Queries must be in English ONLY. Use this only when you need pictures; use 'web_search' for text answers and links, and 'web_scrape' to read a page.
Freshness: set the 'date' field to restrict results by recency - 'd' (past day), 'w' (past week), 'm' (past month), 'y' (past year); leave it empty for all time.
Query operators can be embedded in the query string: 'site:example.com term' limits to one site, double quotes "exact phrase" force an exact match, and a leading '-' excludes a word.
Results are reported per query with a 'status' field (success, no relevant, failed or timeout). A failed query does not fail the others; the call errors only if every query fails. The upstream image search may rate-limit or block requests, which shows up as a failed or timed-out query.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | freshness filter: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time; other values are ignored | |
| queries | Yes | 1-10 image search queries in English, run in parallel; each must be non-empty and at most 512 characters, otherwise the whole call is rejected | |
| max_images | No | maximum images per query, not in total; default 5, values above 10 are clamped to 10 | |
| timeout_ms | No | timeout for the whole call in milliseconds, shared by all queries; default 5000, clamped to 1000-10000; unfinished queries get status 'timeout' |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | Yes | |
| metadata | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/idempotent/non-destructive, yet the description still adds real value: per-query status semantics, partial-failure behavior ("a failed query does not fail the others"), and the upstream rate-limit/block risk. It does not explain result ordering or what fields come back, but the output schema covers that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core behavior and routing decision, then broken into scannable paragraphs for freshness, operators, and failure semantics. Slightly dense, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-param parallel search tool with annotations and an output schema, this covers everything an agent needs: language constraint, batching, freshness, operator syntax, and failure modes. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, and the description goes beyond it by documenting query operators (site:, "exact phrase", leading '-') that are absent from the schema entirely. The freshness codes and clamping are repeated from the schema rather than adding to it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Searches for images by one or more queries") plus the parallel-execution trait. It explicitly names both siblings and what each is for, so an agent can pick the right tool without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use condition ("use this only when you need pictures") and names the two alternatives with their respective purposes. The English-only constraint is flagged as IMPORTANT and front-loaded.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.10- Changed
web_scrape6 fields changed- changed
Input schema / properties / max_chars / descriptionPrevious value: -"truncate each page separately to N characters, default and maximum 20000; only lowers the limit, higher values are ignored"New value: +"character limit applied to each page separately, not to the whole response; default and maximum 20000, so it can only lower the limit; a cut page ends with '[truncated]'" - changed
Input schema / properties / remove_links / descriptionPrevious value: -"strip markdown links from the text"New value: +"if true, markdown links are replaced by their text; default false" - changed
Input schema / properties / robots_txt / descriptionPrevious value: -"respect the page robots.txt"New value: +"if true, pages disallowed by the site robots.txt are not fetched; default false" - changed
Input schema / properties / timeout_ms / descriptionPrevious value: -"timeout for the whole call in milliseconds"New value: +"timeout for the whole call in milliseconds, shared by all URLs; default 5000, clamped to 1000-10000; unfinished pages get status 'timeout'" - changed
Input schema / properties / urls / descriptionPrevious value: -"links to pages, downloaded in parallel"New value: +"1-10 absolute http(s) page URLs, fetched in parallel; one malformed URL rejects the whole call" - added
Input schema / properties / urls / maxItemsAdded value: +10
- Changed
web_search5 fields changed- changed
Input schema / properties / date / descriptionPrevious value: -"filter results by freshness: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time"New value: +"freshness filter: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time; use only these values" - changed
Input schema / properties / max_results / descriptionPrevious value: -"maximum number of snippets per query"New value: +"maximum snippets per query, not in total; default 5, values above 20 are clamped to 20" - changed
Input schema / properties / queries / descriptionPrevious value: -"search queries in English, executed in parallel"New value: +"1-10 search queries in English, run in parallel; each must be non-empty and at most 512 characters, otherwise the whole call is rejected" - added
Input schema / properties / queries / maxItemsAdded value: +10 - changed
Input schema / properties / timeout_ms / descriptionPrevious value: -"timeout for the whole call in milliseconds"New value: +"timeout for the whole call in milliseconds, shared by all queries; default 5000, clamped to 1000-10000; unfinished queries get status 'timeout'"
- Changed
web_search_images5 fields changed- changed
Input schema / properties / date / descriptionPrevious value: -"filter results by freshness: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time"New value: +"freshness filter: 'd' past day, 'w' past week, 'm' past month, 'y' past year; empty means all time; other values are ignored" - changed
Input schema / properties / max_images / descriptionPrevious value: -"maximum number of images per query"New value: +"maximum images per query, not in total; default 5, values above 10 are clamped to 10" - changed
Input schema / properties / queries / descriptionPrevious value: -"queries in English for image search"New value: +"1-10 image search queries in English, run in parallel; each must be non-empty and at most 512 characters, otherwise the whole call is rejected" - added
Input schema / properties / queries / maxItemsAdded value: +10 - changed
Input schema / properties / timeout_ms / descriptionPrevious value: -"timeout for the whole call in milliseconds"New value: +"timeout for the whole call in milliseconds, shared by all queries; default 5000, clamped to 1000-10000; unfinished queries get status 'timeout'"
3 tool updates
v1.0.0- First observed
web_scrape - First observed
web_search - First observed
web_search_images
TDQS
Scored across 3 tools
Each tool targets a distinct modality+action: text search, image search, and full-page fetching. The descriptions explicitly cross-reference each other ('use web_search for text, web_scrape to read a page'), leaving no realistic chance of misselection.
All three names follow the same snake_case verb_noun pattern sharing the 'web_' prefix (web_search, web_search_images, web_scrape). The shared prefix makes the family immediately recognizable while the distinguishing suffix stays descriptive.
Three tightly scoped tools for a retrieval-only server; none is redundant and no filler exists. Search-text, search-images, and scrape cover the full surface without bloat.
The retrieve-then-read workflow is fully supported, with batching, truncation signaling, and per-URL status handling. Minor gaps remain (no structured/raw fetch beyond markdown extraction, no crawl or sitemap traversal), but agents can work around these via repeated scrape calls.
Maintenance
Related MCP Connectors
Free web search for AI agents. No API key required. Hosted MCP in active development.
Docs: https://docs.keenable.ai/mcp-server Keenable is a free, remote MCP server that gives agents access to the web index. Search the web with ranked results and date/site filters, then fetch any indexed page as clean markdown. Works out of the box with no account or API key.
One MCP server for all web data. Scrape, search, crawl, and AI research in one install.
Related MCP Servers
- AlicenseBqualityDmaintenanceA local web scraping MCP server with RAG capabilities that provides intelligent web search, content extraction, and screenshot tools without requiring API keys.46 npmMIT
- AlicenseAqualityDmaintenanceAn MCP server that enables web searching, URL content extraction, and summarization without requiring API keys. It also provides advanced mathematical evaluation and multi-language Wikipedia summary retrieval tools.5400 npm7MIT
- AlicenseAqualityAmaintenanceA local-first, no-API-key MCP server that enables LLMs to search the web, fetch pages, and read documents using multiple engines and smart fallbacks.11167MIT
- AlicenseAqualityAmaintenanceA self-hosted MCP server providing web search and URL fetching tools, running locally without external API keys or accounts.2380 npmMIT