npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chronova/imagerouter-mcp

v1.2.2

Published

MCP server and local dashboard for generating images and videos through the ImageRouter API

Readme

imagerouter-mcp

An MCP server and a local dashboard for ImageRouter. Generate and edit images, generate videos, pick a model and check your balance from Claude Code, Claude Desktop or any stdio MCP client. Results are saved to disk and the tools return the file path. Requires Bun 1.2 or newer.

Quick start

Create an API key at https://imagerouter.io/api-keys, then register the server.

Claude Code:

claude mcp add imagerouter --env IMAGEROUTER_API_KEY=your-key -- bunx @chronova/imagerouter-mcp

Claude Desktop or any client that takes a JSON config:

{
  "mcpServers": {
    "imagerouter": {
      "command": "bunx",
      "args": ["@chronova/imagerouter-mcp"],
      "env": {
        "IMAGEROUTER_API_KEY": "your-key",
        "IMAGEROUTER_DEFAULT_IMAGE_MODEL": "black-forest-labs/FLUX-1-schnell:free"
      }
    }
  }
}

Desktop apps may not have Bun on their PATH; if the server does not start, use the absolute path to bunx (often /home/you/.bun/bin/bunx) as command.

Without a key the server still starts and list_models works; the other tools return an UNAUTHORIZED error that names IMAGEROUTER_API_KEY.

Updating

bunx keeps using the version it downloaded first, so a new release does not reach you on its own. Run the newest release once with the @latest tag, which also refreshes the cached copy:

bunx @chronova/imagerouter-mcp@latest --version

To always start the newest release, put @chronova/imagerouter-mcp@latest in the commands above instead; bunx then checks the registry on every start.

From source

git clone https://github.com/nx-solutions-ug/imagerouter-mcp.git
cd imagerouter-mcp
bun install
bun run build

Then use bun /path/to/imagerouter-mcp/dist/cli.js wherever the examples above say bunx @chronova/imagerouter-mcp, for example:

claude mcp add imagerouter --env IMAGEROUTER_API_KEY=your-key -- bun /path/to/imagerouter-mcp/dist/cli.js

Tools

| Tool | What it does | | ---------------- | --------------------------------------------------------------------------- | | generate_image | Generate an image from a text prompt and save it. | | edit_image | Edit images (image-to-image, mask inpainting, background removal) and save. | | generate_video | Generate a video from a prompt, from images, or both, and save it. | | list_models | List models with capabilities and lowest price in USD. Works without a key. | | get_credits | Show the account balance in USD. |

Every generation tool resolves its model as: the model argument, then IMAGEROUTER_DEFAULT_IMAGE_MODEL / IMAGEROUTER_DEFAULT_VIDEO_MODEL, otherwise it fails with a message telling you to pass one. edit_image uses the image default. Use list_models to find a model; there are about 200, so filter.

Failures come back as an error result such as INSUFFICIENT_CREDITS: ..., never as a crash. The codes are INVALID_REQUEST, UNAUTHORIZED, INSUFFICIENT_CREDITS, NOT_FOUND, RATE_LIMITED, SERVER_ERROR, CONNECTION_ERROR, TIMEOUT, API_ERROR and LOCAL_ERROR.

Two cases to know about:

  • A TIMEOUT or CONNECTION_ERROR on a generation call warns that the request may still complete and be billed. Check get_credits before retrying.
  • If a generation succeeded but downloading or saving the result failed, the error lists the hosted URLs (kept for 30 days) and any files already saved, so nothing you paid for is lost.

Saving arguments (all three generation tools)

| Argument | Meaning | | ------------ | ------------------------------------------------------------------------------------ | | output_dir | Directory to save into. Defaults to IMAGEROUTER_OUTPUT_DIR. | | filename | File name without directory. The extension is set from the result. | | ephemeral | true: ImageRouter does not store the result and no URL is returned, only the file. |

Without filename files are named <yyyyMMdd-HHmmss>-<prompt slug>-<4 hex>.<ext>. Existing files are never overwritten; a numeric suffix is added. The extension comes from the file's own signature when it is recognised, then the download's content type, then the URL, then output_format. A type that cannot be identified is saved as .bin.

