servo-fetch
Fetch and render web pages using the Servo browser engine — a single binary with JS execution, CSS layout, screenshots, and content extraction. Use when a URL returns empty or incomplete content with plain HTTP fetch, when you need a screenshot without GPU, or when you need to ru
Install
npx skills add https://github.com/konippi/servo-fetch/tree/main/skills/servo-fetch
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install konippi-servo-fetch@llmmart
git clone https://github.com/konippi/servo-fetch.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole konippi/servo-fetch collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
servo-fetch
When to use
- A URL returns empty or incomplete content with simple HTTP fetch (SPA, React, Vue)
- You need a screenshot of a web page in CI/Docker (no GPU available)
- You need to evaluate JavaScript in a page context (DOM queries, data extraction)
- You want clean Markdown from a documentation site, blog, or article
- You need to crawl an entire documentation site or blog for RAG / knowledge ingestion
- You need the accessibility tree with bounding boxes for a page
When NOT to use
- The page is simple static HTML (use
curlor built-in web fetch instead) - You need to interact with the page (click, fill forms) — servo-fetch is read-only
- You need full Chromium compatibility for complex web apps
Tools (MCP)
Start the MCP server: servo-fetch mcp (stdio) or servo-fetch mcp --port 8080 (Streamable HTTP)
Large multi-block responses can omit URL-labeled blocks and include an omitted-count summary; paginate fetch output with maxLength and startIndex. Extracted Markdown and JSON use the final document URL after redirects, while batch and crawl block labels preserve the requested URL.
fetch
Extract readable content from a URL. JavaScript is executed, CSS layout is computed, and navigation noise (navbars, sidebars, footers, cookie banners) is stripped automatically.
Parameters:
url(required): URL to fetch (http/https only)format:"markdown"(default),"json","html","text", or"accessibility_tree"selector: CSS selector to extract a specific section instead of full-page extractionmaxLength: max characters to return (default 5000)startIndex: character offset for paginationvisibility:"moderate"(default),"strict", or"off"- common:
timeout(s, default 30),settleMs(ms, default 0),userAgent,cookiesFile,headers
fetch(url: "https://docs.rs/tokio", format: "markdown")
fetch(url: "https://example.com", format: "json", selector: "article")
fetch(url: "https://example.com", format: "accessibility_tree")
PDF URLs are auto-detected via Content-Type and extracted directly.
batch_fetch
Fetch multiple URLs in parallel. Results are returned as separate content entries in completion order. Failed URLs are reported inline without aborting the batch.
Parameters:
urls(required): array of URLs to fetch (http/https only, max 20)format:"markdown"(default),"json","html","text", or"accessibility_tree"selector: CSS selector to extract a specific sectionmaxLength: max characters per URL result (default 5000)visibility:"moderate"(default),"strict", or"off"- common:
timeout(s, default 30),settleMs(ms, default 0),userAgent,cookiesFile,headers
batch_fetch(urls: ["https://a.com", "https://b.com"], format: "markdown")
batch_fetch(urls: ["https://a.com", "https://b.com"], format: "json", selector: "article")
crawl
Crawl a website starting from a URL, following same-site links via BFS. JavaScript is executed, CSS layout is computed, and navigation noise is stripped. Respects robots.txt.
Parameters:
url(required): starting URL to crawl (http/https only)limit: max pages to crawl (default 50, max 500)maxDepth: max link depth from seed (default 3, max 10)format:"markdown"(default) or"json"include: URL path patterns to include (e.g.["/docs/**"])exclude: URL path patterns to excludemaxLength: max characters per page result (default 5000)selector: CSS selector to extract a specific section per page- common:
timeout(s, default 30),settleMs(ms, default 0),userAgent,cookiesFile,headers
crawl(url: "https://docs.example.com", limit: 20, maxDepth: 3)
crawl(url: "https://docs.example.com", include: ["/guide/**"], limit: 50)
screenshot
Capture a PNG screenshot. Uses Servo's software renderer — works without GPU.
Parameters:
url(required): URL to capturefullPage: capture the full scrollable page (default false)- common:
timeout(s, default 30),settleMs(ms, default 0),userAgent,cookiesFile,headers
screenshot(url: "https://example.com")
screenshot(url: "https://example.com", fullPage: true)
execute_js
Evaluate a JavaScript expression after the page loads. Console messages (log, warn, error) are appended to the result.
Parameters:
url(required): URL to loadexpression(required): JavaScript expression to evaluate- common:
timeout(s, default 30),settleMs(ms, default 0),userAgent,cookiesFile,headers
execute_js(url: "https://example.com", expression: "document.title")
execute_js(url: "https://example.com", expression: "[...document.querySelectorAll('h2')].map(e => e.textContent)")
CLI
servo-fetch https://example.com # Markdown (default)
servo-fetch https://example.com --format json # Structured JSON
servo-fetch URL1 URL2 URL3 # Parallel batch (Markdown with separators)
servo-fetch URL1 URL2 --format json # Parallel batch (NDJSON)
servo-fetch https://example.com --format png -o out.png # Save PNG screenshot
servo-fetch https://example.com --js "document.title" # Run JavaScript and print result
servo-fetch https://example.com --selector article # Extract a section by CSS selector
servo-fetch https://example.com --schema schema.json # Schema-driven JSON
servo-fetch https://example.com --cookies cookies.txt # Send session cookies
servo-fetch https://example.com --cookie-jar cookies.txt # Save session cookies (includes HttpOnly)
servo-fetch https://example.com -H "Authorization: Bearer TOKEN" # Custom request header (repeatable)
servo-fetch https://example.com --format html # Raw HTML
servo-fetch https://example.com --format text # Plain text
servo-fetch https://example.com -t 60 # Custom timeout
servo-fetch https://example.com --settle 500 # Extra wait for SPAs
servo-fetch crawl https://docs.example.com --limit 20 # Crawl a site (BFS)
servo-fetch crawl https://docs.example.com --include "/docs/**" # Crawl with path filter
servo-fetch URL --output page.md # Save a single URL to a file
servo-fetch crawl URL --output-dir ./pages/ # One file per page
Gotchas
- Servo's web compatibility is improving but not at Chromium level — best for docs, blogs, and SSR sites
- Private/reserved IP addresses are blocked (SSRF protection)
- CLI batch fetch exits non-zero on any fetch failure that servo-fetch detects, while crawl page failures exit non-zero only when every attempted page fails
- Default timeout is 30 seconds; increase with
timeoutparameter for slow pages - Cookie banners and newsletter popups are stripped via injected user stylesheets
For pagination patterns, format selection, and MCP configuration, see references/guide.md.
Files (servo-fetch)
-
references
-
guide.md 6.1 KB
# servo-fetch Reference Guide ## Pagination Large pages are truncated at `maxLength` (default 5000 characters). The response includes a hint: ```text <content truncated. total_length=42000, next startIndex=5000> ``` Fetch the next chunk: ```text fetch(url: "https://...", startIndex: 5000) ``` ## Batch fetching Use `batch_fetch` to fetch multiple URLs in a single call. ```text batch_fetch(urls: ["https://a.com", "https://b.com", "https://c.com"]) ``` Batch and crawl return URL-labeled blocks that preserve completion order, each starting with its requested URL. Extracted Markdown and JSON resolve links and report metadata against the final document URL after redirects. Oversized results may omit whole blocks and include an omitted-count summary. Failed URLs are reported inline (prefixed with `[error]`) without aborting the batch. CLI equivalent: ```bash servo-fetch https://a.com https://b.com https://c.com # Markdown servo-fetch https://a.com https://b.com https://c.com --format json # NDJSON servo-fetch https://example.com --output page.md # Save single URL to a file servo-fetch https://example.com --cookie-jar cookies.txt # Save cookies sendable to this URL servo-fetch URL1 URL2 --output-dir ./out/ # One file per URL ``` CLI batch fetches attempt every URL, keep successful output, and exit non-zero if any fetch fails. Mixed failures are summarized with deterministic per-category counts and selected by fixed category precedence, not by treating numeric `sysexits` values as severity. Aside from a closed output pipe, command-level output errors are fatal and take precedence over the item-failure summary. ## Crawling Use `crawl` to follow links within a site and extract content from multiple pages. ```text crawl(url: "https://docs.example.com", limit: 20, maxDepth: 3) crawl(url: "https://docs.example.com", include: ["/guide/**"]) ``` Crawl follows same-site links only (eTLD+1), respects `robots.txt`, and applies a 500ms interval between requests by default (CLI: `--delay-ms`, library: `CrawlOptions::delay()`). CLI equivalent: ```bash servo-fetch crawl "https://docs.example.com" --limit 20 --max-depth 3 servo-fetch crawl "https://docs.example.com" --include "/guide/**" ``` CLI `crawl --limit` must be at least 1. Per-page failures exit non-zero only when every attempted page fails; partial success exits zero, while command-level setup, configuration, and output failures other than a closed output pipe are fatal. JSON stats are emitted before an all-pages-failed result whenever the stats stream remains writable. For CLI automation, distinguish Clap syntax/value failures (`2`) from runtime-invalid URLs, headers, glob patterns, and browser-session configurations (`64`, `EX_USAGE`). Other option-combination validation errors use status `1`. Raw or wrapped I/O failures, including failure to read a schema file, exit `74` (`EX_IOERR`), while malformed or invalid schemas exit `65` (`EX_DATAERR`). A closed output pipe remains a successful exit for pipelines. ## Format selection | Goal | Format | | ---- | ------ | | Read content, summarize, answer questions | `markdown` (default) | | Extract title, byline, excerpt, language | `json` | | Get raw HTML for further processing | `html` | | Get plain text (document.body.innerText) | `text` | | Get page structure with roles and bounding boxes | `accessibility_tree` | ## Selector extraction Use `selector` to extract a specific section instead of full-page Readability: ```text fetch(url: "https://example.com", selector: "article") fetch(url: "https://example.com", selector: ".main-content", format: "json") ``` ## Schema extraction For structured data (product catalogs, listings, comment threads), use `--schema` on the CLI with a schema file. No LLM required — selectors pull fields declaratively. ```bash servo-fetch "https://shop.example.com" --schema schema.json servo-fetch URL1 URL2 --schema schema.json # batch → NDJSON ``` Schema: ```json { "base_selector": ".product", "fields": [ { "name": "title", "selector": "h2", "type": "text" }, { "name": "price", "selector": ".price", "type": "text" }, { "name": "url", "selector": "a", "type": "attribute", "attribute": "href" } ] } ``` Field `type` values: `text`, `attribute`, `html`, `inner_html`, `nested_list`. An empty selector (`""`) reads from the matched element itself — handy inside `nested_list` when you want each item's own text or attribute. Schema selectors are validated at load time. ## Troubleshooting | Symptom | Solution | | ------- | -------- | | Empty content | Site may require JS features not yet supported by Servo. Try `execute_js` with `document.body.innerText` | | Timeout | Increase timeout: `fetch(url: "...", timeout: 60)` | | Blocked URL | URL resolves to a private IP (SSRF protection). Use a public URL | | Noisy output | Try `selector` to target the main content area, e.g. `selector: "article"` or `selector: "main"` | ## Screenshots Default viewport is 1280×800. Screenshots are rendered with Servo's software renderer (no GPU). ## Accessibility tree The `accessibility_tree` format returns a JSON object of all AccessKit nodes with roles, names, and bounding boxes. Password input values are automatically masked. ## MCP configuration ### stdio (default) ```json { "mcpServers": { "servo-fetch": { "command": "servo-fetch", "args": ["mcp"] } } } ``` ### Streamable HTTP ```bash servo-fetch mcp --port 8080 ``` Connect your MCP client to `http://127.0.0.1:8080/mcp`. ### HTTP REST API For non-MCP HTTP clients (direct REST calls, Docker deployments): ```bash servo-fetch serve --port 3000 ``` `POST /v1/fetch`, `/v1/batch_fetch`, `/v1/screenshot`, `/v1/execute_js`, `/v1/crawl`, `/v1/map` accept the same parameters as the MCP tools as JSON bodies. `GET /health` and `/version` are also exposed. ### Docker Prebuilt multi-arch image published on every release: ```bash docker run --rm -p 3000:3000 ghcr.io/konippi/servo-fetch:latest ``` The container runs the HTTP API on port 3000 as non-root (UID 1001) and exposes the same endpoints as above.
-
-
SKILL.md 7.3 KB
--- name: servo-fetch description: "Fetch and render web pages using the Servo browser engine — a single binary with JS execution, CSS layout, screenshots, and content extraction. Use when a URL returns empty or incomplete content with plain HTTP fetch, when you need a screenshot without GPU, or when you need to run JavaScript in a page context. No browser download required." --- # servo-fetch ## When to use - A URL returns empty or incomplete content with simple HTTP fetch (SPA, React, Vue) - You need a screenshot of a web page in CI/Docker (no GPU available) - You need to evaluate JavaScript in a page context (DOM queries, data extraction) - You want clean Markdown from a documentation site, blog, or article - You need to crawl an entire documentation site or blog for RAG / knowledge ingestion - You need the accessibility tree with bounding boxes for a page ## When NOT to use - The page is simple static HTML (use `curl` or built-in web fetch instead) - You need to interact with the page (click, fill forms) — servo-fetch is read-only - You need full Chromium compatibility for complex web apps ## Tools (MCP) Start the MCP server: `servo-fetch mcp` (stdio) or `servo-fetch mcp --port 8080` (Streamable HTTP) Large multi-block responses can omit URL-labeled blocks and include an omitted-count summary; paginate `fetch` output with `maxLength` and `startIndex`. Extracted Markdown and JSON use the final document URL after redirects, while batch and crawl block labels preserve the requested URL. ### fetch Extract readable content from a URL. JavaScript is executed, CSS layout is computed, and navigation noise (navbars, sidebars, footers, cookie banners) is stripped automatically. Parameters: - `url` (required): URL to fetch (http/https only) - `format`: `"markdown"` (default), `"json"`, `"html"`, `"text"`, or `"accessibility_tree"` - `selector`: CSS selector to extract a specific section instead of full-page extraction - `maxLength`: max characters to return (default 5000) - `startIndex`: character offset for pagination - `visibility`: `"moderate"` (default), `"strict"`, or `"off"` - common: `timeout` (s, default 30), `settleMs` (ms, default 0), `userAgent`, `cookiesFile`, `headers` ```text fetch(url: "https://docs.rs/tokio", format: "markdown") fetch(url: "https://example.com", format: "json", selector: "article") fetch(url: "https://example.com", format: "accessibility_tree") ``` PDF URLs are auto-detected via Content-Type and extracted directly. ### batch_fetch Fetch multiple URLs in parallel. Results are returned as separate content entries in completion order. Failed URLs are reported inline without aborting the batch. Parameters: - `urls` (required): array of URLs to fetch (http/https only, max 20) - `format`: `"markdown"` (default), `"json"`, `"html"`, `"text"`, or `"accessibility_tree"` - `selector`: CSS selector to extract a specific section - `maxLength`: max characters per URL result (default 5000) - `visibility`: `"moderate"` (default), `"strict"`, or `"off"` - common: `timeout` (s, default 30), `settleMs` (ms, default 0), `userAgent`, `cookiesFile`, `headers` ```text batch_fetch(urls: ["https://a.com", "https://b.com"], format: "markdown") batch_fetch(urls: ["https://a.com", "https://b.com"], format: "json", selector: "article") ``` ### crawl Crawl a website starting from a URL, following same-site links via BFS. JavaScript is executed, CSS layout is computed, and navigation noise is stripped. Respects robots.txt. Parameters: - `url` (required): starting URL to crawl (http/https only) - `limit`: max pages to crawl (default 50, max 500) - `maxDepth`: max link depth from seed (default 3, max 10) - `format`: `"markdown"` (default) or `"json"` - `include`: URL path patterns to include (e.g. `["/docs/**"]`) - `exclude`: URL path patterns to exclude - `maxLength`: max characters per page result (default 5000) - `selector`: CSS selector to extract a specific section per page - common: `timeout` (s, default 30), `settleMs` (ms, default 0), `userAgent`, `cookiesFile`, `headers` ```text crawl(url: "https://docs.example.com", limit: 20, maxDepth: 3) crawl(url: "https://docs.example.com", include: ["/guide/**"], limit: 50) ``` ### screenshot Capture a PNG screenshot. Uses Servo's software renderer — works without GPU. Parameters: - `url` (required): URL to capture - `fullPage`: capture the full scrollable page (default false) - common: `timeout` (s, default 30), `settleMs` (ms, default 0), `userAgent`, `cookiesFile`, `headers` ```text screenshot(url: "https://example.com") screenshot(url: "https://example.com", fullPage: true) ``` ### execute_js Evaluate a JavaScript expression after the page loads. Console messages (log, warn, error) are appended to the result. Parameters: - `url` (required): URL to load - `expression` (required): JavaScript expression to evaluate - common: `timeout` (s, default 30), `settleMs` (ms, default 0), `userAgent`, `cookiesFile`, `headers` ```text execute_js(url: "https://example.com", expression: "document.title") execute_js(url: "https://example.com", expression: "[...document.querySelectorAll('h2')].map(e => e.textContent)") ``` ## CLI ```bash servo-fetch https://example.com # Markdown (default) servo-fetch https://example.com --format json # Structured JSON servo-fetch URL1 URL2 URL3 # Parallel batch (Markdown with separators) servo-fetch URL1 URL2 --format json # Parallel batch (NDJSON) servo-fetch https://example.com --format png -o out.png # Save PNG screenshot servo-fetch https://example.com --js "document.title" # Run JavaScript and print result servo-fetch https://example.com --selector article # Extract a section by CSS selector servo-fetch https://example.com --schema schema.json # Schema-driven JSON servo-fetch https://example.com --cookies cookies.txt # Send session cookies servo-fetch https://example.com --cookie-jar cookies.txt # Save session cookies (includes HttpOnly) servo-fetch https://example.com -H "Authorization: Bearer TOKEN" # Custom request header (repeatable) servo-fetch https://example.com --format html # Raw HTML servo-fetch https://example.com --format text # Plain text servo-fetch https://example.com -t 60 # Custom timeout servo-fetch https://example.com --settle 500 # Extra wait for SPAs servo-fetch crawl https://docs.example.com --limit 20 # Crawl a site (BFS) servo-fetch crawl https://docs.example.com --include "/docs/**" # Crawl with path filter servo-fetch URL --output page.md # Save a single URL to a file servo-fetch crawl URL --output-dir ./pages/ # One file per page ``` ## Gotchas - Servo's web compatibility is improving but not at Chromium level — best for docs, blogs, and SSR sites - Private/reserved IP addresses are blocked (SSRF protection) - CLI batch fetch exits non-zero on any fetch failure that servo-fetch detects, while crawl page failures exit non-zero only when every attempted page fails - Default timeout is 30 seconds; increase with `timeout` parameter for slow pages - Cookie banners and newsletter popups are stripped via injected user stylesheets For pagination patterns, format selection, and MCP configuration, see `references/guide.md`.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.