Skip to main content
Glama

pixelgate

pixelgate is a stdio MCP server that gives Claude Code two image tools, generate_image and edit_image. Requests go only to a CLIProxyAPI gateway on the loopback interface, which forwards them to GPT Image models using your own ChatGPT subscription; pixelgate itself holds no upstream credentials. It is an unofficial personal project and is not affiliated with or endorsed by OpenAI or Anthropic. Routing a subscription through a gateway may conflict with the providers' terms of service, so use it at your own risk. The rest of this document is in Chinese.

1. 这是什么

pixelgate 是一个 stdio 传输的 MCP 服务,向 Claude Code 提供生成图片与编辑图片两个工具。它把请求发给本机回环地址上的 CLIProxyAPI 网关,由网关用 ChatGPT 订阅的凭据转发到 GPT Image 后端。pixelgate 不持有任何上游凭据,也不调用网关的管理接口;每次调用生成一张图,产物连同回执写进调用方指定的目录。

支持的客户端是 Claude Code,包括经 claudex 启动的 Claude Code 会话(claudex 把 Claude Code 的模型请求转到同一个本机网关)。Codex 自带原生的图像生成能力,不需要也不支持接入本服务。

Related MCP server: imaginate-mcp

2. 前置条件

  • uv,以及 uv 托管的 Python 3.14(uv python install --no-bin 3.14)。

  • 一个在本机运行的 CLIProxyAPI 网关:已用 ChatGPT 订阅登录,监听 127.0.0.1 上的某个端口,并配置了一个供客户端使用的 key。本包要求这个 key 是 64 位小写十六进制串,可以用 openssl rand -hex 32 生成。

  • 一个读取这个 key 的可执行文件(下称 helper):无参数运行,stdout 恰好输出一行 key。最简单的写法是把 key 存进一个权限 0600 的文件,helper 只 cat 它:

    #!/bin/sh
    exec cat "$HOME/.config/pixelgate/client.key"

3. 安装

uv tool install --python 3.14 "pixelgate @ git+https://github.com/0-Br/pixelgate@v0.1.0"

安装后命令 pixelgate 在 ~/.local/bin 下。运行依赖在 pyproject.toml 里钉死版本,因为 uv tool install 不读 uv.lock,钉死才能与开发环境一致。升级时换 tag 重新执行同一条命令并加 --reinstall。

4. 配置

mkdir -m 700 ~/.config/pixelgate
cp config.example.json ~/.config/pixelgate/config.json   # 在仓库根目录执行
chmod 600 ~/.config/pixelgate/config.json
pixelgate check-config --config ~/.config/pixelgate/config.json

check-config 对合法配置打印 ok,否则退出码 2,并在 stderr 给出错误类别。配置文件有四个字段,出现别的字段即拒绝:

字段

取值

version

恒为 1

base_url

只接受 http://127.0.0.1:<端口>/v1,端口必须显式写出,不带用户名、密码、query 与 fragment

client_key_helper

helper 的绝对路径,必须可执行;每次请求前无参数调用一次,超时 5 秒,stdout 必须恰为一行 64 位小写十六进制

model_routes

两个键固定为 gpt-image-2.5-sunburst 与 gpt-image-2.5-flare,值是发往网关的请求名,缺任一键即拒绝

model_routes 的值必须是只归属订阅凭据的请求名。同一个模型名可能同时登记在网关里别的 provider(例如按量计费的 API key)下面,而网关不提供按 provider 选路,所以名字相同不等于走同一条路由。填写前经网关管理接口 GET /v0/management/auth-files 与 /v0/management/auth-files/models?name=<文件名> 核对:两个名字只出现在订阅登录的那份凭据上才能直接填;否则先在网关里给订阅凭据配一个唯一的别名(oauth-model-alias),再把别名填进来。核对时只看文件名、provider、账户类型与模型名,凭据文件的其余字段可能含真实的 key,不要打印。

配置文件缺失、JSON 非法、版本不符、有未知字段、helper 不存在或不可执行时,服务一启动就以退出码 2 结束。网关没有运行时,工具调用返回错误类别 gateway_unreachable;pixelgate 不负责拉起网关。

5. 在 Claude Code 中注册

claude mcp add --scope user pixelgate -- ~/.local/bin/pixelgate --config ~/.config/pixelgate/config.json