generate_image

Arguments: prompt (required, up to 20000 characters), model, size (auto or WIDTHxHEIGHT), quality (auto|low|medium|high), output_format (webp|jpeg|png), plus the saving arguments.

{
  "path": "/home/you/Pictures/imagerouter/20261007-140509-a-fox-in-snow-3f9a.webp",
  "url": "https://storage.imagerouter.io/....webp",
  "model": "black-forest-labs/FLUX-1-schnell:free",
  "cost": 0,
  "latency_ms": 2140,
  "width": 1024,
  "height": 1024,
  "metadata_path": "/home/you/Pictures/imagerouter/20261007-140509-a-fox-in-snow-3f9a.webp.json"
}

width and height are the actual pixels, read from the saved file (omitted for video and formats that are not recognised). Every saved file also gets a metadata file next to it; metadata_path names the one of the first file and is omitted if it could not be written. In a files array each entry carries its own width, height and metadata_path.

edit_image

Arguments: images (required, 1 to 16: local paths, http(s) URLs or data URIs), prompt (optional; some models such as background removal take none), masks (optional, same forms, for models with mask support), model, size, quality, output_format, plus the saving arguments. Use list_models with supports_edit to find a model that can edit. The result has the same shape as generate_image.

generate_video

Arguments: prompt, images (start images for image-to-video, up to 16; at least one of prompt or images is required), model, size, seconds (auto or 1 to 60; accepted values depend on the model), plus the saving arguments. Video can take several minutes; if the client sent a progress token the server reports progress every 15 seconds. The result has the same shape as generate_image. When a call returns several files, path and url point at the first and a files array lists all of them.

list_models

Arguments: output (image|video), supports_edit, supports_mask, free_only, search (case-insensitive substring of the id), limit (1 to 300, default 50). Newest models come first.

{
  "total": 41,
  "returned": 1,
  "models": [
    {
      "id": "black-forest-labs/FLUX-1-schnell:free",
      "output": "image",
      "text": true,
      "edit": false,
      "mask": false,
      "quality": false,
      "min_price": 0,
      "release_date": "2024-08-01"
    }
  ]
}

min_price is the lowest price in USD across providers, or null when unknown. sizes and seconds appear when the model restricts them.

get_credits

No arguments.

{
  "remaining_credits": 4.82,
  "credit_usage": 0.18,
  "total_deposits": 5
}

Dashboard

IMAGEROUTER_API_KEY=your-key bunx @chronova/imagerouter-mcp@latest dashboard

Starts a page on http://127.0.0.1:4477 and opens your browser. Options:

  • --port <n> or --port=<n>: port to use (default 4477, or IMAGEROUTER_DASHBOARD_PORT).
  • --no-open: do not open a browser.

Any other option is rejected. The dashboard shows your balance, a form to generate, the result with its cost, latency, path and URL, and a gallery of the images and videos saved in the output directory (files of unrecognised type, saved as .bin, are not shown).

The form has four modes:

| Mode | Takes | Makes | | ------------- | ----------------------- | ----- | | Text → Image | a prompt | image | | Image → Image | images, prompt optional | image | | Text → Video | a prompt | video | | Image → Video | images, prompt optional | video |

The model picker (searchable, with prices and free models marked) lists only the models that can do the selected mode, as ImageRouter reports it. Images have size, quality and format; videos have size and seconds. A video can take several minutes, so keep the tab open.

Input images are added with Add images, by dropping them on the page or by pasting, or with Use as input in the details of a gallery image, which also switches a text mode to the matching image mode. Uploads are PNG, JPEG, WebP or GIF, at most 16 inputs, 10 MB each and 45 MB of uploads in total. They are sent to ImageRouter with the request and are not saved in the output directory.

