Skip to main content
Glama
zztdandan

image-generate-mcp-remote

by zztdandan
README.md
# image-generate-mcp-remote

一个基于 UV + Python 的远程 MCP 图片生成服务,统一封装 OpenAI Images 兼容接口与 Gemini `generateContent` 生图接口。

> 本子项目在源码仓开发时复用工作区根目录 `.venv`。这只适用于开发与测试;正式 systemd 部署推荐使用 wheel 安装到独立部署目录 `.venv`,不要使用源码 editable 安装作为生产形态。

> 注意,timeout 为关键参数;每个 MCP 图片请求固定只发起 `1` 次上游尝试,`retry_count=0`,失败后立即返回失败。各 preset 现有的上游 HTTP timeout 保持不变。如果不设置客户端超时,默认 `30` 秒通常仍不足以等待图片生成。
> 文档仍推荐将 MCP 客户端 `timeout` 显式设置为 `500000` 毫秒(500 秒),用于覆盖单次上游生成预算并为网络抖动留出余量。

## 项目能力

- 提供 `gpt_image_2_official` 工具,兼容 OpenAI Images 风格的文生图与参考图编辑
- 提供 `nano_banana_2_official` 工具,兼容 Gemini `generateContent` 风格的文生图与参考图编辑
- 提供 `gpt_image_2_temporary` 与 `nano_banana_2_temporary` 临时探索工具,用于陌生兼容站点试跑;成功后应固化为正式 preset
- 提供 `list_image_tools_catalog` 工具,用于输出当前服务的 default-active preset、尺寸支持、参数指导与非敏感环境变量信息
- 提供 `skills/gpt-icon-generate/SKILL.md` 图标生成技能,约定规则网格图标板生成、校验和切图流程
- 提供 `skills/img-gen` 独立生图技能,不依赖 MCP 中间层,直接通过 OS 环境变量读取配置并发起 HTTP 请求,与 MCP 服务端具备同等的 GPT Image 2 / Nano Banana 2 生图与编辑能力

## 启动期预设(Preset)

Provider、model、base_url、timeout 及字段派发行为默认由启动期 preset 决定;重试不再属于 preset 可调策略,固定为 `0`。

这次 `1.0.0-beta1` 版本把“不同供应商 / 不同兼容站点的差异”正式上收为一层稳定的预设体系:

- 正式工具对外仍保持稳定的 MCP tool schema,不因为切换供应商就改参数结构
- 站点差异不再散落在 tool 逻辑或零散环境变量里,而是收敛到内置 preset class
- 每个 preset 负责声明自己的 `provider`、`model`、`base_url`、`timeout`、支持 `mode`、尺寸能力与字段派发策略;所有 preset 的 `retry_count` 固定为 `0`
- catalog 的职责也从“配置报告”收敛为“调用指导”:告诉调用方当前 active preset 下该怎么安全传参

可以把 preset 理解为:

> “同一个 MCP 图片工具,在某个供应商 / 某个模型 / 某种协议下,应该怎样发请求、哪些字段该转发、支持哪些尺寸与模式、超时如何设置。”
> 由于不同第三方供应商之间,虽然大致遵循同一个 调用规范,但是总有这里那里的细节不同,有些不能发 quality ,有些不能发size,有些默认就有超时,有些需要我们自己设置超时;所以我们把这些细节都收敛到 preset 里,调用方只要选对 preset,剩下的可以编码处理。


- **启动期选择 active preset**:通过环境变量决定正式工具默认绑定哪个 preset
- **按次临时切换 preset**:正式工具允许本次调用临时传入 `preset + api_key`,但不重新暴露 `base_url`、`model`、`timeout`、`retry` 这类底层运行参数
- **class-first preset registry**:稳定供应商能力通过内置 preset class 注册,而不是 YAML 或运行时自由拼配置
- **临时探索与正式 preset 分离**:陌生兼容站点可以走 `*_temporary` 工具临时跑,如果你觉得合适,就可以提PR或自行修改源码添加新的 preset 预设。
- **具体哪些字段会传到 post 请求以进行真正生图**:现在不用 mcp 调用方指定了,每个预设可以处理这些细节问题——`quality`、`size`、`output_format`、`background`、`moderation` 是否真正发给上游,不再让调用方猜测,而由当前 preset 的 dispatch policy 决定

