gpt-image-mcp 0.2.0 → 0.3.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/README.md +9 -113
- package/dist/config.js +22 -1
- package/dist/images.js +8 -4
- package/dist/index.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,28 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
基于 TypeScript 的本地 `stdio` MCP 服务,调用 GPT Image 完成文生图、图片编辑和参考风格创作,图片保存在本机,返回绝对路径及文件 URI。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 安装与配置
|
|
6
6
|
|
|
7
|
-
需要 Node.js 22 或更高版本,以及具有所选模型调用权限和可用额度的 OpenAI 或兼容服务商 API 密钥。支持 Linux、macOS 和 Windows
|
|
7
|
+
需要 Node.js 22 或更高版本,以及具有所选模型调用权限和可用额度的 OpenAI 或兼容服务商 API 密钥。支持 Linux、macOS 和 Windows。无需手动安装,通过 `npx` 自动下载运行。
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
当前可分发 `gpt-image-mcp-0.2.0.tgz`,尚未发布到公共 npm 注册表。收到安装包后,在文件所在目录执行:
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
npm install --global ./gpt-image-mcp-0.2.0.tgz
|
|
15
|
-
gpt-image-mcp --help
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
安装时 npm 会获取运行依赖,用户无需安装 TypeScript 或自行构建。每位用户在自己的 MCP 客户端中配置 Key、端点和输出目录。
|
|
19
|
-
|
|
20
|
-
macOS / Linux 的 MCP 配置示例:
|
|
9
|
+
MCP 配置(适用于 Claude Code、Claude Desktop、Cursor 等支持 MCP 的客户端):
|
|
21
10
|
|
|
22
11
|
```json
|
|
23
12
|
{
|
|
24
13
|
"mcpServers": {
|
|
25
14
|
"image-gen": {
|
|
26
|
-
"command": "
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "gpt-image-mcp"],
|
|
27
17
|
"env": {
|
|
28
18
|
"OPENAI_API_KEY": "你的 API 密钥",
|
|
29
19
|
"OPENAI_BASE_URL": "https://你的服务商/v1",
|
|
@@ -35,68 +25,9 @@ macOS / Linux 的 MCP 配置示例:
|
|
|
35
25
|
}
|
|
36
26
|
```
|
|
37
27
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"command": "cmd",
|
|
43
|
-
"args": ["/d", "/c", "gpt-image-mcp"]
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
如果 GUI 客户端的 PATH 中没有 npm 全局目录,可运行 `npm root --global` 找到安装位置,再配置 `command: "node"`,将该目录下 `gpt-image-mcp/dist/index.js` 的绝对路径填入 `args`。这个方式适用于三个系统。
|
|
48
|
-
|
|
49
|
-
也可以通过本地压缩包临时运行,无需全局安装(替换为安装包实际路径):
|
|
50
|
-
|
|
51
|
-
```sh
|
|
52
|
-
npx --yes --package="/安装包绝对路径/gpt-image-mcp-0.2.0.tgz" gpt-image-mcp --help
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 从源码运行
|
|
28
|
+
仅 `OPENAI_API_KEY` 必填,其余按需配置。详见下方[配置](#配置)章节。
|
|
56
29
|
|
|
57
|
-
|
|
58
|
-
npm ci
|
|
59
|
-
npm run build
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
在 MCP 客户端配置中注册服务。通过 `node` 直接运行构建结果,启动位置不影响默认输出目录。
|
|
63
|
-
|
|
64
|
-
macOS / Linux 示例(把项目路径改成实际绝对路径):
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
{
|
|
68
|
-
"mcpServers": {
|
|
69
|
-
"image-gen": {
|
|
70
|
-
"command": "node",
|
|
71
|
-
"args": ["/你的项目路径/gpt-image-mcp/dist/index.js"],
|
|
72
|
-
"env": {
|
|
73
|
-
"OPENAI_API_KEY": "你的 API 密钥"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Windows 示例,JSON 中使用正斜杠可避免反斜杠转义:
|
|
81
|
-
|
|
82
|
-
```json
|
|
83
|
-
{
|
|
84
|
-
"mcpServers": {
|
|
85
|
-
"image-gen": {
|
|
86
|
-
"command": "node",
|
|
87
|
-
"args": ["C:/你的项目路径/gpt-image-mcp/dist/index.js"],
|
|
88
|
-
"env": {
|
|
89
|
-
"OPENAI_API_KEY": "你的 API 密钥",
|
|
90
|
-
"IMAGE_GEN_OUTPUT_DIR": "D:/pictures"
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
如果客户端找不到 `node`,将 `command` 替换为本机 Node.js 可执行文件的绝对路径。工具执行超时建议设为至少 360 秒,具体配置字段由客户端决定;服务自身的 API 超时默认为 300 秒。
|
|
98
|
-
|
|
99
|
-
服务启动后会等待 MCP 输入,直接在终端运行时没有欢迎输出属于正常行为。日志只写入 stderr,stdout 保留给 MCP 协议。
|
|
30
|
+
首次启动会自动下载依赖,之后使用缓存。工具执行超时建议设为至少 360 秒;服务自身的 API 超时默认为 300 秒。
|
|
100
31
|
|
|
101
32
|
## 配置
|
|
102
33
|
|
|
@@ -108,8 +39,8 @@ Windows 示例,JSON 中使用正斜杠可避免反斜杠转义:
|
|
|
108
39
|
| `IMAGE_GEN_OUTPUT_DIR` | 用户主目录下的 `gpt-image-mcp/images` | 输出根目录,支持本机绝对路径或 `~/`;自动按本地日期创建 `yyyy/MM/dd` 子目录 |
|
|
109
40
|
| `IMAGE_GEN_TIMEOUT_MS` | `300000` | API 请求超时,单位毫秒,必须为不小于 1000 的整数 |
|
|
110
41
|
| `IMAGE_GEN_RESPONSE_FORMAT` | `b64_json` | API 返回图片的方式:`b64_json`(返回 Base64 数据)或 `url`(返回下载地址,服务自动下载保存)。默认 `b64_json` 时不向 API 发送此参数,仅配置 `url` 时才显式发送。部分代理对新模型(如 `gpt-image-2.5-sunburst`)可能不支持此参数,遇到 `unknown_parameter` 错误时请保持默认值 |
|
|
111
|
-
|
|
112
|
-
|
|
42
|
+
| `IMAGE_GEN_DEFAULT_SIZE` | `auto` | 全局默认分辨率,格式为 `WIDTHxHEIGHT`(如 `1024x1024`)。不填或留空时使用 `auto`,由 API 自行决定。宽高需为 16 的倍数,比例不超过 3:1,总像素 655360~8294400。单次调用仍可通过 `size` 参数覆盖 |
|
|
43
|
+
| `IMAGE_GEN_DEFAULT_QUALITY` | `auto` | 全局默认质量:`auto`、`low`、`medium`、`high`、`xhigh`、`max`。不填或留空时使用 `auto`,由 API 自行决定。单次调用仍可通过 `quality` 参数覆盖 |
|
|
113
44
|
|
|
114
45
|
`OPENAI_BASE_URL` 填写 API 根地址;未配置、空字符串或纯空格均使用官方端点。只有地址不包含路径时自动补 `/v1`,已有路径则按用户配置保留,避免破坏代理前缀或其他版本。尾部斜杠会去除,不会重复追加 `/v1`。
|
|
115
46
|
|
|
@@ -136,12 +67,6 @@ Key、提示词和输入图片会发送到你配置的服务商。服务不会
|
|
|
136
67
|
gpt-image-mcp --check
|
|
137
68
|
```
|
|
138
69
|
|
|
139
|
-
从源码使用 `.env` 时:
|
|
140
|
-
|
|
141
|
-
```sh
|
|
142
|
-
node --env-file=.env dist/index.js --check
|
|
143
|
-
```
|
|
144
|
-
|
|
145
70
|
诊断最多等待 30 秒,不自动重试,只请求 `GET /models`,不会调用图片生成或编辑接口。结果说明:
|
|
146
71
|
|
|
147
72
|
| 字段 | 含义 |
|
|
@@ -238,33 +163,4 @@ Windows: C:\Users\用户名\gpt-image-mcp\images\2026\09\10\cozy-otter-paints-mo
|
|
|
238
163
|
|
|
239
164
|
失败返回 `isError: true` 和错误说明。服务关闭自动重试;超时或断线不代表上游没有执行,重新调用可能再次计费。图片生成成功但本地保存失败时会明确提示,不会重新调用生成接口。客户端取消会传递给 API 请求,但无法保证取消上游已开始的计费。
|
|
240
165
|
|
|
241
|
-
## 开发与验证
|
|
242
|
-
|
|
243
|
-
```sh
|
|
244
|
-
npm run check
|
|
245
|
-
npm run test:package
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
执行类型检查、测试及构建。测试通过真实 OpenAI SDK 的模拟 HTTP 响应,覆盖 MCP 工具发现与调用、文生图、多图编辑、自定义端点路由、诊断结果边界、遮罩校验、本地保存、中文及空格路径、并发命名、失败不重试。测试不需要真实密钥,也不消耗图片 API 额度。
|
|
249
|
-
|
|
250
|
-
`test:package` 会在临时目录打包和安装,验证发布文件白名单、npm 命令入口和安装后的 MCP 握手;安装依赖时需要访问 npm 或具有完整本地缓存。
|
|
251
|
-
|
|
252
|
-
GitHub Actions 配置了 Linux、macOS、Windows 和 Node.js 22/24 的检查矩阵。配置存在不代表已在全部系统实际跑过;本地测试不能代替目标系统 CI 或真实 API 验收。
|
|
253
|
-
|
|
254
166
|
真实验收建议用 `quality: "low"` 各执行一次文生图和图生图,确认账号模型权限、网络、图片效果与客户端展示行为。
|
|
255
|
-
|
|
256
|
-
## 制作分发包
|
|
257
|
-
|
|
258
|
-
在源码目录执行:
|
|
259
|
-
|
|
260
|
-
```sh
|
|
261
|
-
npm ci
|
|
262
|
-
npm run check
|
|
263
|
-
npm pack
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
`npm pack` 会自动构建,生成 `gpt-image-mcp-0.2.0.tgz`。分发包仅包含编译结果、`package.json`、README 和 `.env.example`,不包含真实 `.env`、测试文件、源码或 `node_modules`。同一压缩包可发给三种系统的用户安装,安装时会选择对应平台依赖。
|
|
267
|
-
|
|
268
|
-
如以后发布到公共 npm,需要先确定自己有权使用的包名或作用域、发布账号和许可证。当前未执行 `npm publish`,不能假定注册表中的同名包属于本项目;现阶段请使用此项目生成的 `.tgz` 文件。
|
|
269
|
-
|
|
270
|
-
接口依据:[OpenAI 图片生成文档](https://developers.openai.com/api/docs/guides/image-generation)、[MCP 服务开发文档](https://modelcontextprotocol.io/docs/develop/build-server)。
|
package/dist/config.js
CHANGED
|
@@ -36,11 +36,32 @@ export function readConfig(env = process.env) {
|
|
|
36
36
|
if (responseFormat !== "b64_json" && responseFormat !== "url") {
|
|
37
37
|
throw new Error("IMAGE_GEN_RESPONSE_FORMAT 仅支持 b64_json 或 url。");
|
|
38
38
|
}
|
|
39
|
+
const defaultSize = parseDefaultSize(env.IMAGE_GEN_DEFAULT_SIZE?.trim());
|
|
40
|
+
const validQualities = ["auto", "low", "medium", "high", "xhigh", "max"];
|
|
41
|
+
const defaultQuality = (env.IMAGE_GEN_DEFAULT_QUALITY?.trim() || "auto");
|
|
42
|
+
if (!validQualities.includes(defaultQuality)) {
|
|
43
|
+
throw new Error(`IMAGE_GEN_DEFAULT_QUALITY 仅支持 ${validQualities.join("、")}。`);
|
|
44
|
+
}
|
|
39
45
|
return {
|
|
40
|
-
apiKey, baseURL, model, timeout, responseFormat,
|
|
46
|
+
apiKey, baseURL, model, timeout, responseFormat, defaultSize, defaultQuality,
|
|
41
47
|
outputDir: outputDir ? localPath(outputDir) : path.join(homedir(), "gpt-image-mcp", "images"),
|
|
42
48
|
};
|
|
43
49
|
}
|
|
50
|
+
/** 校验 IMAGE_GEN_DEFAULT_SIZE:空值返回 "auto",否则必须满足 WIDTHxHEIGHT 约束。 */
|
|
51
|
+
function parseDefaultSize(value) {
|
|
52
|
+
if (!value)
|
|
53
|
+
return "auto";
|
|
54
|
+
const match = /^(\d+)x(\d+)$/.exec(value);
|
|
55
|
+
if (!match)
|
|
56
|
+
throw new Error("IMAGE_GEN_DEFAULT_SIZE 格式必须为 WIDTHxHEIGHT(如 1024x1024)。");
|
|
57
|
+
const w = Number(match[1]), h = Number(match[2]);
|
|
58
|
+
if (w % 16 !== 0 || h % 16 !== 0 || w <= 0 || h <= 0
|
|
59
|
+
|| Math.max(w, h) / Math.min(w, h) > 3
|
|
60
|
+
|| w * h < 655_360 || w * h > 8_294_400) {
|
|
61
|
+
throw new Error("IMAGE_GEN_DEFAULT_SIZE 宽高需为 16 的倍数,比例不超过 3:1,总像素 655360~8294400。");
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
44
65
|
/** 仅为无路径地址补 /v1;显式路径代表用户选择,不能猜测并改写。 */
|
|
45
66
|
function normalizeBaseURL(value) {
|
|
46
67
|
let url;
|
package/dist/images.js
CHANGED
|
@@ -56,9 +56,11 @@ export class ImageService {
|
|
|
56
56
|
* @throws 上游请求失败、结果不可解析或本地保存失败时抛出错误。
|
|
57
57
|
*/
|
|
58
58
|
async generate(input, signal) {
|
|
59
|
+
const size = input.size === "auto" ? this.config.defaultSize : input.size;
|
|
60
|
+
const quality = input.quality === "auto" ? this.config.defaultQuality : input.quality;
|
|
59
61
|
const response = await this.client.images.generate({
|
|
60
|
-
model: this.config.model, prompt: input.prompt, size
|
|
61
|
-
quality
|
|
62
|
+
model: this.config.model, prompt: input.prompt, size,
|
|
63
|
+
quality, output_format: input.format, n: 1,
|
|
62
64
|
background: input.background,
|
|
63
65
|
moderation: input.moderation,
|
|
64
66
|
...(this.config.responseFormat === "url" && { response_format: "url" }),
|
|
@@ -94,9 +96,11 @@ export class ImageService {
|
|
|
94
96
|
throw new Error("遮罩必须是带透明通道的 PNG,且尺寸与第一张原图一致。");
|
|
95
97
|
}
|
|
96
98
|
}
|
|
99
|
+
const size = input.size === "auto" ? this.config.defaultSize : input.size;
|
|
100
|
+
const quality = input.quality === "auto" ? this.config.defaultQuality : input.quality;
|
|
97
101
|
const response = await this.client.images.edit({
|
|
98
|
-
model: this.config.model, prompt: input.prompt, size
|
|
99
|
-
quality
|
|
102
|
+
model: this.config.model, prompt: input.prompt, size,
|
|
103
|
+
quality, output_format: input.format, n: 1,
|
|
100
104
|
background: input.background,
|
|
101
105
|
image: images.map((image) => image.upload), mask: mask?.upload,
|
|
102
106
|
...(this.config.responseFormat === "url" && { response_format: "url" }),
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { createServer } from "./server.js";
|
|
|
8
8
|
try {
|
|
9
9
|
const args = process.argv.slice(2);
|
|
10
10
|
if (args.length === 1 && args[0] === "--help") {
|
|
11
|
-
process.stdout.write("gpt-image-mcp\n\n用法:\n gpt-image-mcp 启动本地 stdio MCP 服务\n gpt-image-mcp --check 检查模型列表接口,不发送生图请求\n gpt-image-mcp --help 显示帮助\n\n配置:OPENAI_API_KEY、OPENAI_BASE_URL、IMAGE_GEN_MODEL、IMAGE_GEN_OUTPUT_DIR、IMAGE_GEN_TIMEOUT_MS、IMAGE_GEN_RESPONSE_FORMAT\n");
|
|
11
|
+
process.stdout.write("gpt-image-mcp\n\n用法:\n gpt-image-mcp 启动本地 stdio MCP 服务\n gpt-image-mcp --check 检查模型列表接口,不发送生图请求\n gpt-image-mcp --help 显示帮助\n\n配置:OPENAI_API_KEY、OPENAI_BASE_URL、IMAGE_GEN_MODEL、IMAGE_GEN_OUTPUT_DIR、IMAGE_GEN_TIMEOUT_MS、IMAGE_GEN_RESPONSE_FORMAT、IMAGE_GEN_DEFAULT_SIZE、IMAGE_GEN_DEFAULT_QUALITY\n");
|
|
12
12
|
}
|
|
13
13
|
else if (args.length === 1 && args[0] === "--check") {
|
|
14
14
|
const config = readConfig();
|
package/dist/server.js
CHANGED
|
@@ -50,7 +50,7 @@ async function toolResult(operation) {
|
|
|
50
50
|
*/
|
|
51
51
|
export function createServer(config, client = createApiClient(config)) {
|
|
52
52
|
const service = new ImageService(client, config);
|
|
53
|
-
const server = new McpServer({ name: "gpt-image-mcp", version: "0.
|
|
53
|
+
const server = new McpServer({ name: "gpt-image-mcp", version: "0.3.0" });
|
|
54
54
|
const annotations = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
55
55
|
server.registerTool("check_endpoint", {
|
|
56
56
|
title: "端点检查",
|