midjourney-mcp
Midjourney MCP + CLI
Midjourney MCP server and CLI for Claude Code and AI agents. 32 tools for generating images, following jobs to completion, downloading the real files, and building moodboards that make a style reusable.
Midjourney publishes no API, so this drives a real Chrome that is signed in as you.
There is no key to paste and no cookie to export. You sign in once, in a window, and the session lives in a browser profile rather than in a config file.
32 tools, on both surfaces. It waits for jobs to finish and hands back the actual files, not a screenshot of them.
Built and maintained by Navid Moazzez.
Two ways to use it
Command line
midjourney-cli in your terminal, for scripting, cron, pipes, or a quick
question without opening anything:
midjourney-cli # every command, one line each
midjourney-cli login # sign in once, in a window
midjourney-cli imagine "a red fox in snow" --ar 16:9 --confirm
midjourney-cli list-jobs --limit 5 --select id,prompt --json
midjourney-cli download-job <job-id> --out-dir ./renders
midjourney-cli list-moodboards --json | jq -r '.moodboards[].title'
midjourney-cli which "save my pictures to disk" # find the right command
midjourney-cli <command> --help # what any command takes--confirm is the shell spelling of the confirmation that generating requires.
--json gives JSON, --compact puts it on one line, --select id,status keeps
only the fields you name, and errors are JSON on stderr whichever you pick.
Handlers return data rather than pre-rendered text, so --json gives real
fields on every command and jq works the same way everywhere.
MCP server, for AI agents
midjourney-mcp is what Claude Code, Claude Desktop, Cursor and the rest
launch. You never run it by hand:
claude mcp add midjourney -- npx -y @thenavidm/midjourney-mcp-cli@latestThere is nothing to put in -e. Run midjourney-cli login first.
Then just ask: "shoot that campaign in the style of my High Fashion moodboard".
Every other client is in section 3.
Which one
Where you are | What you can reach |
An agent that can run shell commands, like Claude Code or Cursor | Both. The CLI is the cheaper one: it costs nothing until you type it |
claude.ai or a phone | Neither. Your logged-in browser is on this machine, and a cloud connector cannot reach it |
A terminal, a script, cron or CI | The CLI only. There is no MCP client in a shell |
They are the same program reading the same tool definitions, so anything one can do, the other can.
Features
Every tool is both a command and an MCP tool, with the same name. The command is the tool name with dashes.
Capability | CLI command | MCP tool |
Who am I, is the session live |
|
|
Generate and wait for the images |
|
|
Generate without waiting |
|
|
Re-run a job, or re-render at HD |
|
|
Vary one image from a grid |
|
|
Recent generations |
|
|
One job by id |
|
|
Wait for a job to finish |
|
|
What is rendering now |
|
|
Save the real files to disk |
|
|
List and read moodboards |
|
|
Create a moodboard |
|
|
Add to, remove from a moodboard |
|
|
Personalisation profiles |
|
|
Folders and storage |
|
|
The public explore feed |
|
|
Any endpoint with no named tool |
|
|
Check your setup |
| not a tool |
Sign in |
| not a tool |
Record what the web app calls |
| not a tool |
Find the right command |
| not a tool |
All 27 with their arguments are in section 6.
Contents
Section | ||
1 | Real prompts, not features | |
2 | No key, no cookie | |
3 | Every client, copy and paste, plus the shell | |
4 | What scripts branch on | |
5 | ~8,900 tokens a turn, or nothing | |
6 | All 27, by what they reach | |
7 | Why generating asks twice | |
8 | The grammar, validated before you pay | |
9 | Turning a look into something reusable | |
10 | Architecture, and why a browser | |
11 | What is stored and where | |
12 | Read this before you install | |
13 | When something breaks | |
14 | Every knob, and its default | |
15 | Including what an MCP server is |
1. What you can ask it
Make me a 16:9 hero image of a red fox asleep in snow, muted palette
Shoot that campaign in the style of my High Fashion moodboard
Make a moodboard for cold Nordic product shots, fill it, then shoot a jar of face cream in that style
Generate four logo concepts at low stylize so they stay literal, and save them
Vary the second one, strong, and save the results
Upscale that one and turn it into a video
Take that last image's seed and try it again with chaos 40
What is in my Midjourney queue right now?
Download everything I generated today into ./renders
Show me my last ten jobs with just the prompt and the image URLs
Re-run job 3f9c1a2b with the prompt changed to say "at dusk"
The thing you cannot do without this: hand an agent a brief and get finished image files back. Every other route stops at a job id, or at a screenshot of the image rather than the image. This waits for the render and writes the real bytes to disk, so the next step in a pipeline has something to open.
2. Sign in once
There is no API key. Midjourney does not issue one, and this server never handles a credential of any kind.
Instead it runs Chrome against a profile of its own, at
~/.midjourney-mcp/chrome-profile. You sign in there once and the session
persists, exactly as it would in a browser you use by hand.
npx -y @thenavidm/midjourney-mcp-cli@latest loginA Chrome window opens on midjourney.com. Sign in. The command waits, notices, and exits.
The profile is separate from your everyday Chrome on purpose. Nothing here can see your normal browsing, your other logins, or your history, and your normal browser does not need to be running.
To revoke it, sign out in that window, or delete the profile:
rm -rf ~/.midjourney-mcp/chrome-profile3. Install
Node 22 or newer, and Google Chrome. Nothing else.
npx -y @thenavidm/midjourney-mcp-cli --versionNode 22 is the floor because the browser connection uses the global WebSocket
that landed in that release. That is also why it has no dependency doing it.
Claude Code
claude mcp add midjourney -- npx -y @thenavidm/midjourney-mcp-cli@latest--scope user makes it available in every project rather than the current one.
Claude Desktop
Platform | Path |
macOS |
|
Windows |
|
{
"mcpServers": {
"midjourney": {
"command": "npx",
"args": ["-y", "@thenavidm/midjourney-mcp-cli@latest"]
}
}
}There is also a one-click .mcpb bundle on the release page, installed through
Settings, Extensions, Install Extension.
Claude Desktop does not inherit your shell PATH, so a barenpx can fail silently. Use the absolute path from which npx, and fully quit the app rather than closing the window.
Cursor
.cursor/mcp.json, the same JSON shape as Claude Desktop, key mcpServers.
VS Code
.vscode/mcp.json. The key is servers, not mcpServers, and the entry takes
"type": "stdio".
{
"servers": {
"midjourney": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@thenavidm/midjourney-mcp-cli@latest"]
}
}
}Codex CLI
~/.codex/config.toml:
[mcp_servers.midjourney]
command = "npx"
args = ["-y", "@thenavidm/midjourney-mcp-cli@latest"]The shell
Both binaries come from the same install. midjourney-cli with no arguments
lists every command.
Check it worked
npx -y @thenavidm/midjourney-mcp-cli@latest doctorIt checks in dependency order and stops at the first real problem, because these failures all produce the same symptom from a tool call and need completely different fixes.
The two that actually happen:
browser running: FAIL. Chrome is not up on the DevTools port. It starts on
demand on the first tool call, so this is only a problem if you have set
MIDJOURNEY_CHROME_LAUNCH=0. Run login to start it by hand.
signed in: FAIL. The window is open but the profile is signed out. Run
login again.
4. Output and exit codes
Results on stdout, errors on stderr as JSON, so one parse handles both.
Flag | Result |
none | pretty JSON |
| JSON, always |
| the same JSON on one line |
| keep only these fields. Dotted paths descend, arrays are traversed element-wise |
| compact JSON. Never implies |
--select matters more here than it looks. One explore page is tens of
kilobytes, most of it layout metadata, and an agent piping that into its context
pays for every byte.
--agent deliberately does not imply confirmation, unlike the equivalent in
some other CLIs. A flag an agent passes by habit must never be the thing that
authorises a charge.
Code | Means |
| it worked |
| it failed: signed out, a refused write, an API error |
| it was typed wrong: a missing flag, a bad value, a bad |
5. Which surface, and what each costs
An MCP server is expensive and a CLI is free.
The tools/list payload for these 32 tools is about 11,062 tokens, plus the
server instructions. That is charged on every turn of every conversation, used
or not, because the descriptions are long and carry the parameter grammar.
A CLI costs nothing until it is called. The skill mentions it in one line, and the model pays only when it runs something.
So the two are not competing:
Where you are | What you can reach |
An agent that can run shell commands | Both. The CLI costs nothing until you type it |
A terminal, a script, cron or CI | The CLI only |
6. Tools
Making images
Tool | What it does |
| Generate, wait for the job, return the images. Optionally save them. Spends |
| Submit and return the job id without waiting. Spends |
| Run an existing job again, optionally with new wording or at HD. Spends |
| Four variations of one image from a grid, subtle or strong. Spends |
| Upscale one image to full resolution, subtle or creative. Spends |
| Turn one image into a video. Spends |
| Extend the frame left, right, up or down. Spends |
| Pull the camera back and fill the new space. Spends |
| Re-render an image against a new prompt, keeping its composition. Spends |
| Send a job type this server does not model yet. Spends |
Following work
Tool | What it does |
| Recent generations, newest first, with status and image URLs |
| One job by id, with its real status |
| Block until a job finishes, fails or is moderated |
| What is running now, and how much concurrency the plan allows |
| The live delta feed the web app itself polls |
Getting the files
Tool | What it does |
| Write a job's images to disk. Real files, full resolution |
| Write one asset to disk by URL |
Moodboards and style
Tool | What it does |
| Every board, with how many reference images each holds |
| One board by name, and the references a generation would use |
| Start a new board for a look |
| Put a job's renders, or any URLs, onto a board |
| Take images off a board. Needs |
| Profiles, with how many images each was trained on |
Your account
Tool | What it does |
| Which account is signed in, and whether the browser is reachable |
| Folders in the Organise view |
| Storage used against what the plan allows |
| Creators this account follows |
| Pending rating tasks, which earn fast hours |
| Contest rounds completed |
Explore, and the escape hatch
Tool | What it does |
| The public feed, with prompts and image URLs |
| Which styles this account has liked |
| Any |
midjourney-cli which "<what you want>" resolves a capability described in
words to the command that does it, so you do not have to read this table.
7. Spending safely
Reads work freely. What is guarded is spending.
Every generation burns GPU time from a paid plan and there are no refunds, so
imagine, submit_imagine, rerun_job, vary_image and submit_raw_job take
confirm: true, or --confirm at the terminal.
Nothing reversible asks. Adding to a moodboard does not, because
remove_from_moodboard undoes it, and confirming reversible things is how a
model learns to pass confirm by reflex, which defeats the gate on spending.
A generation is not annotated destructive, because it destroys nothing. It has its own risk level, so a client deciding what to auto-approve is told the truth about what it is approving.
MIDJOURNEY_READ_ONLY=1 removes every tool that is not a read, 17 remain
MIDJOURNEY_ALLOW_DESTRUCTIVE=0 keeps reads and downloads, blocks anything that spends
MIDJOURNEY_AUDIT_LOG=<path> one JSON line per attempted change, allowed and blocked8. Prompts and parameters
Write the subject in prompt and everything else as named arguments. Do not put
--ar inside the prompt string.
The arguments are validated before anything is spent. Midjourney is not: it silently ignores or clamps most malformed parameters rather than reporting them, so a typo costs a generation and comes back looking like a bad result rather than a mistake.
Argument | What it does |
|
|
| 0-1000. Low follows the prompt, high looks prettier and drifts |
| 0-100. How different the four results are from each other |
| Reuse with an identical prompt to iterate on one image |
| An image URL, a numeric code, or |
| Carry a character or object across images. The v7+ replacement for |
| Direct image URLs, including |
| Things to keep out. Sent as |
| Less automatic prettification. Good for photographic work |
| Much faster and cheaper, lower fidelity. Good for exploring |
|
|
At the terminal, Midjourney's own spellings work as aliases: --ar, --sref,
--oref, --iw, --sw, --ow, --q, --no, --v.
9. Moodboards
A moodboard is a set of images the account has curated. Applying one is the same mechanism the web app's Personalize panel uses: the board becomes a personalization code on the prompt, resolved for you from its name.
midjourney-cli imagine "a ceramic jar of face cream" --moodboard "Nordic Skincare" --confirmThat is worth stating because there is a plausible wrong way to do the same
thing: sampling the board's images into --sref URLs. It only registers at a
high --sw, and that weight is what makes output look over-processed. The
personalization code needs no weight and does not compete with your wording.
The loop:
midjourney-cli create-moodboard "Nordic Skincare"
midjourney-cli imagine "<a long, specific style description>" --confirm
midjourney-cli add-to-moodboard "Nordic Skincare" --job-id <job>
midjourney-cli imagine "a ceramic jar of face cream" --moodboard "Nordic Skincare" --confirmPartial names work: "High Fashion" finds "High Fashion | Woman". An ambiguous
name errors with the candidates rather than guessing, because picking the wrong
board costs a generation to discover.
--p accepts several codes, so a moodboard and a personalization profile apply
together. profile is the other kind of personalization: it biases toward
images the account has rated, rather than toward a set of pictures.
Leave the sliders alone
Midjourney's own defaults for stylize, weirdness and variety sit near the
minimum. Raising stylize trades fidelity for a prettier, more generic image.
Set them when you want that; otherwise a strong result comes from the prompt and
the reference.
10. How it works
Midjourney publishes no API. The endpoints under /api/ are the ones its own
web app calls, and they sit behind a Cloudflare interstitial that answers a plain
client with a 403 challenge page rather than JSON.
That challenge is not defeated by a header. The cf_clearance cookie is bound to
the IP, the User-Agent and the TLS fingerprint together, so a cookie lifted out
of a browser and replayed from Node is a different client and gets stopped.
So rather than impersonate a browser, this drives one. Requests are issued by
fetch() running inside a real midjourney.com page, in a real Chrome that is
really signed in. Same origin, same cookies, same fingerprint, same IP,
credentials attached by the browser itself. There is nothing to spoof because
nothing is being faked.
Chrome 136 stopped honouring --remote-debugging-port on the default profile, so
this owns a profile instead: a dedicated user-data-dir you sign into once.
Both surfaces are generated from one ALL_TOOLS array. register() turns a spec
into an MCP tool and cli.ts turns the same spec into a shell command, through
the same handler and the same write guard, so a tool added tomorrow is a command
tomorrow and the two cannot drift. A test asserts that.
Downloads are read with an in-page fetch, which needs no new tab and no visible
activity. The CDN sends access-control-allow-origin: *, so the bytes come back
exactly as served.
11. Your data
Nothing leaves your machine except the requests to Midjourney that you asked for. There is no telemetry, no analytics and no backend.
The session lives in a Chrome profile on your own disk. This process never reads a cookie, stores a token, or sees a password.
Downloads go where you point them, ~/Downloads/midjourney by default. The audit
log, when enabled, is a local file.
12. Risks
This is unofficial, and Midjourney's terms do not permit automated access. Every unofficial client carries a risk to the account, this one included. It moves at human pace and acts through a real browser session rather than imitating one, which is the honest limit of what any tool here can do about that.
It spends money. A loop over twenty prompt ideas is twenty charges. Use
MIDJOURNEY_READ_ONLY=1 when pointing an unattended agent at the account, and
MIDJOURNEY_AUDIT_LOG when you want a record.
The endpoints are undocumented and can change without notice. Job records are parsed defensively and partial answers are preferred to failures, but a large enough upstream change will still break something.
13. Troubleshooting
Start with doctor. It orders the checks so the first failure is the one to fix.
Symptom | Cause |
| The interstitial has not been cleared in that profile. Open the window and let it finish once |
| Signed out, or the session expired. Run |
| Chrome is not where it is normally looked for. Set |
| Another Chrome is using that profile directory. Quit it, or set |
| Out of fast hours, or the subscription lapsed. Switch to |
Job accepted, then never appears | The account is at its concurrent-job limit. Check |
| Normal on relax mode. The job is still running; raise |
Every command times out at once | A native dialog was left open in the window. Dialogs are auto-dismissed now; if it persists, close the tab |
Downloads are empty or fail | The asset URL expired. Re-read the job with |
14. Environment variables
Every one of these is optional. The defaults are what you want unless you are doing something unusual.
Variable | Default | What it does |
|
| The browser profile holding the session |
| found automatically | The Chrome binary |
|
| Start Chrome on demand. |
|
| Where DevTools listens |
|
| Run without a window. Sign in first, a window is needed for that |
|
| The site being driven |
| discovered | Skip user-id discovery |
|
|
|
|
| Model version appended as |
|
| Where downloads land |
|
| Per-request deadline |
|
| Floor between requests, jittered |
|
| Retries on 429 and 5xx |
|
| How long to wait for a job |
|
| First poll interval, widening from there |
|
| Reload the open window after a generation so it shows the new work |
|
| Hide everything that is not a read |
|
|
|
| unset | Append-only log of every attempted change |
|
| Port for |
|
| Interface for |
| unset | Bearer token. Required to listen off loopback |
15. FAQ
An MCP server is a standard way to give an AI assistant real access to a tool, so it can act rather than guess. You install it once, your assistant gains the tools, and it works in Claude, Cursor, ChatGPT and anything else speaking MCP.
Midjourney is an image generation service. You write a prompt, it renders four images, and you refine from there. It runs on the web at midjourney.com and in Discord, on a paid subscription.
Midjourney has no public API and has never shipped one. Every "Midjourney API" on sale is an unofficial wrapper around the same web endpoints this server uses, usually running on somebody else's account. This one at least runs on yours, in your browser, on your machine.
Midjourney's terms do not permit automated access, so yes, and there is no way to build this that does not. Any tool of this kind carries a risk to the account. Decide whether that trade is worth it before installing, and know that no unofficial client can promise otherwise.
You need to be comfortable pasting one command into a terminal and signing in to a website. There is no key to generate, no dashboard to navigate, and no config file to edit by hand.
Nothing leaves your machine except the requests to Midjourney that you asked for. The server has no telemetry, no analytics and no backend. Your session lives in a Chrome profile on your own disk and this process never reads it.
It refuses to generate anything without an explicit confirmation on every call, and it records what it attempted when you set MIDJOURNEY_AUDIT_LOG. Set MIDJOURNEY_READ_ONLY=1 and the generating tools disappear from the list entirely, which is the setting to use when pointing an unattended agent at the account.
It puts generation into a pipeline. An agent can take a brief, build a validated prompt, wait for the render, download the files and hand them to the next step, without a person clicking through four screens. It also refuses malformed parameters before they cost you a generation, which the website does not.
It works with Cursor, VS Code, Codex CLI, Windsurf and anything else that runs a local MCP server over stdio. claude.ai on the web runs connectors from Anthropic's cloud, so it cannot reach a browser on your machine and this is not usable there.
You can set MIDJOURNEY_HEADLESS=1 once the profile is signed in, though signing in needs a window, so do that first. Expect Cloudflare to be less forgiving of a headless session than a visible one.
The browser connection uses the global WebSocket that became stable in Node 22. Relying on it means the part of this server that matters most has no dependencies at all.
Remove the entry from your client's config, then delete ~/.midjourney-mcp/chrome-profile to drop the session. Nothing else is left behind.
Questions
Run into a problem or have a question? Open an issue and I will help.
About the author 👋
Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. This Midjourney MCP server is one piece of that system.
Links
Personal website: navid.me
Link in bio: navid.bio
Navid Media: navid.media
YouTube: @thenavidm and @thenavidai
X: @thenavidm
Instagram: @thenavidm
LinkedIn: thenavidm
Dependencies
Library | Licence | What it does |
MIT | The MCP protocol, stdio and HTTP transports | |
MIT | One schema per tool, driving both surfaces |
The browser connection uses Node's built-in WebSocket and needs nothing else.
License
MIT. Free to use, modify, and share.
Not affiliated with, endorsed by, or sponsored by Midjourney, Inc. Midjourney is a trademark of Midjourney, Inc.
© 2026 NM Media. Made with ❤️ by Navid Moazzez.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/thenavidm/midjourney-mcp-cli'
If you have feedback or need assistance with the MCP directory API, please join our Discord server