注册后工具名是 mcp__pixelgate__generate_image 与 mcp__pixelgate__edit_image。两个工具在工具清单里都带 _meta["anthropic/requiresUserInteraction"]=true,Claude Code 每次调用前都会请用户批准。

6. 工具

工具

必填

可选

行为

generate_image

prompt(非空,不超过 32,000 字符)、output_dir(已存在目录的绝对路径)

references(图片引用数组,0 到 5 张)、model、size、quality、background

没有 references 时走 generations 端点;有则走 edits 端点,参考图依次作为输入图

edit_image

prompt、parent(图片引用)、output_dir

references(0 到 4 张,与 parent 合计不超过 5)、mask(图片引用)、model、size、quality、background

走 edits 端点,parent 为第一张输入图,references 依次在后;回执记录 parent

图片引用的形态是 {"path": "<绝对路径>", "sha256": "<64 位小写十六进制>"}。发出请求前逐张核对:文件存在;不超过 32 MiB;哈希与声明一致;Pillow 能识别(png、jpeg、webp)并完整解码;宽或高不超过 8192,总像素不超过 16,777,216。发送的是读取时形成的内存快照。mask 必须与 parent 格式相同、尺寸相同,并且带 alpha 通道。

参数

取值

model

gpt-image-2.5-sunburst(默认)或 gpt-image-2.5-flare;裸名 gpt-image-2.5、带日期的快照名与其他型号一律拒绝

size

auto(默认)或 <W>x<H>:W 与 H 为 16 的倍数,宽高比在 1:3 到 3:1 之间,单边不超过 3840,总像素在 655,360 到 3,686,400 之间。官方上限是 8,294,400,超过 3,686,400 的部分被官方标为实验性,以 size_experimental 拒绝;超过 8,294,400 以 size_invalid 拒绝

quality

auto(默认)、low、medium、high、xhigh、max

background

auto(默认)、opaque、transparent;透明背景要求输出 png 或 webp,本包固定请求 png,产物带 alpha 通道;后端是否真的给出透明背景,以回执与解码结果为准

每次请求固定发送 n=1、output_format="png"、stream=False,客户端不重试。HTTP 超时为 600 秒,按单次读写操作计,所以上游持续慢速回传时,整次调用可能超过 600 秒。同一个服务进程里已有调用在跑时,第二个调用立即返回 busy,不排队;锁只在进程内生效,同时开着的两个 Claude Code 会话各连一个服务进程,彼此不互斥。

本版没有取消通道:客户端取消一次调用时,服务仍等工作线程跑完,那一次的产物与终态回执照常写盘(成功即 completed),只是客户端拿不到返回。要知道结果,读 output_dir 下最新产物目录里的 receipt.json。

成功时,structuredContent 是回执摘要,content 是一段文本(图片路径、预览路径、尺寸、格式、state)加一个 JPEG 预览图像块。预览质量 85,最长边从 768 像素起,按 100 KB 的 base64 预算依次降到 512、384;仍超预算就省略图像块,并在 warnings 里记 preview_omitted。失败时 isError=true,文本只含错误类别与不含敏感信息的字段,structuredContent 同样是回执摘要。

7. 产物

每次调用在 output_dir 下排他创建目录 <UTC 时间戳>-<uuid4 前 8 位>/(目录权限 0700,文件 0600),内容如下:

文件

内容

inputs/

输入图与 mask 的快照副本:parent.<ext>、ref-<n>.<ext>、mask.<ext>;没有输入图的纯生成调用不建这个目录

prompt.txt

发出的 prompt

request.json

发出的参数,不含凭据与图片字节

receipt.json

回执,字段见下表

image.png

上游返回的原图,不转码

preview.jpg

独立的预览副本

输入预检失败时不创建目录;任何目标文件已经存在即报 artifact_collision,不覆盖。

回执字段(缺失的值写 null,不拿请求值冒充返回值):

键

类型

说明

schema

int

恒为 1

request_id

str

本地生成的 uuid4

operation

str

generate 或 edit

state

str

started、completed、failed、unknown

requested_model、route_model

str

调用方给的型号,与发往网关的请求名

actual_model

str 或 null

上游响应里的 model 字段

requested_size、requested_quality、requested_background

str

发出的值

parent、references、mask

引用对象、数组、引用对象或 null

输入图引用

started_at

str

ISO 8601 UTC,在请求发出前写入

finished_at

str 或 null

到达终态的时间