- `gpt_image_2_official` 与 `nano_banana_2_official` 允许按次传入 `preset` 与 `api_key` 做临时覆盖
- 如果按次传入 `preset`,则同一请求里必须同时传入 `api_key`
- 不传按次覆盖参数时,仍回退到环境变量配置的 preset 与 API Key

- 通过local的或服务式配置环境变量 `IMG_GEN_GPT_IMAGE_2_OFFICIAL_PRESET` 选择 `gpt_image_2_official` 的 active preset,例如 `openai_gpt_image_2`、`right_codes_gpt_image_2`、`apiyi_gpt_image_2`、`laozhang_gpt_image_2_default`、`laozhang_gpt_image_2_sora_official`、`laozhang_gpt_image_2_enterprise`、`laozhang_gpt_image_2_vip`
- 通过 `IMG_GEN_NANO_BANANA_2_OFFICIAL_PRESET` 选择 `nano_banana_2_official` 的 active preset,例如 `google_nano_banana`、`apiyi_nano_banana_2`
- 不配置时回退到内置默认 preset(`openai_gpt_image_2` / `google_nano_banana`)

典型接口:
  - `POST /v1/images/generations`
  - `POST /v1/images/edits`
  - `POST /v1beta/models/{model}:generateContent`

## 通过 uv / PyPI / wheel 安装使用

`uv` 本身没有单独的“官方包仓库”,常规做法是把包发布到 `PyPI`,然后让用户通过 `uv` 直接下载运行。

当前发布链路会把 GitHub Release 对应版本自动发布到 `PyPI`。

- PyPI 项目名:`image-generate-mcp-remote`
- 本地开发可用:`uv tool install image-generate-mcp-remote`
- 正式部署更推荐:构建 `.whl` 后安装到部署目录自己的 `.venv`
- 推荐阅读真实部署与 MCP 配置导览:`./SYSTEMD_DEPLOYMENT_GUIDE.md`

例如,安装 `v1.0.0-beta1` 后可用于远端 MCP 服务部署或供 MCP 客户端以 `stdio` 模式拉起:

```bash
# 安装为全局工具
uv tool install image-generate-mcp-remote

# 指定版本
uv tool install --refresh image-generate-mcp-remote==1.0.0-beta1
```

如果你要做正式的 `systemd --user` 远端部署,推荐流程不是直接把源码目录长期放在线上运行,而是:

```bash
uv build
cp dist/image_generate_mcp_remote-1.0.0b1-py3-none-any.whl <deploy-root>/wheels/
uv venv <deploy-root>/.venv
uv pip install --python <deploy-root>/.venv/bin/python <deploy-root>/wheels/image_generate_mcp_remote-1.0.0b1-py3-none-any.whl
```

这样部署后,服务运行代码来自 wheel 安装结果,而不是源码 editable 注入。

## 从源码安装与启动(开发模式)

这一节只用于本地开发、测试、调试,不是推荐的正式部署方式。

### 1. 安装依赖

```bash
uv sync
cp .env.example .env
```

### 2. 配置环境变量

至少填写你要使用的工具对应 API Key:

- `IMG_GEN_GPT_IMAGE_2_OFFICIAL_API_KEY`
- `IMG_GEN_NANO_BANANA_2_OFFICIAL_API_KEY`

### 3. 启动服务

```bash
# Streamable HTTP(默认)
uv run image-generate-mcp-remote --transport streamable-http --host 127.0.0.1 --port 3001

# SSE
uv run image-generate-mcp-remote --transport sse --host 127.0.0.1 --port 3001
```

这里不再单列 `stdio` 的独立启动命令;对本项目而言,`stdio` 的意义在于由 MCP 客户端按配置拉起,而不是人工单独启动。真正的 MCP 配置导览请直接看 `./SYSTEMD_DEPLOYMENT_GUIDE.md`。

## 当前实际部署(systemd --user)

本项目当前真正使用中的远端 MCP 服务,不是 `stdio` 直连,而是 `systemd --user` 托管的 `streamable-http` 服务。

推荐的正式部署形态是:

- 部署目录保存 `.env`、`.venv`、`storage/`、`wheels/`
- `.venv` 中安装的是已构建好的 `.whl`
- systemd 只启动部署目录 `.venv/bin/image-generate-mcp-remote`
- 不依赖源码树是否存在或是否被改动

