使用说明
openPic-mcp
openPic-mcp 是一个基于 MCP (Model Context Protocol) 协议的图像能力服务器,为 AI 编程助手提供图片理解、图片比较、图片生成和图片编辑能力。它支持任何 OpenAI-Compatible 的图像 API 服务。
⚠️ 当前版本说明:当前主路径是 stdio 传输,可使用本地编译后的可执行文件,也可通过
go run github.com/AoManoh/openPic-mcp/cmd/vision-mcp@master在线拉取源码并在本机运行。uvx/npx包装入口和远端 Streamable HTTP 服务仍属于后续规划。
功能特性
- MCP 协议兼容:实现 MCP 协议规范,支持 stdio 传输,内置并发服务器引擎
- OpenAI-Compatible:支持任何兼容 OpenAI 图像能力接口的服务
- 能力级凭证:vision 与 image 能力可分别配置 Base URL / Key,适配分组网关部署
- 多种图片输入与格式:Base64、Data URI、HTTP/HTTPS URL、本地文件路径;10 种图片格式
- 图像理解与比较:单图描述与 2-4 张图片的智能比较分析
- 图片生成与编辑:通过 OpenAI-Compatible
/images/generations和/images/edits路由生成或编辑图片 - 异步任务:submit / get / list / cancel 工具集承载长耗时生成任务,不阻塞会话、支持磁盘持久化
快速开始
前置条件
- Go 1.23 或更高版本(本地构建)
- OpenAI API 密钥或兼容服务的访问凭证
本地运行
- 克隆项目
git clone https://github.com/AoManoh/openPic-mcp.git
cd openPic-mcp
- 配置环境变量
cp .env.example .env
# 编辑 .env 文件,填写实际配置
- 构建并运行
go build -o openPic-mcp ./cmd/vision-mcp
./openPic-mcp
在线拉取运行(Go)
如果本机已安装 Go 1.23 或更高版本,可以不手动克隆仓库,直接在 MCP 客户端中使用 go run 拉取并运行:
{
"mcpServers": {
"openPic-mcp": {
"command": "go",
"args": [
"run",
"github.com/AoManoh/openPic-mcp/cmd/vision-mcp@master"
],
"env": {
"OPENPIC_API_BASE_URL": "https://your-server.com/v1",
"OPENPIC_API_KEY": "your-api-key",
"OPENPIC_VISION_MODEL": "your-vision-model-name",
"OPENPIC_IMAGE_MODEL": "your-image-model-name",
"OPENPIC_TIMEOUT": "5m"
}
}
}
}
国内网络环境下,可在 env 中追加 "GOPROXY": "https://goproxy.cn,direct" 与 "GOSUMDB": "sum.golang.google.cn" 加速首次依赖下载。该方式需本机安装 Go,首次启动会下载依赖并编译。
Docker 运行
⚠️ 注意:当前版本仅支持 stdio 传输,Docker 部署暂时无法直接用于 MCP 服务配置。Docker 相关文件是为后续支持 HTTP 传输(Streamable HTTP)预留的,届时将支持端口暴露和远程调用。当前阶段请使用本地运行方式。
Docker 命令参考(开发测试用)
- 配置环境变量
cp .env.example .env
# 编辑 .env 文件,填写实际配置
- 使用 Docker Compose 启动
docker-compose up -d --build
- 查看日志
docker-compose logs -f
- 停止服务
docker-compose down
直接使用 Docker
docker build -t openpic-mcp:latest .
docker run -it --rm \
-e OPENPIC_API_BASE_URL=https://api.openai.com/v1 \
-e OPENPIC_API_KEY=your-api-key \
-e OPENPIC_VISION_MODEL=gpt-5.5 \
-e OPENPIC_IMAGE_MODEL=gpt-image-2 \
openpic-mcp:latest
配置说明
所有配置通过环境变量设置。可以创建 .env 文件或直接设置环境变量。新配置优先使用 OPENPIC_*,并兼容旧的 VISION_*。
| 环境变量 | 必填 | 默认值 | 说明 |
|---|---|---|---|
OPENPIC_API_BASE_URL |
是 | - | OpenAI-Compatible API 基础 URL,兼容 VISION_API_BASE_URL |
OPENPIC_API_KEY |
是 | - | API 密钥,兼容 VISION_API_KEY |
OPENPIC_VISION_MODEL |
是 | - | 视觉理解模型,兼容 VISION_MODEL |
OPENPIC_IMAGE_MODEL |
使用 generate_image 或 edit_image 时必填 |
- | 图片生成或编辑模型 |
OPENPIC_VISION_API_BASE_URL |
否 | 空(回落全局) | vision 能力(describe_image / compare_images)专用 Base URL |
OPENPIC_VISION_API_KEY |
否 | 空(回落全局) | vision 能力专用 API 密钥 |
OPENPIC_IMAGE_API_BASE_URL |
否 | 空(回落全局) | image 能力(generate_image / edit_image 及异步任务)专用 Base URL |
OPENPIC_IMAGE_API_KEY |
否 | 空(回落全局) | image 能力专用 API 密钥 |
OPENPIC_TIMEOUT |
否 | 5m | API 请求超时时间,兼容 VISION_TIMEOUT |
OPENPIC_LOG_LEVEL |
否 | info | 日志级别,兼容 VISION_LOG_LEVEL |
OPENPIC_OUTPUT_DIR |
否 | 空(使用 os.TempDir()/openpic-mcp/) |
generate_image / edit_image 默认落盘目录,必须为绝对路径;可被工具入参 output_dir 覆盖 |
OPENPIC_FILENAME_PREFIX |
否 | 空(使用工具上下文 generate / edit) |
默认文件名前缀,仅允许 [A-Za-z0-9._-]、最长 32 字符、不能以 . 开头;可被工具入参 filename_prefix 覆盖 |
OPENPIC_MAX_INLINE_PAYLOAD_BYTES |
否 | 1048576(1 MiB) | 内联 base64 payload 字节上限。b64_json 模式下超阈直接拒绝;file_path 模式下追加警告。设置 0 / 负值会回退到默认 |
OPENPIC_OVERWRITE |
否 | false | 落盘文件命名冲突时的策略:false 追加 -2/-3 等后缀,true 覆盖同名文件;可被工具入参 overwrite 覆盖 |
OPENPIC_MAX_CONCURRENT_REQUESTS |
否 | 16 | 同时执行的 tools/call 上限;硬上限 100;0/负值/解析失败回退默认;超过上限自动 clamp |
OPENPIC_REQUEST_QUEUE_SIZE |
否 | 64 | tools/call 等待 worker 的有界队列长度;硬上限 10000;同上的 clamp/回退规则。队列满时 recv loop 同步回退处理(绝不丢请求) |
OPENPIC_REQUEST_TIMEOUT |
否 | 0s(不限) | 单个 tools/call 的最大执行时间。0s 表示不超时;图片生成可能需要 1-4 分钟,缺省值正是为了不误杀 |
OPENPIC_SHUTDOWN_TIMEOUT |
否 | 30s | 收到 SIGINT / SIGTERM 后等待 in-flight tools/call 完成的预算;超时则 engineCancel 强制收尾。必须 > 0 |
OPENPIC_LOG_FORMAT |
否 | text | text 或 json。所有日志一律写 stderr,stdout 仅承载 MCP JSON-RPC 帧 |
OPENPIC_TASK_STORE_ENABLED |
否 | true | 异步任务工具集总开关。false 时 submit_image_task / get_task_result / list_tasks / cancel_task 不注册,且不构造 store/dispatcher |
OPENPIC_TASK_DISK_PERSIST |
否 | true | 是否把任务 manifest 落盘到 <OPENPIC_OUTPUT_DIR>/tasks/。true → DiskStore(启动期 fail-fast 校验目录可写);false → MemoryStore,重启即丢 |
OPENPIC_TASK_MAX_QUEUED |
否 | 256 | store 中 queued 状态任务上限;硬上限 10000;满则 submit 返回 ErrQueueFull |
OPENPIC_TASK_MAX_RETAINED |
否 | 1024 | 终态任务保留窗口;硬上限 100000;超过时按 finished_at 升序淘汰最旧 |
OPENPIC_TASK_TTL |
否 | 24h | 终态保留时间(Go duration)。GC 按此清理过期任务;非法/零/负值在 Load 直接报错 |
注意:
OPENPIC_TIMEOUT/VISION_TIMEOUT必须使用 Go 的 duration 格式,例如:30s(30秒)、2m(2分钟)、5m(5分钟)。纯数字如120会导致解析错误。部分图片生成或编辑模型单次推理可能需要 1-4 分钟,不建议将该值设置得过低。服务器并发与生命周期相关的 5 项变量同样使用 Go duration(
*_TIMEOUT)和正整数(*_REQUESTS、*_QUEUE_SIZE)格式。详见下方 服务器行为与调优 章节。
能力级凭证解析优先级:4 个能力级变量均可选、逐字段独立回落。以 vision 的 KEY 为例,解析链为 OPENPIC_VISION_API_KEY > OPENPIC_API_KEY > VISION_API_KEY(legacy);BASE_URL 与 image 方向同构。注意 legacy 变量 VISION_API_BASE_URL 是全局语义,与能力级的 OPENPIC_VISION_API_BASE_URL 是两回事。安全规则:某能力覆盖了 *_API_BASE_URL 却未显式设置对应 *_API_KEY 时,启动直接报错(防止全局 key 被静默发往陌生主机);反向的"只覆盖 KEY、URL 回落全局"完全合法,且是分组网关的主场景。
配置示例
OpenAI(截至 2026-04-29,以 OpenAI API 实际可用为准):
OPENPIC_API_BASE_URL=https://api.openai.com/v1
OPENPIC_API_KEY=your-openai-api-key
# 视觉模型可选:
# - gpt-5.5(2026-04-23 旗舰,推荐默认)、gpt-5.5-pro(高精度)
# - gpt-5.4 / gpt-5.4-pro(平衡)
# - gpt-5.4-mini / gpt-5.4-nano(轻量、高并发、低成本)
# - gpt-5 / gpt-5.2(旧版 snapshot 回退)
OPENPIC_VISION_MODEL=gpt-5.5
# 图像模型可选:gpt-image-2(2026-04-21 旗舰、原生 4K、思考模式)、gpt-image-1.5 / gpt-image-1(前代回退)
OPENPIC_IMAGE_MODEL=gpt-image-2
其他 OpenAI-Compatible 服务(Azure OpenAI / 自托管等):替换 OPENPIC_API_BASE_URL 为对应入口(Azure 形如 https://your-resource.openai.azure.com/openai/deployments/your-deployment),模型名按服务方实际部署填写即可。
分组网关(new-api 类,同一入口、视觉与生图模型分属不同分组 token):
# 全局凭证 = 识图分组 token,vision 工具使用
OPENPIC_API_BASE_URL=https://gateway.example.com/v1
OPENPIC_API_KEY=sk-vision-group-token
OPENPIC_VISION_MODEL=gemini-3.5-flash
# 生图工具单独走生图分组 token,Base URL 自动回落全局
OPENPIC_IMAGE_API_KEY=sk-image-group-token
OPENPIC_IMAGE_MODEL=gemini-3.0-pro-image
双网关(视觉与生图在两家服务上,URL + KEY 成对覆盖):
OPENPIC_API_BASE_URL=https://vision-gateway.example.com/v1
OPENPIC_API_KEY=sk-vision-xxx
OPENPIC_VISION_MODEL=gpt-5.5
# 覆盖了 IMAGE 的 BASE_URL,必须同时显式设置 IMAGE 的 KEY
OPENPIC_IMAGE_API_BASE_URL=https://image-gateway.example.com/v1
OPENPIC_IMAGE_API_KEY=sk-image-xxx
OPENPIC_IMAGE_MODEL=gpt-image-2
排障:model_not_found / 分组无可用渠道
现象:describe_image 正常,但 generate_image / edit_image 报类似错误:
upstream API error (status 503): 分组 xxx 下模型 yyy 无可用渠道(欲了解更多,请咨询管理员)(type=new_api_error, code=model_not_found)
原因:new-api 系网关的一个 token 绑定一个分组,分组按模型路由。视觉模型和生图模型不在同一分组时,单一 token 只能覆盖其中一类工具。错误信息是网关原文透传,分组名与模型名以网关返回为准。
解法:按上方"分组网关"示例,为生图分组单独发一个 token 并设置 OPENPIC_IMAGE_API_KEY(Base URL 不变时无需设置 OPENPIC_IMAGE_API_BASE_URL)。反过来若全局放生图 token,则设置 OPENPIC_VISION_API_KEY 即可。
MCP 配置示例
支持两种 stdio 使用方式:本地编译后的可执行文件路径,或 go run github.com/AoManoh/openPic-mcp/cmd/vision-mcp@master 在线拉取运行(见快速开始)。uvx / npx 包装入口暂未提供。
配置文件位置:
| 客户端 | macOS | Windows |
|---|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json |
%APPDATA%\Claude\claude_desktop_config.json |
| Cursor | ~/.cursor/mcp.json |
%USERPROFILE%\.cursor\mcp.json |
{
"mcpServers": {
"openPic-mcp": {
"command": "/path/to/openPic-mcp",
"args": [],
"env": {
"OPENPIC_API_BASE_URL": "https://api.openai.com/v1",
"OPENPIC_API_KEY": "your-api-key",
"OPENPIC_VISION_MODEL": "gpt-5.5",
"OPENPIC_IMAGE_MODEL": "gpt-image-2",
"OPENPIC_TIMEOUT": "5m"
}
}
}
}
重要:
args字段必须显式指定(即使为空数组[]),否则 MCP 客户端可能无法正确启动服务。Windows 下command使用转义路径,如D:\\path\\to\\openPic-mcp.exe。分组网关 / 双网关部署在
env中追加能力级凭证即可,如"OPENPIC_IMAGE_API_KEY": "sk-image-group-token";变量语义与安全规则见配置说明。
服务器行为与调优
openPic-mcp 内置 MCP 服务器引擎(internal/server.Server),负责 JSON-RPC 调度、并发执行 tools/call、取消传播与优雅停机,无需额外服务。调度要点:
tools/call走 worker pool,同时最多并发OPENPIC_MAX_CONCURRENT_REQUESTS个;队列满时由 recv loop 同步回退执行,永不丢请求。initialize/tools/list/notifications/*等轻量消息在 recv loop 同步派发。notifications/cancelled直达对应 in-flight 请求的 ctx,取消立即传播到上游 HTTP 调用。- 收到
SIGINT/SIGTERM后按序收尾:停收新请求 → 排空队列 → 等待 in-flight(预算OPENPIC_SHUTDOWN_TIMEOUT,超时强制取消)→ 关闭 stdio,保证响应不被截断。
调优开关
| 维度 | 变量 | 默认值 | 调优建议 |
|---|---|---|---|
| 并发 worker 数 | OPENPIC_MAX_CONCURRENT_REQUESTS |
16 |
上游账户并发额度紧张时降低;本机算力富余、上游放得开时提高(最大 100) |
| 排队 buffer | OPENPIC_REQUEST_QUEUE_SIZE |
64 |
客户端瞬时高并发但希望尽量异步处理时调大(最大 10000);不希望累积时调小 |
| 单请求预算 | OPENPIC_REQUEST_TIMEOUT |
0s(不限) |
0s 是为了不误杀图片生成;如需为 tools/call 设硬超时,建议 ≥ 90s |
| 优雅停机预算 | OPENPIC_SHUTDOWN_TIMEOUT |
30s |
工具长耗时(图片生成)建议拉长到 60s–120s;日志/CI 场景缩到 5s–10s 也可 |
| 日志格式 | OPENPIC_LOG_FORMAT |
text |
接 ELK/Loki 等日志栈选 json;本地终端调试选 text |
所有日志经 slog 统一写 stderr(stdout 仅承载 MCP 协议帧),生命周期与每条请求链路均有结构化事件。重点关注两个信号:req.queue_full_fallback 持续出现说明并发配置不足;server.shutdown_timeout_exceeded 说明停机预算被长耗时工具打穿,建议拉长 OPENPIC_SHUTDOWN_TIMEOUT。
异步任务模型
为支持长耗时图片生成(90 秒 ~ 4 分钟),提供异步 submit/get 工具集:客户端立即拿到 task_id 不阻塞会话,再按需轮询结果。任务由独立 worker pool 执行,与同步 tools/call 的 pool 完全解耦——毫秒级请求不会被 90 秒级生图任务挤占槽位。
状态机:queued → running → completed / failed / cancelled;进程停机或重启时未完成任务转 abandoned,结果确定可查、不悬挂。
4 个工具
| 工具 | 入参 | 返回 | 用途 |
|---|---|---|---|
submit_image_task |
kind (generate_image/edit_image) + params(与同步工具同 schema) |
{task_id, state, submitted_at} |
立即返回,不阻塞会话 |
get_task_result |
task_id + 可选 wait(Go duration,严格 ≤ 5m,超出硬报错) |
完整 Task(状态+结果+错误+时间戳) |
wait=0s 立即快照;wait>0 long-poll 至终态或超时;超过 5m 的预算请通过重新轮询拼接 |
list_tasks |
可选 states[] / kinds[] / since (RFC3339) / all |
{tasks, count} |
默认仅本进程任务;all=true 包含其他 PID 残留。响应体量上限:未过滤时受 OPENPIC_TASK_MAX_RETAINED 约束(默认 1024 → ~1.3 MB,硬上限 100000 → ~10 MB);MCP stdio 不流式,建议高任务量场景下用 since / states 过滤分桶 |
cancel_task |
task_id + 可选 hint |
取消后的 Task |
跨 PID 拒绝;终态任务返回当前快照不变 |
调用示例
// 1. 提交一个生图任务,立即拿到 task_id
{
"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{
"name":"submit_image_task",
"arguments":{
"kind":"generate_image",
"params":{"prompt":"a cat","size":"1024x1024","response_format":"file_path"}
}
}
}
// → {"task_id":"tsk_28341_2026...","state":"queued","submitted_at":"..."}
// 2. 轮询(long-poll,最多 30 秒)
{
"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{
"name":"get_task_result",
"arguments":{"task_id":"tsk_28341_2026...","wait":"30s"}
}
}
// → 终态 Task:state=completed, result.file_path=...
// 3. 列出最近 1 小时的所有 running 任务
{
"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{
"name":"list_tasks",
"arguments":{"states":["running"],"since":"2026-04-29T10:00:00Z"}
}
}
持久化与取消语义
OPENPIC_TASK_DISK_PERSIST=true(默认):每次状态迁移原子写盘到<OPENPIC_OUTPUT_DIR>/tasks/<task_id>.json;重启时把残留的queued/running任务自动转abandoned(hint=process_restart),由调用方决定是否重提。false为纯内存模式,重启即丢,适合无写盘权限的环境。- 跨 PID 隔离:
list_tasks默认只返回本进程任务;cancel_task跨 PID 拒绝,避免误改他人任务。 cancel_task在 MCP 层是确定性的:立即置cancelled、关闭任务 ctx(即刻断开与上游的 TCP 连接)、释放 worker 槽。但**"取消是否节省上游配额"取决于上游实现,本项目不做承诺**——OpenAI 官方与各类代理通常在客户端断连后仍可能完成计算并计费。请把cancel_task当作释放本地资源的工具,而非节流上游配额的手段;担心计费时第一选择是避免发起昂贵请求。- 实测上游 safety filter 改写或 502/503 抖动较多时,首选
submit_image_task异步路径:服务端持久化 +get_task_result(wait=…)可无副作用地等待与重试,而同步路径每次失败都消耗一次tools/call预算。
长耗时调用建议
/v1/images/edits 实测单次 70-220 秒,复合 prompt 可能超过 5 分钟。对所有可能 > 30 秒的图像请求建议用 submit_image_task:即便客户端断连(IDE 重启 / 网络抖动 / long-poll 5m 上限),重连后仍可凭 task_id 取回结果。注意区分两个超时:OPENPIC_TIMEOUT 是对上游的 HTTP client 超时;OPENPIC_REQUEST_TIMEOUT 是单个 tools/call 的 MCP 执行预算。
API/工具说明
describe_image
分析并描述图片内容。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
image |
string | 是 | 图片数据,支持 Base64 编码、Data URI、HTTP/HTTPS URL 或本地文件路径 |
prompt |
string | 否 | 自定义分析提示词,不提供则使用默认提示词 |
detail_level |
string | 否 | 描述详细程度:brief、normal(默认)、detailed |
示例请求:
{
"name": "describe_image",
"arguments": {
"image": "https://example.com/image.jpg",
"prompt": "描述这张图片中的主要内容",
"detail_level": "detailed"
}
}
响应为文本描述;image 也可传本地绝对路径(如 /path/to/image.jpg)。
compare_images
比较多张图片,分析它们的相似点和差异。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
images |
array | 是 | 图片数组(2-4张),每个元素支持 Base64、URL 或本地文件路径 |
prompt |
string | 否 | 自定义比较提示词,不提供则使用默认提示词 |
detail_level |
string | 否 | 比较详细程度:brief、normal(默认)、detailed |
示例请求:
{
"name": "compare_images",
"arguments": {
"images": [
"https://example.com/image1.jpg",
"/path/to/image2.png"
],
"prompt": "比较这两张图片的主要差异",
"detail_level": "detailed"
}
}
响应为文本形式的相似点 / 差异点分析。
generate_image
根据文本提示词生成图片。该工具调用 OpenAI-Compatible /images/generations 路由,需要配置 OPENPIC_IMAGE_MODEL。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
prompt |
string | 是 | 图片生成提示词 |
size |
string | 否 | 输出尺寸,默认 1024x1024;支持 1024x1024、1024x1536、1536x1024、2048x2048 |
quality |
string | 否 | 输出质量,实际取值取决于服务支持情况 |
response_format |
string | 否 | 响应格式:file_path、url 或 b64_json,默认 file_path;仅显式选择 b64_json 时返回内联 Base64;若上游在 url 模式返回 Data URI,服务端会自动落盘并返回 file_path |
n |
number | 否 | 生成图片数量,当前仅支持 1 |
output_dir |
string | 否 | 单次调用的落盘目录,绝对路径,无 .. 段;覆盖 OPENPIC_OUTPUT_DIR;response_format=b64_json 时被忽略 |
filename_prefix |
string | 否 | 单次调用的文件名前缀;规则同 OPENPIC_FILENAME_PREFIX;覆盖部署级默认 |
overwrite |
boolean | 否 | 单次调用的覆盖策略;覆盖 OPENPIC_OVERWRITE |
示例请求:
{
"name": "generate_image",
"arguments": {
"prompt": "一只橘猫坐在窗边,电影感光影",
"size": "1024x1024",
"response_format": "file_path",
"output_dir": "/var/lib/openpic-mcp/images",
"filename_prefix": "demo",
"n": 1
}
}
响应为结构化 JSON,含 images[](file_path / format)与 requested / applied / files[] 等字段,详见下方结构化结果合同。
edit_image
根据输入图片、文本提示词和可选 mask 编辑图片。该工具调用 OpenAI-Compatible /images/edits 路由,需要配置 OPENPIC_IMAGE_MODEL。
参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
image |
string | 是 | 待编辑图片,支持本地文件路径、HTTP/HTTPS URL、Data URI 或原始 Base64 |
prompt |
string | 是 | 图片编辑提示词 |
mask |
string | 否 | 可选 mask 图片,支持本地文件路径、HTTP/HTTPS URL、Data URI 或原始 Base64 |
size |
string | 否 | 输出尺寸,默认 1024x1024;支持 1024x1024、1024x1536、1536x1024、2048x2048 |
quality |
string | 否 | 输出质量,实际取值取决于服务支持情况 |
response_format |
string | 否 | 响应格式:file_path、url 或 b64_json,默认 file_path;仅显式选择 b64_json 时返回内联 Base64;若上游在 url 模式返回 Data URI,服务端会自动落盘并返回 file_path |
n |
number | 否 | 编辑结果数量,当前仅支持 1 |
output_dir |
string | 否 | 单次调用的落盘目录,绝对路径,无 .. 段;覆盖 OPENPIC_OUTPUT_DIR;response_format=b64_json 时被忽略 |
filename_prefix |
string | 否 | 单次调用的文件名前缀;规则同 OPENPIC_FILENAME_PREFIX;覆盖部署级默认 |
overwrite |
boolean | 否 | 单次调用的覆盖策略;覆盖 OPENPIC_OVERWRITE |
示例请求:
{
"name": "edit_image",
"arguments": {
"image": "/path/to/input.png",
"prompt": "给这只猫添加一顶红色帽子",
"size": "1024x1024",
"response_format": "file_path",
"output_dir": "/var/lib/openpic-mcp/images",
"n": 1
}
}
响应结构与 generate_image 一致。
图片生成与编辑兼容性说明
以下说明仅适用于 generate_image 与 edit_image,对 describe_image / compare_images 不生效。
response_format 语义
response_format 是纯 MCP 客户端侧的交付方式:
file_path(默认):openPic-mcp 把上游返回的 base64 字节落到本地临时文件,客户端只看到file_path,避免在 MCP 消息中传输大段 base64。b64_json:openPic-mcp 在响应中保留 base64 字段,适用于客户端需要直接拿到字节的场景。url:等同于file_path,仅在上游返回的是真正可访问的 URL(非 data URI)时才保留为 URL。GPT image 等模型默认只返回 base64,因此通常会被 openPic-mcp 落盘为file_path。
无论入参选哪一种,openPic-mcp 都不会把 response_format 转发给上游 API。社区已确认 GPT image models 在 images/edits 上传该字段会触发与“模型不支持”混淆的错误,因此 server 内部一律省略。
size 与 aspect_ratio
size 默认仅信任 OpenAI 官方 enum:1024x1024、1024x1536、1536x1024。2048x2048 仅在部分 OpenAI-Compatible 代理上可用,原生 OpenAI 不一定支持。
为了避免直接面对像素值,可以使用 aspect_ratio:
1:1→1024x10244:3→1536x10243:4→1024x153616:9→1536x1024(最近的横向预设)9:16→1024x1536(最近的纵向预设)auto→ 留空 size,由上游决定
当 size 与 aspect_ratio 同时给出时,size 优先。
output_format
output_format 用于控制上游生成图片的编码格式(png / jpeg / webp),openPic-mcp 会原样转发到上游。该字段是可选的,留空则使用上游默认(通常为 png)。
声明 vs 实际:
output_format是 advisory 字段,openPic-mcp 无法强制兑现。社区已确认部分 OpenAI-Compatible 实现会静默吞掉output_format:
- OpenAI 官方
gpt-image-1在/v1/images/edits端点对output_format=webp直接返回 400"Supported values are: 'png' and 'jpeg'"。- 多个第三方代理(如 sub2api)会返回成功响应但实际内容仍为 PNG。
为此 openPic-mcp 会在每张返回图片上做 magic bytes 检测,并通过两条额外字段告诉调用方真实情况:
images[i].format:实际检测到的格式(png/jpeg/webp等),文件扩展名也按这个值打。warnings[]:当请求的output_format与检测格式不一致时附加的提示(例如images[0]: requested output_format="webp" but upstream returned "png"; saved as .png)。调用
list_image_capabilities可拿到output_format_enforcement: "advisory"与output_format_notes完整披露。
输出路径策略
generate_image / edit_image 在 response_format=file_path(默认)或 url 模式下会把上游字节落到本地磁盘。落盘行为遵循下列优先级:
- 单次调用入参
output_dir/filename_prefix/overwrite。 - 部署级环境变量
OPENPIC_OUTPUT_DIR/OPENPIC_FILENAME_PREFIX/OPENPIC_OVERWRITE。 - 默认值:
os.TempDir()/openpic-mcp/、工具上下文generate/edit、不覆盖。
文件名模板为 <prefix>-YYYYMMDD-HHMMSS-<8hex>.<ext>,其中:
<ext>来自 magic-byte 检测出的真实格式(png/jpeg/webp/ ...),与output_format是否兑现解耦。<8hex>是 4 字节随机数的十六进制;overwrite=false模式同名冲突时追加-2/-3直到唯一。
output_dir 必须是绝对路径且不含 .. 段,否则在到达上游前直接返回错误。filename_prefix 限制在 [A-Za-z0-9._-]、最长 32 字符且不能以 . 开头。
结构化结果合同
generate_image / edit_image 的响应在保留 images / created / warnings 兼容字段之外,新增以下结构化字段,便于 MCP 客户端区分"调用方传入"与"服务端实际生效":
requested:调用方实际传入的关键参数(prompt/size/aspect_ratio/quality/output_format/response_format/n/output_dir/filename_prefix/overwrite)。未传字段用omitempty省略。applied:发往上游的参数(size/quality/output_format/n)以及最终生效的交付参数(response_format/output_dir/filename_prefix/overwrite)。files[]:每张落盘文件的index/path/size_bytes/format。response_format=b64_json时该字段被省略。usage:仅在上游响应里携带usage时透传input_tokens/output_tokens/total_tokens,缺字段以omitempty省略。openPic-mcp 不会伪造任何 token 数。
内联 payload 字节预算
OPENPIC_MAX_INLINE_PAYLOAD_BYTES 默认 1048576(1 MiB)。
response_format=b64_json模式下若解码后超阈:直接返回isError工具结果,提示改用file_path或下调quality/size,不会静默切换交付方式。response_format=file_path/url模式下若超阈:照常落盘,但响应里会附加一条warnings[],便于调用方主动调参或扩大预算。- 设置为
0或负值会被忽略,回退到默认,避免误关 guard。
502 / upstream_error 误读指南
OpenAI-Compatible 图像上游可能把多种失败都包装为 502 upstream_error。常见情况包括:
- 上游服务临时不可用,可稍后重试。
- 请求参数与目标模型不兼容,例如不支持的
size、response_format或模型路由。 - 图像编辑端点对输入图片本身触发内容审核,但上游没有返回明确的 moderation 错误。
如果同一张图片在多个无害 prompt 下反复 edit 失败、而其他图片同时可以 edit 成功,可能是上游 image moderation 触发。客户端无法可靠区分该情况,建议停止重试并更换输入图片。openPic-mcp 不会自动重试 502/503/504,避免在不可恢复场景下扩大错误面。
图片输入与格式
四种输入方式:Base64 编码、Data URI(data:image/jpeg;base64,...)、HTTP/HTTPS URL、本地文件路径(支持绝对/相对路径,MIME 自动检测)。
支持格式:JPEG、PNG、WebP、GIF、BMP、TIFF、ICO、HEIC/HEIF、AVIF、SVG。实际支持情况取决于上游 API,部分格式(HEIC、AVIF、SVG)可能不被所有服务支持。
开发指南
项目结构
openPic-mcp/
├── cmd/vision-mcp/ # 主程序入口与装配
├── internal/
│ ├── config/ # 配置加载(env / 分层源)+ slog Logger
│ ├── errors/ # 错误定义
│ ├── image/ # 图片输入处理(本地文件、MIME 检测)
│ ├── protocol/ # JSON-RPC / MCP 协议层与取消登记
│ ├── provider/openai/ # OpenAI-Compatible Provider(vision/image 双实例)
│ ├── retry/ # 重试机制
│ ├── server/ # MCP 服务器引擎(worker pool / 队列 / 优雅停机)
│ ├── service/tool/ # 工具管理器
│ ├── taskstore/ # 异步任务存储(Memory / Disk)
│ ├── tools/ # 9 个 MCP 工具实现 + 异步 Dispatcher
│ └── transport/ # 传输层(stdio)
├── pkg/types/ # 公共类型定义
└── .env.example # 环境变量事实源
常用命令
go build -o openPic-mcp ./cmd/vision-mcp # 构建可执行文件
go test -race -count=1 ./... # 运行全量测试(含竞态检测)
go fmt ./... && go vet ./... # 格式化与静态检查
docker build -t openpic-mcp:latest . # 构建 Docker 镜像(HTTP 传输预留)
路线图
v1.0(当前版本)
- ✅ MCP 协议核心实现(stdio 传输)+ 并发服务器引擎
- ✅ OpenAI-Compatible Vision / Image API 支持,能力级凭证覆盖
- ✅ describe_image、compare_images、generate_image、edit_image、list_image_capabilities 工具
- ✅ 异步任务工具集(submit / get / list / cancel)含磁盘持久化
- ✅ 本地文件路径与多格式图片支持(10 种格式)
v1.x(规划中)
- 🔲 图片压缩功能(已设计,待实现)
- 🔲 HTTP/SSE 传输支持
- 🔲 Docker 容器化部署(依赖 HTTP 传输)
- 🔲 发布到 npm,支持
npx方式调用 - 🔲 更多 Vision 工具(UI 分析、代码提取等)
v2.0(远期规划)
- 🔲 托管服务,用户无需部署即可使用
- 🔲 多 Provider 支持(Anthropic、Google 等)
许可证
MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.