The mode and, per mode, the model are remembered. When there is no remembered or configured model, or that model is hidden by the current filter or cannot do the mode, the picker selects the first visible free model so a first click never spends credits by accident; when the filter leaves no free model, it shows a disabled "Choose a model" entry and Generate stays blocked until you pick one. Your choice is only changed by you and by a successful generation, so clearing the filter brings it back. IMAGEROUTER_DEFAULT_IMAGE_MODEL is the configured model of the image modes, IMAGEROUTER_DEFAULT_VIDEO_MODEL of the video modes.

Files that have a metadata file show their model and pixel size under the thumbnail, with the prompt as tooltip; a video is marked "Video". Click a file for its details: prompt, model, requested size and actual pixels, quality, format, seconds, cost, latency, creation time and file name, with buttons to copy the prompt, the path and the hosted URL. A video plays there. The search box above the gallery filters by prompt, model or file name, and "Spent $X.XX on N files" next to the count sums the recorded costs of all N matching files (not only the tiles shown), counting a multi-result request once.

Use these settings loads the prompt, model, size, quality and format of a text → image record into the form and switches to that mode. It never submits; if the recorded model is no longer offered, the other fields are still loaded and you are told. Fields the record lacks, or values the model does not offer, are set to neutral defaults (empty prompt, auto, auto, webp). It is not offered for edits or videos, whose input images cannot be restored. Files without a metadata file (for example from before that feature) still show, without details.

Masks are available through the edit_image tool only.

It listens on 127.0.0.1 only and answers only requests addressed to localhost or 127.0.0.1 on its own port. Cross-site POSTs are refused and responses carry security headers. Your API key stays in the server process; the browser never sees it. The browser can hand over image bytes and the name of a file in the output directory, never a path.

Configuration

| Variable | Default | Purpose | | --------------------------------- | ---------------------------- | --------------------------------------------- | | IMAGEROUTER_API_KEY | none | Required for everything except listing models | | IMAGEROUTER_BASE_URL | https://api.imagerouter.io | Override for testing | | IMAGEROUTER_OUTPUT_DIR | ~/Pictures/imagerouter | Where results are saved | | IMAGEROUTER_DEFAULT_IMAGE_MODEL | none | Used when a call omits model | | IMAGEROUTER_DEFAULT_VIDEO_MODEL | none | Same, for video | | IMAGEROUTER_IMAGE_TIMEOUT_MS | 180000 | Request timeout, image calls | | IMAGEROUTER_VIDEO_TIMEOUT_MS | 900000 | Request timeout, video calls | | IMAGEROUTER_DASHBOARD_PORT | 4477 | Dashboard port (--port overrides) |

Where files go and what is public

Results are saved to ~/Pictures/imagerouter unless IMAGEROUTER_OUTPUT_DIR or the output_dir argument says otherwise. Unless you pass ephemeral: true, ImageRouter also stores each result for 30 days at a hosted URL that anyone holding the link can open. Use ephemeral: true when the content must not be stored on ImageRouter; you then get only the local file and no URL, and the result cannot be fetched again if saving fails.

Next to every saved file X the server writes X.json (for example fox.jpg.json) with the prompt, model, requested size, quality and format, the actual pixel size, byte size, cost and latency of the request, the hosted URL, whether it was ephemeral, the input images and masks you passed (a data URI is stored as the literal data-uri, never its content), the creation time and, for a request that returned several files, the index and count. Each file of such a request carries the same cost, the cost of the whole request. The prompt is stored in plain text in the output directory, also for ephemeral requests, which only skip ImageRouter's storage; do not put a prompt there that you would not leave on disk. The metadata file is best-effort: if it cannot be written the generation still succeeds and metadata_path is left out. Delete the .json to forget a record; the sidecar file itself is not served by the dashboard and not shown as an image (its contents are returned by /api/images).

Development

bun install
bun run test        # unit and integration tests, no network
bun run test:live   # smoke test against the real API, needs IMAGEROUTER_API_KEY
bun run build       # bundle into dist/
bun run dashboard   # build, then start the dashboard

bun run test:live is skipped without a key and uses only the free models test/test and ir/test-video, so it costs nothing. Before opening a pull request also run bun run type-check, bun run lint and bun run format:check. See CONTRIBUTING.md and AGENTS.md.

License

MIT, see LICENSE.