- 服务名:`image-generate-mcp.service`
- unit 文件位置模式:`~/.config/systemd/user/image-generate-mcp.service`
- 工作目录:部署目录 `<deploy-root>`
- 环境文件:`<deploy-root>/.env`
- 当前接入地址:`http://127.0.0.1:25235/mcp`

部署、更新、修改环境变量、重启服务、OpenCode MCP JSON 配置的完整说明见:

- `./SYSTEMD_DEPLOYMENT_GUIDE.md`

对于当前这个远端服务,需要特别注意:

- 改 OpenCode MCP JSON 里的 `env`,不会改变已启动服务的环境变量
- 要改服务配置,必须修改 `<deploy-root>/.env` 或 `image-generate-mcp.service`
- 改 `.env` 后执行 `systemctl --user restart image-generate-mcp.service`
- 改 `.service` 后执行 `systemctl --user daemon-reload && systemctl --user restart image-generate-mcp.service`

## MCP 配置方式

以下配置示例均为当前项目可直接使用的正确写法。

如果你关注的是真实远端部署、systemd 托管、客户端如何接入在线 MCP 服务,建议优先阅读 `./SYSTEMD_DEPLOYMENT_GUIDE.md`;本节仅保留最常见配置摘要。

### 方式一:通用 stdio 直连(推荐本地开发)

适用于使用通用 MCP 配置风格的客户端,主要是 claude code

```json
{
  "mcpServers": {
    "image-generate-mcp-remote": {
      "type": "stdio",
      "command": "uv",
      "args": [
        "run",
        "image-generate-mcp-remote",
        "--transport",
        "stdio"
      ],
      "timeout": 500000,
      "cwd": "/Users/zhongting/workspace/image-generate-mcp-remote",
      "env": {
        "IMG_GEN_GPT_IMAGE_2_OFFICIAL_API_KEY": "sk-xxxx",
        "IMG_GEN_GPT_IMAGE_2_OFFICIAL_PRESET": "openai_gpt_image_2",
        "IMG_GEN_NANO_BANANA_2_OFFICIAL_API_KEY": "sk-xxxx",
        "IMG_GEN_NANO_BANANA_2_OFFICIAL_PRESET": "google_nano_banana",
        "IMAGE_OUTPUT_DIR": "storage/images",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}
```

### 方式二:OpenCode 本地 stdio 直连

OpenCode 的 `opencode.json` 使用自己的 MCP 配置结构:本地 MCP 需要声明 `type: "local"`,并把启动命令和参数合并写入 `command` 数组;环境变量字段名是 `environment`,不是通用示例里的 `env`;OpenCode 也不使用 `mcpServers` 作为顶层字段,而是使用 `mcp`。

适用于项目级配置文件,例如:`<project>/.opencode/opencode.json`。

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "image-generate-mcp-remote": {
      "type": "local",
      "command": [
        "uv",
        "run",
        "--directory",
        "/absolute/path/to/image-generate-mcp-remote",
        "image-generate-mcp-remote",
        "--transport",
        "stdio"
      ],
      "enabled": true,
      "timeout": 500000,
      "environment": {
        "IMG_GEN_GPT_IMAGE_2_OFFICIAL_API_KEY": "sk-xxxx",
        "IMG_GEN_GPT_IMAGE_2_OFFICIAL_PRESET": "openai_gpt_image_2",
        "IMG_GEN_NANO_BANANA_2_OFFICIAL_API_KEY": "sk-xxxx",
        "IMG_GEN_NANO_BANANA_2_OFFICIAL_PRESET": "google_nano_banana",
        "IMAGE_OUTPUT_DIR": "storage/images",
        "LOG_LEVEL": "INFO"
      }
    }
  }
}
```

两种 stdio 配置的区别:

- 通用 MCP 客户端常见字段:`mcpServers.command + args + cwd + env`
- OpenCode 字段:`mcp.<name>.type=local + command[] + environment`
- 两者启动的是同一个本地 MCP server,差异只在客户端配置 schema,不是服务端能力差异
- 图片生成务必保留较长的客户端侧 `timeout`,推荐 `500000` 毫秒

### 方式三:Streamable HTTP 远程接入

先启动服务:

```bash
uv run image-generate-mcp-remote --transport streamable-http --host 127.0.0.1 --port 3001
```

服务默认 MCP 路径为:`/mcp`

```json
{
  "mcpServers": {
    "image-generate-mcp-remote": {
      "url": "http://127.0.0.1:3001/mcp",
      "timeout": 500000
    }
  }
}
```

上面的 `timeout` 不要省略。每个 MCP 图片请求只进行 `1` 次上游尝试且不会重试;active preset 的现有上游 HTTP timeout 保持不变。文档示例继续推荐 `500000` 毫秒(500 秒),用于覆盖单次生成预算并为网络抖动留出余量。

### 方式四:SSE 远程接入

先启动服务:

```bash
uv run image-generate-mcp-remote --transport sse --host 127.0.0.1 --port 3001
```

服务默认路径为:

- SSE 入口:`/sse`
- 消息通道:`/messages/`

对于要求分别填写 SSE 地址与消息地址的客户端,可使用:

- `http://127.0.0.1:3001/sse`
- `http://127.0.0.1:3001/messages/`

