{
  "markdown": "# webfetch\n\n[![npm version](https://img.shields.io/npm/v/getwebfetch?color=0a7)](https://www.npmjs.com/package/getwebfetch)\n[![CI](https://github.com/ashlrai/webfetch/actions/workflows/ci.yml/badge.svg)](https://github.com/ashlrai/webfetch/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)\n[![webfetch MCP server](https://glama.ai/mcp/servers/ashlrai/webfetch/badges/score.svg)](https://glama.ai/mcp/servers/ashlrai/webfetch)\n[![Discord](https://img.shields.io/badge/discord-join-5865F2)](https://getwebfetch.com/discord)\n[![GitHub stars](https://img.shields.io/github/stars/ashlrai/webfetch?style=social)](https://github.com/ashlrai/webfetch)\n\n**The license-first image layer for AI agents and humans.**\n\nOne MCP server, one CLI, and one HTTP server that federate across 25 image\nproviders, rank results license-first, and reject `UNKNOWN` results by default.\nAny agent that speaks MCP (Claude Code, Cursor, Cline,\nContinue, Roo Code, Codex) wires up from one config line. Landing page,\npricing, and hosted usage live at **[getwebfetch.com](https://getwebfetch.com)**.\n\n## Install\n\n| Surface       | One-liner |\n| ------------- | --------- |\n| npm           | `npm i -g getwebfetch` |\n| Homebrew      | `brew tap ashlrai/webfetch && brew install webfetch` |\n| Docker        | `docker run --rm ghcr.io/ashlrai/webfetch cli help` |\n| curl \\| bash  | `curl -fsSL https://raw.githubusercontent.com/ashlrai/webfetch/main/install/install.sh \\| bash` |\n\nThe `curl | bash` installer also wires webfetch into Claude Code's\n`~/.claude/settings.json` idempotently. Re-run any time to update.\n\n## Surfaces\n\n| Surface | Best for | Entry point |\n| ------- | -------- | ----------- |\n| CLI | scripts, shell work, agent handoff | `webfetch search ...` |\n| MCP server | Claude Code, Cursor, Cline, Continue, Roo Code, Codex | `npx -y getwebfetch-mcp` |\n| HTTP server | local integrations and extensions | `npx -y webfetch-server` |\n| Core library | TypeScript apps and custom tooling | `npm i webfetch-core` |\n| Browser layer | fallback extraction and managed-browser flows | `npm i webfetch-browser` |\n| Hosted cloud | pooled keys, usage tracking, team controls | [app.getwebfetch.com](https://app.getwebfetch.com) |\n\nPackage-level API notes live in [`packages/core/README.md`](./packages/core/README.md),\n[`packages/browser/README.md`](./packages/browser/README.md), and the other\npackage READMEs under `packages/`.\n\n## 30-second usage\n\nCLI:\n\n```bash\nwebfetch search \"drake portrait\" --limit 5\nwebfetch artist \"Taylor Swift\" --kind portrait --min-width 1200\nwebfetch download <url> --out ./portrait.jpg\nprintf \"drake portrait\\nradiohead album\\n\" | webfetch batch --jsonl --continue-on-error\n```\n\nMCP (from inside any MCP-speaking agent):\n\n```\nsearch_images({ query: \"drake portrait\", limit: 5 })\nsearch_artist_images({ artist: \"Taylor Swift\", kind: \"portrait\" })\ndownload_image({ url: \"...\" })\n```\n\nTypeScript library:\n\n```ts\nimport { searchArtistImages, pickBest, downloadImage } from \"webfetch-core\";\n\nconst { candidates } = await searchArtistImages(\"Drake\", \"portrait\");\nconst best = pickBest(candidates, { minWidth: 1200 });\nif (best) {\n  const { cachedPath, sha256 } = await downloadImage(best.url);\n  console.log(best.attributionLine, \"->\", cachedPath);\n}\n```\n\n## What problem this solves\n\nManually sourcing an image has four failure modes:\n\n1. **You don't know the license**, so you can't safely ship the result.\n2. **You can't script it** — every new site means another afternoon.\n3. **Google's Image Search API is retired**; scraping is brittle and ToS-grey.\n4. **No shared cache** — you re-download the same file dozens of times.\n\nwebfetch fixes all four by federating across direct-source APIs that have\nstable terms and structured license metadata, ranking candidates\nlicense-first, and exposing the result as a single MCP tool.\n\n## Providers\n\n| Provider         | Covers                                   | License default      | Auth                         | Opt-in |\n| ---------------- | ---------------------------------------- | -------------------- | ---------------------------- | ------ |\n| wikimedia        | portraits, events, logos, history        | CC_BY_SA (metadata)  | —                            | no     |\n| openverse        | any CC-licensed content                  | CC_BY (metadata)     | —                            | no     |\n| unsplash         | high-quality photography                 | `UNSPLASH_LICENSE`   | `UNSPLASH_ACCESS_KEY`        | no     |\n| pexels           | stock photography                        | `PEXELS_LICENSE`     | `PEXELS_API_KEY`             | no     |\n| pixabay          | stock photos + illustrations             | `PIXABAY_LICENSE`    | `PIXABAY_API_KEY`            | no     |\n| itunes           | album covers, artist portraits           | EDITORIAL_LICENSED   | —                            | no     |\n| musicbrainz-caa  | canonical album art                      | EDITORIAL_LICENSED   | —                            | no     |\n| spotify          | artist + album images                    | EDITORIAL_LICENSED   | `SPOTIFY_CLIENT_ID/SECRET`   | no     |\n| youtube-thumb    | video thumbnails                         | EDITORIAL_LICENSED   | —                            | yes    |\n| brave            | general web image search                 | UNKNOWN (+heuristic) | `BRAVE_API_KEY`              | no     |\n| bing             | general web image search                 | UNKNOWN (+heuristic) | `BING_API_KEY`               | yes    |\n| serpapi          | Google Images + reverse lookup           | UNKNOWN (+heuristic) | `SERPAPI_KEY`                | yes    |\n| browser          | headless fallback vs images.google.com   | UNKNOWN              | —                            | yes    |\n| managed-browser  | Bright Data managed browser fallback     | UNKNOWN              | `BRIGHTDATA_API_TOKEN`       | yes    |\n| flickr           | CC / public-domain photography           | CC_BY (metadata)     | `FLICKR_API_KEY`             | no     |\n| internet-archive | public-domain / CC archive media         | PUBLIC_DOMAIN        | —                            | no     |\n| smithsonian      | Open Access museum media                 | CC0                  | `SMITHSONIAN_API_KEY`        | no     |\n| nasa             | NASA imagery                             | PUBLIC_DOMAIN        | —                            | no     |\n| met-museum       | The Met Open Access                      | CC0                  | —                            | no     |\n| europeana        | European cultural heritage               | CC_BY (metadata)     | `EUROPEANA_API_KEY`          | no     |\n| library-of-congress | US historical archive                 | PUBLIC_DOMAIN        | —                            | no     |\n| wellcome-collection | medical/historical imagery            | CC_BY (metadata)     | —                            | no     |\n| rawpixel         | CC0 stock slice                          | CC0                  | `RAWPIXEL_API_KEY` optional  | no     |\n| burst            | Shopify Burst stock photos               | CC0                  | —                            | no     |\n| europeana-archival | Europeana text/manuscript records      | CC_BY (metadata)     | `EUROPEANA_API_KEY`          | yes    |\n\nSee [`docs/PROVIDERS.md`](./docs/PROVIDERS.md) for gotchas, rate limits, and\n[`docs/PROVIDER_TUNING.md`](./docs/PROVIDER_TUNING.md) for per-use-case picks.\n\n## Local and cloud modes\n\nThe CLI is local-first: by default `webfetch search`, `artist`, `album`,\n`download`, `probe`, `license`, and `batch` call `webfetch-core` in-process\nand use provider API keys from your environment. Pass `--cloud` or set\n`WEBFETCH_MODE=cloud` to call `https://api.getwebfetch.com/v1/*` with\n`WEBFETCH_API_KEY` or `webfetch config set apiKey wf_live_...`.\n\nUse local mode when you want direct provider calls and a local cache. Use cloud\nmode when you want hosted auth, pooled provider keys, managed browser fallback,\nusage accounting, or team controls.\n\n## Why license-first\n\nThe only outcome we reject by default is an image we can't justify. A\nmarginally-better photo under an unknown license is worthless to a pipeline\nthat needs to ship without human review. Relevance ties are easy to break;\nprovenance is not.\n\nThe ranker sorts by: **license tag -> metadata confidence -> resolution ->\nprovider priority**. `UNKNOWN` is rejected by default (Berne Convention:\nmost of the web is all-rights-reserved unless proven otherwise). See\n[`docs/LICENSE_POLICY.md`](./docs/LICENSE_POLICY.md).\n\n### Migration: CC0 stock providers\n\nOlder webfetch builds treated Unsplash, Pexels, and Pixabay as `CC0`. Current\nbuilds expose their platform terms explicitly:\n\n| Old tag | New tag | What to check |\n| --- | --- | --- |\n| `CC0` from Unsplash | `UNSPLASH_LICENSE` | Unsplash terms; not Creative Commons |\n| `CC0` from Pexels | `PEXELS_LICENSE` | Pexels terms; not Creative Commons |\n| `CC0` from Pixabay | `PIXABAY_LICENSE` | Pixabay terms; not Creative Commons |\n\nMost callers should keep `licensePolicy: \"safe-only\"` because it still allows\nopen, platform, editorial, and press-kit categories while rejecting `UNKNOWN`.\nPipelines that require only Creative Commons or public-domain assets should use\n`licensePolicy: \"open-only\"` and update type guards to handle the three\nplatform tags separately.\n\n## webfetch vs alternatives\n\n| Capability                            | webfetch | Raw Google Images | Unsplash-only | Bing CSE |\n| ------------------------------------- | -------- | ----------------- | ------------- | -------- |\n| Scriptable via API                    | yes      | no (retired)      | yes           | yes      |\n| License metadata per result           | yes      | no                | yes (one lic) | partial  |\n| Covers editorial music art            | yes      | partial           | no            | partial  |\n| Covers CC / public-domain             | yes      | no                | no            | no       |\n| Safe-by-default (rejects UNKNOWN)     | yes      | n/a               | n/a           | no       |\n| Shared content-addressed cache        | yes      | no                | no            | no       |\n| Attribution line pre-built            | yes      | no                | no            | no       |\n| One MCP config line across all IDEs   | yes      | no                | no            | no       |\n| No per-query cost on defaults         | yes      | n/a               | yes           | no       |\n\n## Architecture\n\n```\n                             +------------------+\n                             |  webfetch-core  |\n                             |  (ranker, cache, |\n                             |   license coerce)|\n                             +---------+--------+\n                                       |\n          +----------------+-----------+-----------+----------------+\n          |                |                       |                |\n  +-------v------+  +------v-------+       +-------v------+  +------v-------+\n  | webfetch     |  | webfetch-mcp |       | webfetch-    |  | browser      |\n  | CLI          |  | (stdio)      |       | server (HTTP)|  | extensions   |\n  +-------+------+  +------+-------+       +-------+------+  +------+-------+\n          |                |                       |                |\n          |                |                       |                |\n          +----------------+-----------+-----------+----------------+\n                                       |\n                 +---------------------v---------------------+\n                 |              provider adapters            |\n                 |  wikimedia  openverse  unsplash  pexels    |\n                 |  pixabay    itunes     mb-caa    spotify   |\n                 |  youtube    brave      bing      serpapi   |\n                 |  flickr     nasa       met       europeana |\n                 |  loc        wellcome   rawpixel  burst     |\n                 |  browser + managed-browser + archival opt-in|\n                 +-------------------------------------------+\n```\n\nEvery surface shares `~/.webfetch/cache/` keyed by SHA-256, so a download\nfrom the CLI is instantly available to the MCP server and vice versa.\n\n## Safety defaults\n\n- `licensePolicy: \"safe-only\"` — open, platform-license, and editorial/press categories are allowed; `UNKNOWN` is rejected.\n- `safeSearch: \"strict\"`.\n- Opt-in providers (`youtube-thumb`, `bing`, `serpapi`, `browser`, `managed-browser`, `europeana-archival`) off by default.\n- 20 MB per-download cap, content-type guard, host blocklist.\n- `robots.txt` respected on generic page probes.\n\n## Roadmap\n\n- `webfetch watch` — daemon mode for repeated queries / incremental refresh.\n- Bring-your-own-provider plugin API.\n- Hosted tier at [getwebfetch.com](https://getwebfetch.com) — pooled provider keys, managed browser fallback, team usage dashboard.\n\n## Contributing\n\nIssues and PRs welcome. Run `bun install && bun test` to get started. See\n[`docs/`](./docs/) for per-area reference docs.\n\n## License\n\nMIT.\n",
  "bytes": 13085,
  "sha": "207f1affb0972bb6ee1aa7f8e60575b049b4777f3535135052eefd4706315378",
  "repo_slug": "ashlrai/webfetch",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_ashlrai_webfetch_45b8d039/readme"
}