codex-imagegen-mcp 0.1.2
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/CHANGELOG.md +96 -0
- package/LICENSE +201 -0
- package/NOTICE +19 -0
- package/README.md +373 -0
- package/dist/src/auth/borrowed.js +77 -0
- package/dist/src/auth/borrowed.js.map +1 -0
- package/dist/src/auth/browser-login.js +179 -0
- package/dist/src/auth/browser-login.js.map +1 -0
- package/dist/src/auth/device-login.js +39 -0
- package/dist/src/auth/device-login.js.map +1 -0
- package/dist/src/auth/jwt.js +69 -0
- package/dist/src/auth/jwt.js.map +1 -0
- package/dist/src/auth/manager.js +289 -0
- package/dist/src/auth/manager.js.map +1 -0
- package/dist/src/auth/oauth.js +246 -0
- package/dist/src/auth/oauth.js.map +1 -0
- package/dist/src/auth/pages.js +39 -0
- package/dist/src/auth/pages.js.map +1 -0
- package/dist/src/auth/pkce.js +14 -0
- package/dist/src/auth/pkce.js.map +1 -0
- package/dist/src/auth/store.js +75 -0
- package/dist/src/auth/store.js.map +1 -0
- package/dist/src/backend/images-client.js +223 -0
- package/dist/src/backend/images-client.js.map +1 -0
- package/dist/src/backend/ratelimits.js +183 -0
- package/dist/src/backend/ratelimits.js.map +1 -0
- package/dist/src/cli.js +407 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config.js +87 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.js +52 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/doctor.js +122 -0
- package/dist/src/doctor.js.map +1 -0
- package/dist/src/errors.js +76 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/generation.js +183 -0
- package/dist/src/generation.js.map +1 -0
- package/dist/src/history.js +47 -0
- package/dist/src/history.js.map +1 -0
- package/dist/src/images/chroma.js +200 -0
- package/dist/src/images/chroma.js.map +1 -0
- package/dist/src/images/codec.js +159 -0
- package/dist/src/images/codec.js.map +1 -0
- package/dist/src/images/inputs.js +83 -0
- package/dist/src/images/inputs.js.map +1 -0
- package/dist/src/images/output.js +100 -0
- package/dist/src/images/output.js.map +1 -0
- package/dist/src/images/preview.js +20 -0
- package/dist/src/images/preview.js.map +1 -0
- package/dist/src/images/resize.js +135 -0
- package/dist/src/images/resize.js.map +1 -0
- package/dist/src/install/opencode.js +138 -0
- package/dist/src/install/opencode.js.map +1 -0
- package/dist/src/install/skill.js +128 -0
- package/dist/src/install/skill.js.map +1 -0
- package/dist/src/install/snippets.js +127 -0
- package/dist/src/install/snippets.js.map +1 -0
- package/dist/src/log.js +58 -0
- package/dist/src/log.js.map +1 -0
- package/dist/src/remove-background.js +101 -0
- package/dist/src/remove-background.js.map +1 -0
- package/dist/src/server/context.js +2 -0
- package/dist/src/server/context.js.map +1 -0
- package/dist/src/server/index.js +94 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/instructions.js +20 -0
- package/dist/src/server/instructions.js.map +1 -0
- package/dist/src/server/login-coordinator.js +73 -0
- package/dist/src/server/login-coordinator.js.map +1 -0
- package/dist/src/server/progress.js +33 -0
- package/dist/src/server/progress.js.map +1 -0
- package/dist/src/server/prompts.js +45 -0
- package/dist/src/server/prompts.js.map +1 -0
- package/dist/src/server/resources.js +73 -0
- package/dist/src/server/resources.js.map +1 -0
- package/dist/src/server/tools.js +338 -0
- package/dist/src/server/tools.js.map +1 -0
- package/dist/src/server/workspace.js +45 -0
- package/dist/src/server/workspace.js.map +1 -0
- package/dist/src/status.js +86 -0
- package/dist/src/status.js.map +1 -0
- package/dist/src/util/format.js +36 -0
- package/dist/src/util/format.js.map +1 -0
- package/dist/src/util/fs.js +117 -0
- package/dist/src/util/fs.js.map +1 -0
- package/dist/src/util/http.js +65 -0
- package/dist/src/util/http.js.map +1 -0
- package/dist/src/util/invocation.js +43 -0
- package/dist/src/util/invocation.js.map +1 -0
- package/dist/src/util/open.js +41 -0
- package/dist/src/util/open.js.map +1 -0
- package/docs/ARCHITECTURE.md +123 -0
- package/docs/AUTH.md +242 -0
- package/docs/BACKEND.md +169 -0
- package/docs/CLIENTS.md +154 -0
- package/docs/DEVELOPMENT.md +171 -0
- package/docs/README.md +84 -0
- package/docs/TOOLS.md +221 -0
- package/package.json +67 -0
- package/skill/imagegen/LICENSE.txt +201 -0
- package/skill/imagegen/SKILL.md +189 -0
- package/skill/imagegen/references/prompting.md +112 -0
- package/skill/imagegen/references/sample-prompts.md +418 -0
- package/skill/imagegen/references/tools.md +90 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner-development.jpg" width="100%" alt="Development — a travel-poster illustration of a surveyor's camp: a brass theodolite on a tripod aimed at a distant peak, a canvas tent and a work table with a toolbox">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Development
|
|
6
|
+
|
|
7
|
+
Build it, test it without touching OpenAI, test it live, and ship it.
|
|
8
|
+
|
|
9
|
+
**On this page:** [Setup](#setup) · [Layout](#layout) · [Tests](#tests) · [Continuous integration](#continuous-integration) · [Live testing](#live-testing) · [Conventions](#conventions) · [Artwork](#artwork) · [Updating from upstream Codex](#updating-from-upstream-codex) · [Releasing](#releasing)
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
You need Node.js 22 or newer.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git clone https://github.com/ShalomObongo/codex-imagegen-mcp.git && cd codex-imagegen-mcp
|
|
17
|
+
npm ci
|
|
18
|
+
npm run build # tsc → dist/, marks dist/src/cli.js executable (works on Windows too)
|
|
19
|
+
npm test # build + the node:test suite
|
|
20
|
+
npm run typecheck
|
|
21
|
+
npm link # optional: expose `codex-imagegen-mcp` globally for manual testing
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Contribution guidelines, commit style and the pull-request checklist are in [CONTRIBUTING.md](../.github/CONTRIBUTING.md).
|
|
25
|
+
|
|
26
|
+
## Layout
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
src/ TypeScript sources (see ARCHITECTURE.md)
|
|
30
|
+
test/ node:test suites; test/helpers/mock-openai.ts mocks auth.openai.com + the ChatGPT backend
|
|
31
|
+
skill/imagegen/ the Agent Skill shipped with the server
|
|
32
|
+
upstream/ byte-exact copy of the Codex skill it was adapted from
|
|
33
|
+
scripts/ compose-doc-art.py builds docs/assets from raw generations
|
|
34
|
+
docs/ this documentation; docs/assets holds the artwork
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Tests
|
|
38
|
+
|
|
39
|
+
The suite never talks to OpenAI. Every test runs against a scriptable mock and an isolated temp home:
|
|
40
|
+
|
|
41
|
+
```mermaid
|
|
42
|
+
flowchart LR
|
|
43
|
+
tests["node:test suites"]:::ink
|
|
44
|
+
subgraph sandbox ["isolated temp home (test/helpers/env.ts)"]
|
|
45
|
+
server["codex-imagegen-mcp<br/>(in-process or over stdio)"]:::rust
|
|
46
|
+
files[("auth.json · history · images")]:::cream
|
|
47
|
+
end
|
|
48
|
+
subgraph mock ["test/helpers/mock-openai.ts"]
|
|
49
|
+
oauth["OAuth: PKCE-checked code exchange<br/>rotating single-use refresh tokens · revoke · device code"]:::teal
|
|
50
|
+
api["backend: images/generations · images/edits · wham/usage<br/>scripted 401 · 429 · 5xx · policy · Cloudflare"]:::teal
|
|
51
|
+
end
|
|
52
|
+
tests --> server
|
|
53
|
+
server --> files
|
|
54
|
+
server -- "CODEX_IMAGEGEN_AUTH_ISSUER" --> oauth
|
|
55
|
+
server -- "CODEX_IMAGEGEN_BASE_URL" --> api
|
|
56
|
+
classDef ink fill:#2A2523,stroke:#9A8C76,color:#E4D9C6
|
|
57
|
+
classDef rust fill:#A6553B,stroke:#7E3F2B,color:#FFFFFF
|
|
58
|
+
classDef teal fill:#4E6E63,stroke:#3A544B,color:#FFFFFF
|
|
59
|
+
classDef cream fill:#E4D9C6,stroke:#A89A80,color:#2A2523
|
|
60
|
+
style sandbox fill:#D9A05B1F,stroke:#B5813F,color:#B5813F
|
|
61
|
+
style mock fill:#D9A05B1F,stroke:#B5813F,color:#B5813F
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- **The mock behaves like the real service where it matters.** It checks the PKCE `code_verifier` against the challenge and the `redirect_uri`, and its refresh tokens are **single-use**: a second use returns `refresh_token_reused`, just as OpenAI does.
|
|
65
|
+
- **Scripting failures:** queue responses in `state.imageQueue` to simulate 401, 429, 5xx, policy and Cloudflare errors, and set delays to exercise timeouts and locking.
|
|
66
|
+
- **Nothing real is touched.** `test/helpers/env.ts` builds an isolated `CODEX_IMAGEGEN_*` environment in a temp directory, so tests never read or write your credentials. The installer tests also point `HOME` and `XDG_CONFIG_HOME` at temp directories.
|
|
67
|
+
|
|
68
|
+
| Suite | Covers |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `auth-primitives` | JWT claims, PKCE, authorize URL, the 0600 store, the cross-process lock, stale locks |
|
|
71
|
+
| `auth-manager` | Refresh (three concurrent processes → one refresh), permanent vs transient failures, borrowed sources, 401 recovery, revoke |
|
|
72
|
+
| `login-flows` | Browser round trip, state mismatch, authorize errors, failed exchange, cancel, timeout, device code |
|
|
73
|
+
| `images-client` | Exact request body and headers, edits, retries, usage limits, policy/invalid/Cloudflare mapping, the usage API |
|
|
74
|
+
| `image-processing` | Codec, previews, chroma key, output planning, no-overwrite writes, input validation |
|
|
75
|
+
| `install` | JSONC-preserving opencode edits, backups, idempotency, conflict protection, uninstall, snippets |
|
|
76
|
+
| `server` | Full MCP over stdio: tools, resources, prompts, progress, errors, sign-in via the tool and then generation |
|
|
77
|
+
| `cli` | Every command end to end against the mock |
|
|
78
|
+
|
|
79
|
+
## Continuous integration
|
|
80
|
+
|
|
81
|
+
Every push to `main` and every pull request runs [CI](../.github/workflows/ci.yml):
|
|
82
|
+
|
|
83
|
+
| Job | What it checks |
|
|
84
|
+
|---|---|
|
|
85
|
+
| **Node 22 · 24 · 26** on Linux | `npm ci`, `npm run typecheck`, `npm test`, a CLI smoke test |
|
|
86
|
+
| **Node 24** on macOS and Windows | The same, on the other two platforms |
|
|
87
|
+
| **Package and install** | `npm pack`, a global install of the tarball, and that the installed CLI runs and ships its skill |
|
|
88
|
+
|
|
89
|
+
Actions are pinned to commit SHAs, and [Dependabot](../.github/dependabot.yml) keeps them and the npm dependencies current. CodeQL code scanning runs on GitHub's default setup.
|
|
90
|
+
|
|
91
|
+
## Live testing
|
|
92
|
+
|
|
93
|
+
> [!CAUTION]
|
|
94
|
+
> These commands use your real ChatGPT quota. `status`, `doctor` and `auth_status` are free; every generated image counts.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
node dist/src/cli.js status # auth + usage, no quota
|
|
98
|
+
node dist/src/cli.js generate "a red apple" -o tmp/live/apple.png
|
|
99
|
+
node dist/src/cli.js install opencode && opencode mcp list
|
|
100
|
+
opencode run -m openai/gpt-5.5 "make a transparent sticker of a cactus, save to assets/cactus.png"
|
|
101
|
+
opencode run -m github-copilot/claude-sonnet-5 "…" # Copilot providers take a different media path in opencode
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`tmp/` is git-ignored. To see what the server did inside a client, set `CODEX_IMAGEGEN_LOG_LEVEL=debug` and read `~/.local/share/codex-imagegen-mcp/server.log`.
|
|
105
|
+
|
|
106
|
+
## Conventions
|
|
107
|
+
|
|
108
|
+
- **stdout is the protocol.** Never write to it from server code paths.
|
|
109
|
+
- **Errors carry the next step.** Raise `ImagegenError(kind, message)`; each kind maps to that step in `describeError`.
|
|
110
|
+
- **Limits live in descriptions too.** Some clients strip schema constraints before the model sees them.
|
|
111
|
+
- **Claims about the backend must be measured.** Record them in [Backend](BACKEND.md) with the date.
|
|
112
|
+
- **The skill tracks upstream.** Diff changes against `upstream/codex-imagegen-skill/` and keep the prompting guidance aligned.
|
|
113
|
+
|
|
114
|
+
## Artwork
|
|
115
|
+
|
|
116
|
+
Every image in the docs was generated with this server, following the art-direction record in [docs/assets](assets/README.md). The raw generations stay out of git (about 2 MB each). `scripts/compose-doc-art.py` turns them into the committed assets:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# 1. regenerate any source with the prompts in docs/assets/README.md, saving into tmp/art/
|
|
120
|
+
# 2. rebuild every committed asset (Pillow + numpy; Superclarendon ships with macOS)
|
|
121
|
+
python3 scripts/compose-doc-art.py --art tmp/art --out docs/assets
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The script does five things:
|
|
125
|
+
- **Snaps alpha.** The service returns 251–254 inside opaque areas; this rounds it to 255.
|
|
126
|
+
- **Typesets wording locally.** Poster titles are set in Superclarendon, so no text is ever generated.
|
|
127
|
+
- **Slices the badge grid** into six PNGs.
|
|
128
|
+
- **Builds the showcase sheets.**
|
|
129
|
+
- **Writes the social preview.**
|
|
130
|
+
|
|
131
|
+
Paper grain is seeded, so reruns are byte-stable.
|
|
132
|
+
|
|
133
|
+
## Updating from upstream Codex
|
|
134
|
+
|
|
135
|
+
1. **Extract the current skill:** `CODEX_HOME=$(mktemp -d) /Applications/ChatGPT.app/Contents/Resources/codex debug prompt-input hi >/dev/null`. This installs the embedded system skills into `$CODEX_HOME/skills/.system/`.
|
|
136
|
+
2. **Diff and port.** Compare that `imagegen/` with `upstream/codex-imagegen-skill/`, update the copy, and port the relevant guidance into `skill/imagegen/`.
|
|
137
|
+
3. **Check the tool.** Look at `codex-rs/ext/image-generation/src/tool.rs` upstream for changes to the request body, model id or limits.
|
|
138
|
+
|
|
139
|
+
## Releasing
|
|
140
|
+
|
|
141
|
+
Releases are automated. A maintainer only has to:
|
|
142
|
+
|
|
143
|
+
1. Make sure `main` is green in CI, and run the live smoke test: `status`, one `generate`, one edit with `-b transparent`, `doctor`, plus one `opencode run`.
|
|
144
|
+
2. Bump `version` in `package.json` (then `npm install --package-lock-only`) and add a `## [X.Y.Z] - YYYY-MM-DD` entry to `CHANGELOG.md`, with its compare link at the bottom.
|
|
145
|
+
3. Commit, then tag and push: `git tag -a vX.Y.Z -m "…" && git push origin main vX.Y.Z`.
|
|
146
|
+
|
|
147
|
+
The [release workflow](../.github/workflows/release.yml) then:
|
|
148
|
+
|
|
149
|
+
```mermaid
|
|
150
|
+
flowchart LR
|
|
151
|
+
tag(["push tag vX.Y.Z"]):::ink --> test["npm ci · npm test"]:::teal
|
|
152
|
+
test --> check{"tag = package.json<br/>version?"}:::cream
|
|
153
|
+
check -- "no" --> fail(["fail the release"]):::ochre
|
|
154
|
+
check -- "yes" --> pack["npm pack<br/>+ stable-named copy<br/>+ SHA256SUMS"]:::rust
|
|
155
|
+
pack --> notes["notes from<br/>CHANGELOG.md"]:::rust
|
|
156
|
+
notes --> attest["sign build-provenance<br/>attestation"]:::teal
|
|
157
|
+
attest --> release(["GitHub release<br/>+ announcement discussion"]):::ink
|
|
158
|
+
classDef ink fill:#2A2523,stroke:#9A8C76,color:#E4D9C6
|
|
159
|
+
classDef rust fill:#A6553B,stroke:#7E3F2B,color:#FFFFFF
|
|
160
|
+
classDef ochre fill:#D9A05B,stroke:#B5813F,color:#2A2523
|
|
161
|
+
classDef teal fill:#4E6E63,stroke:#3A544B,color:#FFFFFF
|
|
162
|
+
classDef cream fill:#E4D9C6,stroke:#A89A80,color:#2A2523
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Each release carries `codex-imagegen-mcp-X.Y.Z.tgz`, the same file as `codex-imagegen-mcp.tgz` (so `releases/latest/download/codex-imagegen-mcp.tgz` always points at the newest build), and `SHA256SUMS`. Anyone can verify a download with `gh attestation verify codex-imagegen-mcp-X.Y.Z.tgz --repo ShalomObongo/codex-imagegen-mcp`.
|
|
166
|
+
|
|
167
|
+
The package itself contains `dist/src`, `skill`, `docs/*.md`, `README.md`, `CHANGELOG.md`, `LICENSE` and `NOTICE`; the artwork is excluded to keep it small. `npm pack --dry-run` shows the list.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
<p align="center"><a href="ARCHITECTURE.md">← Architecture</a> · <a href="README.md">Docs home</a> · <a href="../README.md">README</a></p>
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner-docs.jpg" width="100%" alt="Documentation — a travel-poster illustration of a wooden signpost with blank arrow boards at a desert crossroads, roads fanning out toward a sun rising behind a peak">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Documentation
|
|
6
|
+
|
|
7
|
+
codex-imagegen-mcp puts the image generation of OpenAI Codex into any MCP client, running on your ChatGPT plan. These pages cover how to use it, how it signs in, where it plugs in, and how it works.
|
|
8
|
+
|
|
9
|
+
<table>
|
|
10
|
+
<tr>
|
|
11
|
+
<td width="33%" valign="top">
|
|
12
|
+
<a href="TOOLS.md"><img src="assets/thumbs/banner-tools.jpg" alt="Tools"></a><br>
|
|
13
|
+
<b>1 · <a href="TOOLS.md">Tools</a></b><br>
|
|
14
|
+
<sub>Parameters, results, resources, prompts, errors, progress and timeouts.</sub>
|
|
15
|
+
</td>
|
|
16
|
+
<td width="33%" valign="top">
|
|
17
|
+
<a href="AUTH.md"><img src="assets/thumbs/banner-auth.jpg" alt="Authentication"></a><br>
|
|
18
|
+
<b>2 · <a href="AUTH.md">Authentication</a></b><br>
|
|
19
|
+
<sub>Browser and device-code sign-in, token storage and rotation, borrowing, security.</sub>
|
|
20
|
+
</td>
|
|
21
|
+
<td width="33%" valign="top">
|
|
22
|
+
<a href="CLIENTS.md"><img src="assets/thumbs/banner-clients.jpg" alt="Clients"></a><br>
|
|
23
|
+
<b>3 · <a href="CLIENTS.md">Clients</a></b><br>
|
|
24
|
+
<sub>opencode (automated), Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, Gemini CLI, Codex.</sub>
|
|
25
|
+
</td>
|
|
26
|
+
</tr>
|
|
27
|
+
<tr>
|
|
28
|
+
<td width="33%" valign="top">
|
|
29
|
+
<a href="BACKEND.md"><img src="assets/thumbs/banner-backend.jpg" alt="Backend"></a><br>
|
|
30
|
+
<b>4 · <a href="BACKEND.md">Backend</a></b><br>
|
|
31
|
+
<sub>The Codex skill and built-in tool, the HTTP API, and what the service really honors.</sub>
|
|
32
|
+
</td>
|
|
33
|
+
<td width="33%" valign="top">
|
|
34
|
+
<a href="ARCHITECTURE.md"><img src="assets/thumbs/banner-architecture.jpg" alt="Architecture"></a><br>
|
|
35
|
+
<b>5 · <a href="ARCHITECTURE.md">Architecture</a></b><br>
|
|
36
|
+
<sub>Module map, request flow, and the reasoning behind each design decision.</sub>
|
|
37
|
+
</td>
|
|
38
|
+
<td width="33%" valign="top">
|
|
39
|
+
<a href="DEVELOPMENT.md"><img src="assets/thumbs/banner-development.jpg" alt="Development"></a><br>
|
|
40
|
+
<b>6 · <a href="DEVELOPMENT.md">Development</a></b><br>
|
|
41
|
+
<sub>Build, the mock-backed test suite, live testing, artwork, releases.</sub>
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
</table>
|
|
45
|
+
|
|
46
|
+
## Where to start
|
|
47
|
+
|
|
48
|
+
| If you want to… | Read |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Install it and make a first image | The [README quick start](../README.md#quick-start), then [Tools](TOOLS.md) |
|
|
51
|
+
| Know how it signs in, and whether that's safe | [Authentication](AUTH.md) |
|
|
52
|
+
| Use it outside opencode | [Clients](CLIENTS.md) |
|
|
53
|
+
| Understand what Codex does under the hood | [Backend](BACKEND.md) |
|
|
54
|
+
| Change the code | [Architecture](ARCHITECTURE.md), then [Development](DEVELOPMENT.md) |
|
|
55
|
+
|
|
56
|
+
## At a glance
|
|
57
|
+
|
|
58
|
+
```mermaid
|
|
59
|
+
flowchart LR
|
|
60
|
+
agent["Your coding agent<br/>opencode · Claude Code · Cursor · VS Code"]:::ink
|
|
61
|
+
server["codex-imagegen-mcp<br/>local stdio MCP server"]:::rust
|
|
62
|
+
skill["imagegen skill<br/>how to prompt, where to save"]:::ochre
|
|
63
|
+
oauth["auth.openai.com<br/>ChatGPT sign-in"]:::teal
|
|
64
|
+
backend["chatgpt.com/backend-api/codex<br/>/images/generations · /images/edits"]:::teal
|
|
65
|
+
files[("your workspace<br/>assets/hero.png")]:::cream
|
|
66
|
+
skill -. guides .-> agent
|
|
67
|
+
agent -- "tools/call" --> server
|
|
68
|
+
server -- "OAuth · refresh" --> oauth
|
|
69
|
+
server -- "Bearer token" --> backend
|
|
70
|
+
server -- "PNG, never overwritten" --> files
|
|
71
|
+
classDef ink fill:#2A2523,stroke:#9A8C76,color:#E4D9C6
|
|
72
|
+
classDef rust fill:#A6553B,stroke:#7E3F2B,color:#FFFFFF
|
|
73
|
+
classDef ochre fill:#D9A05B,stroke:#B5813F,color:#2A2523
|
|
74
|
+
classDef teal fill:#4E6E63,stroke:#3A544B,color:#FFFFFF
|
|
75
|
+
classDef cream fill:#E4D9C6,stroke:#A89A80,color:#2A2523
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## About the artwork
|
|
79
|
+
|
|
80
|
+
Every picture in these docs was generated **with codex-imagegen-mcp itself**, using the `imagegen` skill it ships: the poster banners, the badges, the logo and the examples. The series follows one art direction, a 1930s WPA silkscreen travel poster in five flat inks. [The prompts, the direction record and how to rebuild the assets →](assets/README.md)
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
<p align="center"><a href="../README.md">← Back to the README</a> · <a href="TOOLS.md">Start with Tools →</a></p>
|
package/docs/TOOLS.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner-tools.jpg" width="100%" alt="Tools — a travel-poster illustration of five colossal tools planted upright on a desert plain: a paintbrush, a pencil, scissors, a compass and a key">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Tools
|
|
6
|
+
|
|
7
|
+
The server exposes **five tools**, three **resources** and two **prompts**. This page documents every parameter, every result field and every error.
|
|
8
|
+
|
|
9
|
+
**On this page:** [Choosing a tool](#choosing-a-tool) · [generate_image](#generate_image) · [edit_image](#edit_image) · [remove_background](#remove_background) · [auth_status](#auth_status) · [sign_in](#sign_in) · [Errors](#errors) · [Resources](#resources) · [Prompts](#prompts) · [Progress, timeouts and cancellation](#progress-timeouts-and-cancellation)
|
|
10
|
+
|
|
11
|
+
| Tool | Purpose | Network | Quota |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| [`generate_image`](#generate_image) | A new image from a text prompt | ChatGPT | 1 image per variant |
|
|
14
|
+
| [`edit_image`](#edit_image) | Edit images, or generate guided by 1–5 references | ChatGPT | 1 image per variant |
|
|
15
|
+
| [`remove_background`](#remove_background) | Key out a flat, solid-colour backdrop | none | none |
|
|
16
|
+
| [`auth_status`](#auth_status) | Sign-in, plan, credential source, usage windows | ChatGPT (usage only) | none |
|
|
17
|
+
| [`sign_in`](#sign_in) | Start a ChatGPT sign-in and return a link or code | OpenAI auth | none |
|
|
18
|
+
|
|
19
|
+
The server's name in client configs defaults to `imagegen`, and clients add a prefix to the tool names:
|
|
20
|
+
|
|
21
|
+
| Client | Tool name as the model sees it |
|
|
22
|
+
|---|---|
|
|
23
|
+
| opencode | `imagegen_generate_image` |
|
|
24
|
+
| Claude Code, OpenAI Codex | `mcp__imagegen__generate_image` |
|
|
25
|
+
| Other clients | listed under the `imagegen` server |
|
|
26
|
+
|
|
27
|
+
> [!NOTE]
|
|
28
|
+
> **Relative paths** resolve against the **workspace root**. That is the first `file://` root the client reports through MCP roots (opencode reports the project directory). Without one, the server uses the directory it was started in. A filesystem root such as `/` falls back to your home directory.
|
|
29
|
+
|
|
30
|
+
## Choosing a tool
|
|
31
|
+
|
|
32
|
+
```mermaid
|
|
33
|
+
flowchart LR
|
|
34
|
+
start(["request"]):::ink --> q1{"existing<br/>image?"}:::cream
|
|
35
|
+
q1 -- "no" --> gen["generate_image"]:::rust
|
|
36
|
+
q1 -- "yes" --> q2{"only a flat<br/>backdrop to remove?"}:::cream
|
|
37
|
+
q2 -- "yes" --> rb["remove_background<br/>local · no quota"]:::teal
|
|
38
|
+
q2 -- "no" --> edit["edit_image<br/>edit or use as reference"]:::rust
|
|
39
|
+
gen --> q3{"needs<br/>transparency?"}:::cream
|
|
40
|
+
edit --> q3
|
|
41
|
+
q3 -- "yes" --> tr["background: transparent<br/>check 'alpha verified'"]:::ochre
|
|
42
|
+
q3 -- "no" --> done(["save to output_path,<br/>report the path"]):::ink
|
|
43
|
+
tr --> done
|
|
44
|
+
classDef ink fill:#2A2523,stroke:#9A8C76,color:#E4D9C6
|
|
45
|
+
classDef rust fill:#A6553B,stroke:#7E3F2B,color:#FFFFFF
|
|
46
|
+
classDef ochre fill:#D9A05B,stroke:#B5813F,color:#2A2523
|
|
47
|
+
classDef teal fill:#4E6E63,stroke:#3A544B,color:#FFFFFF
|
|
48
|
+
classDef cream fill:#E4D9C6,stroke:#A89A80,color:#2A2523
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## generate_image
|
|
52
|
+
|
|
53
|
+
Generate a new image from a text prompt. The server calls `POST https://chatgpt.com/backend-api/codex/images/generations`.
|
|
54
|
+
|
|
55
|
+
| Parameter | Type | Default | Description |
|
|
56
|
+
|---|---|---|---|
|
|
57
|
+
| `prompt` | string, 1–32 000 chars | required | The image description. Structure it: use case, subject, style, composition, lighting, palette, exact text in quotes, constraints. |
|
|
58
|
+
| `aspect_ratio` | enum | `auto` | `1:1` `4:5` `5:4` `4:3` `3:4` `3:2` `2:3` `16:9` `9:16` `21:9` `9:21`. Appended to the prompt as, for example, `Aspect ratio: 16:9, wide landscape (horizontal) canvas.` |
|
|
59
|
+
| `background` | enum | `auto` | `transparent` returns a PNG with real alpha. `opaque` asks for a filled background. |
|
|
60
|
+
| `n` | int, 1–4 | `1` | Variants of the *same* prompt, sent as concurrent requests. Each counts against the quota. |
|
|
61
|
+
| `output_path` | string | image library | A `.png`, `.jpg` or `.jpeg` file, or a directory (existing, or ending in `/`). With `n > 1`, `-1`, `-2`… is inserted before the extension. |
|
|
62
|
+
| `output_format` | `png` · `jpeg` | `png` | JPEG is converted locally, flattened on white, and can't be transparent. It's inferred from the `output_path` extension. |
|
|
63
|
+
| `overwrite` | bool | `false` | When false, an existing file is never replaced; the next free `name-2.png`, `name-3.png`… is used. |
|
|
64
|
+
| `include_preview` | bool | `true` | Attach a JPEG preview (longest edge 1024 px, transparency shown as a checkerboard). |
|
|
65
|
+
|
|
66
|
+
> [!TIP]
|
|
67
|
+
> The service picks the pixel size itself and sizes the canvas from the prompt. Measured results: `16:9` → 1672×941, `9:16` → 941×1672, `21:9` → 1916×821, `1:1` → 1254×1254. For exact dimensions, generate the closest ratio, then resize or crop locally.
|
|
68
|
+
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> `background: "opaque"` is a **hint**. In one measured case the service returned a transparent PNG when the prompt described a backdrop that "will be keyed out", even though `opaque` was sent. If you need a filled background, describe it as part of the picture.
|
|
71
|
+
|
|
72
|
+
**Default location** (no `output_path`): `$CODEX_IMAGEGEN_OUTPUT_DIR`, which defaults to `~/.local/share/codex-imagegen-mcp/images`, in `/YYYY-MM-DD/HHMMSS-<prompt-slug>.png`.
|
|
73
|
+
|
|
74
|
+
**The result has three parts:**
|
|
75
|
+
|
|
76
|
+
1. **Text.** One line per saved file (path, dimensions, format, size, background, id), then any warnings, then guidance for the model.
|
|
77
|
+
2. **Image blocks.** One preview per saved file, when `include_preview` is on.
|
|
78
|
+
3. **`structuredContent`**, validated against the declared `outputSchema`:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"images": [
|
|
83
|
+
{ "id": "img_aa289474550c", "path": "/abs/project/assets/hero.png", "mime_type": "image/png",
|
|
84
|
+
"bytes": 2063882, "width": 1672, "height": 941, "background": "opaque" }
|
|
85
|
+
],
|
|
86
|
+
"prompt": "…the exact prompt sent, including the aspect-ratio line…",
|
|
87
|
+
"elapsed_ms": 22834,
|
|
88
|
+
"failures": [],
|
|
89
|
+
"warnings": []
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
When transparency was requested, each image also carries `transparent: true|false`. It records whether the decoded PNG actually contains non-opaque pixels, which is what the text reports as *alpha verified*.
|
|
94
|
+
|
|
95
|
+
**Partial success:** with `n > 1`, finished variants are saved and returned, and failed ones are listed in `failures`. The call is an error (`isError: true`) only if nothing was produced.
|
|
96
|
+
|
|
97
|
+
## edit_image
|
|
98
|
+
|
|
99
|
+
Edit images, or generate using reference images. The server calls `POST https://chatgpt.com/backend-api/codex/images/edits` with the images inlined as data URLs. It takes every `generate_image` parameter, plus:
|
|
100
|
+
|
|
101
|
+
| Parameter | Type | Description |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `images` | string[], 1–5 | Local paths (absolute, `~/…`, workspace-relative), `file://` URLs, `http(s)://` URLs (downloaded with a 60 s timeout), or `data:image/…;base64,…`. PNG, JPEG or WebP, up to 15 MB each, detected by magic bytes. |
|
|
104
|
+
|
|
105
|
+
- `images[0]` is **Image 1**, the primary edit target. Refer to the inputs by index in the prompt, and spell out what must stay unchanged.
|
|
106
|
+
- The input files are never modified.
|
|
107
|
+
- To iterate on a result, pass the previous output path as Image 1.
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
Image 1: add a tiny woven straw hat on top of the cactus, tilted slightly.
|
|
111
|
+
Keep the cactus, flowers, pot, outline and transparent background exactly unchanged.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## remove_background
|
|
115
|
+
|
|
116
|
+
A local chroma-key cutout, ported to TypeScript from the Codex skill's `scripts/remove_chroma_key.py`. It uses the same algorithm, makes no network call and costs no quota.
|
|
117
|
+
|
|
118
|
+
| Parameter | Type | Default | Description |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| `input_path` | string | required | PNG or JPEG |
|
|
121
|
+
| `output_path` | string (`.png`) | `<input>-transparent.png` | Never overwrites unless `overwrite: true` |
|
|
122
|
+
| `key_color` | `#rrggbb` | auto | When omitted, the median of a 6 px border band |
|
|
123
|
+
| `soft_matte` | bool | `true` | Smoothstep alpha between `transparent_threshold` and `opaque_threshold`, combined with key-channel dominance |
|
|
124
|
+
| `despill` | bool | `true` | Caps key-coloured channels on semi-transparent pixels |
|
|
125
|
+
| `tolerance` | 0–255 | `12` | Hard key (`soft_matte: false`): the maximum per-channel distance treated as background |
|
|
126
|
+
| `transparent_threshold` | 0–255 | `12` | Soft matte: at or below this distance a pixel is fully transparent |
|
|
127
|
+
| `opaque_threshold` | 0–255 | `96` | Soft matte: at or above this distance a pixel is fully opaque |
|
|
128
|
+
| `edge_contract` | 0–16 | `0` | Erode the matte N px (3×3 minimum filter) to remove halos |
|
|
129
|
+
| `edge_feather` | 0–64 | `0` | Gaussian blur radius for the alpha edge |
|
|
130
|
+
| `overwrite`, `include_preview` | bool | `false`, `true` | As above |
|
|
131
|
+
|
|
132
|
+
The result reports the key colour it used and the percentage of fully transparent and soft-edge pixels. It warns when nothing matched the key, or when more than 97% of the image became transparent.
|
|
133
|
+
|
|
134
|
+
<p align="center">
|
|
135
|
+
<img src="assets/examples/remove-background.jpg" width="78%" alt="A striped balloon generated on a flat green backdrop, and the same balloon cut out with remove_background">
|
|
136
|
+
<br><sub>Real run: key auto-detected as <code>#03f902</code> · 63.8% fully transparent · 0.4% soft edge pixels.</sub>
|
|
137
|
+
</p>
|
|
138
|
+
|
|
139
|
+
## auth_status
|
|
140
|
+
|
|
141
|
+
| Parameter | Default | Description |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `check_usage` | `true` | Also fetch `GET /backend-api/wham/usage` (free) for the usage windows |
|
|
144
|
+
|
|
145
|
+
The text report covers:
|
|
146
|
+
- the active source, account email, plan and account suffix;
|
|
147
|
+
- when the token expires;
|
|
148
|
+
- the usage windows, e.g. `Codex 5-hour window: 6% used, resets in 32m`;
|
|
149
|
+
- any sign-in in progress, and the outcome of the last one;
|
|
150
|
+
- every credential source with its state: `✓` ready, `·` missing, `✗` expired or unusable, `-` disabled.
|
|
151
|
+
|
|
152
|
+
## sign_in
|
|
153
|
+
|
|
154
|
+
| Parameter | Default | Description |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `method` | `browser` | `browser`: an authorize link that redirects to `http://localhost:1455` on this machine. `device`: a code to enter at `https://auth.openai.com/codex/device` from any device. |
|
|
157
|
+
| `open_browser` | `true` | Try to open the link on this machine |
|
|
158
|
+
| `force` | `false` | Start a new sign-in even when one already exists, e.g. to switch account or workspace |
|
|
159
|
+
|
|
160
|
+
The tool returns the link or code **immediately**, and the sign-in completes in the background. Only one sign-in runs at a time, so a second call returns the pending one. The model should relay the link or code verbatim, then call `auth_status` to confirm. [How sign-in works →](AUTH.md)
|
|
161
|
+
|
|
162
|
+
## Errors
|
|
163
|
+
|
|
164
|
+
Errors come back as `isError: true` results. The text states both the problem and the next step:
|
|
165
|
+
|
|
166
|
+
| Kind | Typical message → next step |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `not_signed_in` | *Not signed in to ChatGPT. Sign in by running `… login` … or call the `sign_in` tool* |
|
|
169
|
+
| `session_expired` | *Your sign-in was invalidated … Please sign in again.* |
|
|
170
|
+
| `auth_failed` | HTTP 401 means the credentials were rejected; 403 means the plan or workspace lacks the feature |
|
|
171
|
+
| `usage_limit` | *You've hit your ChatGPT image-generation usage limit (plus plan). It resets in 1h 12m …* → don't retry |
|
|
172
|
+
| `content_policy` | *The request was rejected by OpenAI's safety system: …* → rephrase |
|
|
173
|
+
| `invalid_request` · `invalid_input` · `unsupported` | Bad parameters, paths, formats or sizes → fix the arguments |
|
|
174
|
+
| `server_error` · `network` · `timeout` | Transient. The server already retried 5xx and network errors twice (after 1 s and 3 s), so one more try is reasonable |
|
|
175
|
+
| `blocked` | A Cloudflare challenge → try later or from another network |
|
|
176
|
+
|
|
177
|
+
The ChatGPT request id (`x-codex-imagegen-request-id`) is appended when available.
|
|
178
|
+
|
|
179
|
+
## Resources
|
|
180
|
+
|
|
181
|
+
| URI | Type | Content |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `imagegen://history` | `application/json` | The 50 most recent saved images, newest first: id, time, tool, path, size, prompt, inputs, request ids |
|
|
184
|
+
| `imagegen://images/{id}` | image blob | The saved file, or a 2048 px JPEG preview if it is larger than 8 MB. The listing shows the 25 most recent. |
|
|
185
|
+
| `imagegen://skill/SKILL.md`, `imagegen://skill/references/*.md` | `text/markdown` | The bundled skill, for clients without Agent Skills support |
|
|
186
|
+
|
|
187
|
+
History is also appended to `$CODEX_IMAGEGEN_HOME/history.jsonl`.
|
|
188
|
+
|
|
189
|
+
## Prompts
|
|
190
|
+
|
|
191
|
+
| Prompt | Arguments | Expands to |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| `generate` | `description` | A request to use `generate_image` with the skill's workflow checklist |
|
|
194
|
+
| `edit` | `image`, `change` | A request to use `edit_image` with invariant-preserving instructions |
|
|
195
|
+
|
|
196
|
+
In opencode they appear as `/imagegen:generate` and `/imagegen:edit`.
|
|
197
|
+
|
|
198
|
+
## Progress, timeouts and cancellation
|
|
199
|
+
|
|
200
|
+
```mermaid
|
|
201
|
+
sequenceDiagram
|
|
202
|
+
participant C as MCP client
|
|
203
|
+
participant S as imagegen server
|
|
204
|
+
participant B as ChatGPT backend
|
|
205
|
+
C->>S: tools/call (with a progress token)
|
|
206
|
+
S->>B: POST /images/generations
|
|
207
|
+
loop every 5 s
|
|
208
|
+
S-->>C: notifications/progress, which resets the client's request timeout
|
|
209
|
+
end
|
|
210
|
+
B-->>S: PNG after 15–60 s
|
|
211
|
+
S-->>C: result
|
|
212
|
+
Note over C,S: notifications/cancelled aborts the HTTP request immediately
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- **Progress:** while a request runs, the server sends a progress notification every 5 s, provided the client supplied a progress token. opencode supplies one and resets its request timeout on each notification (`resetTimeoutOnProgress`), so 15–60 s generations never hit its 60 s default.
|
|
216
|
+
- **Timeout:** the backend request itself times out after `CODEX_IMAGEGEN_TIMEOUT_MS`, 300 s by default.
|
|
217
|
+
- **Cancellation:** cancelling the tool call aborts the HTTP request.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
<p align="center"><a href="README.md">← Docs home</a> · <a href="AUTH.md">Authentication →</a></p>
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codex-imagegen-mcp",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "MCP server + Agent Skill that brings OpenAI Codex's image generation to any MCP client (opencode, Claude Code, Cursor, VS Code and more), running on your ChatGPT plan with no API key.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Shalom Obongo (https://github.com/ShalomObongo)",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/ShalomObongo/codex-imagegen-mcp.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/ShalomObongo/codex-imagegen-mcp#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/ShalomObongo/codex-imagegen-mcp/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"codex-imagegen-mcp": "dist/src/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"main": "dist/src/server/index.js",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist/src",
|
|
22
|
+
"skill",
|
|
23
|
+
"docs/*.md",
|
|
24
|
+
"README.md",
|
|
25
|
+
"CHANGELOG.md",
|
|
26
|
+
"LICENSE",
|
|
27
|
+
"NOTICE"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=22"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
34
|
+
"build": "npm run clean && tsc -p tsconfig.json && node -e \"require('node:fs').chmodSync('dist/src/cli.js', 0o755)\"",
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
+
"test": "npm run build && node --test --test-concurrency=1 \"dist/test/**/*.test.js\"",
|
|
37
|
+
"start": "node dist/src/cli.js serve",
|
|
38
|
+
"prepack": "npm run build"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"mcp",
|
|
42
|
+
"mcp-server",
|
|
43
|
+
"model-context-protocol",
|
|
44
|
+
"image-generation",
|
|
45
|
+
"image-editing",
|
|
46
|
+
"gpt-image",
|
|
47
|
+
"codex",
|
|
48
|
+
"openai-codex",
|
|
49
|
+
"chatgpt",
|
|
50
|
+
"opencode",
|
|
51
|
+
"claude-code",
|
|
52
|
+
"cursor",
|
|
53
|
+
"agent-skills"
|
|
54
|
+
],
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
57
|
+
"jpeg-js": "^0.4.4",
|
|
58
|
+
"jsonc-parser": "^3.3.1",
|
|
59
|
+
"pngjs": "^7.0.0",
|
|
60
|
+
"zod": "^4.6.5"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^26.6.2",
|
|
64
|
+
"@types/pngjs": "^6.0.5",
|
|
65
|
+
"typescript": "^7.0.2"
|
|
66
|
+
}
|
|
67
|
+
}
|