如果客户端还支持单独配置 MCP tool-call 超时,也应显式设置 `timeout`;文档推荐值为 `500000` 毫秒(500 秒),用于覆盖单次上游生成预算,并为网络抖动留出余量。

## 工具列表

### `list_image_tools_catalog`

输出当前服务暴露的图片工具目录,包括:

- 默认网关地址
- 当前有效模型
- 支持模型列表
- 非敏感环境变量生效值

### `gpt_image_2_official`

OpenAI Images 兼容工具。

- `mode=generate` 时调用文生图
- `mode=edit` 时调用参考图编辑 / 图生图
- provider、model、base_url、timeout 及字段派发默认由启动期 preset 决定;上游请求固定只尝试一次
- 可按次传入 `preset` 与 `api_key` 临时切换 preset;若传 `preset`,必须同传 `api_key`
- 尺寸输入统一为 `image_size` + `aspect_ratio` 两个枚举,preset 按共享尺寸合同映射到对应 GPT 请求像素尺寸
- 支持识别 `data[0].b64_json` 与 `data[0].url`;解码或下载及本地落盘在后台线程继续执行
- 如传入不支持的枚举组合,错误信息会直接列出该工具支持的尺寸预设;也可先调用 `list_image_tools_catalog` 查看 `supported_size_presets`

### `nano_banana_2_official`

Gemini `generateContent` 兼容工具。

- `mode=generate` 时调用文生图
- `mode=edit` 时调用参考图编辑 / 图生图
- provider、model、base_url、timeout 及字段派发默认由启动期 preset 决定;上游请求固定只尝试一次
- 可按次传入 `preset` 与 `api_key` 临时切换 preset;若传 `preset`,必须同传 `api_key`
- 鉴权请求头同时发送 `Authorization: Bearer <key>` 与 `x-goog-api-key: <key>` 以兼容更多 Gemini 兼容网关
- 响应解析兼容 `inlineData` / `inline_data` 与 `mimeType` / `mime_type`
- 尺寸输入统一为 `image_size` + `aspect_ratio` 两个枚举,服务会按共享尺寸合同映射到 `imageConfig`
- 共享尺寸合同已同时记录 `gpt` 请求尺寸与 `nano banana` 实际输出尺寸

### `gpt_image_2_temporary`

OpenAI Images 兼容站点的临时探索工具。

- 允许按次传入 `api_key`、`base_url`、`model`、`timeout_seconds`
- 默认只发送保守字段:`model`、`prompt`、由 `image_size + aspect_ratio` 映射得到的 `size`
- `quality`、`output_format`、`background`、`moderation` 默认不发送;只有显式设置对应 `send_*` 参数时才转发
- 不进入 preset registry,不应作为生产默认工具;试跑成功后应新增 provider guide 与正式 preset class
- 输出检测兼容常见 `b64_json`、`url`、markdown 图片链接、data URL 等形态

### `nano_banana_2_temporary`

Gemini `generateContent` 兼容站点的临时探索工具。

- 允许按次传入 `api_key`、`base_url`、`model`、`timeout_seconds`
- 默认发送文本 prompt 与保守 `generationConfig.imageConfig`
- 不进入 preset registry,不应作为生产默认工具;试跑成功后应新增 provider guide 与正式 preset class
- 输出检测兼容 Gemini `inlineData` / `inline_data`,也会扫描文本中的 markdown 图片链接、data URL 与 HTTPS URL

## 异步响应与后台落盘

四个图片生成工具在收到并校验上游 JSON 响应后,会先识别原始图片载荷类型,再启动后台线程完成 base64 解码或 URL 下载、尺寸校验和本地落盘。MCP 调用固定等待 `1` 秒后返回确认结果,不再等待落盘完成。