output

对象或 null

{path, sha256, format, width, height, bytes}

size_mismatch

bool

请求的尺寸不是 auto、实际尺寸又不同时为 true

usage

对象或 null

上游 usage 中的 input_tokens、output_tokens、total_tokens

upstream_request_id

str 或 null

响应头 x-request-id

revised_prompt

str 或 null

上游返回的改写后 prompt,原样记录

preview

对象或 null

{path, bytes, edge}

error

对象或 null

{category, http_status, message_safe}

warnings

str 数组

size_mismatch、preview_omitted

state 的含义:started 在请求发出前写入;completed 只在图片解码成功、全部文件写盘之后写入;请求发出后连接中断、超时或写盘前中断,写 unknown;本地预检失败、建连失败(请求没有发出)与上游返回明确错误,写 failed。持久回执停在 started 的,是进程被杀或机器重启留下的,读取者应理解为「上游结果未知」;本版不做恢复扫描。MCP 返回的摘要包含 request_id、operation、state、requested_model、actual_model、output、preview、size_mismatch、usage、error、warnings、artifact_dir。

output_dir 由调用方给出,本包不设默认值。建议固定用一个用户级的生成库,例如 ~/.local/share/pixelgate/,放在任何 git 仓库之外:每个时间戳目录是一次调用的过程产物,用于溯源与核对额度,数量会随着试构图和改稿不断增长。选中的成品由使用者复制进项目自己的资产目录,随项目做版本管理。清理时按时间戳目录整个删除,删之前看一眼 receipt.json,确认没有别处还在引用它;本包不做自动清理。

8. 错误类别

下表是完整枚举:

类别

含义

config_invalid

配置文件缺失、非法或不符合第 4 节

auth_helper_failed

helper 非零退出、超时或输出格式不符

request_invalid

参数形态错误:类型不符、超长、output_dir 不是已存在目录的绝对路径

input_missing、input_hash_mismatch、input_undecodable、input_too_large

输入图不存在、哈希不符、不能完整解码、超过字节或像素上限

mask_mismatch

mask 与 parent 的格式或尺寸不同,或没有 alpha 通道

model_not_allowed、size_invalid、size_experimental、quality_invalid、background_invalid

型号不在白名单、尺寸不合法、尺寸落在实验区间、质量取值非法、背景取值非法

target_denied

传输层拒绝了发往非回环地址或非 Images 路径的请求;正常调用不会触发,只出现在测试与日志里

gateway_unreachable

连不上配置里的网关,请求没有发出;state 为 failed,不消耗额度

upstream_interrupted

请求已发出,连接在响应读完之前中断;state 为 unknown,上游可能已经生成并消耗了额度

upstream_error

上游返回明确的错误状态

upstream_no_image、upstream_bad_image

响应里的图片数量不为 1,或 base64 非法、解码失败、超过像素上限

response_too_large

响应累计读取超过 64 MiB,中止

artifact_collision、artifact_write_failed

产物目标已存在,或写盘失败

busy

已有调用在跑

timeout

单次读写操作超过 600 秒

cancelled

调用被取消;本版没有取消通道,不会写出这个类别(见第 6 节)

9. 安全边界

  • 构造客户端期间,临时摘掉 OPENAI_BASE_URL、OPENAI_API_KEY、OPENAI_CUSTOM_HEADERS 等 OPENAI_* 变量与各个代理环境变量,构造完成后原样放回;HTTP 客户端不读环境里的代理设置,也不读 .env。

  • 传输层只放行 http://127.0.0.1:<配置端口> 下的 /v1/images/generations 与 /v1/images/edits,不跟随重定向。

  • client key 只在进程内经 helper 取得,不进参数、日志、回执与返回。

  • stdout 上只有 MCP 协议帧;诊断信息写 stderr,而且不含 prompt、图片内容、上游原文与凭据。

10. 开发

uv sync --locked --group dev --python 3.14
uv run --locked pytest
uv run --locked ruff check .
uv run --locked ruff format --check .
uv run --locked basedpyright

测试全部离线:tests/conftest.py 提供合成图片、假 HOME 下的合成 key、回环上的假网关、代理陷阱与诱饵网关,不访问真实网关。类型检查相对仓库里的基线 .basedpyright/baseline.json 不新增 error。

11. 许可证

MIT,见 LICENSE。

Related MCP Connectors

Related MCP Servers