compress-image-mcp 1.0.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.
Files changed (3) hide show
  1. package/README.md +45 -0
  2. package/index.js +132 -0
  3. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # compress-image MCP Server
2
+
3
+ 基于 Tinify 的图片压缩 MCP 服务,供 Cursor 等客户端调用。
4
+
5
+ ## 依赖
6
+
7
+ - 项目根目录的 `internals/compress-image/api-key-list.js` 中已配置 Tinify API Key
8
+ - 项目根目录已安装 `tinify`(与 CLI 共用)
9
+
10
+ ## 安装与运行
11
+
12
+ ```bash
13
+ cd internals/compress-image-mcp
14
+ npm install
15
+ npm start
16
+ ```
17
+
18
+ ## 在 Cursor 中启用
19
+
20
+ 在 Cursor 的 MCP 配置(如 `~/.cursor/mcp.json`)的 `mcpServers` 中添加:
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "compress-image": {
26
+ "command": "node",
27
+ "args": ["/绝对路径/renderbus-neo/internals/compress-image-mcp/index.js"],
28
+ "env": {
29
+ "COMPRESS_IMAGE_API_KEYS": "你的Tinify-API-Key,多个用英文逗号分隔"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ - **args**:仅用于启动进程,不能传 `apiKeyList`。
37
+ - **env.COMPRESS_IMAGE_API_KEYS**:默认 Tinify API Key,多个用英文逗号分隔。配置后调用 `compress_image` 时可不传 `apiKeyList`;调用时若传了 `apiKeyList` 则优先用传入的。
38
+
39
+ 将 `/绝对路径/renderbus-neo` 和 `你的Tinify-API-Key` 替换为实际值。保存后重启 Cursor,即可在对话中调用 `compress_image` 工具。
40
+
41
+ ## 工具说明
42
+
43
+ - **compress_image**
44
+ - `folderPath`(可选):要压缩的目录路径(相对项目根或绝对路径)。不传则压缩当前 git 暂存区中的图片。
45
+ - 支持格式:jpg、png、gif、webp。
package/index.js ADDED
@@ -0,0 +1,132 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
5
+ import { z } from 'zod'
6
+ import { getAllImageFiles, compressImageList } from './core.js'
7
+
8
+ // MCP 由 Cursor 启动时 cwd 一般为工作区根目录
9
+ const projectRoot = process.cwd()
10
+
11
+ // 默认 Key:从环境变量 COMPRESS_IMAGE_API_KEYS 读取(逗号分隔),可在 mcp.json 的 env 中配置
12
+ const defaultApiKeyList = (process.env.COMPRESS_IMAGE_API_KEYS || '')
13
+ .split(',')
14
+ .map((k) => k.trim())
15
+ .filter(Boolean)
16
+
17
+ const server = new McpServer({
18
+ name: 'compress-image',
19
+ version: '1.0.0',
20
+ })
21
+
22
+ async function handleCompressImage(args) {
23
+ const folderPath = args && args.folderPath
24
+ const keys =
25
+ args && args.apiKeyList && args.apiKeyList.length ? args.apiKeyList : defaultApiKeyList
26
+ if (!keys || keys.length === 0) {
27
+ return {
28
+ content: [
29
+ {
30
+ type: 'text',
31
+ text: '未配置 Tinify API Key。请在 mcp.json 的 compress-image.env 中设置 COMPRESS_IMAGE_API_KEYS(逗号分隔),或调用时传入 apiKeyList 参数。',
32
+ },
33
+ ],
34
+ }
35
+ }
36
+ let imgFilePathList = []
37
+ if (folderPath) {
38
+ imgFilePathList = getAllImageFiles(folderPath, projectRoot)
39
+ if (imgFilePathList.length === 0) {
40
+ return {
41
+ content: [
42
+ { type: 'text', text: `路径不存在或该目录下没有 jpg/png/gif/webp 图片: ${folderPath}` },
43
+ ],
44
+ }
45
+ }
46
+ } else {
47
+ const { execSync } = await import('child_process')
48
+ try {
49
+ const diffOutput = execSync('git diff --staged --diff-filter=ACMR --name-only -z', {
50
+ encoding: 'utf8',
51
+ cwd: projectRoot,
52
+ })
53
+ const filePaths = diffOutput.trim() ? diffOutput.trim().split('\x00') : []
54
+ imgFilePathList = filePaths.filter((item) => /\.(jpg|png|gif|webp)$/i.test(item))
55
+ } catch (e) {
56
+ return {
57
+ content: [
58
+ {
59
+ type: 'text',
60
+ text: `获取 git 暂存区文件失败: ${e.message}。可传入 folderPath 指定目录压缩。`,
61
+ },
62
+ ],
63
+ }
64
+ }
65
+ if (imgFilePathList.length === 0) {
66
+ return {
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: '暂存区中没有 jpg/png/gif/webp 图片。请先 git add 图片文件,或传入 folderPath 指定目录。',
71
+ },
72
+ ],
73
+ }
74
+ }
75
+ }
76
+
77
+ const lines = []
78
+ const result = await compressImageList(projectRoot, imgFilePathList, keys, {
79
+ onProgress(current, total, filePath) {
80
+ lines.push(`[${current}/${total}] 已压缩: ${filePath}`)
81
+ },
82
+ })
83
+
84
+ let text = `共处理 ${imgFilePathList.length} 张,成功压缩 ${result.compressed} 张。`
85
+ if (result.failed.length) {
86
+ text += `\n失败 ${result.failed.length} 张: ${result.failed.join(', ')}`
87
+ }
88
+ if (result.errors.length) {
89
+ text += '\n' + result.errors.join('\n')
90
+ }
91
+ if (lines.length) {
92
+ text += '\n\n' + lines.join('\n')
93
+ }
94
+
95
+ return {
96
+ content: [{ type: 'text', text }],
97
+ }
98
+ }
99
+
100
+ server.registerTool(
101
+ 'compress_image',
102
+ {
103
+ description:
104
+ '使用 Tinify 压缩项目中的图片(jpg/png/gif/webp)。可指定 folderPath 压缩该目录下所有图片,不指定则压缩 git 暂存区中的图片。API Key 可在 mcp.json 的 env.COMPRESS_IMAGE_API_KEYS 中配置,或调用时传 apiKeyList。',
105
+ inputSchema: {
106
+ folderPath: z
107
+ .string()
108
+ .optional()
109
+ .describe(
110
+ '可选。要压缩的目录路径(相对项目根或绝对路径)。不传则压缩当前 git 暂存区中的图片。',
111
+ ),
112
+ apiKeyList: z
113
+ .array(z.string())
114
+ .optional()
115
+ .describe(
116
+ '可选。Tinify API Key 数组。不传则使用 mcp.json 中 env.COMPRESS_IMAGE_API_KEYS 的配置(逗号分隔)。',
117
+ ),
118
+ },
119
+ },
120
+ handleCompressImage,
121
+ )
122
+
123
+ async function main() {
124
+ const transport = new StdioServerTransport()
125
+ await server.connect(transport)
126
+ console.error('compress-image MCP Server running on stdio')
127
+ }
128
+
129
+ main().catch((err) => {
130
+ console.error('Fatal error:', err)
131
+ process.exit(1)
132
+ })
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "compress-image-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for compressing images with Tinify",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "compress-image-mcp": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js",
12
+ "publish:public": "npm publish --access public"
13
+ },
14
+ "keywords": [
15
+ "mcp",
16
+ "model-context-protocol",
17
+ "image",
18
+ "compress",
19
+ "tinify"
20
+ ],
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/your-username/compress-image-mcp.git"
25
+ },
26
+ "homepage": "https://github.com/your-username/compress-image-mcp#readme",
27
+ "bugs": {
28
+ "url": "https://github.com/your-username/compress-image-mcp/issues"
29
+ },
30
+ "files": [
31
+ "index.js"
32
+ ],
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.0.0",
35
+ "tinify": "^1.6.0",
36
+ "zod": "^3.23.0"
37
+ }
38
+ }