Skip to main content
Glama
README.md
<div align="center">

<img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/banner.webp" width="640" alt="no-api-media-mcp logo">

[![ci](https://github.com/farhan6667/no-api-media-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/farhan6667/no-api-media-mcp/actions/workflows/ci.yml)
[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
![Node 22+](https://img.shields.io/badge/node-22%2B-339933?logo=node.js&logoColor=white)
<br>
![MCP compatible](https://img.shields.io/badge/MCP-compatible-6E56CF)
![Claude Code ready](https://img.shields.io/badge/Claude%20Code-ready-D97757)
![No API key](https://img.shields.io/badge/API%20key-not%20needed-14B8A6)

**no-api-media-mcp is an open source MCP server (Apache-2.0, Node 22+) that lets Claude Code, Cursor, Codex and other MCP clients make images and videos for your projects with the AI subscriptions you already pay for.**<br>
**No API keys. No second bill.** Uses your own ChatGPT, Google AI Pro, Higgsfield and Grok accounts.

<p align="center">
  <a href="https://opencollective.com/nexaforge-oss"><picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/img/sponsor-button-dark.webp">
    <img src="docs/img/sponsor-button-light.webp" width="480" alt="Support NexaForge: an animated gold Support button that opens the sponsor page">
  </picture></a>
</p>

[Intro video](#watch-the-72-second-intro) • [Features](#features) • [Quick start](#quick-start) • [Connect accounts](#connect-your-accounts) • [Installation](#installation) • [Tools](#tools) • [CLI commands](#cli-commands) • [Troubleshooting](#troubleshooting)

</div>

---

<p align="center"><img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/workflow.webp" width="100%" alt="Overview: your AI assistant (Claude Code, Cursor, Codex, Windsurf or any MCP client) talks to no-api-media-mcp, which uses the AI plans you already pay for (ChatGPT via Codex, Google Flow, Gemini, Higgsfield, Grok) and puts finished, checked media in your project"></p>

## Watch the 72 second intro

https://github.com/user-attachments/assets/c96b3ad1-4795-4c54-91e7-95d3cd4627d3

A short narrated tour, 1080p: the problem it solves, the server making a real image from a prompt, and how to install it. The video itself was made with our own intro video tool and its synthetic NexaForge narrator. [Download the MP4 (9.4 MB)](https://github.com/farhan6667/no-api-media-mcp/releases/download/v1.3.0/no-api-media-mcp-intro.mp4).

## Features

- **Images and videos from your own plans**: GPT Image (ChatGPT via Codex), Nano Banana and Veo 3.1 (Google Flow), Gemini, Higgsfield (Seedance, Kling and more), Grok
- **No API keys at all**: you sign in once, by hand, in a private Chrome window. API-key variables are stripped before any tool runs
- **Understands your project**: reads what it does, its colours, fonts, 3D or animation libraries and existing images, then matches the style (luxury, premium, playful, corporate, modest)
- **Premium by default**: writes a real creative brief for every asset, with named looks like `neon-glass` (the style of the graphics on this page)
- **Built-in media studio** *(new in 0.2)*: background removal, video editing for Reels and Shorts, and every social size from one image, all running locally
- **Saves straight into your project**: full quality, no Download folder, no Save dialog, never outside the project
- **Shrinks for the web without visible loss**: WebP and H.264, checked with an SSIM quality score
- **Credit-safe**: shows the cost first, hard `max_credits` cap, one job at a time
- **Add any site with a small JSON file**, no code

## What's new in 1.x

<p align="center"><img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/whats-new-1.webp" width="100%" alt="What's new in 1.x: compose sets your real headline and logo, deliver makes the exact file for each platform, measured audits, it remembers your corrections, several sessions in one browser, prompts that never contradict"></p>

<sub>Made the way the server now recommends: the background came from `design_brief` and `image_generate` (Codex on a ChatGPT plan), every word and logo was set on top in HTML instead of being drawn by the model, then `composition_check` and `media_optimize` checked and shrank it. None of the graphics on this page show another company's logo.</sub>

| Tool | What it does |
|---|---|
| `compose` | Sets your real headline and a registered brand's logo over generated art: measured placement, at least 4.5:1 contrast, the brand's fonts, no glow |
| `deliver` | The exact file a platform wants (linkedin-feed, instagram-story, x-post, github-social and more): size, smallest JPEG that still looks identical, under the size limit |
| `brand_profiles` | The brands you publish under, with who publishes (a person or a company) and their real logo files, so the right mark is never guessed |
| `design_feedback` | Remembers what you said was wrong and applies it to every later brief, per brand if you like |
| `composition_check` | Finds empty bands at the edges and crops them while keeping your target shape |
| `browser_done` | Closes the browser when the work is finished, never while another session still uses it |

### The media studio (since 0.2)

| Tool | What it does |
|---|---|
| `background_remove` | Cuts out the subject into a transparent PNG with BiRefNet models via [rembg](https://github.com/danielgatis/rembg). Fully local, nothing uploaded. Quality: `fast`, `best`, `portrait`, `anime` |
| `video_edit` | Trim, reframe to 9:16 / 1:1 / 16:9 / 4:5, speed, fade, mute, replace audio, poster frame, GIF, text overlay, logo, burned-in subtitles, join clips |
| `social_sizes` | One image into Open Graph, LinkedIn, X, Instagram square/portrait/story, YouTube thumbnail, Pinterest, GitHub social preview, favicon and app icons. Cover, blurred-fill or solid padding |
| `media_probe` | Duration, size, frame rate and codecs of any file |

Try:

```text
Remove the background from public/products/lamp.jpg.
Turn this 16:9 clip into a 9:16 Reel with our logo top-right and these subtitles.
Make every social size from public/og.png.
```

## Quick start

```bash
git clone https://github.com/farhan6667/no-api-media-mcp
cd no-api-media-mcp
npm install && npm run build
node dist/src/index.js setup
```

`setup` checks your machine, opens a Chrome window where you sign in to ChatGPT and Google, and prints the line to add to your AI client. Then just ask your agent for what you need.

## No prompt writing needed

<p align="center"><img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/how-it-works.svg" width="900" alt="You ask your AI agent, the MCP reads your project, writes the art direction, generates with your plan, checks the result and saves it into your project"></p>

You don't write image prompts. When your AI client connects, this server hands it a full workflow, and the agent follows it on its own:

1. **Reads your project**: what it does (from the README or site), colours, fonts, 3D or animation libraries, existing images
2. **Writes a real creative brief**: what the project is, where the image goes, who sees it, what it must achieve, and a premium quality bar. This is the part that makes results look high-end instead of generic
3. **Generates** with the right tool: GPT Image (ChatGPT) for designs with text, Google Flow for photo and 3D scenes
4. **Checks every result** against a design checklist (spelling, brand fit, no third-party logos, crop) and retries with a corrected brief
5. **Shrinks and places** the winner in your project, with real alt text

### Try one of these

Copy any of these into Claude Code, Cursor or Codex, inside your project:

```text
Look at this project and tell me where images or video would make the site better, then make them and put them in.
```

```text
Make a premium 16:9 hero image for the landing page that matches our brand.
```

```text
Create a 1200x630 social preview image for this repo, with the project name spelled exactly.
```

```text
Make a premium infographic that explains what this project does, for the top of the README.
```

```text
Make an 8 second calm background video for the hero, quote the credits first.
```

That's the whole interface. Say "premium", "luxury", "minimal" or "playful" if you want a specific level, otherwise it aims for premium.

### Made with this MCP

Both of these came out of the prompts above, through Google Flow on an AI Pro plan, 0 credits, no API key:

<p align="center">
<img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/example-infographic.webp" width="49%" alt="Infographic generated by no-api-media-mcp: your AI client, the MCP server and your AI subscriptions, with the media saved in your project">
<img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/example-hero.webp" width="49%" alt="Hero image generated by no-api-media-mcp: a developer at night with glowing images and video frames floating from the laptop">
</p>

### At a glance

<p align="center">
<img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/product-overview.webp" width="49%" alt="How it works in six steps: you ask in plain words, it reads your project, writes a designer's brief, your AI plan makes the art, it checks every draft, and it delivers the final file">
<img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/poster.webp" width="42%" alt="Make images and videos with the AI plan you already pay for. No API keys, no second bill. Works with ChatGPT via Codex, Google Flow, Gemini, Higgsfield and Grok, in Claude Code, Cursor, Codex, Windsurf and any MCP client">
</p>

## It designs for who's actually looking

Tell `design_brief` who sees the asset (`context.audience`, plain English: "CISOs", "developers", "the open source community", "security analysts", "the general public") and it recognises a few real audiences and changes the art direction for them: tone, a default style tier and a palette when you haven't set your own, plus one honest critique question asked from that reader's seat.

| You said | It assumes | Tier | A question it adds |
|---|---|---|---|
| CISOs, executives, buyers | time-pressed, skeptical of a hard sell | corporate | Would they get the one thing that matters in three seconds? |
| developers, engineers | can tell marketing gloss from substance | minimal | Would they believe it, or tune it out? |
| the open source community, GitHub | scanning a repo list, not a product page | premium | Does it read as open source, not a corporate ad? |
| security analysts, pentesters, SOC teams | seen a hundred vendor decks already | premium | Would a working analyst trust it? |
| the general public, gamers, consumers | scrolling for fun | playful | Is it fun without turning childish? |

Don't invent an audience it doesn't recognise, say so plainly and it's simply left unset.

## It sets the text and logo itself, then delivers the final file

Generated art is only half a post. Register the brands you publish under once:

```sh
brand_profiles(action="set", id="sfa", name="SFA", publisher="person", logo_dark="/path/sfa-logo.webp")
```

Then `compose` sets the headline and that brand's real logo over the art. It measures the picture to find the calmest corner, keeps the text out of the busy part, picks the text colour and a soft scrim for at least 4.5:1 contrast, and never adds a glow. `deliver` turns the result into the file a platform wants:

```sh
compose(input_path="art.png", headline="Shadow AI", brand_id="sfa", platform="linkedin-feed")
deliver(input_path="art-composed-linkedin-feed.png", platform="linkedin-feed")
```

That gives an exact 1080x1350 JPEG, as small as it can be without a visible change, metadata stripped, under LinkedIn's limit, and checked for an empty band.

## It measures its own work, and remembers your corrections

`design_audit` doesn't only take the model's word for it: given the file, it measures it, and an empty band at an edge or a washed-out thumbnail caps the score so a weak result can't ship. `composition_check` does the same on demand and gives a crop that keeps your target shape.

When you say a result was wrong (the crop, the colours, the wrong logo), the assistant records it with `design_feedback`, and every later brief applies it. A correction can be tied to one brand, so "use my personal mark" never leaks onto company posts.

## It handles several sessions at once

Each Claude (or Cursor, or Codex) session runs its own copy of this server, but there's only one signed-in browser profile. By default a second session simply opens its own tab in the same browser, so both jobs run side by side.

This works through a loopback-only Chrome devtools port that's open while the browser is open. On your own computer that's fine. On a shared machine, turn it off:

```sh
no-api-media-mcp config set share_browser false
```

With sharing off, the second session waits in line instead and says so in its progress messages: its place in the queue, how long it has waited, and an estimate once there's enough history (taken from how long recent jobs on your machine really took). It carries on by itself when the browser frees up.

The brief also asks before it guesses now: if it doesn't know where an image will be used or what post it goes with, `design_brief` returns `needs_from_user` with those questions, so your assistant asks you once instead of producing the wrong size or the wrong message.

## It knows 3D and WebGL sites need different assets

Two more asset types for `design_brief`: `texture` (a seamless, tileable surface for a background or a Three.js material) and `environment-map` (a seamless 2:1 equirectangular panorama for reflections and lighting in a Three.js or WebGL scene). Each gets its own critique checklist instead of the usual photo-realism one, since neither is meant to be looked at directly.

```sh
loop_check(input_path=".ai-media/flow/hero-loop.mp4")
```

Compares a looping video's first and last frame the same way `media_optimize` checks quality loss, and tells you if the loop will actually look seamless before it ships.

```sh
palette_extract(input_path="public/images/hero.jpg", count=6)
```

Pulls the real dominant colours out of a generated (or any) image and returns a ready `:root` CSS block, so the site's design system can match what actually got made instead of a guess.

The server also recognises the kind of project it's in on its own now: a GitHub repo, a single social post, a 3D/WebGL site, or an animated landing page, and reaches for the matching asset types without being told each time.

## It remembers what actually shipped

`design_audit` can carry the `style` (tier and look) a draft used. Once enough drafts of one asset type have shipped under the same tier, `design_brief` defaults to it on its own next time, instead of always starting from premium. Ask for a specific tier or look and that always wins; this only fills in the gap when you didn't ask.

## It compares drafts side by side

```sh
contact_sheet(input_paths=["dir1/a.png", "dir1/b.png", "dir1/c.png"], output_path=".ai-media/compare/hero.jpg")
```

Lays up to 12 images on one grid instead of one at a time. No text is baked into the image; the result lists which grid position holds which file.

## It knows what actually keeps platforms from cutting your reach

Meta has said plainly that a plain "AI info" label does not by itself reduce a post's reach. What does get penalised is content that reads as a real photo of an event, person or statement that never happened. `design_brief`'s critique list now asks that question directly for every realistic asset type, and `social_sizes` covers Facebook, YouTube and X/Twitter cover sizes alongside LinkedIn, Instagram and Pinterest.

## It falls back when a provider breaks

Browser-driven providers depend on the site's own pages, and a redesign can break a selector overnight. Pass `fallback_providers` to `image_generate` and it tries the next one automatically instead of failing the whole run:

```sh
image_generate(provider="flow", fallback_providers=["codex", "gemini"], ...)
```

The result always lists every attempt and why each one failed, so nothing is silently swallowed. A second local journal (separate from the design one) tracks these outcomes, and when a provider fails the same way three times in a row, the next error says so plainly instead of staying a mystery.

## It checks for a new version

Once a day, the server checks this project's GitHub releases. If a newer one is out, it tells you at startup
and in `status`/`setup`: what changed, and the exact command to update. It never patches itself while running,
and it never installs anything unless you turn that on:

| Setting | Default | What it does |
|---|---|---|
| `NOAPI_CHECK_UPDATES=0` | checks on | stop checking entirely |
| `NOAPI_AUTO_UPDATE=1` | off | once a newer version is found, run `npm install -g no-api-media-mcp@latest` for you; it takes effect the next time the server starts, never mid-run |
| `NOAPI_UPDATE_CHECK_HOURS` | 24 | how often to check |

The check is a plain, unauthenticated read of this repo's own GitHub releases, with a size cap and a short
timeout, and a failed check never breaks a real tool call.

## It learns from its own mistakes

Every time the model scores an image with `design_audit` (and tells it the asset type), the server writes the scores to a small local journal in your no-api-media folder. It is never uploaded and never lives inside a project. The next `design_brief` for that kind of asset reads it back: any criterion that has fallen short at least twice (for example "not template" or "brand presence") is turned into advice and put into every prompt up front. A mistake that happened twice stops happening a third time.

On top of that, `design_brief` carries a short list of built-in lessons from real use, such as these:

- Never ask the model to draw a real logo or to spell words. Leave a calm area, then place the real logo file and the text afterwards.
- If the image will be cropped much wider than 16:9, keep every important element in the middle band. Set `context.targetAspect` (for example `3.2:1` for a profile banner) and the brief adds this guidance for you.
- A single big centred object reads as stock. Ask for an abstract backdrop with open space and let the real brand mark be the focal point.
- A black-background logo dropped on busy art washes out. Put it on a dark glass plate or a feathered mask.

The full list, with the reasons and the provider notes, is in [docs/lessons.md](docs/lessons.md).

## It keeps your project tidy

Generated drafts land in `<project>/.ai-media`. Left alone, that folder fills up with rejected attempts. The server now tracks what happened to each draft:

| Status | How it gets there | When it is removed |
|---|---|---|
| draft | just generated | after 30 days |
| shortlisted | `design_audit` said ship | after 60 days |
| rejected | `design_audit` said revise | after 3 days |
| used | `media_optimize` made a final file from it | after 14 days, and only if that final file still exists |

Pass the draft's `file` to `design_audit` and `media_optimize` does the rest on its own. The final image goes to your project's own images folder, so nothing important stays in `.ai-media`.

Cleanup runs once per session, and you can run it yourself with `media_cleanup` (a dry run by default, so it first shows what would go and how much space it frees). It is strict on purpose: it only looks inside `.ai-media`, never touches your final files, skips symbolic links, and ignores anything that is not a media file. Turn the automatic part off with `no-api-media-mcp config set auto_cleanup false` or `NOAPI_AUTO_CLEANUP=0`.

## Connect your accounts

You sign in yourself, once. The server never asks for or sees a password.

| Account | You need | How to connect | Ready when `status` shows |
|---|---|---|---|
| **Google AI Pro / Ultra** (Flow, Gemini) | A Google account with the plan | Sign in at the Google tab in the setup window | `google  signed in, PRO, j***@gmail.com` |
| **ChatGPT** (images) | ChatGPT Plus or Pro | `npm i -g @openai/codex` then `codex login`, choose ChatGPT | `Codex CLI  ok, signed in with ChatGPT` |
| **Higgsfield** | A Higgsfield plan | `npm i -g @higgsfield/cli`, `higgsfield auth login`, then `higgsfield workspace set <id>` | `Higgsfield CLI  ok, signed in` |
| **Grok** or any JSON site | That site's plan | Ask your agent to run `accounts_login` with `grok` | `grok  signed in` |

> Close the whole setup window when you're done. The server can't use the private profile while it is open.

## Installation

Requirements: **Node 22+**, **Google Chrome**, and **ffmpeg** for shrinking and editing. Optional: **rembg** for background removal (`uv tool install "rembg[cpu,cli]"` or `pip install "rembg[cpu,cli]"`; the model downloads once on first use).

<details open>
<summary><b>Claude Code</b></summary>

```bash
# all projects
claude mcp add --scope user no-api-media -- node /full/path/to/no-api-media-mcp/dist/src/index.js

# this project only
claude mcp add no-api-media -- node /full/path/to/no-api-media-mcp/dist/src/index.js
```
</details>

<details>
<summary><b>Claude Desktop / Cursor / Windsurf</b></summary>

Add to your MCP config:

```json
{
  "mcpServers": {
    "no-api-media": {
      "command": "node",
      "args": ["/full/path/to/no-api-media-mcp/dist/src/index.js"]
    }
  }
}
```

Config file locations:

| App | File |
|---|---|
| Claude Desktop (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Cursor | `~/.cursor/mcp.json` or `.cursor/mcp.json` in the project |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |

Restart the app after editing.
</details>

<details>
<summary><b>VS Code</b></summary>

`.vscode/mcp.json`:

```json
{
  "servers": {
    "no-api-media": { "command": "node", "args": ["/full/path/to/no-api-media-mcp/dist/src/index.js"] }
  }
}
```
</details>

<details>
<summary><b>Codex CLI</b></summary>

```bash
codex mcp add no-api-media -- node /full/path/to/no-api-media-mcp/dist/src/index.js
```
</details>

## Tools

| Tool | What it does |
|---|---|
| `accounts_login` | Opens the private Chrome window so **you** sign in |
| `accounts_status` | Which accounts are ready, plan tier, low-credit warnings |
| `providers_list` | Every provider and JSON site, and what each can make |
| `project_profile` | Reads the project: style tier, 3D/animated, colours, fonts, reference images |
| `design_brief` | Writes a real creative brief (project, purpose, placement, premium quality bar) with concept directions and a critique checklist. Asset types: logo, app icon, hero, illustration, product shot, social post, banner, infographic, poster, background video, product video |
| `design_audit` | The art-director check after you look at an image (pass `asset_type` so it learns, and `file` so a rejected draft can be cleaned up): score eight criteria (focal point, thumbnail, hierarchy, palette, topic cues, brand presence, text accuracy, not template) and get ship or revise with the exact fix for each weak point |
| `image_generate` | Makes images with `codex`, `chatgpt`, `flow`, `gemini`, `higgsfield`, `grok` or your own site |
| `video_quote` | Exact credit cost for a Flow or Higgsfield job, generates nothing |
| `video_generate` | Veo 3.1 / Omni in Flow, Seedance / Kling in Higgsfield, or Grok, with a credit cap |
| `media_optimize` | Image to WebP, video to H.264, smaller with no visible change. Strips embedded metadata by default and reports it (see the behaviour notice); `keep_metadata: true` to keep |
| `background_remove` | Transparent cutout, local BiRefNet models via rembg |
| `video_edit` | Trim, reframe, speed, fade, mute, audio, poster frame, GIF, text, logo, subtitles, join |
| `social_sizes` | Every social and icon size from one image |
| `media_probe` | Duration, size, fps, codecs |

<details>
<summary><b>Providers in detail</b></summary>

| id | Makes | Signs in with | Notes |
|---|---|---|---|
| `codex` | images | Codex CLI, ChatGPT login | Most reliable ChatGPT route |
| `chatgpt` | images | chatgpt.com in the private profile | Cloudflare may ask for a human check; use `codex` then |
| `flow` | images, videos | Google, in the private profile | Nano Banana 2 images were 0 credits on AI Pro when tested; videos cost credits |
| `gemini` | images | Google, in the private profile | |
| `higgsfield` | images, videos | official CLI (OAuth) | Exact cost shown before every job |
| `grok` | images, videos | grok.com in the private profile | Limits depend on your plan |
</details>

## Where files go

- No `output_path`: `<project>/.ai-media/<provider>/<date>-<prompt>.<ext>`, ignored by git, with a `manifest.jsonl` of every prompt
- With `output_path` (e.g. `public/images/hero.png`): must be inside the project and a media file, checked before anything is generated

## CLI commands

| Command | What it does |
|---|---|
| `node dist/src/index.js setup` | Check everything, open the sign-in window, print client config |
| `node dist/src/index.js login google` | Sign in to one service again (`google`, `chatgpt`, or `chatgpt,google`) |
| `node dist/src/index.js status` | Show which accounts are ready, without opening a window |
| `node dist/src/index.js --version` | Print the version |
| `node dist/src/index.js config` | Show `strip_ai_metadata` and where its value comes from |
| `node dist/src/index.js config set strip_ai_metadata false` | Keep embedded metadata in optimized files (`true` to strip again) |
| `node dist/src/index.js help` | List these commands |
| `codex login status` | Check the Codex CLI is signed in with ChatGPT |
| `higgsfield workspace list` | List Higgsfield workspaces to pick one |
| `npm test` | Run the test suite (unit and security tests) |

Without a command, `dist/src/index.js` runs as the MCP server. That's what your AI client starts.

## Troubleshooting

| You see | Do this |
|---|---|
| `profile is already open` | The sign-in window (or another copy of the server) is still open. Close that Chrome window and try again |
| `Not signed in. Run accounts_login` | Run `login google` or `login chatgpt` and sign in in the window |
| `chatgpt.com is asking for a human check` | ChatGPT's Cloudflare noticed automation. The server never solves these. Use `codex` for ChatGPT images, or `flow` |
| `Codex must be signed in with ChatGPT (not an API key)` | Run `codex login` and choose **Sign in with ChatGPT** |
| `Codex limit is used up` | Your plan's Codex quota is spent. Use `flow` or wait for the reset |
| `Pick a Higgsfield workspace once` | `higgsfield workspace list`, then `higgsfield workspace set <id>` |
| `That Google account is not signed in` | Sign in with the account that has your AI plan, or set `NOAPI_GOOGLE_EMAIL` to it |
| `Flow no longer offers "..."` or a menu not found | Google changed the Flow page. Update to the latest version or [open an issue](https://github.com/farhan6667/no-api-media-mcp/issues) |
| `running low on Google Flow credits` | Video credits are low. Images on Nano Banana 2 usually still work |
| `Google Chrome not found` | Install Chrome or set `NOAPI_CHROME` to its path |
| `ffmpeg not found` | `winget install Gyan.FFmpeg` (Windows), `brew install ffmpeg` (macOS), `sudo apt install ffmpeg` (Linux) |
| `Background removal needs rembg` | `uv tool install "rembg[cpu,cli]"` or `pip install "rembg[cpu,cli]"` |
| `rembg is installed without a backend` | `uv tool install --force "rembg[cpu,cli]"` |
| `certificate check` while downloading a model | Your network inspects TLS. The server passes your system certificates to rembg automatically; if it still fails, run once on another network, the model is cached afterwards |
| `Refusing to write outside the allowed folders` | Use a path inside the project, like `public/images/hero.png` |
| Nothing happens on a Linux server | Chrome needs a display. Run under Xvfb |

## Configuration

All optional.

| Variable | Default | Meaning |
|---|---|---|
| `NOAPI_HOME` | `~/.no-api-media` | Private profile and state. Delete it to sign out of everything |
| `NOAPI_OUTPUT_ROOTS` | the folder the client starts the server in | Folders the server may write to |
| `NOAPI_GOOGLE_EMAIL` | first signed-in account | Which Google account to use |
| `NOAPI_MIN_GAP` | `20` | Seconds between two generations on one provider |
| `NO_API_MEDIA_KEEP_METADATA` | unset | `1` keeps embedded metadata in `media_optimize` output. Same as `strip_ai_metadata=false` in `config.json`; the environment wins |
| `NOAPI_CHROME`, `NOAPI_FFMPEG`, `NOAPI_CODEX_JS`, `NOAPI_HIGGSFIELD`, `NOAPI_REMBG` | auto-detected | Binary locations |

## Add another site without code

Put a file in `~/.no-api-media/providers/<id>.json`. Start from [`examples/providers/template.json`](examples/providers/template.json). Media is only downloaded from the hosts you list in `mediaHosts`, and specs are never read from a project folder.

## Safety and terms

- Your password never touches this code, there is no network port, and the server can't write outside your project. The full threat model is in [SECURITY.md](SECURITY.md).
- Web providers drive the consumer sites the way you would by hand. OpenAI's, Google's and xAI's terms restrict automated use of those sites, so **using them is your call and your account's risk**. The server works at human pace, stops at captchas and sign-in pages, and doesn't hide that it is automation. Official CLIs (Codex, Higgsfield) are the safer routes.

## Behaviour notice: metadata is stripped from optimized files

Since 0.3.0, `media_optimize` removes embedded metadata from the files it writes: EXIF, XMP, text chunks and **C2PA content credentials** (the signed manifest that ChatGPT, Codex, Google Flow, Gemini and Veo embed, and that platforms such as LinkedIn turn into a "Content credentials" badge). This is what most web image optimizers and CDNs do, and in fact 0.2 already dropped it as a silent side effect of re-encoding. 0.3 makes it explicit: every result lists what was removed, and you can turn it off.

- **Your originals are never touched.** Generated files in `.ai-media/` keep their manifests; only the optimized copy is stripped.
- **Turn it off** in any of three ways: `keep_metadata: true` on a call, the environment variable `NO_API_MEDIA_KEEP_METADATA=1`, or `node dist/src/index.js config set strip_ai_metadata false`.
- **What it does not do.** This removes embedded *metadata* only. It does **not** remove invisible watermarks such as Google SynthID, which live in the pixels, so platforms and detectors may still identify the AI origin. It is not a way to pass AI images off as real photographs. You are responsible for the rules of the platforms you post to and for any disclosure requirements that apply to you.
- A signed C2PA manifest cannot survive re-encoding anyway (it is bound to the original bytes), so with `keep_metadata: true` the result is honest about what the encoder lost rather than copying an invalid manifest.

## Frequently asked questions

### How do I generate images and videos in Claude Code without an API key?
Install this MCP server, then sign in once to ChatGPT, Google (Flow and Gemini), Higgsfield or Grok in the browser window it opens. After that you can ask Claude Code, Cursor or Codex for an image or a video and it uses the plan you already pay for.

### Does it see my password?
No. You type your password yourself in a normal browser window. The server never asks for it, types it or stores it, and it drives the browser over a pipe. The one network port it can open is a loopback-only devtools port for `share_browser` (on by default, easy to turn off on a shared machine, see below).

### Can it bill my API account by accident?
It is built to prevent that. API key variables are removed from every child process, and Codex only runs when its login status shows a ChatGPT login.

### Which clients and providers does it work with?
Any MCP client, including Claude Code, Cursor, Codex and Windsurf. Providers are ChatGPT through Codex, Google Flow (Veo and Nano Banana), Gemini, Higgsfield and Grok, plus any other site you describe in a JSON file.

### Which assistant model should I use?
The images themselves come from your provider's image model (GPT Image through Codex or ChatGPT, Nano Banana through Flow or Gemini), so picking a different assistant model doesn't change the picture directly. It does change the result: your assistant writes the brief, looks at every draft and scores it honestly, and sets the final text and logo. Use a current top-tier model with good image understanding and tool use; small, fast models tend to skip steps or pass weak drafts. For designs with words, `codex` renders text best; for photo and 3D scenes, Flow.

### What do I need to install to use it?
An MCP client to talk to it, plus whatever sign-in the providers you want need.

- **Claude Code**: in the terminal, the desktop app, or the [Claude Code extension for VS Code](https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code). See [claude.com/claude-code](https://claude.com/claude-code). Cursor and Windsurf work too.
- **Codex as your assistant** (optional): the [Codex IDE extension](https://marketplace.visualstudio.com/items?itemName=openai.chatgpt) for VS Code, Cursor and Windsurf ([docs](https://developers.openai.com/codex/ide)), or the [Codex CLI](https://github.com/openai/codex).
- **For the `codex` image provider** you need the [Codex CLI](https://github.com/openai/codex) itself, installed with `npm i -g @openai/codex` and signed in with `codex login` using your ChatGPT plan (not an API key). The server calls the CLI, so the editor extension alone isn't enough for this provider.
- **For Flow, Gemini and ChatGPT on the web**, Google Chrome, and a one-time sign-in in the window `accounts_login` opens.

### Does it leave browser windows open?
No. Each job's tab closes when the job ends, and the window itself closes when your assistant calls `browser_done` at the end of the work. If that never happens, a safety net closes it after 20 idle minutes (`no-api-media-mcp config set browser_idle_minutes` changes that). While the work is still going, between rounds of edits, it deliberately stays open so the next step doesn't have to start the browser again.

### Does it remove AI watermarks?
No. `media_optimize` strips embedded metadata (EXIF, XMP and C2PA content credentials) from the files it writes, by default and with a report, and you can switch that off. It never touches invisible watermarks such as SynthID.

### Can it do more than generate?
Yes. It removes backgrounds locally, edits video with ffmpeg, exports every social media size and shrinks files for the web. The `design_brief` and `design_audit` tools help the model art direct and judge its own results.

### Are the providers fine with this?
The browser-driven providers work like you would by hand, and their terms restrict automated use of the consumer sites, so using them is your call. Official command line routes such as Codex and Higgsfield are the safer ones. See [Safety and terms](#safety-and-terms).

### Does it put text and logos on the image for me?
Yes. `compose` renders your headline and a registered brand's real logo over the generated art, measuring where the calm area is and checking contrast. The image model itself never draws your logo or your words.

### How does it get the right size and format for LinkedIn or X?
`deliver` takes a platform name (linkedin-feed, x-post, instagram-story, github-social and others) and produces that exact size as an optimized JPEG under the platform's file limit. For a LinkedIn feed post it's 1080x1350; 1200x627 is only for link previews.

### I run several Claude sessions. Why did one say the browser is busy?
With `share_browser` on (the default) sessions work side by side as separate tabs, so you'll mostly see this when sharing is off or the other browser couldn't be joined. The waiting session queues, reports its place and an estimate, and continues on its own.

### Can it make assets for a three.js or WebGL site?
Yes: `design_brief` has an `environment-map` asset type (a seamless 2:1 panorama for reflections and lighting) and a `texture` asset type (a seamless tileable surface), on top of the usual hero and background-video. Both get checked for seams instead of photo-realism.

### Does Facebook or another platform penalise AI-made images?
Not for being AI-made and disclosed as such; Meta has said that label alone doesn't cut reach. What does get penalised hard is content that reads as a real photo of an event or statement that never happened. design_brief now asks that question for every realistic asset type, and the honest fix is the same as always: make it obviously a graphic or a considered shot, not a faked real moment.

### What happens if a provider's page changes and a call breaks?
Pass `fallback_providers` to `image_generate` (for example `["codex", "gemini"]`) and it tries the next one in order. The result reports every attempt and its failure reason. A local, redacted journal also tracks this over time, so a real pattern (the same provider failing the same way repeatedly) gets called out instead of looking like one bad run.

### Does it know who the image is for?
If you tell `design_brief` who sees it (`context.audience`), it recognises a short list of real audiences (CISOs, developers, the open source community, security analysts, the general public) and adjusts tone, default tier, palette and the critique question accordingly. It won't guess an audience you didn't name.

### Will it update itself without telling me?
No. It checks once a day and tells you when a newer version exists, with the exact command to run. It only installs it for you if you explicitly set `NOAPI_AUTO_UPDATE=1`, and even then only for the next run, never while the server is live.

### Where do the palette and font suggestions in design_brief come from?
From a reviewed UI design skill's colour and typography database, picked by the same topic detection the brief already does. They are only used when you don't supply your own brand colours, and you can always override them.

### Does it learn from my past results?
Yes, locally. `design_audit` writes each score sheet to a small journal on your machine, and `design_brief` turns the criteria that keep falling short into advice at the top of the next prompt for that asset type. It also carries built-in lessons from real use. Nothing is uploaded.

### Will it fill my disk with old drafts?
No. Rejected drafts are removed after 3 days, drafts that already became a final file after 14 days, and untouched ones after 30. It only ever looks inside `.ai-media`, never touches your final files, and you can switch it off or run it by hand with `media_cleanup`.

### Is it free?
The server is free and open source under Apache-2.0. It uses the AI plans you already have, so it adds no API bill.

## Contributing

Fixes for broken selectors and new site specs are the most useful help. See [CONTRIBUTING.md](CONTRIBUTING.md).

## Contact and support

- **Tried it? Tell me how it went**, good or bad, with the [feedback form](https://github.com/farhan6667/no-api-media-mcp/issues/new?template=feedback.yml). It takes two minutes.
- **Bugs, questions, ideas:** open a [GitHub issue](https://github.com/farhan6667/no-api-media-mcp/issues) or start a [discussion](https://github.com/farhan6667/no-api-media-mcp/discussions).
- **Security problems:** use a private security advisory, see [SECURITY.md](SECURITY.md).
- **Work with NexaForge** (cyber security, vibe coding, web development and IT infrastructure): [nexaforge.services@gmail.com](mailto:nexaforge.services@gmail.com) or [nexaforge.eu.cc/contact](https://nexaforge.eu.cc/contact).
- If this saved you an API bill, a star on the repo is the easiest way to say thanks.
- **Sponsor the work.** If your company can help with hosting, tools or funding, the [sponsor page](https://github.com/farhan6667/farhan6667/blob/main/SPONSOR.md) explains how. GitHub Sponsors is not available in Pakistan, so it works by email.

## License

[Apache-2.0](LICENSE). See [NOTICE](NOTICE) for the attribution and trademark note.

---

<div align="center">

<a href="https://nexaforge.eu.cc/">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/brand/nexaforge-lockup-dark.webp">
    <img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/brand/nexaforge-lockup-light.webp" height="48" alt="NexaForge">
  </picture>
</a>
&nbsp;&nbsp;&nbsp;
<a href="https://github.com/farhan6667">
  <img src="https://raw.githubusercontent.com/farhan6667/no-api-media-mcp/main/docs/img/brand/sfa-logo.webp" height="72" alt="SFA, Syed Farhan Ahmed">
</a>

**Built by [Syed Farhan Ahmed](https://github.com/farhan6667) (SFA)** at **[NexaForge](https://nexaforge.eu.cc/)**<br>
Cyber security · Vibe coding · Web development and IT infrastructure

<a href="https://nexaforge.eu.cc/">Website</a> ·
<a href="https://www.linkedin.com/in/sfa6667">LinkedIn</a> ·
<a href="https://farhan6667.github.io/portfolio/">Portfolio</a> ·
<a href="mailto:nexaforge.services@gmail.com">Email</a>

</div>