@thenavidm/midjourney-mcp-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +677 -0
- package/SKILL.md +184 -0
- package/dist/api/client.d.ts +72 -0
- package/dist/api/client.js +278 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/download.d.ts +41 -0
- package/dist/api/download.js +108 -0
- package/dist/api/download.js.map +1 -0
- package/dist/api/errors.d.ts +75 -0
- package/dist/api/errors.js +166 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/jobs.d.ts +140 -0
- package/dist/api/jobs.js +296 -0
- package/dist/api/jobs.js.map +1 -0
- package/dist/api/moodboards.d.ts +88 -0
- package/dist/api/moodboards.js +189 -0
- package/dist/api/moodboards.js.map +1 -0
- package/dist/capture.d.ts +27 -0
- package/dist/capture.js +162 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +92 -0
- package/dist/cli.js +633 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +90 -0
- package/dist/config.js.map +1 -0
- package/dist/content/prompt.d.ts +69 -0
- package/dist/content/prompt.js +173 -0
- package/dist/content/prompt.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.js +161 -0
- package/dist/doctor.js.map +1 -0
- package/dist/format/jobs.d.ts +71 -0
- package/dist/format/jobs.js +211 -0
- package/dist/format/jobs.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -0
- package/dist/safety.d.ts +52 -0
- package/dist/safety.js +100 -0
- package/dist/safety.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +57 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/create.d.ts +96 -0
- package/dist/tools/create.js +375 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/download.d.ts +17 -0
- package/dist/tools/download.js +47 -0
- package/dist/tools/download.js.map +1 -0
- package/dist/tools/explore.d.ts +8 -0
- package/dist/tools/explore.js +57 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +16 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +18 -0
- package/dist/tools/jobs.js +92 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/kit.d.ts +84 -0
- package/dist/tools/kit.js +104 -0
- package/dist/tools/kit.js.map +1 -0
- package/dist/tools/library.d.ts +22 -0
- package/dist/tools/library.js +185 -0
- package/dist/tools/library.js.map +1 -0
- package/dist/tools/profile.d.ts +2 -0
- package/dist/tools/profile.js +89 -0
- package/dist/tools/profile.js.map +1 -0
- package/dist/transport/cdp.d.ts +217 -0
- package/dist/transport/cdp.js +607 -0
- package/dist/transport/cdp.js.map +1 -0
- package/dist/transport/http.d.ts +18 -0
- package/dist/transport/http.js +48 -0
- package/dist/transport/http.js.map +1 -0
- package/package.json +72 -0
package/README.md
ADDED
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="https://cdn.navid.media/connectors/midjourney-icon.png" alt="Midjourney" width="88">
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
# Midjourney MCP + CLI
|
|
6
|
+
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
[](https://youtube.com/@thenavidm?sub_confirmation=1)
|
|
9
|
+
[](https://x.com/thenavidm)
|
|
10
|
+
|
|
11
|
+
Midjourney MCP server and CLI for Claude Code and AI agents. 27 tools for generating images, following jobs to completion, downloading the real files, and building moodboards that make a style reusable.
|
|
12
|
+
|
|
13
|
+
Midjourney publishes no API, so this drives a real Chrome that is signed in as you.
|
|
14
|
+
|
|
15
|
+
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.
|
|
16
|
+
|
|
17
|
+
27 tools, on both surfaces. It waits for jobs to finish and hands back the actual files, not a screenshot of them.
|
|
18
|
+
|
|
19
|
+
Built and maintained by [Navid Moazzez](https://navid.me).
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
You: make a moodboard for cold Nordic product shots, fill it, then shoot a jar of face cream in that style
|
|
23
|
+
|
|
24
|
+
Claude: Built the board and used it.
|
|
25
|
+
|
|
26
|
+
moodboard Nordic Skincare | Still Life 4 images
|
|
27
|
+
job f44b0a9d-e184-4e18-811f-a1ef9482d286
|
|
28
|
+
prompt a ceramic jar of face cream, lid beside it
|
|
29
|
+
style from the moodboard, not the prompt
|
|
30
|
+
|
|
31
|
+
~/Downloads/midjourney/f44b0a9d-0.png 1.8 MB 960x1200
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Two ways to use it
|
|
35
|
+
|
|
36
|
+
### Command line
|
|
37
|
+
|
|
38
|
+
`midjourney-cli` in your terminal, for scripting, cron, pipes, or a quick
|
|
39
|
+
question without opening anything:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
midjourney-cli # every command, one line each
|
|
43
|
+
midjourney-cli login # sign in once, in a window
|
|
44
|
+
midjourney-cli imagine "a red fox in snow" --ar 16:9 --confirm
|
|
45
|
+
midjourney-cli list-jobs --limit 5 --select id,prompt --json
|
|
46
|
+
midjourney-cli download-job <job-id> --out-dir ./renders
|
|
47
|
+
midjourney-cli list-moodboards --json | jq -r '.moodboards[].title'
|
|
48
|
+
midjourney-cli which "save my pictures to disk" # find the right command
|
|
49
|
+
midjourney-cli <command> --help # what any command takes
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`--confirm` is the shell spelling of the confirmation that generating requires.
|
|
53
|
+
`--json` gives JSON, `--compact` puts it on one line, `--select id,status` keeps
|
|
54
|
+
only the fields you name, and errors are JSON on stderr whichever you pick.
|
|
55
|
+
|
|
56
|
+
Handlers return data rather than pre-rendered text, so `--json` gives real
|
|
57
|
+
fields on every command and `jq` works the same way everywhere.
|
|
58
|
+
|
|
59
|
+
### MCP server, for AI agents
|
|
60
|
+
|
|
61
|
+
`midjourney-mcp` is what Claude Code, Claude Desktop, Cursor and the rest
|
|
62
|
+
launch. You never run it by hand:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
claude mcp add midjourney -- npx -y @thenavidm/midjourney-mcp-cli@latest
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
There is nothing to put in `-e`. Run `midjourney-cli login` first.
|
|
69
|
+
|
|
70
|
+
Then just ask: _"shoot that campaign in the style of my High Fashion moodboard"._
|
|
71
|
+
|
|
72
|
+
Every other client is in [section 3](#3-install).
|
|
73
|
+
|
|
74
|
+
### Which one
|
|
75
|
+
|
|
76
|
+
| What you are doing | Use |
|
|
77
|
+
|---|---|
|
|
78
|
+
| Inside a conversation with an agent | MCP |
|
|
79
|
+
| On claude.ai or your phone | Neither. The browser is on your machine, so a cloud connector cannot reach it |
|
|
80
|
+
| Piping, scripting, cron, CI | CLI |
|
|
81
|
+
| A one-off question in a terminal | CLI |
|
|
82
|
+
|
|
83
|
+
They are the same program reading the same tool definitions, so anything one
|
|
84
|
+
can do, the other can.
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
Every tool is both a command and an MCP tool, with the same name. The command is
|
|
89
|
+
the tool name with dashes.
|
|
90
|
+
|
|
91
|
+
| Capability | CLI command | MCP tool |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Who am I, is the session live | `midjourney-cli whoami` | `whoami` |
|
|
94
|
+
| Generate and wait for the images | `midjourney-cli imagine` | `imagine` |
|
|
95
|
+
| Generate without waiting | `midjourney-cli submit-imagine` | `submit_imagine` |
|
|
96
|
+
| Re-run a job, or re-render at HD | `midjourney-cli rerun-job` | `rerun_job` |
|
|
97
|
+
| Vary one image from a grid | `midjourney-cli vary-image` | `vary_image` |
|
|
98
|
+
| Recent generations | `midjourney-cli list-jobs` | `list_jobs` |
|
|
99
|
+
| One job by id | `midjourney-cli get-job` | `get_job` |
|
|
100
|
+
| Wait for a job to finish | `midjourney-cli wait-for-job` | `wait_for_job` |
|
|
101
|
+
| What is rendering now | `midjourney-cli get-queue` | `get_queue` |
|
|
102
|
+
| Save the real files to disk | `midjourney-cli download-job` / `download-url` | `download_job` / `download_url` |
|
|
103
|
+
| List and read moodboards | `midjourney-cli list-moodboards` / `get-moodboard` | `list_moodboards` / `get_moodboard` |
|
|
104
|
+
| Create a moodboard | `midjourney-cli create-moodboard` | `create_moodboard` |
|
|
105
|
+
| Add to, remove from a moodboard | `midjourney-cli add-to-moodboard` / `remove-from-moodboard` | `add_to_moodboard` / `remove_from_moodboard` |
|
|
106
|
+
| Personalisation profiles | `midjourney-cli list-personalized-profiles` | `list_personalized_profiles` |
|
|
107
|
+
| Folders and storage | `midjourney-cli list-folders` / `get-storage` | `list_folders` / `get_storage` |
|
|
108
|
+
| The public explore feed | `midjourney-cli explore-feed` | `explore_feed` |
|
|
109
|
+
| Any endpoint with no named tool | `midjourney-cli api-get` / `submit-raw-job` | `api_get` / `submit_raw_job` |
|
|
110
|
+
| Check your setup | `midjourney-cli doctor` | not a tool |
|
|
111
|
+
| Sign in | `midjourney-cli login` | not a tool |
|
|
112
|
+
| Record what the web app calls | `midjourney-cli capture` | not a tool |
|
|
113
|
+
| Find the right command | `midjourney-cli which "..."` | not a tool |
|
|
114
|
+
|
|
115
|
+
All 27 with their arguments are in [section 6](#6-tools).
|
|
116
|
+
|
|
117
|
+
## Contents
|
|
118
|
+
|
|
119
|
+
| | Section | |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| 1 | [What you can ask it](#1-what-you-can-ask-it) | Real prompts, not features |
|
|
122
|
+
| 2 | [Sign in once](#2-sign-in-once) | No key, no cookie |
|
|
123
|
+
| 3 | [Install](#3-install) | Every client, copy and paste, plus the shell |
|
|
124
|
+
| 4 | [Output and exit codes](#4-output-and-exit-codes) | What scripts branch on |
|
|
125
|
+
| 5 | [Which surface, and what each costs](#5-which-surface-and-what-each-costs) | ~8,900 tokens a turn, or nothing |
|
|
126
|
+
| 6 | [Tools](#6-tools) | All 27, by what they reach |
|
|
127
|
+
| 7 | [Spending safely](#7-spending-safely) | Why generating asks twice |
|
|
128
|
+
| 8 | [Prompts and parameters](#8-prompts-and-parameters) | The grammar, validated before you pay |
|
|
129
|
+
| 9 | [Moodboards](#9-moodboards) | Turning a look into something reusable |
|
|
130
|
+
| 10 | [How it works](#10-how-it-works) | Architecture, and why a browser |
|
|
131
|
+
| 11 | [Your data](#11-your-data) | What is stored and where |
|
|
132
|
+
| 12 | [Risks](#12-risks) | Read this before you install |
|
|
133
|
+
| 13 | [Troubleshooting](#13-troubleshooting) | When something breaks |
|
|
134
|
+
| | [Environment variables](#environment-variables) | Every knob, and its default |
|
|
135
|
+
| 14 | [FAQ](#14-faq) | Including what an MCP server is |
|
|
136
|
+
|
|
137
|
+
## 1. What you can ask it
|
|
138
|
+
|
|
139
|
+
- Make me a 16:9 hero image of a red fox asleep in snow, muted palette
|
|
140
|
+
- Shoot that campaign in the style of my High Fashion moodboard
|
|
141
|
+
- Make a moodboard for cold Nordic product shots, fill it, then shoot a jar of face cream in that style
|
|
142
|
+
- Generate four logo concepts at low stylize so they stay literal, and save them
|
|
143
|
+
- Vary the second one, strong, and save the results
|
|
144
|
+
- Take that last image's seed and try it again with chaos 40
|
|
145
|
+
- What is in my Midjourney queue right now?
|
|
146
|
+
- Download everything I generated today into ./renders
|
|
147
|
+
- Show me my last ten jobs with just the prompt and the image URLs
|
|
148
|
+
- Re-run job 3f9c1a2b with the prompt changed to say "at dusk"
|
|
149
|
+
|
|
150
|
+
The thing you cannot do without this: hand an agent a brief and get finished
|
|
151
|
+
image files back. Every other route stops at a job id, or at a screenshot of the
|
|
152
|
+
image rather than the image. This waits for the render and writes the real bytes
|
|
153
|
+
to disk, so the next step in a pipeline has something to open.
|
|
154
|
+
|
|
155
|
+
## 2. Sign in once
|
|
156
|
+
|
|
157
|
+
There is no API key. Midjourney does not issue one, and this server never
|
|
158
|
+
handles a credential of any kind.
|
|
159
|
+
|
|
160
|
+
Instead it runs Chrome against a profile of its own, at
|
|
161
|
+
`~/.midjourney-mcp/chrome-profile`. You sign in there once and the session
|
|
162
|
+
persists, exactly as it would in a browser you use by hand.
|
|
163
|
+
|
|
164
|
+
npx -y @thenavidm/midjourney-mcp-cli@latest login
|
|
165
|
+
|
|
166
|
+
A Chrome window opens on midjourney.com. Sign in. The command waits, notices,
|
|
167
|
+
and exits.
|
|
168
|
+
|
|
169
|
+
The profile is separate from your everyday Chrome on purpose. Nothing here can
|
|
170
|
+
see your normal browsing, your other logins, or your history, and your normal
|
|
171
|
+
browser does not need to be running.
|
|
172
|
+
|
|
173
|
+
To revoke it, sign out in that window, or delete the profile:
|
|
174
|
+
|
|
175
|
+
rm -rf ~/.midjourney-mcp/chrome-profile
|
|
176
|
+
|
|
177
|
+
## 3. Install
|
|
178
|
+
|
|
179
|
+
Node 22 or newer, and Google Chrome. Nothing else.
|
|
180
|
+
|
|
181
|
+
npx -y @thenavidm/midjourney-mcp-cli --version
|
|
182
|
+
|
|
183
|
+
> [!NOTE]
|
|
184
|
+
> Not published to npm yet. Until it is, clone the repo and run `npm install && npm run build`, then use `node dist/index.js` wherever this page says `npx -y @thenavidm/midjourney-mcp-cli@latest`.
|
|
185
|
+
|
|
186
|
+
Node 22 is the floor because the browser connection uses the global `WebSocket`
|
|
187
|
+
that landed in that release. That is also why it has no dependency doing it.
|
|
188
|
+
|
|
189
|
+
### Claude Code
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
claude mcp add midjourney -- npx -y @thenavidm/midjourney-mcp-cli@latest
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`--scope user` makes it available in every project rather than the current one.
|
|
196
|
+
|
|
197
|
+
### Claude Desktop
|
|
198
|
+
|
|
199
|
+
| Platform | Path |
|
|
200
|
+
|---|---|
|
|
201
|
+
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
202
|
+
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"mcpServers": {
|
|
207
|
+
"midjourney": {
|
|
208
|
+
"command": "npx",
|
|
209
|
+
"args": ["-y", "@thenavidm/midjourney-mcp-cli@latest"]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
There is also a one-click `.mcpb` bundle on the release page, installed through
|
|
216
|
+
**Settings, Extensions, Install Extension**.
|
|
217
|
+
|
|
218
|
+
> [!TIP]
|
|
219
|
+
> Claude Desktop does not inherit your shell PATH, so a bare `npx` can fail silently. Use the absolute path from `which npx`, and fully quit the app rather than closing the window.
|
|
220
|
+
|
|
221
|
+
### Cursor
|
|
222
|
+
|
|
223
|
+
`.cursor/mcp.json`, the same JSON shape as Claude Desktop, key `mcpServers`.
|
|
224
|
+
|
|
225
|
+
### VS Code
|
|
226
|
+
|
|
227
|
+
`.vscode/mcp.json`. The key is `servers`, not `mcpServers`, and the entry takes
|
|
228
|
+
`"type": "stdio"`.
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"servers": {
|
|
233
|
+
"midjourney": {
|
|
234
|
+
"type": "stdio",
|
|
235
|
+
"command": "npx",
|
|
236
|
+
"args": ["-y", "@thenavidm/midjourney-mcp-cli@latest"]
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Codex CLI
|
|
243
|
+
|
|
244
|
+
`~/.codex/config.toml`:
|
|
245
|
+
|
|
246
|
+
```toml
|
|
247
|
+
[mcp_servers.midjourney]
|
|
248
|
+
command = "npx"
|
|
249
|
+
args = ["-y", "@thenavidm/midjourney-mcp-cli@latest"]
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### The shell
|
|
253
|
+
|
|
254
|
+
Both binaries come from the same install. `midjourney-cli` with no arguments
|
|
255
|
+
lists every command.
|
|
256
|
+
|
|
257
|
+
### Check it worked
|
|
258
|
+
|
|
259
|
+
npx -y @thenavidm/midjourney-mcp-cli@latest doctor
|
|
260
|
+
|
|
261
|
+
It checks in dependency order and stops at the first real problem, because these
|
|
262
|
+
failures all produce the same symptom from a tool call and need completely
|
|
263
|
+
different fixes.
|
|
264
|
+
|
|
265
|
+
The two that actually happen:
|
|
266
|
+
|
|
267
|
+
**`browser running: FAIL`.** Chrome is not up on the DevTools port. It starts on
|
|
268
|
+
demand on the first tool call, so this is only a problem if you have set
|
|
269
|
+
`MIDJOURNEY_CHROME_LAUNCH=0`. Run `login` to start it by hand.
|
|
270
|
+
|
|
271
|
+
**`signed in: FAIL`.** The window is open but the profile is signed out. Run
|
|
272
|
+
`login` again.
|
|
273
|
+
|
|
274
|
+
## 4. Output and exit codes
|
|
275
|
+
|
|
276
|
+
Results on stdout, errors on stderr as JSON, so one parse handles both.
|
|
277
|
+
|
|
278
|
+
| Flag | Result |
|
|
279
|
+
|---|---|
|
|
280
|
+
| none | pretty JSON |
|
|
281
|
+
| `--json` | JSON, always |
|
|
282
|
+
| `--compact` | the same JSON on one line |
|
|
283
|
+
| `--select a,b.c` | keep only these fields. Dotted paths descend, arrays are traversed element-wise |
|
|
284
|
+
| `--agent` | compact JSON. Never implies `--confirm` |
|
|
285
|
+
|
|
286
|
+
`--select` matters more here than it looks. One explore page is tens of
|
|
287
|
+
kilobytes, most of it layout metadata, and an agent piping that into its context
|
|
288
|
+
pays for every byte.
|
|
289
|
+
|
|
290
|
+
`--agent` deliberately does **not** imply confirmation, unlike the equivalent in
|
|
291
|
+
some other CLIs. A flag an agent passes by habit must never be the thing that
|
|
292
|
+
authorises a charge.
|
|
293
|
+
|
|
294
|
+
| Code | Means |
|
|
295
|
+
|---|---|
|
|
296
|
+
| `0` | it worked |
|
|
297
|
+
| `1` | it failed: signed out, a refused write, an API error |
|
|
298
|
+
| `2` | it was typed wrong: a missing flag, a bad value, a bad `--ar` |
|
|
299
|
+
|
|
300
|
+
## 5. Which surface, and what each costs
|
|
301
|
+
|
|
302
|
+
An MCP server is expensive and a CLI is free.
|
|
303
|
+
|
|
304
|
+
The `tools/list` payload for these 27 tools is about **8,900 tokens**, plus the
|
|
305
|
+
server instructions. That is charged on every turn of every conversation, used
|
|
306
|
+
or not, because the descriptions are long and carry the parameter grammar.
|
|
307
|
+
|
|
308
|
+
A CLI costs nothing until it is called. The skill mentions it in one line, and
|
|
309
|
+
the model pays only when it runs something.
|
|
310
|
+
|
|
311
|
+
So the two are not competing:
|
|
312
|
+
|
|
313
|
+
| Where the work happens | Surface |
|
|
314
|
+
|---|---|
|
|
315
|
+
| Inside a conversation with an agent | MCP |
|
|
316
|
+
| Piping, scripting, cron, CI | CLI |
|
|
317
|
+
| A one-off question in a terminal | CLI |
|
|
318
|
+
|
|
319
|
+
## 6. Tools
|
|
320
|
+
|
|
321
|
+
### Making images
|
|
322
|
+
|
|
323
|
+
| Tool | What it does |
|
|
324
|
+
|---|---|
|
|
325
|
+
| `imagine` | Generate, wait for the job, return the images. Optionally save them. Spends |
|
|
326
|
+
| `submit_imagine` | Submit and return the job id without waiting. Spends |
|
|
327
|
+
| `rerun_job` | Run an existing job again, optionally with new wording or at HD. Spends |
|
|
328
|
+
| `vary_image` | Four variations of one image from a grid, subtle or strong. Spends |
|
|
329
|
+
| `submit_raw_job` | Send a job type this server does not model yet. Spends |
|
|
330
|
+
|
|
331
|
+
### Following work
|
|
332
|
+
|
|
333
|
+
| Tool | What it does |
|
|
334
|
+
|---|---|
|
|
335
|
+
| `list_jobs` | Recent generations, newest first, with status and image URLs |
|
|
336
|
+
| `get_job` | One job by id, with its real status |
|
|
337
|
+
| `wait_for_job` | Block until a job finishes, fails or is moderated |
|
|
338
|
+
| `get_queue` | What is running now, and how much concurrency the plan allows |
|
|
339
|
+
| `job_updates` | The live delta feed the web app itself polls |
|
|
340
|
+
|
|
341
|
+
### Getting the files
|
|
342
|
+
|
|
343
|
+
| Tool | What it does |
|
|
344
|
+
|---|---|
|
|
345
|
+
| `download_job` | Write a job's images to disk. Real files, full resolution |
|
|
346
|
+
| `download_url` | Write one asset to disk by URL |
|
|
347
|
+
|
|
348
|
+
### Moodboards and style
|
|
349
|
+
|
|
350
|
+
| Tool | What it does |
|
|
351
|
+
|---|---|
|
|
352
|
+
| `list_moodboards` | Every board, with how many reference images each holds |
|
|
353
|
+
| `get_moodboard` | One board by name, and the references a generation would use |
|
|
354
|
+
| `create_moodboard` | Start a new board for a look |
|
|
355
|
+
| `add_to_moodboard` | Put a job's renders, or any URLs, onto a board |
|
|
356
|
+
| `remove_from_moodboard` | Take images off a board. Needs `confirm` |
|
|
357
|
+
| `list_personalized_profiles` | Profiles, with how many images each was trained on |
|
|
358
|
+
|
|
359
|
+
### Your account
|
|
360
|
+
|
|
361
|
+
| Tool | What it does |
|
|
362
|
+
|---|---|
|
|
363
|
+
| `whoami` | Which account is signed in, and whether the browser is reachable |
|
|
364
|
+
| `list_folders` | Folders in the Organise view |
|
|
365
|
+
| `get_storage` | Storage used against what the plan allows |
|
|
366
|
+
| `list_following` | Creators this account follows |
|
|
367
|
+
| `list_model_ratings` | Pending rating tasks, which earn fast hours |
|
|
368
|
+
| `get_contest_ranking_count` | Contest rounds completed |
|
|
369
|
+
|
|
370
|
+
### Explore, and the escape hatch
|
|
371
|
+
|
|
372
|
+
| Tool | What it does |
|
|
373
|
+
|---|---|
|
|
374
|
+
| `explore_feed` | The public feed, with prompts and image URLs |
|
|
375
|
+
| `explore_style_likes` | Which styles this account has liked |
|
|
376
|
+
| `api_get` | Any `/api/` path, for endpoints with no named tool yet |
|
|
377
|
+
|
|
378
|
+
`midjourney-cli which "<what you want>"` resolves a capability described in
|
|
379
|
+
words to the command that does it, so you do not have to read this table.
|
|
380
|
+
|
|
381
|
+
## 7. Spending safely
|
|
382
|
+
|
|
383
|
+
Reads work freely. What is guarded is spending.
|
|
384
|
+
|
|
385
|
+
Every generation burns GPU time from a paid plan and there are no refunds, so
|
|
386
|
+
`imagine`, `submit_imagine`, `rerun_job`, `vary_image` and `submit_raw_job` take
|
|
387
|
+
`confirm: true`, or `--confirm` at the terminal.
|
|
388
|
+
|
|
389
|
+
Nothing reversible asks. Adding to a moodboard does not, because
|
|
390
|
+
`remove_from_moodboard` undoes it, and confirming reversible things is how a
|
|
391
|
+
model learns to pass `confirm` by reflex, which defeats the gate on spending.
|
|
392
|
+
|
|
393
|
+
A generation is not annotated destructive, because it destroys nothing. It has
|
|
394
|
+
its own risk level, so a client deciding what to auto-approve is told the truth
|
|
395
|
+
about what it is approving.
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
MIDJOURNEY_READ_ONLY=1 removes every tool that is not a read, 17 remain
|
|
399
|
+
MIDJOURNEY_ALLOW_DESTRUCTIVE=0 keeps reads and downloads, blocks anything that spends
|
|
400
|
+
MIDJOURNEY_AUDIT_LOG=<path> one JSON line per attempted change, allowed and blocked
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## 8. Prompts and parameters
|
|
404
|
+
|
|
405
|
+
Write the subject in `prompt` and everything else as named arguments. Do not put
|
|
406
|
+
`--ar` inside the prompt string.
|
|
407
|
+
|
|
408
|
+
The arguments are validated before anything is spent. Midjourney is not: it
|
|
409
|
+
silently ignores or clamps most malformed parameters rather than reporting them,
|
|
410
|
+
so a typo costs a generation and comes back looking like a bad result rather
|
|
411
|
+
than a mistake.
|
|
412
|
+
|
|
413
|
+
| Argument | What it does |
|
|
414
|
+
|---|---|
|
|
415
|
+
| `aspect` | `"16:9"`, `"3:2"`, `"1:1"`. Sent as `--ar` |
|
|
416
|
+
| `stylize` | 0-1000. Low follows the prompt, high looks prettier and drifts |
|
|
417
|
+
| `chaos` | 0-100. How different the four results are from each other |
|
|
418
|
+
| `seed` | Reuse with an identical prompt to iterate on one image |
|
|
419
|
+
| `style_refs` | An image URL, a numeric code, or `random`. Sent as `--sref` |
|
|
420
|
+
| `omni_refs` | Carry a character or object across images. The v7+ replacement for `--cref` |
|
|
421
|
+
| `image_prompts` | Direct image URLs, including `s.mj.run` links, used as visual input |
|
|
422
|
+
| `negative` | Things to keep out. Sent as `--no` |
|
|
423
|
+
| `raw` | Less automatic prettification. Good for photographic work |
|
|
424
|
+
| `draft` | Much faster and cheaper, lower fidelity. Good for exploring |
|
|
425
|
+
| `speed` | `fast`, `relax` or `turbo` |
|
|
426
|
+
|
|
427
|
+
At the terminal, Midjourney's own spellings work as aliases: `--ar`, `--sref`,
|
|
428
|
+
`--oref`, `--iw`, `--sw`, `--ow`, `--q`, `--no`, `--v`.
|
|
429
|
+
|
|
430
|
+
## 9. Moodboards
|
|
431
|
+
|
|
432
|
+
A moodboard is a curated pile of reference images. Naming one is far more
|
|
433
|
+
reliable than describing a look in words, because the board *is* the look.
|
|
434
|
+
|
|
435
|
+
The loop:
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
midjourney-cli create-moodboard "Nordic Skincare | Still Life"
|
|
439
|
+
midjourney-cli imagine "<a long, specific style description>" --confirm
|
|
440
|
+
midjourney-cli add-to-moodboard "Nordic Skincare" --job-id <job>
|
|
441
|
+
midjourney-cli imagine "a ceramic jar of face cream, lid beside it" \
|
|
442
|
+
--moodboard "Nordic Skincare" --sw 400 --confirm
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
After the third line the style is a name, and a nine-word prompt reproduces it.
|
|
446
|
+
|
|
447
|
+
Partial names work: `"High Fashion"` finds `"High Fashion | Woman"`. An ambiguous
|
|
448
|
+
name errors with the candidates rather than guessing, because picking the wrong
|
|
449
|
+
board costs a generation to discover. References are sampled across the board
|
|
450
|
+
rather than taken from the front, so a 242-image board does not always draw on
|
|
451
|
+
its oldest images.
|
|
452
|
+
|
|
453
|
+
`profile` does something different: it biases toward images the account has
|
|
454
|
+
rated, rather than toward a set of pictures.
|
|
455
|
+
|
|
456
|
+
## 10. How it works
|
|
457
|
+
|
|
458
|
+
Midjourney publishes no API. The endpoints under `/api/` are the ones its own
|
|
459
|
+
web app calls, and they sit behind a Cloudflare interstitial that answers a plain
|
|
460
|
+
client with a 403 challenge page rather than JSON.
|
|
461
|
+
|
|
462
|
+
That challenge is not defeated by a header. The `cf_clearance` cookie is bound to
|
|
463
|
+
the IP, the User-Agent and the TLS fingerprint together, so a cookie lifted out
|
|
464
|
+
of a browser and replayed from Node is a different client and gets stopped.
|
|
465
|
+
|
|
466
|
+
So rather than impersonate a browser, this drives one. Requests are issued by
|
|
467
|
+
`fetch()` running inside a real midjourney.com page, in a real Chrome that is
|
|
468
|
+
really signed in. Same origin, same cookies, same fingerprint, same IP,
|
|
469
|
+
credentials attached by the browser itself. There is nothing to spoof because
|
|
470
|
+
nothing is being faked.
|
|
471
|
+
|
|
472
|
+
Chrome 136 stopped honouring `--remote-debugging-port` on the default profile, so
|
|
473
|
+
this owns a profile instead: a dedicated `user-data-dir` you sign into once.
|
|
474
|
+
|
|
475
|
+
Both surfaces are generated from one `ALL_TOOLS` array. `register()` turns a spec
|
|
476
|
+
into an MCP tool and `cli.ts` turns the same spec into a shell command, through
|
|
477
|
+
the same handler and the same write guard, so a tool added tomorrow is a command
|
|
478
|
+
tomorrow and the two cannot drift. A test asserts that.
|
|
479
|
+
|
|
480
|
+
Downloads are read with an in-page `fetch`, which needs no new tab and no visible
|
|
481
|
+
activity. The CDN sends `access-control-allow-origin: *`, so the bytes come back
|
|
482
|
+
exactly as served.
|
|
483
|
+
|
|
484
|
+
## 11. Your data
|
|
485
|
+
|
|
486
|
+
Nothing leaves your machine except the requests to Midjourney that you asked for.
|
|
487
|
+
There is no telemetry, no analytics and no backend.
|
|
488
|
+
|
|
489
|
+
The session lives in a Chrome profile on your own disk. This process never reads
|
|
490
|
+
a cookie, stores a token, or sees a password.
|
|
491
|
+
|
|
492
|
+
Downloads go where you point them, `~/Downloads/midjourney` by default. The audit
|
|
493
|
+
log, when enabled, is a local file.
|
|
494
|
+
|
|
495
|
+
## 12. Risks
|
|
496
|
+
|
|
497
|
+
**This is unofficial, and Midjourney's terms do not permit automated access.**
|
|
498
|
+
Every unofficial client carries a risk to the account, this one included. It
|
|
499
|
+
moves at human pace and acts through a real browser session rather than
|
|
500
|
+
imitating one, which is the honest limit of what any tool here can do about
|
|
501
|
+
that.
|
|
502
|
+
|
|
503
|
+
**It spends money.** A loop over twenty prompt ideas is twenty charges. Use
|
|
504
|
+
`MIDJOURNEY_READ_ONLY=1` when pointing an unattended agent at the account, and
|
|
505
|
+
`MIDJOURNEY_AUDIT_LOG` when you want a record.
|
|
506
|
+
|
|
507
|
+
**The endpoints are undocumented and can change without notice.** Job records are
|
|
508
|
+
parsed defensively and partial answers are preferred to failures, but a large
|
|
509
|
+
enough upstream change will still break something.
|
|
510
|
+
|
|
511
|
+
## 13. Troubleshooting
|
|
512
|
+
|
|
513
|
+
Start with `doctor`. It orders the checks so the first failure is the one to fix.
|
|
514
|
+
|
|
515
|
+
| Symptom | Cause |
|
|
516
|
+
|---|---|
|
|
517
|
+
| `Cloudflare served a challenge` | The interstitial has not been cleared in that profile. Open the window and let it finish once |
|
|
518
|
+
| `The browser profile is not signed in` | Signed out, or the session expired. Run `login` |
|
|
519
|
+
| `No Chrome or Chromium found` | Chrome is not where it is normally looked for. Set `MIDJOURNEY_CHROME_PATH` |
|
|
520
|
+
| `DevTools never answered` | Another Chrome is using that profile directory. Quit it, or set `MIDJOURNEY_CHROME_PROFILE` elsewhere |
|
|
521
|
+
| `Midjourney refused ... for billing reasons` | Out of fast hours, or the subscription lapsed. Switch to `speed: "relax"` |
|
|
522
|
+
| Job accepted, then never appears | The account is at its concurrent-job limit. Check `get_queue` |
|
|
523
|
+
| `had not finished after 600s` | Normal on relax mode. The job is still running; raise `MIDJOURNEY_JOB_TIMEOUT_MS` |
|
|
524
|
+
| 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 |
|
|
525
|
+
| Downloads are empty or fail | The asset URL expired. Re-read the job with `get_job` for fresh URLs |
|
|
526
|
+
|
|
527
|
+
## Environment variables
|
|
528
|
+
|
|
529
|
+
Every one of these is optional. The defaults are what you want unless you are doing something unusual.
|
|
530
|
+
|
|
531
|
+
| Variable | Default | What it does |
|
|
532
|
+
|---|---|---|
|
|
533
|
+
| `MIDJOURNEY_CHROME_PROFILE` | `~/.midjourney-mcp/chrome-profile` | The browser profile holding the session |
|
|
534
|
+
| `MIDJOURNEY_CHROME_PATH` | found automatically | The Chrome binary |
|
|
535
|
+
| `MIDJOURNEY_CHROME_LAUNCH` | `1` | Start Chrome on demand. `0` only attaches to a running one |
|
|
536
|
+
| `MIDJOURNEY_CDP_URL` | `http://127.0.0.1:9222` | Where DevTools listens |
|
|
537
|
+
| `MIDJOURNEY_HEADLESS` | `0` | Run without a window. Sign in first, a window is needed for that |
|
|
538
|
+
| `MIDJOURNEY_ORIGIN` | `https://www.midjourney.com` | The site being driven |
|
|
539
|
+
| `MIDJOURNEY_USER_ID` | discovered | Skip user-id discovery |
|
|
540
|
+
| `MIDJOURNEY_DEFAULT_SPEED` | `fast` | `fast`, `relax` or `turbo` |
|
|
541
|
+
| `MIDJOURNEY_DEFAULT_VERSION` | `7` | Model version appended as `--v` |
|
|
542
|
+
| `MIDJOURNEY_DOWNLOAD_DIR` | `~/Downloads/midjourney` | Where downloads land |
|
|
543
|
+
| `MIDJOURNEY_REQUEST_TIMEOUT_MS` | `30000` | Per-request deadline |
|
|
544
|
+
| `MIDJOURNEY_MIN_REQUEST_INTERVAL_MS` | `700` | Floor between requests, jittered |
|
|
545
|
+
| `MIDJOURNEY_MAX_RETRIES` | `3` | Retries on 429 and 5xx |
|
|
546
|
+
| `MIDJOURNEY_JOB_TIMEOUT_MS` | `600000` | How long to wait for a job |
|
|
547
|
+
| `MIDJOURNEY_JOB_POLL_INTERVAL_MS` | `3000` | First poll interval, widening from there |
|
|
548
|
+
| `MIDJOURNEY_REFRESH_VIEW` | `1` | Reload the open window after a generation so it shows the new work |
|
|
549
|
+
| `MIDJOURNEY_READ_ONLY` | `0` | Hide everything that is not a read |
|
|
550
|
+
| `MIDJOURNEY_ALLOW_DESTRUCTIVE` | `1` | `0` blocks anything that spends |
|
|
551
|
+
| `MIDJOURNEY_AUDIT_LOG` | unset | Append-only log of every attempted change |
|
|
552
|
+
| `MIDJOURNEY_HTTP_PORT` | `8787` | Port for `--http` |
|
|
553
|
+
| `MIDJOURNEY_HTTP_HOST` | `127.0.0.1` | Interface for `--http` |
|
|
554
|
+
| `MIDJOURNEY_HTTP_TOKEN` | unset | Bearer token. Required to listen off loopback |
|
|
555
|
+
|
|
556
|
+
## 14. FAQ
|
|
557
|
+
|
|
558
|
+
<details>
|
|
559
|
+
<summary><b>What is an MCP server?</b></summary>
|
|
560
|
+
|
|
561
|
+
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.
|
|
562
|
+
|
|
563
|
+
</details>
|
|
564
|
+
|
|
565
|
+
<details>
|
|
566
|
+
<summary><b>What is Midjourney?</b></summary>
|
|
567
|
+
|
|
568
|
+
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.
|
|
569
|
+
|
|
570
|
+
</details>
|
|
571
|
+
|
|
572
|
+
<details>
|
|
573
|
+
<summary><b>Does Midjourney have an API?</b></summary>
|
|
574
|
+
|
|
575
|
+
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.
|
|
576
|
+
|
|
577
|
+
</details>
|
|
578
|
+
|
|
579
|
+
<details>
|
|
580
|
+
<summary><b>Is this against Midjourney's terms?</b></summary>
|
|
581
|
+
|
|
582
|
+
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.
|
|
583
|
+
|
|
584
|
+
</details>
|
|
585
|
+
|
|
586
|
+
<details>
|
|
587
|
+
<summary><b>Do I need to be technical?</b></summary>
|
|
588
|
+
|
|
589
|
+
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.
|
|
590
|
+
|
|
591
|
+
</details>
|
|
592
|
+
|
|
593
|
+
<details>
|
|
594
|
+
<summary><b>Is my data sent anywhere?</b></summary>
|
|
595
|
+
|
|
596
|
+
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.
|
|
597
|
+
|
|
598
|
+
</details>
|
|
599
|
+
|
|
600
|
+
<details>
|
|
601
|
+
<summary><b>Can it spend money without me noticing?</b></summary>
|
|
602
|
+
|
|
603
|
+
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.
|
|
604
|
+
|
|
605
|
+
</details>
|
|
606
|
+
|
|
607
|
+
<details>
|
|
608
|
+
<summary><b>What can it do that the website cannot?</b></summary>
|
|
609
|
+
|
|
610
|
+
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.
|
|
611
|
+
|
|
612
|
+
</details>
|
|
613
|
+
|
|
614
|
+
<details>
|
|
615
|
+
<summary><b>Does it work with ChatGPT and Cursor?</b></summary>
|
|
616
|
+
|
|
617
|
+
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.
|
|
618
|
+
|
|
619
|
+
</details>
|
|
620
|
+
|
|
621
|
+
<details>
|
|
622
|
+
<summary><b>Can I run it without a visible browser window?</b></summary>
|
|
623
|
+
|
|
624
|
+
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.
|
|
625
|
+
|
|
626
|
+
</details>
|
|
627
|
+
|
|
628
|
+
<details>
|
|
629
|
+
<summary><b>Why does it need Node 22?</b></summary>
|
|
630
|
+
|
|
631
|
+
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.
|
|
632
|
+
|
|
633
|
+
</details>
|
|
634
|
+
|
|
635
|
+
<details>
|
|
636
|
+
<summary><b>How do I disconnect it?</b></summary>
|
|
637
|
+
|
|
638
|
+
Remove the entry from your client's config, then delete `~/.midjourney-mcp/chrome-profile` to drop the session. Nothing else is left behind.
|
|
639
|
+
|
|
640
|
+
</details>
|
|
641
|
+
|
|
642
|
+
## Questions
|
|
643
|
+
|
|
644
|
+
Run into a problem or have a question? [Open an issue](https://github.com/navidmoazzez/midjourney-mcp-cli/issues) and I will help.
|
|
645
|
+
|
|
646
|
+
## About the author 👋
|
|
647
|
+
|
|
648
|
+
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.
|
|
649
|
+
|
|
650
|
+
**Links**
|
|
651
|
+
|
|
652
|
+
- Personal website: [navid.me](https://navid.me)
|
|
653
|
+
- Store: [navid.bio](https://navid.bio)
|
|
654
|
+
- Navid Media: [navid.media](https://navid.media)
|
|
655
|
+
- YouTube: [@thenavidm](https://youtube.com/@thenavidm?sub_confirmation=1) and [@thenavidai](https://youtube.com/@thenavidai?sub_confirmation=1)
|
|
656
|
+
- X: [@thenavidm](https://x.com/thenavidm)
|
|
657
|
+
- Instagram: [@thenavidm](https://instagram.com/thenavidm)
|
|
658
|
+
- LinkedIn: [thenavidm](https://linkedin.com/in/thenavidm)
|
|
659
|
+
|
|
660
|
+
## Dependencies
|
|
661
|
+
|
|
662
|
+
| Library | Licence | What it does |
|
|
663
|
+
|---|---|---|
|
|
664
|
+
| [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) | MIT | The MCP protocol, stdio and HTTP transports |
|
|
665
|
+
| [zod](https://github.com/colinhacks/zod) | MIT | One schema per tool, driving both surfaces |
|
|
666
|
+
|
|
667
|
+
The browser connection uses Node's built-in `WebSocket` and needs nothing else.
|
|
668
|
+
|
|
669
|
+
## License
|
|
670
|
+
|
|
671
|
+
[MIT](./LICENSE). Free to use, modify, and share.
|
|
672
|
+
|
|
673
|
+
Not affiliated with, endorsed by, or sponsored by Midjourney, Inc. Midjourney is a trademark of Midjourney, Inc.
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
© 2026 [NM Media](https://navid.media). Made with ❤️ by [Navid Moazzez](https://navid.me).
|