- `request_completed=true` 表示本轮上游请求已成功返回,不表示后台落盘已经结束
- `persistence_status=processing` 表示应继续等待 `save_path` 出现;后台任务不会再次请求上游
- base64 / `inlineData` 响应返回 `raw_result_type`、具体 `response_format` 和 `estimated_file_size_bytes`,不会返回 URL 或额外的 provider 信息
- URL 响应额外直接返回 `source_url`,但 `message` 会明确要求调用方优先使用 `save_path` 的落盘成果,仅把 URL 作为备用
- 后台解析或落盘失败会写入服务日志;由于 MCP 确认结果已返回,不能回写或改变本次调用结果

## 内置技能

### `img-gen`

- 技能文件:`skills/img-gen/SKILL.md`
- 用途:直接图像生成/编辑,不依赖 MCP 中间层
- 能力:与 MCP 服务端的 `gpt_image_2_official` / `nano_banana_2_official` 同等覆盖 13 个 preset(GPT Image 2 × 10、Nano Banana 2 × 3),支持文生图与参考图编辑
- 配置:纯 OS 环境变量驱动,不读取任何 .env 文件,不绑定特定 profile 路径;所需变量与 MCP 服务端一致(`IMG_GEN_GPT_IMAGE_2_OFFICIAL_API_KEY`、`IMG_GEN_NANO_BANANA_2_OFFICIAL_API_KEY` 等)
- 检测:`python3 scripts/check_env.py` 报告各渠道可用状态与缺省配置,供大模型直接读取判断当前哪个渠道可用
- 适用场景:当 MCP 服务不可用或不需要 MCP 中间层时,直接在终端或 Agent 会话中生图

### `gpt-icon-generate`

- 技能文件:`skills/gpt-icon-generate/SKILL.md`
- 用途:批量图标板生成、规则网格校验、透明 PNG 切图、UI 图标库落盘
- 默认链路:优先使用 `gpt_image_2_official` 生成 `2K`、`1:1`、`4x4 / 16` 图标板
- 附带脚本:`skills/gpt-icon-generate/scripts/verify_image_output.py`、`skills/gpt-icon-generate/scripts/plan_icon_sheet_params.py`、`skills/gpt-icon-generate/scripts/split_icon_sheet_connected_bbox.py`

## 环境变量说明

### GPT Image 工具

| 变量名 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `IMG_GEN_GPT_IMAGE_2_OFFICIAL_API_KEY` | 是 | 空 | `gpt_image_2_official` 使用的 API Key |
| `IMG_GEN_GPT_IMAGE_2_OFFICIAL_PRESET` | 否 | `openai_gpt_image_2` | 启动期 active preset id |

### Nano Banana 工具

| 变量名 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `IMG_GEN_NANO_BANANA_2_OFFICIAL_API_KEY` | 是 | 空 | `nano_banana_2_official` 使用的 API Key |
| `IMG_GEN_NANO_BANANA_2_OFFICIAL_PRESET` | 否 | `google_nano_banana` | 启动期 active preset id |

### 通用变量

| 变量名 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `IMAGE_OUTPUT_DIR` | 否 | `storage/images` | 生成图片的落盘目录 |
| `LOG_LEVEL` | 否 | `INFO` | 日志级别 |


## 许可证

本项目采用 `MIT` 许可证,完整文本见 `LICENSE`。

TDQS

B3.3/5.0

Scored across 6 tools

Disambiguation4/5

The two list tools are clearly distinct, and generation tools are separated by provider and official/temporary mode. However, the official/temporary pairs for each provider still overlap in their core generate/edit action, so an agent may need to read descriptions carefully to choose correctly.

Naming Consistency3/5

Tool names split into list_*_tool and *_official/*_temporary patterns, so there is no uniform verb_noun convention across the server. Within each subset the names are consistent and readable, but the mixed structure prevents a higher score.

Tool Count5/5

Six tools is well-scoped for an image generation server: two config/discovery tools and four generation variants covering two providers and two operating modes. Each tool fills a clear role without feeling redundant.

Completeness5/5

The tool surface covers configuration discovery and both generate/edit workflows via both providers, including a temporary exploration path for unknown providers. Presets are clearly externally managed, so listing them is sufficient and there are no obvious dead ends.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive