Skip to main content
Glama
CosLynxAI

open-media-finder

by CosLynxAI
README.md
<div align="center">

# open-media-finder

**One search across seven open collections, keeping only what each item's own licence field says you may reuse, with the credit line written for you.**

<img src="docs/search.jpg" alt="Six results of one real search for 'harbor': a Wikimedia Commons photo of Lindau harbour (CC BY 4.0, credit required), a NASA photo (public domain), a drawing from The Met, paintings from the Art Institute of Chicago and the Cleveland Museum of Art (all CC0), and a Poly Haven HDRI (CC0)" width="100%">

![Node](https://img.shields.io/badge/node-%E2%89%A5%2018.17-339933?logo=node.js&logoColor=white)
![Dependencies](https://img.shields.io/badge/dependencies-0-2ea44f)
![MCP](https://img.shields.io/badge/MCP-server-6e40c9)
![Tests](https://img.shields.io/badge/tests-8%20passing-2ea44f)
![License](https://img.shields.io/badge/license-MIT-blue)

[Why](#why) · [Sources](#sources) · [Install](#install) · [Usage](#usage) · [MCP](#use-it-from-an-ai-agent-mcp) · [How it works](#how-it-works) · [Limits](#limits)

</div>

---

Images, artworks, HDRIs, textures and 3D models from Wikimedia Commons, NASA, the Smithsonian, The Met, the Art Institute of Chicago, the Cleveland Museum of Art and Poly Haven. Each result is kept only when its own record says CC0, public domain or CC BY (CC BY-SA if you allow it). Every download is checked again at its source and added to a `CREDITS.md` beside the files. CLI, Node library and MCP server; no dependencies.

The picture above is one real run, laid out: the six results of `open-media-finder search harbor --source commons,nasa,met,aic,cleveland,polyhaven --limit 1`. Three more were passed over because their own licence did not allow free reuse.

## Why

"Free to use" is usually a label on a whole site, and whole sites are mixed:

- **Wikimedia Commons** keeps CC BY-SA and GFDL files next to CC0 ones, and flags trademarks and personality rights separately from copyright.
- **NASA** hosts photos it credits to other people, and those are not US government works.
- **Museums** put public-domain works beside works still in copyright, often on the same search page.

Trusting the site's label can get you a takedown. Reading each item's licence by hand takes an afternoon. This tool reads the field each source publishes for that one item, drops everything that is not clearly free, says how many it dropped, and writes the attribution the licence asks for.

## Sources

| Key | Source | What you get | The field it checks, item by item |
| --- | --- | --- | --- |
| `commons` | [Wikimedia Commons](https://commons.wikimedia.org) | photos, diagrams, SVGs | `extmetadata.LicenseShortName`, then `LicenseUrl`; the `Restrictions` field (trademarks, personality rights) is passed on as a note |
| `nasa` | [NASA Image and Video Library](https://images.nasa.gov) | space and mission photos | US government work, unless the item's description or credit fields name someone else (©, "courtesy of", a stock agency) |
| `smithsonian` | [Smithsonian Open Access](https://www.si.edu/openaccess) | museum objects, art, specimens | each image's `usage.access` = `CC0` |
| `met` | [The Met](https://www.metmuseum.org/about-the-met/policies-and-documents/open-access) | artworks | `isPublicDomain`, object by object (its search has no such filter) |
| `aic` | [Art Institute of Chicago](https://www.artic.edu/open-access/open-access-images) | artworks | `is_public_domain` |
| `cleveland` | [Cleveland Museum of Art](https://www.clevelandart.org/open-access) | artworks | `share_license_status` = `CC0` |
| `polyhaven` | [Poly Haven](https://polyhaven.com) | HDRIs, PBR textures, glTF models | all CC0; downloads at 2k |

## Install

Node.js 18.17 or newer, on Windows, macOS or Linux. No npm dependencies, no API keys needed.

```sh
# run it once, without installing
npx github:CosLynxAI/open-media-finder search "lighthouse"

# or install the command
npm install -g github:CosLynxAI/open-media-finder

# or from source
git clone https://github.com/CosLynxAI/open-media-finder && cd open-media-finder
node bin/cli.js search "lighthouse"
```

## Usage

```
open-media-finder search <words> [--source commons,nasa,...] [--limit 5] [--licence by] [--json] [--download <dir>]
open-media-finder check <page-or-file-url> [--licence by] [--json]
open-media-finder get <page-url>... --out <dir> [--licence by]
open-media-finder mcp
```

| Option | Default | |
| --- | --- | --- |
| `--source` | all seven | a comma-separated list of the keys in [Sources](#sources) |
| `--limit` | `5` | results per source, 1 to 50 |
| `--licence` | `by` | the most permissive licence to accept (below) |
| `--json` | off | the full result as JSON |
| `--download <dir>` | off | `search` only: download every result into `<dir>`, with its credits |
| `--out <dir>` | | `get` only, required: where to save |

| `--licence` | Accepts |
| --- | --- |
| `cc0` | CC0 and public domain: no credit needed |
| `by` | the above, plus CC BY: credit needed |
| `by-sa` | the above, plus CC BY-SA: credit needed, and adapted work must be shared under the same licence |

NonCommercial (NC) and NoDerivatives (ND) licences, GFDL-only files and anything without a clear licence field are never offered.

### search

```
$ open-media-finder search lighthouse --limit 1
[commons] "Port and lighthouse overnight storm with lightning in Port-la-Nouvelle" by Maxime Raynal from France
  licence: CC BY 2.0, credit required
  page:    https://commons.wikimedia.org/wiki/File:Port_and_lighthouse_overnight_storm_with_lightning_in_Port-la-Nouvelle.jpg

[nasa] "Lighthouse Moon" by NASA/JPL/Space Science Institute
  licence: Public domain (US government work)
  page:    https://images.nasa.gov/details/PIA09879
  note:    NASA's insignia and logos, and identifiable people, are not free to use in ads or endorsements

[smithsonian] "Design for a Lighthouse" by A. Le Canu, French, active 1746 – 1768
  licence: CC0
  page:    https://collections.si.edu/search/detail/edanmdm:chndm_1921-6-293-4

[met] "Lighthouse" by Henry Farrer
  licence: CC0 (Open Access)
  page:    https://www.metmuseum.org/art/collection/search/382738

[aic] "Rocks at the Lighthouse, Biarritz" by Joaquín Sorolla y Bastida
  licence: CC0 (public domain work)
  page:    https://www.artic.edu/artworks/66144

[cleveland] "Lighthouse Village (also known as Cape Elizabeth)" by Edward Hopper (American, 1882–1967)
  licence: CC0
  page:    https://clevelandart.org/art/1930.851

6 found, 5 passed over for their licence.
```

Poly Haven has no lighthouse, so it returned nothing. A source that fails (a rate limit, an outage) is reported on stderr and the others still answer.

### search --download

```
$ open-media-finder search "brick wall" --source polyhaven,met --limit 1 --download ./media
[polyhaven] "Brick Wall 001" by Rob Tuytel, Dimitrios Savva
  licence: CC0
  page:    https://polyhaven.com/a/brick_wall_001
  saved:   polyhaven-brick_wall_001/brick_wall_001_diffuse_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_nor_gl_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_rough_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_ao_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_displacement_2k.jpg

1 found, 1 passed over for their licence; credits in ./media/CREDITS.md.
```

A texture comes as its five main maps (diffuse, OpenGL normal, roughness, AO, displacement), an HDRI as its `.hdr`, a model as its glTF with every file it includes, in the folder layout it expects.

### check

Reads one item's licence again, fresh, by its page or file address. Exit code 1 when it is not free enough:

```
$ open-media-finder check "https://commons.wikimedia.org/wiki/File:Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg"
OK to reuse
[commons] "Lindau Harbor Lake Constance MS Schwaben 01" by Julian Herzog ( Website )
  licence: CC BY 4.0, credit required
  page:    https://commons.wikimedia.org/wiki/File:Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg
  file:    https://upload.wikimedia.org/wikipedia/commons/e/e3/Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg
  credit:  "Lindau Harbor Lake Constance MS Schwaben 01" by Julian Herzog ( Website ), CC BY 4.0 (https://creativecommons.org/licenses/by/4.0), via Wikimedia Commons, https://commons.wikimedia.org/wiki/File:Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg

$ open-media-finder check "https://commons.wikimedia.org/wiki/File:Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg" --licence cc0
open-media-finder: Wikimedia Commons states "CC BY 4.0" for https://commons.wikimedia.org/wiki/File:Lindau_Harbor_Lake_Constance_MS_Schwaben_01.jpg, beyond --licence cc0
```

It knows Commons file pages and `upload.wikimedia.org` files, `images.nasa.gov` pages and asset files, Smithsonian record addresses, Met, AIC and Cleveland artwork pages, and Poly Haven asset pages and `dl.polyhaven.org` files.

### get

Downloads items by their page addresses, each checked again first:

```sh
open-media-finder get https://www.metmuseum.org/art/collection/search/382738 https://polyhaven.com/a/abandoned_bakery --out ./media
```

## Output

**`CREDITS.md`** in the output folder, rewritten on every download. Items that need a credit come first, in the Title, Author, Licence, Source form [Creative Commons recommends](https://wiki.creativecommons.org/wiki/Best_practices_for_attribution). The file from the run above:

```md
# Credits

Written by open-media-finder. Each licence was read from the item's own record at its source when it was downloaded.

## No credit required (CC0, public domain)

- "Brick Wall 001" by Rob Tuytel, Dimitrios Savva, CC0, via Poly Haven, https://polyhaven.com/a/brick_wall_001 (no credit required)
  Files: polyhaven-brick_wall_001/brick_wall_001_diffuse_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_nor_gl_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_rough_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_ao_2k.jpg, polyhaven-brick_wall_001/brick_wall_001_displacement_2k.jpg
```

**`credits.json`** beside it: one record per item (`source`, `id`, `title`, `author`, `licence`, `level`, `page`, `credit`, `notes`, `files`, `downloadedAt`). Downloading the same item again replaces its record.

**`--json`** prints `{ items, skipped, errors }`. Each item: `source`, `id`, `title`, `author`, `licence` (as the source states it), `level` (`cc0`, `pd`, `by` or `by-sa`), `licenceUrl` (Commons), `page`, `preview`, `file`, `credit`, and `notes` when the source flags something beyond copyright.

## Use it from an AI agent (MCP)

`open-media-finder mcp` runs a [Model Context Protocol](https://modelcontextprotocol.io) server on stdio (JSON-RPC 2.0, no SDK) with three tools:

| Tool | Arguments | Does |
| --- | --- | --- |
| `search_media` | `query`, `sources`, `limit` (1-20), `licence` | the search above, with ready credit lines |
| `check_media` | `url`, `licence` | one item's licence read fresh; an error with the reason when it is not free |
| `download_media` | `url`, `dir`, `licence` | check, download, and add to the folder's `CREDITS.md` |

Claude Code:

```sh
claude mcp add open-media-finder -- npx -y github:CosLynxAI/open-media-finder mcp
```

Claude Desktop, Cursor and other clients (`mcpServers` in their config file):

```json
{
  "mcpServers": {
    "open-media-finder": { "command": "npx", "args": ["-y", "github:CosLynxAI/open-media-finder", "mcp"] }
  }
}
```

Then ask: *"find three CC0 photos of steam locomotives and save them to ./media with credits"*. The agent gets each licence from its source instead of guessing it.

## Use it from code

```js
const { search, check, download } = require("open-media-finder");

const { items, skipped, errors } = await search("lighthouse", { sources: ["commons", "met"], limit: 3, licence: "by" });
const item = await check(items[0].page);   // throws with the reason if it is not free enough
await download(item.page, "./media");      // file(s) + credits.json + CREDITS.md
```

## How it works

1. **Search.** All chosen sources are asked at once, each through its own public API, for a few times `--limit` candidates (the Met's search returns object IDs only, so each object is fetched). Where an API can filter (Smithsonian `media_usage:CC0`, AIC `is_public_domain`, Cleveland `cc0=1`), it does, and the item's own field is still read.
2. **Classify.** Each item's licence text or URL is mapped to one of four levels, most free first: `cc0`, `pd`, `by`, `by-sa`. Anything naming NC or ND, or matching none of them, is null and never offered. NASA items are public domain unless their description or credit fields carry ©, "copyright", "courtesy of" or a stock agency's name.
3. **Filter and count.** Items at or under `--licence` are kept, up to `--limit` a source; the rest are counted in `skipped`.
4. **Check again on download.** A download never trusts the search result: it reads the item's record again, refuses it if the licence changed, then streams the file(s). File names are made safe segment by segment, so an asset's own folder layout cannot write outside the output folder.
5. **Credit.** The record is merged into `credits.json` and `CREDITS.md` is rewritten from it.

Every request sends the user agent `open-media-finder/<version> (+https://github.com/CosLynxAI/open-media-finder)`, as Wikimedia's, Poly Haven's and the Art Institute of Chicago's API rules ask. No personal details are sent. A 429 or 5xx answer is retried twice, after a short wait.

## Limits

- **A free licence covers copyright only.** Trademarks (logos, NASA's insignia), the rights of people shown in a photo, and museum loans are separate questions. When a source flags them, the result carries `notes`.
- **It reads what each source states.** A wrong licence at the source is a wrong licence here. This is not legal advice: if a use matters, open the item's page and read it.
- **Smithsonian:** the API needs an api.data.gov key. Without one the shared `DEMO_KEY` is used, which allows only a few dozen searches an hour and answers HTTP 429 after that. Get a free key at [api.data.gov/signup](https://api.data.gov/signup/) and set `SI_API_KEY`.
- **Search quality is each source's own.** Poly Haven is matched locally on whole words of its asset names, tags and categories; the others use their own search engines.
- **Previews:** the Art Institute of Chicago's image server can answer 403 to a plain browser, so an `aic` preview link may not open in a tab. Downloads through the tool send the header it asks for.
- **Poly Haven** asks apps to show where its content comes from: every result and credit line here names it.

## Contributing

Issues and pull requests are welcome, especially a new open-access source. A source is one object in `src/sources.js` (`search`, `match`, `one`) that reads the licence from each item's own field. Add its fixtures to `test/finder.test.js`. The tests run offline, with the network replaced by fixtures:

```sh
npm test
```

## Licence

MIT, see [LICENSE](LICENSE). The media you find carries its own licence, as stated in each result and in `CREDITS.md`.

The image at the top shows six search results: "Lindau Harbor Lake Constance MS Schwaben 01" by Julian Herzog, CC BY 4.0, via Wikimedia Commons; "NASA's Boeing Crew Flight Test Landing", NASA/Aubrey Gemignani, public domain; "Harbor Scene" by Nikolaus Gottfried Stuber, The Met, CC0; "York Harbor, Coast of Maine" by Martin Johnson Heade, Art Institute of Chicago, CC0; "Harbor of Boston, with the City in the Distance" by Fitz Henry Lane, Cleveland Museum of Art, CC0; "Small Harbor 01" by Greg Zaal, Poly Haven, CC0.

## Made by Coslynx

[Coslynx](https://coslynx.com) makes Content Factory, software that makes short-form video for brands and channels on your own computer, with your own Claude plan. We built this tool while making it, and keep it open.