oss-mcp-plus 1.0.11 → 1.0.12

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/dist/index.js CHANGED
@@ -802,7 +802,9 @@ ${configNames2.map((name) => `- ${name}`).join("\n")}`
802
802
 
803
803
  \u7B2C 2 \u6B65\uFF1A\u5982\u679C\u56FE\u7247\u5728 OSS \u4E0A\uFF08\u5FC5\u987B\u5728\u8C03\u7528\u672C\u5DE5\u5177\u4E4B\u524D\u5B8C\u6210\uFF01\uFF09
804
804
  - \u5148\u4F7F\u7528 list_oss_files \u5217\u51FA\u6587\u4EF6
805
- - \u4F7F\u7528 download_file \u5C06\u56FE\u7247\u4E0B\u8F7D\u5230\u672C\u5730\u4E34\u65F6\u76EE\u5F55\uFF08\u5982 /tmp/compress-images/\uFF09
805
+ - \u26A0\uFE0F \u91CD\u8981\uFF1A\u4E0B\u8F7D\u5230\u3010\u9879\u76EE\u76EE\u5F55\u3011\u4E0B\u7684 .tmp-compress/ \u6587\u4EF6\u5939\uFF0C\u4E0D\u80FD\u7528 /tmp/\uFF01
806
+ \uFF08Playwright MCP \u53EA\u80FD\u8BBF\u95EE\u9879\u76EE\u76EE\u5F55\u5185\u7684\u6587\u4EF6\uFF09
807
+ - \u4F7F\u7528 download_file \u5C06\u56FE\u7247\u4E0B\u8F7D\u5230\u9879\u76EE\u76EE\u5F55\u4E0B
806
808
  - \u53EA\u6709\u4E0B\u8F7D\u5230\u672C\u5730\u540E\u624D\u80FD\u8C03\u7528\u672C\u5DE5\u5177
807
809
 
808
810
  \u7B2C 3 \u6B65\uFF1A\u8C03\u7528\u672C\u5DE5\u5177
@@ -960,8 +962,9 @@ ${JSON.stringify(questions, null, 2)}
960
962
  \u2705 \u7B2C 1 \u6B65\uFF1A\u9A8C\u8BC1 Playwright MCP \u53EF\u7528
961
963
  \u2192 \u8C03\u7528 browser_snapshot\uFF0C\u5982\u679C\u62A5\u9519\u5219\u505C\u6B62\u5E76\u63D0\u793A\u7528\u6237\u542F\u7528
962
964
 
963
- \u2705 \u7B2C 2 \u6B65\uFF1A\u786E\u4FDD\u56FE\u7247\u5728\u672C\u5730
964
- \u2192 OSS \u56FE\u7247\u5FC5\u987B\u5148\u7528 download_file \u4E0B\u8F7D\u5230\u672C\u5730
965
+ \u2705 \u7B2C 2 \u6B65\uFF1A\u786E\u4FDD\u56FE\u7247\u5728\u9879\u76EE\u76EE\u5F55\u5185
966
+ \u2192 OSS \u56FE\u7247\u5FC5\u987B\u5148\u7528 download_file \u4E0B\u8F7D\u5230\u3010\u9879\u76EE\u76EE\u5F55\u3011\u4E0B\u7684 .tmp-compress/ \u6587\u4EF6\u5939
967
+ \u2192 \u26A0\uFE0F \u4E0D\u80FD\u7528 /tmp/\uFF0CPlaywright \u65E0\u6CD5\u8BBF\u95EE\u9879\u76EE\u5916\u7684\u8DEF\u5F84\uFF01
965
968
 
966
969
  \u2705 \u7B2C 3 \u6B65\uFF1A\u8C03\u7528 check_compress_prerequisites
967
970
  \u2192 \u9A8C\u8BC1\u6587\u4EF6\u5E76\u83B7\u53D6\u8BE2\u95EE\u6A21\u677F
@@ -1143,6 +1146,19 @@ ${JSON.stringify(resultInfo, null, 2)}
1143
1146
  // 生成 TinyPNG 自动化指令
1144
1147
  generateTinyPngInstructions(batches, outputFormat) {
1145
1148
  let instructions = "";
1149
+ instructions += `### \u26A0\uFE0F \u91CD\u8981\u63D0\u793A
1150
+
1151
+ `;
1152
+ instructions += `1. **\u56FE\u7247\u5FC5\u987B\u5728\u9879\u76EE\u76EE\u5F55\u5185**\uFF1APlaywright MCP \u53EA\u80FD\u8BBF\u95EE\u9879\u76EE\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u3002
1153
+ `;
1154
+ instructions += ` - \u4E0D\u80FD\u4F7F\u7528 \`/tmp/\` \u7B49\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55
1155
+ `;
1156
+ instructions += ` - \u8BF7\u5C06\u56FE\u7247\u4E0B\u8F7D\u5230\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u7684 \`.tmp-compress/\` \u6587\u4EF6\u5939
1157
+ `;
1158
+ instructions += `2. **\u4E0A\u4F20\u524D\u5FC5\u987B\u5148\u89E6\u53D1\u6587\u4EF6\u9009\u62E9\u6846**\uFF1A\u5148\u70B9\u51FB\u4E0A\u4F20\u533A\u57DF\uFF0C\u7B49\u5F85 Modal state \u663E\u793A "File chooser" \u540E\u518D\u8C03\u7528 \`browser_file_upload\`
1159
+
1160
+ `;
1161
+ const needsFormatConversion = outputFormat && outputFormat !== "png";
1146
1162
  for (let i = 0; i < batches.length; i++) {
1147
1163
  const batch = batches[i];
1148
1164
  instructions += `#### \u6279\u6B21 ${i + 1}/${batches.length}
@@ -1151,30 +1167,43 @@ ${JSON.stringify(resultInfo, null, 2)}
1151
1167
  instructions += `**\u6587\u4EF6**: ${batch.map((img) => path2.basename(img.path)).join(", ")}
1152
1168
 
1153
1169
  `;
1154
- instructions += `1. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://tinypng.com/\`
1170
+ let stepNum = 1;
1171
+ instructions += `${stepNum++}. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://tinypng.com/\`
1155
1172
  `;
1156
- instructions += `2. **\u7B49\u5F85\u52A0\u8F7D**: \u4F7F\u7528 \`browser_snapshot\` \u786E\u8BA4\u9875\u9762\u52A0\u8F7D\u5B8C\u6210
1173
+ instructions += `${stepNum++}. **\u7B49\u5F85\u52A0\u8F7D**: \u4F7F\u7528 \`browser_snapshot\` \u786E\u8BA4\u9875\u9762\u52A0\u8F7D\u5B8C\u6210
1157
1174
  `;
1158
- instructions += `3. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
1175
+ if (needsFormatConversion) {
1176
+ instructions += `${stepNum++}. **\u5F00\u542F\u683C\u5F0F\u8F6C\u6362\u5F00\u5173**:
1159
1177
  `;
1160
- for (const img of batch) {
1161
- instructions += ` - \`${img.path}\`
1178
+ instructions += ` - \u5728\u9875\u9762\u5E95\u90E8\u627E\u5230 "Convert my images automatically" \u5F00\u5173
1179
+ `;
1180
+ instructions += ` - \u4F7F\u7528 \`browser_click\` \u70B9\u51FB\u5F00\u5173\u5F00\u542F\u5B83\uFF08\u5982\u679C\u662F\u5173\u95ED\u72B6\u6001\uFF09
1181
+ `;
1182
+ instructions += ` - \u5F00\u542F\u540E\u4F1A\u51FA\u73B0\u683C\u5F0F\u9009\u62E9\u9009\u9879
1183
+ `;
1184
+ instructions += `${stepNum++}. **\u9009\u62E9\u8F93\u51FA\u683C\u5F0F**:
1185
+ `;
1186
+ instructions += ` - \u70B9\u51FB\u9009\u62E9 "${outputFormat.toUpperCase()}" \u683C\u5F0F
1162
1187
  `;
1163
1188
  }
1164
- instructions += `4. **\u7B49\u5F85\u538B\u7F29**: \u4F7F\u7528 \`browser_wait_for\` \u7B49\u5F85 "Download all" \u6216\u5404\u6587\u4EF6\u7684 "download" \u6309\u94AE\u51FA\u73B0
1189
+ instructions += `${stepNum++}. **\u89E6\u53D1\u6587\u4EF6\u9009\u62E9\u6846**:
1165
1190
  `;
1166
- if (outputFormat && outputFormat !== "png") {
1167
- instructions += `5. **\u9009\u62E9\u8F93\u51FA\u683C\u5F0F**:
1191
+ instructions += ` - \u4F7F\u7528 \`browser_click\` \u70B9\u51FB\u4E0A\u4F20\u533A\u57DF\uFF08"Drop your .webp, .png or .jpg files here!" \u6587\u5B57\u533A\u57DF\uFF09
1168
1192
  `;
1169
- instructions += ` - \u70B9\u51FB\u538B\u7F29\u7ED3\u679C\u53F3\u4FA7\u7684\u683C\u5F0F\u9009\u62E9\u4E0B\u62C9\u6846
1193
+ instructions += ` - \u7B49\u5F85 \`browser_snapshot\` \u8FD4\u56DE\u7ED3\u679C\u4E2D Modal state \u663E\u793A "[File chooser]"
1170
1194
  `;
1171
- instructions += ` - \u9009\u62E9 "${outputFormat.toUpperCase()}"
1195
+ instructions += `${stepNum++}. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
1196
+ `;
1197
+ for (const img of batch) {
1198
+ instructions += ` - \`${img.path}\`
1172
1199
  `;
1173
1200
  }
1174
- instructions += `${outputFormat && outputFormat !== "png" ? "6" : "5"}. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download all" \u6216\u9010\u4E2A\u4E0B\u8F7D
1201
+ instructions += `${stepNum++}. **\u7B49\u5F85\u538B\u7F29**: \u4F7F\u7528 \`browser_wait_for\` \u7B49\u5F85 "Download all" \u6216\u5404\u6587\u4EF6\u7684 "download" \u6309\u94AE\u51FA\u73B0
1202
+ `;
1203
+ instructions += `${stepNum++}. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download all" \u6216\u9010\u4E2A\u4E0B\u8F7D
1175
1204
  `;
1176
1205
  if (i < batches.length - 1) {
1177
- instructions += `${outputFormat && outputFormat !== "png" ? "7" : "6"}. **\u5237\u65B0\u9875\u9762**: \u4F7F\u7528 \`browser_navigate\` \u91CD\u65B0\u8BBF\u95EE \`https://tinypng.com/\` \u51C6\u5907\u4E0B\u4E00\u6279
1206
+ instructions += `${stepNum++}. **\u5237\u65B0\u9875\u9762**: \u4F7F\u7528 \`browser_navigate\` \u91CD\u65B0\u8BBF\u95EE \`https://tinypng.com/\` \u51C6\u5907\u4E0B\u4E00\u6279
1178
1207
  `;
1179
1208
  }
1180
1209
  instructions += `
@@ -1185,6 +1214,18 @@ ${JSON.stringify(resultInfo, null, 2)}
1185
1214
  // 生成 AnyWebP 自动化指令
1186
1215
  generateAnyWebPInstructions(batches) {
1187
1216
  let instructions = "";
1217
+ instructions += `### \u26A0\uFE0F \u91CD\u8981\u63D0\u793A
1218
+
1219
+ `;
1220
+ instructions += `1. **\u56FE\u7247\u5FC5\u987B\u5728\u9879\u76EE\u76EE\u5F55\u5185**\uFF1APlaywright MCP \u53EA\u80FD\u8BBF\u95EE\u9879\u76EE\u76EE\u5F55\u4E0B\u7684\u6587\u4EF6\u3002
1221
+ `;
1222
+ instructions += ` - \u4E0D\u80FD\u4F7F\u7528 \`/tmp/\` \u7B49\u7CFB\u7EDF\u4E34\u65F6\u76EE\u5F55
1223
+ `;
1224
+ instructions += ` - \u8BF7\u5C06\u56FE\u7247\u4E0B\u8F7D\u5230\u9879\u76EE\u6839\u76EE\u5F55\u4E0B\u7684 \`.tmp-compress/\` \u6587\u4EF6\u5939
1225
+ `;
1226
+ instructions += `2. **\u4E0A\u4F20\u524D\u5FC5\u987B\u5148\u89E6\u53D1\u6587\u4EF6\u9009\u62E9\u6846**\uFF1A\u5148\u70B9\u51FB\u4E0A\u4F20\u533A\u57DF\uFF0C\u7B49\u5F85 Modal state \u663E\u793A "File chooser" \u540E\u518D\u8C03\u7528 \`browser_file_upload\`
1227
+
1228
+ `;
1188
1229
  for (let i = 0; i < batches.length; i++) {
1189
1230
  const batch = batches[i];
1190
1231
  instructions += `#### \u6279\u6B21 ${i + 1}/${batches.length}
@@ -1193,22 +1234,29 @@ ${JSON.stringify(resultInfo, null, 2)}
1193
1234
  instructions += `**\u6587\u4EF6**: ${batch.map((img) => path2.basename(img.path)).join(", ")}
1194
1235
 
1195
1236
  `;
1196
- instructions += `1. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://anywebp.com/convert-to-webp.html\`
1237
+ let stepNum = 1;
1238
+ instructions += `${stepNum++}. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://anywebp.com/convert-to-webp.html\`
1239
+ `;
1240
+ instructions += `${stepNum++}. **\u7B49\u5F85\u52A0\u8F7D**: \u4F7F\u7528 \`browser_snapshot\` \u786E\u8BA4\u9875\u9762\u52A0\u8F7D\u5B8C\u6210
1241
+ `;
1242
+ instructions += `${stepNum++}. **\u89E6\u53D1\u6587\u4EF6\u9009\u62E9\u6846**:
1243
+ `;
1244
+ instructions += ` - \u4F7F\u7528 \`browser_click\` \u70B9\u51FB "Drop your images here!" \u4E0A\u4F20\u533A\u57DF
1197
1245
  `;
1198
- instructions += `2. **\u7B49\u5F85\u52A0\u8F7D**: \u4F7F\u7528 \`browser_snapshot\` \u786E\u8BA4\u9875\u9762\u52A0\u8F7D\u5B8C\u6210\uFF0C\u627E\u5230 "Drop your images here" \u533A\u57DF
1246
+ instructions += ` - \u7B49\u5F85 \`browser_snapshot\` \u8FD4\u56DE\u7ED3\u679C\u4E2D Modal state \u663E\u793A "[File chooser]"
1199
1247
  `;
1200
- instructions += `3. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
1248
+ instructions += `${stepNum++}. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
1201
1249
  `;
1202
1250
  for (const img of batch) {
1203
1251
  instructions += ` - \`${img.path}\`
1204
1252
  `;
1205
1253
  }
1206
- instructions += `4. **\u7B49\u5F85\u8F6C\u6362**: \u4F7F\u7528 \`browser_wait_for\` \u7B49\u5F85\u8F6C\u6362\u5B8C\u6210\uFF0C\u51FA\u73B0 "Download" \u6309\u94AE
1254
+ instructions += `${stepNum++}. **\u7B49\u5F85\u8F6C\u6362**: \u4F7F\u7528 \`browser_wait_for\` \u7B49\u5F85\u8F6C\u6362\u5B8C\u6210\uFF0C\u51FA\u73B0 "Download" \u6309\u94AE
1207
1255
  `;
1208
- instructions += `5. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download All" \u6216\u9010\u4E2A\u4E0B\u8F7D WebP \u6587\u4EF6
1256
+ instructions += `${stepNum++}. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download All" \u6216\u9010\u4E2A\u4E0B\u8F7D WebP \u6587\u4EF6
1209
1257
  `;
1210
1258
  if (i < batches.length - 1) {
1211
- instructions += `6. **\u5237\u65B0\u9875\u9762**: \u4F7F\u7528 \`browser_navigate\` \u91CD\u65B0\u8BBF\u95EE\u51C6\u5907\u4E0B\u4E00\u6279
1259
+ instructions += `${stepNum++}. **\u5237\u65B0\u9875\u9762**: \u4F7F\u7528 \`browser_navigate\` \u91CD\u65B0\u8BBF\u95EE\u51C6\u5907\u4E0B\u4E00\u6279
1212
1260
  `;
1213
1261
  }
1214
1262
  instructions += `
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/services/oss.service.ts","../src/config/oss.config.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * 实现阿里云OSS文件上传功能。\n * - 上传文件到阿里云OSS\n * - 获取可用的OSS配置\n */\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { OssMcpServer } from \"./server.js\";\nimport { getServerConfig } from \"./config/oss.config.js\";\nimport { resolve } from \"path\";\nimport { config } from \"dotenv\";\n\n// 加载当前工作目录中的.env文件\nconfig({ path: resolve(process.cwd(), \".env\") });\n\nexport async function startServer(): Promise<void> {\n // 检查是否在stdio模式下运行\n const isStdioMode = process.env.NODE_ENV === \"cli\" || process.argv.includes(\"--stdio\");\n\n // 获取服务器配置\n const serverConfig = getServerConfig(isStdioMode);\n\n // 创建OSS MCP服务器\n const server = new OssMcpServer();\n\n if (isStdioMode) {\n // 在stdio模式下运行\n const transport = new StdioServerTransport();\n await server.connect(transport);\n } else {\n // 在HTTP模式下运行\n console.log(`初始化OSS MCP服务器,HTTP模式,端口: ${serverConfig.port}...`);\n await server.startHttpServer(serverConfig.port);\n }\n}\n\n// 启动服务器\nstartServer().catch((error) => {\n console.error(\"启动服务器失败:\", error);\n process.exit(1);\n});\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { ossService } from \"./services/oss.service.js\";\nimport express, { Request, Response } from \"express\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { IncomingMessage, ServerResponse } from \"http\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport fs from 'fs';\nimport path from 'path';\nimport https from 'https';\nimport http from 'http';\n\nexport const Logger = {\n log: (...args: any[]) => {\n console.log(...args);\n },\n error: (...args: any[]) => {\n console.error(...args);\n }\n};\n\nexport class OssMcpServer {\n private readonly server: McpServer;\n private sseTransport: SSEServerTransport | null = null;\n\n constructor() {\n this.server = new McpServer(\n {\n name: \"@yhy2001/oss-mcp\",\n version: \"1.0.0\",\n },\n // 使用正确格式的capabilities配置\n {\n capabilities: {\n tools: { listChanged: true },\n resources: { listChanged: true },\n prompts: { listChanged: true },\n logging: {}\n }\n }\n );\n\n this.registerTools();\n }\n\n private registerTools(): void {\n // 获取可用的OSS配置\n const configs = ossService.getConfigs();\n const configNames = configs.map(config => config.id);\n\n // 工具:上传文件到OSS\n this.server.tool(\n \"upload_to_oss\",\n \"将文件上传到阿里云OSS\",\n {\n filePath: z.string().describe(\"要上传的本地文件路径\"),\n targetDir: z.string().optional().describe(\"OSS中的目标目录路径(可选)\"),\n fileName: z.string().optional().describe(\"上传后的文件名(可选,默认使用原文件名)\"),\n configName: z.string().optional().describe(`OSS配置名称(可选,默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ filePath, targetDir, fileName, configName }) => {\n try {\n Logger.log(`准备上传: ${filePath} 到 ${targetDir || '根目录'}`);\n\n if (!filePath) {\n throw new Error(\"文件路径是必需的\");\n }\n\n // 检查文件是否存在\n if (!fs.existsSync(filePath)) {\n throw new Error(`文件不存在: ${filePath}`);\n }\n\n // 执行上传\n const result = await ossService.uploadFile({\n filePath,\n targetDir,\n fileName,\n configName\n });\n\n if (result.success) {\n Logger.log(`上传成功: ${result.url}`);\n return {\n content: [{\n type: \"text\",\n text: `文件上传成功!\\n文件名: ${path.basename(filePath)}\\n目标位置: ${targetDir || '根目录'}\\nURL: ${result.url}\\n配置名称: ${result.ossConfigName}`\n }]\n };\n } else {\n Logger.error(`上传失败: ${result.error}`);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `上传失败: ${result.error}`\n }]\n };\n }\n } catch (error) {\n Logger.error(`上传过程中出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `上传出错: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出可用的OSS配置\n this.server.tool(\n \"list_oss_configs\",\n \"列出可用的阿里云OSS配置\",\n {},\n async () => {\n try {\n const configs = ossService.getConfigs();\n const configNames = configs.map(config => config.id);\n\n if (configNames.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: \"未找到OSS配置。请检查环境变量设置。\"\n }]\n };\n }\n\n return {\n content: [{\n type: \"text\",\n text: `可用的OSS配置:\\n${configNames.map(name => `- ${name}`).join('\\n')}`\n }]\n };\n } catch (error) {\n Logger.error(`获取OSS配置列表时出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `获取配置列表失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:批量重命名OSS文件\n this.server.tool(\n \"batch_rename_files\",\n \"批量重命名阿里云OSS文件。通过copy+delete实现。【重要】首次调用必须使用dryRun=true预览,展示给用户确认后,用户同意才能用dryRun=false执行实际重命名。禁止跳过预览直接执行!\",\n {\n directory: z.string().describe(\"OSS中的目录路径(如 'images/icons',根目录传空字符串 '')\"),\n renameRules: z.array(z.object({\n oldName: z.string().describe(\"原文件名\"),\n newName: z.string().describe(\"新文件名\")\n })).describe(\"重命名规则数组,每项包含原文件名和新文件名\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`),\n dryRun: z.boolean().optional().describe(\"是否为预览模式(默认false)。为true时只返回将要执行的操作,不实际重命名\")\n },\n async ({ directory, renameRules, configName = 'default', dryRun = false }) => {\n try {\n Logger.log(`OSS批量重命名: 目录=${directory}, 规则数=${renameRules.length}, 配置=${configName}, 预览模式=${dryRun}`);\n\n let results: { oldName: string; newName: string; success: boolean; error?: string }[];\n\n if (dryRun) {\n // 预览模式:只返回将要执行的操作\n results = renameRules.map(rule => ({\n oldName: rule.oldName,\n newName: rule.newName,\n success: true\n }));\n } else {\n // 实际执行OSS重命名\n results = await ossService.batchRenameFiles(renameRules, directory, configName);\n }\n\n const successCount = results.filter(r => r.success).length;\n const failCount = results.filter(r => !r.success).length;\n\n let resultText = dryRun ? `【预览模式】以下是将要执行的OSS文件重命名操作:\\n\\n` : `OSS文件批量重命名完成:\\n\\n`;\n resultText += `配置: ${configName}\\n`;\n resultText += `目录: ${directory || '根目录'}\\n`;\n resultText += `成功: ${successCount} 个, 失败: ${failCount} 个\\n\\n`;\n\n if (results.length > 0) {\n resultText += '详细结果:\\n';\n for (const r of results) {\n if (r.success) {\n resultText += `✅ ${r.oldName} → ${r.newName}\\n`;\n } else {\n resultText += `❌ ${r.oldName} → ${r.newName} (${r.error})\\n`;\n }\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`OSS批量重命名出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `OSS批量重命名失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出本地目录文件\n this.server.tool(\n \"list_directory_files\",\n \"列出本地文件系统中指定目录下的所有文件。注意:此工具仅支持本地路径,如果要列出 OSS 中的文件,请使用 list_oss_files 工具。\",\n {\n directory: z.string().describe(\"要查看的目录路径\"),\n pattern: z.string().optional().describe(\"文件名过滤模式(可选),如 '*.png' 或 'icon_*'\")\n },\n async ({ directory, pattern }) => {\n try {\n Logger.log(`列出目录文件: ${directory}, 过滤: ${pattern || '无'}`);\n\n // 检查目录是否存在\n if (!fs.existsSync(directory)) {\n throw new Error(`目录不存在: ${directory}`);\n }\n\n const stat = fs.statSync(directory);\n if (!stat.isDirectory()) {\n throw new Error(`路径不是目录: ${directory}`);\n }\n\n let files = fs.readdirSync(directory);\n\n // 过滤掉隐藏文件\n files = files.filter(f => !f.startsWith('.'));\n\n // 如果有 pattern,进行简单的通配符匹配\n if (pattern) {\n const regex = new RegExp(\n '^' + pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.') + '$',\n 'i'\n );\n files = files.filter(f => regex.test(f));\n }\n\n // 获取文件信息\n const fileInfos = files.map(f => {\n const filePath = path.join(directory, f);\n const fileStat = fs.statSync(filePath);\n return {\n name: f,\n isDirectory: fileStat.isDirectory(),\n size: fileStat.size\n };\n });\n\n // 排序:目录在前,文件在后,按名称排序\n fileInfos.sort((a, b) => {\n if (a.isDirectory !== b.isDirectory) {\n return a.isDirectory ? -1 : 1;\n }\n return a.name.localeCompare(b.name);\n });\n\n if (fileInfos.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: `目录 ${directory} 下没有找到匹配的文件${pattern ? ` (过滤: ${pattern})` : ''}`\n }]\n };\n }\n\n let resultText = `目录: ${directory}\\n`;\n if (pattern) {\n resultText += `过滤: ${pattern}\\n`;\n }\n resultText += `共 ${fileInfos.length} 个项目:\\n\\n`;\n\n for (const f of fileInfos) {\n if (f.isDirectory) {\n resultText += `📁 ${f.name}/\\n`;\n } else {\n const sizeStr = f.size < 1024\n ? `${f.size}B`\n : f.size < 1024 * 1024\n ? `${(f.size / 1024).toFixed(1)}KB`\n : `${(f.size / 1024 / 1024).toFixed(1)}MB`;\n resultText += `📄 ${f.name} (${sizeStr})\\n`;\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`列出目录文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出目录失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出OSS目录文件\n this.server.tool(\n \"list_oss_files\",\n \"列出阿里云OSS指定目录下的所有文件。用于查看 OSS 中的文件以便进行重命名或其他操作。注意:如果要列出本地文件,请使用 list_directory_files 工具。\",\n {\n directory: z.string().describe(\"OSS中的目录路径(如 'images/icons',根目录传空字符串 '')\"),\n pattern: z.string().optional().describe(\"文件名过滤模式(可选),如 '*.png' 或 'icon_*'\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ directory, pattern, configName = 'default' }) => {\n try {\n Logger.log(`列出OSS目录文件: ${directory || '根目录'}, 过滤: ${pattern || '无'}, 配置: ${configName}`);\n\n const result = await ossService.listFiles(directory, configName, pattern);\n\n if (!result.success) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出OSS文件失败: ${result.error}`\n }]\n };\n }\n\n const files = result.files || [];\n\n if (files.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: `OSS目录 ${directory || '根目录'} 下没有找到匹配的文件${pattern ? ` (过滤: ${pattern})` : ''}\\n配置: ${configName}`\n }]\n };\n }\n\n const sizeStr = (size: number) => size < 1024\n ? `${size}B`\n : size < 1024 * 1024\n ? `${(size / 1024).toFixed(1)}KB`\n : `${(size / 1024 / 1024).toFixed(1)}MB`;\n\n let resultText = `OSS目录: ${directory || '根目录'}\\n`;\n resultText += `配置: ${configName}\\n`;\n if (pattern) {\n resultText += `过滤: ${pattern}\\n`;\n }\n resultText += `共 ${files.length} 个文件:\\n\\n`;\n\n for (const f of files) {\n resultText += `📄 ${f.name} (${sizeStr(f.size)})\\n`;\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`列出OSS目录文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出OSS目录失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:下载文件\n this.server.tool(\n \"download_file\",\n \"从 URL 下载文件到本地目录。支持 HTTP/HTTPS 链接,可自定义保存文件名。\",\n {\n url: z.string().describe(\"要下载的文件 URL\"),\n targetDir: z.string().describe(\"保存文件的本地目录路径\"),\n fileName: z.string().optional().describe(\"保存的文件名(可选,默认从 URL 提取)\")\n },\n async ({ url, targetDir, fileName }) => {\n try {\n Logger.log(`下载文件: ${url} 到 ${targetDir}`);\n\n // 检查目录是否存在,不存在则创建\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n Logger.log(`创建目录: ${targetDir}`);\n }\n\n const stat = fs.statSync(targetDir);\n if (!stat.isDirectory()) {\n throw new Error(`路径不是目录: ${targetDir}`);\n }\n\n // 从 URL 提取文件名\n let finalFileName = fileName;\n if (!finalFileName) {\n const urlObj = new URL(url);\n finalFileName = path.basename(urlObj.pathname);\n // 如果 URL 没有文件名,生成一个\n if (!finalFileName || finalFileName === '/') {\n finalFileName = `download_${Date.now()}`;\n }\n }\n\n const filePath = path.join(targetDir, finalFileName);\n\n // 检查文件是否已存在\n if (fs.existsSync(filePath)) {\n throw new Error(`文件已存在: ${filePath}`);\n }\n\n // 下载文件\n await new Promise<void>((resolve, reject) => {\n const urlObj = new URL(url);\n const protocol = urlObj.protocol === 'https:' ? https : http;\n\n const request = protocol.get(url, (response) => {\n // 处理重定向\n if (response.statusCode === 301 || response.statusCode === 302) {\n const redirectUrl = response.headers.location;\n if (redirectUrl) {\n Logger.log(`重定向到: ${redirectUrl}`);\n const redirectProtocol = redirectUrl.startsWith('https:') ? https : http;\n redirectProtocol.get(redirectUrl, (redirectResponse) => {\n if (redirectResponse.statusCode !== 200) {\n reject(new Error(`下载失败,HTTP 状态码: ${redirectResponse.statusCode}`));\n return;\n }\n const fileStream = fs.createWriteStream(filePath);\n redirectResponse.pipe(fileStream);\n fileStream.on('finish', () => {\n fileStream.close();\n resolve();\n });\n fileStream.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n }).on('error', reject);\n return;\n }\n }\n\n if (response.statusCode !== 200) {\n reject(new Error(`下载失败,HTTP 状态码: ${response.statusCode}`));\n return;\n }\n\n const fileStream = fs.createWriteStream(filePath);\n response.pipe(fileStream);\n\n fileStream.on('finish', () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n });\n\n request.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n\n request.setTimeout(60000, () => {\n request.destroy();\n fs.unlink(filePath, () => {});\n reject(new Error('下载超时(60秒)'));\n });\n });\n\n // 获取文件大小\n const downloadedStat = fs.statSync(filePath);\n const sizeStr = downloadedStat.size < 1024\n ? `${downloadedStat.size}B`\n : downloadedStat.size < 1024 * 1024\n ? `${(downloadedStat.size / 1024).toFixed(1)}KB`\n : `${(downloadedStat.size / 1024 / 1024).toFixed(1)}MB`;\n\n return {\n content: [{\n type: \"text\",\n text: `文件下载成功!\\n源URL: ${url}\\n保存路径: ${filePath}\\n文件大小: ${sizeStr}`\n }]\n };\n } catch (error) {\n Logger.error(`下载文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `下载失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:检查压缩图片的前置条件\n this.server.tool(\n \"check_compress_prerequisites\",\n `检查图片压缩的前置条件并返回用户询问模板。\n\n【⚠️ 极其重要 - AI 必须严格按以下顺序执行】\n\n第 1 步:检查 Playwright MCP(必须在调用本工具之前完成!)\n- 调用 browser_snapshot 工具\n- 如果成功:继续执行\n- 如果失败/报错:立即停止,告知用户需要启用 Playwright MCP\n\n第 2 步:如果图片在 OSS 上(必须在调用本工具之前完成!)\n- 先使用 list_oss_files 列出文件\n- 使用 download_file 将图片下载到本地临时目录(如 /tmp/compress-images/)\n- 只有下载到本地后才能调用本工具\n\n第 3 步:调用本工具\n- 传入本地图片路径数组\n- 获取用户询问模板\n\n第 4 步:询问用户\n- 使用 AskUserQuestion 询问压缩引擎、输出格式等\n\n第 5 步:执行压缩\n- 调用 compress_images 工具`,\n {\n images: z.array(z.string()).describe(\"要压缩的【本地】图片路径数组。如果图片在 OSS 上,必须先用 download_file 下载到本地!\")\n },\n async ({ images }) => {\n try {\n // 验证图片文件\n const validImages: { path: string; name: string; ext: string; size: number }[] = [];\n const errors: string[] = [];\n\n for (const imgPath of images) {\n if (!fs.existsSync(imgPath)) {\n errors.push(`文件不存在: ${imgPath}`);\n continue;\n }\n const stat = fs.statSync(imgPath);\n if (stat.size > 5 * 1024 * 1024) {\n errors.push(`文件超过 5MB 限制: ${imgPath}`);\n continue;\n }\n const ext = path.extname(imgPath).toLowerCase().slice(1);\n if (!['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext)) {\n errors.push(`不支持的格式: ${imgPath}`);\n continue;\n }\n validImages.push({\n path: imgPath,\n name: path.basename(imgPath, path.extname(imgPath)),\n ext: ext === 'jpg' ? 'jpeg' : ext,\n size: stat.size\n });\n }\n\n if (validImages.length === 0) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `没有有效的图片可处理:\\n${errors.join('\\n')}`\n }]\n };\n }\n\n // 构建需要询问用户的问题\n const questions = {\n playwrightCheck: {\n instruction: \"请先使用 browser_snapshot 工具测试 Playwright MCP 是否可用。如果报错说明未配置。\"\n },\n engineQuestion: {\n question: \"请选择压缩引擎\",\n header: \"压缩引擎\",\n options: [\n { label: \"TinyPNG (推荐)\", description: \"支持 PNG/JPEG/WebP 输出,压缩质量高,每批最多 3 个文件\" },\n { label: \"AnyWebP\", description: \"固定输出 WebP 格式,每批最多 20 个文件\" }\n ]\n },\n formatQuestion: {\n question: \"是否需要转换输出格式?\",\n header: \"输出格式\",\n options: [\n { label: \"保持原格式\", description: \"不转换格式,仅压缩\" },\n { label: \"转换为 WebP\", description: \"转换为 WebP 格式,体积更小\" },\n { label: \"转换为 JPEG\", description: \"转换为 JPEG 格式(仅 TinyPNG)\" },\n { label: \"转换为 PNG\", description: \"转换为 PNG 格式(仅 TinyPNG)\" }\n ]\n },\n deleteOriginalQuestion: {\n question: \"转换格式后是否删除原文件?\",\n header: \"删除原文件\",\n options: [\n { label: \"保留原文件\", description: \"在 OSS 上保留原格式文件\" },\n { label: \"删除原文件\", description: \"转换后删除 OSS 上的原格式文件\" }\n ],\n condition: \"仅当选择了转换格式时才需要询问\"\n }\n };\n\n const sizeStr = (size: number) => size < 1024\n ? `${size}B`\n : size < 1024 * 1024\n ? `${(size / 1024).toFixed(1)}KB`\n : `${(size / 1024 / 1024).toFixed(1)}MB`;\n\n let resultText = `## 图片压缩前置检查\\n\\n`;\n resultText += `### ✅ 有效图片 (${validImages.length} 个)\\n`;\n for (const img of validImages) {\n resultText += `- ${path.basename(img.path)} (${sizeStr(img.size)})\\n`;\n }\n\n if (errors.length > 0) {\n resultText += `\\n### ⚠️ 跳过的文件\\n`;\n for (const err of errors) {\n resultText += `- ${err}\\n`;\n }\n }\n\n resultText += `\\n### 📋 AI 执行步骤\\n\\n`;\n resultText += `1. **检查 Playwright**: 调用 \\`browser_snapshot\\` 测试是否可用\\n`;\n resultText += ` - 如果报错,提示用户需要配置 Playwright MCP\\n`;\n resultText += `2. **询问用户**: 使用 AskUserQuestion 一次性询问以下问题:\\n`;\n resultText += ` - 选择压缩引擎 (TinyPNG / AnyWebP)\\n`;\n resultText += ` - 是否转换格式 (保持原格式 / WebP / JPEG / PNG)\\n`;\n resultText += ` - 如果转格式,是否删除原文件\\n`;\n resultText += `3. **执行压缩**: 根据用户选择调用 \\`compress_images\\`\\n`;\n\n return {\n content: [\n {\n type: \"text\",\n text: resultText\n },\n {\n type: \"text\",\n text: `\\n---\\n**询问模板 (JSON)**:\\n\\`\\`\\`json\\n${JSON.stringify(questions, null, 2)}\\n\\`\\`\\``\n }\n ]\n };\n } catch (error) {\n Logger.error(`检查前置条件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `检查失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:压缩图片(生成压缩指令,由 AI 调用 Playwright MCP 执行)\n this.server.tool(\n \"compress_images\",\n `压缩图片工具。生成 Playwright 自动化压缩指令。\n\n【⚠️ 禁止直接调用!必须先完成以下步骤】\n\n✅ 第 1 步:验证 Playwright MCP 可用\n → 调用 browser_snapshot,如果报错则停止并提示用户启用\n\n✅ 第 2 步:确保图片在本地\n → OSS 图片必须先用 download_file 下载到本地\n\n✅ 第 3 步:调用 check_compress_prerequisites\n → 验证文件并获取询问模板\n\n✅ 第 4 步:询问用户偏好\n → 使用 AskUserQuestion 询问引擎、格式、是否删除原文件\n\n✅ 第 5 步:调用本工具\n → 传入用户选择的参数\n\n【后续流程】\n1. 按返回的指令使用 Playwright MCP 执行网页自动化\n2. 下载压缩结果\n3. 使用 upload_to_oss 上传回 OSS`,\n {\n images: z.array(z.string()).describe(\"要压缩的本地图片路径数组\"),\n engine: z.enum(['tinypng', 'anywebp']).describe(\"压缩引擎 (必须先询问用户选择)\"),\n outputFormat: z.enum(['png', 'jpeg', 'webp']).optional().describe(\"输出格式 (必须先询问用户选择,仅 tinypng 支持多格式)\"),\n deleteOriginal: z.boolean().optional().describe(\"转格式时是否删除原文件 (必须先询问用户选择)\"),\n ossDirectory: z.string().optional().describe(\"OSS 目标目录 (用于上传压缩后的文件)\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ images, engine, outputFormat, deleteOriginal = false, ossDirectory, configName = 'default' }) => {\n try {\n Logger.log(`压缩图片: 引擎=${engine}, 格式=${outputFormat || '原格式'}, 图片数=${images.length}`);\n\n // 验证图片文件存在\n const validImages: { path: string; name: string; ext: string; size: number }[] = [];\n const errors: string[] = [];\n\n for (const imgPath of images) {\n if (!fs.existsSync(imgPath)) {\n errors.push(`文件不存在: ${imgPath}`);\n continue;\n }\n const stat = fs.statSync(imgPath);\n if (stat.size > 5 * 1024 * 1024) {\n errors.push(`文件超过 5MB 限制: ${imgPath}`);\n continue;\n }\n const ext = path.extname(imgPath).toLowerCase().slice(1);\n if (!['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext)) {\n errors.push(`不支持的格式: ${imgPath}`);\n continue;\n }\n validImages.push({\n path: imgPath,\n name: path.basename(imgPath, path.extname(imgPath)),\n ext: ext === 'jpg' ? 'jpeg' : ext,\n size: stat.size\n });\n }\n\n if (validImages.length === 0) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `没有有效的图片可处理:\\n${errors.join('\\n')}`\n }]\n };\n }\n\n // 生成压缩指令\n const actualOutputFormat = engine === 'anywebp' ? 'webp' : (outputFormat || null);\n const batchSize = engine === 'tinypng' ? 3 : 20;\n const batches: typeof validImages[] = [];\n\n for (let i = 0; i < validImages.length; i += batchSize) {\n batches.push(validImages.slice(i, i + batchSize));\n }\n\n // 构建指令文本\n let instructions = `## 图片压缩指令\\n\\n`;\n instructions += `**引擎**: ${engine === 'tinypng' ? 'TinyPNG (https://tinypng.com/)' : 'AnyWebP (https://anywebp.com/convert-to-webp)'}\\n`;\n instructions += `**输出格式**: ${actualOutputFormat || '保持原格式'}\\n`;\n instructions += `**总图片数**: ${validImages.length}\\n`;\n instructions += `**批次数**: ${batches.length} (每批最多 ${batchSize} 个)\\n\\n`;\n\n if (errors.length > 0) {\n instructions += `### ⚠️ 跳过的文件\\n`;\n for (const err of errors) {\n instructions += `- ${err}\\n`;\n }\n instructions += `\\n`;\n }\n\n instructions += `### 📋 执行步骤\\n\\n`;\n instructions += `**前置检查**: 请确认 Playwright MCP 已配置并可用\\n\\n`;\n\n if (engine === 'tinypng') {\n instructions += this.generateTinyPngInstructions(batches, actualOutputFormat);\n } else {\n instructions += this.generateAnyWebPInstructions(batches);\n }\n\n // 添加后续处理指令\n instructions += `\\n### 📤 后续处理\\n\\n`;\n instructions += `压缩完成后,请执行以下操作:\\n\\n`;\n\n for (const img of validImages) {\n const newExt = actualOutputFormat || img.ext;\n const isFormatChange = newExt !== img.ext;\n const newFileName = `${img.name}.${newExt}`;\n const downloadPath = path.join(path.dirname(img.path), `${img.name}-compressed.${newExt}`);\n\n instructions += `**${path.basename(img.path)}**:\\n`;\n instructions += `1. 下载压缩结果到: \\`${downloadPath}\\`\\n`;\n\n if (ossDirectory) {\n if (isFormatChange) {\n instructions += `2. 上传到 OSS: \\`upload_to_oss(\"${downloadPath}\", \"${ossDirectory}\", \"${newFileName}\", \"${configName}\")\\`\\n`;\n if (deleteOriginal) {\n instructions += `3. 删除原文件: 在 OSS 上删除 \\`${ossDirectory}/${path.basename(img.path)}\\`\\n`;\n }\n } else {\n instructions += `2. 覆盖上传到 OSS: \\`upload_to_oss(\"${downloadPath}\", \"${ossDirectory}\", \"${path.basename(img.path)}\", \"${configName}\")\\`\\n`;\n }\n }\n instructions += `\\n`;\n }\n\n // 返回信息\n const resultInfo = {\n engine,\n outputFormat: actualOutputFormat,\n deleteOriginal: actualOutputFormat ? deleteOriginal : false,\n ossDirectory,\n configName,\n totalImages: validImages.length,\n batches: batches.length,\n batchSize,\n images: validImages.map(img => ({\n originalPath: img.path,\n originalName: path.basename(img.path),\n originalExt: img.ext,\n originalSize: img.size,\n newExt: actualOutputFormat || img.ext,\n isFormatChange: (actualOutputFormat || img.ext) !== img.ext\n }))\n };\n\n return {\n content: [\n {\n type: \"text\",\n text: instructions\n },\n {\n type: \"text\",\n text: `\\n---\\n**压缩任务数据 (JSON)**:\\n\\`\\`\\`json\\n${JSON.stringify(resultInfo, null, 2)}\\n\\`\\`\\``\n }\n ]\n };\n } catch (error) {\n Logger.error(`生成压缩指令出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `生成压缩指令失败: ${error}`\n }]\n };\n }\n }\n );\n }\n\n // 生成 TinyPNG 自动化指令\n private generateTinyPngInstructions(batches: { path: string; name: string; ext: string; size: number }[][], outputFormat: string | null): string {\n let instructions = '';\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n instructions += `#### 批次 ${i + 1}/${batches.length}\\n\\n`;\n instructions += `**文件**: ${batch.map(img => path.basename(img.path)).join(', ')}\\n\\n`;\n\n instructions += `1. **打开网站**: 使用 \\`browser_navigate\\` 访问 \\`https://tinypng.com/\\`\\n`;\n instructions += `2. **等待加载**: 使用 \\`browser_snapshot\\` 确认页面加载完成\\n`;\n instructions += `3. **上传文件**: 使用 \\`browser_file_upload\\` 上传以下文件:\\n`;\n for (const img of batch) {\n instructions += ` - \\`${img.path}\\`\\n`;\n }\n instructions += `4. **等待压缩**: 使用 \\`browser_wait_for\\` 等待 \"Download all\" 或各文件的 \"download\" 按钮出现\\n`;\n\n if (outputFormat && outputFormat !== 'png') {\n instructions += `5. **选择输出格式**: \\n`;\n instructions += ` - 点击压缩结果右侧的格式选择下拉框\\n`;\n instructions += ` - 选择 \"${outputFormat.toUpperCase()}\"\\n`;\n }\n\n instructions += `${outputFormat && outputFormat !== 'png' ? '6' : '5'}. **下载结果**: 点击 \"Download all\" 或逐个下载\\n`;\n\n if (i < batches.length - 1) {\n instructions += `${outputFormat && outputFormat !== 'png' ? '7' : '6'}. **刷新页面**: 使用 \\`browser_navigate\\` 重新访问 \\`https://tinypng.com/\\` 准备下一批\\n`;\n }\n instructions += `\\n`;\n }\n\n return instructions;\n }\n\n // 生成 AnyWebP 自动化指令\n private generateAnyWebPInstructions(batches: { path: string; name: string; ext: string; size: number }[][]): string {\n let instructions = '';\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n instructions += `#### 批次 ${i + 1}/${batches.length}\\n\\n`;\n instructions += `**文件**: ${batch.map(img => path.basename(img.path)).join(', ')}\\n\\n`;\n\n instructions += `1. **打开网站**: 使用 \\`browser_navigate\\` 访问 \\`https://anywebp.com/convert-to-webp.html\\`\\n`;\n instructions += `2. **等待加载**: 使用 \\`browser_snapshot\\` 确认页面加载完成,找到 \"Drop your images here\" 区域\\n`;\n instructions += `3. **上传文件**: 使用 \\`browser_file_upload\\` 上传以下文件:\\n`;\n for (const img of batch) {\n instructions += ` - \\`${img.path}\\`\\n`;\n }\n instructions += `4. **等待转换**: 使用 \\`browser_wait_for\\` 等待转换完成,出现 \"Download\" 按钮\\n`;\n instructions += `5. **下载结果**: 点击 \"Download All\" 或逐个下载 WebP 文件\\n`;\n\n if (i < batches.length - 1) {\n instructions += `6. **刷新页面**: 使用 \\`browser_navigate\\` 重新访问准备下一批\\n`;\n }\n instructions += `\\n`;\n }\n\n return instructions;\n }\n\n async connect(transport: Transport): Promise<void> {\n try {\n await this.server.connect(transport);\n\n Logger.log = (...args: any[]) => {\n try {\n this.server.server.sendLoggingMessage({\n level: \"info\",\n data: args,\n });\n } catch (error) {\n console.log(...args);\n }\n };\n\n Logger.error = (...args: any[]) => {\n try {\n this.server.server.sendLoggingMessage({\n level: \"error\",\n data: args,\n });\n } catch (error) {\n console.error(...args);\n }\n };\n\n Logger.log(\"OSS MCP服务器已连接并准备处理请求\");\n } catch (error) {\n console.error(\"连接到传输时出错:\", error);\n }\n }\n\n async startHttpServer(port: number): Promise<void> {\n const app = express();\n\n // SSE连接端点 - 修复头部发送冲突\n app.get(\"/sse\", (req: Request, res: Response) => {\n // 初始化SSE传输,不再自己设置头部,而是让SDK处理\n this.sseTransport = new SSEServerTransport(\n \"/messages\",\n res as unknown as ServerResponse<IncomingMessage>\n );\n\n try {\n // 连接到传输层\n this.server.connect(this.sseTransport)\n .catch((err) => {\n console.error(\"连接到SSE传输时出错:\", err);\n });\n\n // 处理客户端断开连接\n req.on('close', () => {\n console.log('SSE客户端断开连接');\n this.sseTransport = null;\n });\n } catch (error) {\n console.error(\"建立SSE连接时出错:\", error);\n // 如果连接失败,关闭响应\n if (!res.writableEnded) {\n res.status(500).end();\n }\n }\n });\n\n // 消息端点\n app.post(\"/messages\", async (req: Request, res: Response) => {\n if (!this.sseTransport) {\n console.log(\"尝试发送消息,但SSE传输未初始化\");\n res.status(400).json({\n error: 'SSE连接未建立',\n message: '请先连接到/sse端点'\n });\n return;\n }\n\n try {\n await this.sseTransport.handlePostMessage(\n req as unknown as IncomingMessage,\n res as unknown as ServerResponse<IncomingMessage>\n );\n } catch (error) {\n console.error(\"处理消息时出错:\", error);\n if (!res.writableEnded) {\n res.status(500).json({\n error: \"内部服务器错误\",\n message: String(error)\n });\n }\n }\n });\n\n // 启动服务器\n app.listen(port, () => {\n Logger.log = console.log;\n Logger.error = console.error;\n\n Logger.log(`HTTP服务器监听端口: ${port}`);\n Logger.log(`SSE端点: http://localhost:${port}/sse`);\n Logger.log(`消息端点: http://localhost:${port}/messages`);\n });\n }\n}\n","import OSS from 'ali-oss';\nimport fs from 'fs';\nimport path from 'path';\nimport { OssConfig, getOssConfig, getAllOssConfigs } from '../config/oss.config.js';\nimport { z } from 'zod';\n\n// 上传文件参数验证Schema\nexport const UploadFileParamsSchema = z.object({\n filePath: z.string(),\n targetDir: z.string().optional(),\n fileName: z.string().optional(),\n configName: z.string().optional(),\n});\n\n// 导出上传文件参数类型\nexport type UploadFileParams = z.infer<typeof UploadFileParamsSchema>;\n\n// 上传结果验证Schema\nexport const UploadResultSchema = z.object({\n success: z.boolean(),\n url: z.string().optional(),\n error: z.string().optional(),\n ossConfigName: z.string().optional(),\n});\n\n// 导出上传结果类型\nexport type UploadResult = z.infer<typeof UploadResultSchema>;\n\n/**\n * OSS配置接口(包含ID和名称)\n */\nexport interface OssConfigWithMeta extends OssConfig {\n id: string;\n name: string;\n}\n\n/**\n * 阿里云OSS服务类\n */\nexport class OssService {\n private clients: Map<string, OSS> = new Map();\n\n /**\n * 获取所有OSS配置\n * @returns OSS配置列表\n */\n getConfigs(): OssConfigWithMeta[] {\n const configs: OssConfigWithMeta[] = [];\n const allConfigs = getAllOssConfigs();\n\n for (const [id, config] of Object.entries(allConfigs)) {\n configs.push({\n id,\n name: `${id.charAt(0).toUpperCase()}${id.slice(1)} 配置`,\n ...config\n });\n }\n\n return configs;\n }\n\n /**\n * 获取OSS客户端\n * @param configName 配置名称\n * @returns OSS客户端实例\n */\n private getClient(configName: string = 'default'): OSS | null {\n // 检查缓存中是否已有客户端\n if (this.clients.has(configName)) {\n return this.clients.get(configName) as OSS;\n }\n\n // 获取配置并创建客户端\n const config = getOssConfig(configName);\n if (!config) {\n return null;\n }\n\n try {\n const client = new OSS({\n region: config.region,\n accessKeyId: config.accessKeyId,\n accessKeySecret: config.accessKeySecret,\n bucket: config.bucket,\n endpoint: config.endpoint\n });\n\n // 缓存客户端实例\n this.clients.set(configName, client);\n return client;\n } catch (error) {\n console.error(`Failed to create OSS client for ${configName}:`, error);\n return null;\n }\n }\n\n /**\n * 上传文件到OSS\n * @param params 上传参数\n * @returns 上传结果\n */\n async uploadFile(params: UploadFileParams): Promise<UploadResult> {\n // 验证并解析参数\n const validParams = UploadFileParamsSchema.parse(params);\n const { filePath, targetDir = '', fileName, configName = 'default' } = validParams;\n\n try {\n // 检查文件是否存在\n if (!fs.existsSync(filePath)) {\n return UploadResultSchema.parse({\n success: false,\n error: `File not found: ${filePath}`,\n ossConfigName: configName\n });\n }\n\n // 获取OSS客户端\n const client = this.getClient(configName);\n if (!client) {\n return UploadResultSchema.parse({\n success: false,\n error: `OSS config not found for: ${configName}`,\n ossConfigName: configName\n });\n }\n\n // 确定文件名\n const actualFileName = fileName || path.basename(filePath);\n\n // 构建OSS路径,确保正斜杠格式\n let ossPath = actualFileName;\n if (targetDir) {\n // 规范化目标目录:移除头尾斜杠,然后加上结尾斜杠\n const normalizedDir = targetDir.replace(/^\\/+|\\/+$/g, '');\n ossPath = normalizedDir ? `${normalizedDir}/${actualFileName}` : actualFileName;\n }\n\n // 上传文件\n const result = await client.put(ossPath, filePath);\n\n return UploadResultSchema.parse({\n success: true,\n url: result.url,\n ossConfigName: configName\n });\n } catch (error) {\n return UploadResultSchema.parse({\n success: false,\n error: `Upload failed: ${(error as Error).message}`,\n ossConfigName: configName\n });\n }\n }\n\n /**\n * 重命名OSS文件(通过 copy + delete 实现)\n * @param oldKey 原文件路径\n * @param newKey 新文件路径\n * @param configName 配置名称\n * @returns 重命名结果\n */\n async renameFile(oldKey: string, newKey: string, configName: string = 'default'): Promise<{ success: boolean; error?: string }> {\n try {\n const client = this.getClient(configName);\n if (!client) {\n return { success: false, error: `OSS config not found for: ${configName}` };\n }\n\n // 规范化路径:移除开头的斜杠\n const normalizedOldKey = oldKey.replace(/^\\/+/, '');\n const normalizedNewKey = newKey.replace(/^\\/+/, '');\n\n // 检查源文件是否存在\n try {\n await client.head(normalizedOldKey);\n } catch (_e) {\n return { success: false, error: `源文件不存在: ${normalizedOldKey}` };\n }\n\n // 检查目标文件是否已存在\n try {\n await client.head(normalizedNewKey);\n // 如果到这里说明文件存在\n if (normalizedOldKey !== normalizedNewKey) {\n return { success: false, error: `目标文件已存在: ${normalizedNewKey}` };\n }\n } catch (_e) {\n // 文件不存在,可以继续\n }\n\n // Step 1: 复制文件到新位置\n await client.copy(normalizedNewKey, normalizedOldKey);\n\n // Step 2: 删除原文件\n await client.delete(normalizedOldKey);\n\n return { success: true };\n } catch (error) {\n return { success: false, error: `重命名失败: ${(error as Error).message}` };\n }\n }\n\n /**\n * 列出OSS目录下的文件\n * @param directory OSS目录路径\n * @param configName 配置名称\n * @param pattern 文件名过滤模式(可选)\n * @returns 文件列表\n */\n async listFiles(\n directory: string = '',\n configName: string = 'default',\n pattern?: string\n ): Promise<{ success: boolean; files?: Array<{ name: string; size: number; lastModified: Date }>; error?: string }> {\n try {\n const client = this.getClient(configName);\n if (!client) {\n return { success: false, error: `OSS config not found for: ${configName}` };\n }\n\n // 规范化目录路径\n const normalizedDir = directory.replace(/^\\/+|\\/+$/g, '');\n const prefix = normalizedDir ? `${normalizedDir}/` : '';\n\n // 列出文件\n const result = await client.list({\n prefix,\n delimiter: '/',\n 'max-keys': 1000\n }, {});\n\n const files: Array<{ name: string; size: number; lastModified: Date }> = [];\n\n // 处理文件对象\n if (result.objects) {\n for (const obj of result.objects) {\n // 跳过目录本身(以 / 结尾的)\n if (obj.name.endsWith('/')) continue;\n\n // 提取文件名(去掉目录前缀)\n const fileName = obj.name.replace(prefix, '');\n if (!fileName) continue;\n\n // 如果有 pattern,进行简单的通配符匹配\n if (pattern) {\n const regex = new RegExp(\n '^' + pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.') + '$',\n 'i'\n );\n if (!regex.test(fileName)) continue;\n }\n\n files.push({\n name: fileName,\n size: obj.size,\n lastModified: new Date(obj.lastModified)\n });\n }\n }\n\n // 按文件名排序\n files.sort((a, b) => a.name.localeCompare(b.name));\n\n return { success: true, files };\n } catch (error) {\n return { success: false, error: `列出文件失败: ${(error as Error).message}` };\n }\n }\n\n /**\n * 批量重命名OSS文件\n * @param rules 重命名规则数组\n * @param directory OSS目录路径\n * @param configName 配置名称\n * @returns 批量重命名结果\n */\n async batchRenameFiles(\n rules: Array<{ oldName: string; newName: string }>,\n directory: string = '',\n configName: string = 'default'\n ): Promise<Array<{ oldName: string; newName: string; success: boolean; error?: string }>> {\n const results: Array<{ oldName: string; newName: string; success: boolean; error?: string }> = [];\n\n // 规范化目录路径\n const normalizedDir = directory.replace(/^\\/+|\\/+$/g, '');\n const dirPrefix = normalizedDir ? `${normalizedDir}/` : '';\n\n for (const rule of rules) {\n const oldKey = `${dirPrefix}${rule.oldName}`;\n const newKey = `${dirPrefix}${rule.newName}`;\n\n const result = await this.renameFile(oldKey, newKey, configName);\n results.push({\n oldName: rule.oldName,\n newName: rule.newName,\n success: result.success,\n error: result.error\n });\n }\n\n return results;\n }\n}\n\n// 导出单例实例\nexport const ossService = new OssService();\n","import { config } from \"dotenv\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport { z } from \"zod\";\n\nconfig();\n\n// OSS配置验证Schema\nexport const OssConfigSchema = z.object({\n region: z.string(),\n accessKeyId: z.string(),\n accessKeySecret: z.string(),\n bucket: z.string(),\n endpoint: z.string(),\n});\n\n// 导出OSS配置类型\nexport type OssConfig = z.infer<typeof OssConfigSchema>;\n\n// 服务器配置接口\nexport interface ServerConfig {\n port: number;\n ossConfig: Record<string, OssConfig>;\n configSources: {\n port: \"cli\" | \"env\" | \"default\";\n ossConfig: \"cli\" | \"env\" | \"default\";\n };\n}\n\n// 掩码函数,用于打印敏感信息\nfunction maskSecret(secret: string): string {\n if (secret.length <= 4) return \"****\";\n return `${secret.substring(0, 4)}****${secret.slice(-4)}`;\n}\n\n// 获取服务器配置\nexport function getServerConfig(isStdioMode: boolean = false): ServerConfig {\n // 解析命令行参数\n const argv = yargs(hideBin(process.argv))\n .options({\n \"oss-config\": {\n type: \"string\",\n description: \"OSS配置JSON字符串\",\n },\n port: {\n type: \"number\",\n description: \"服务器运行端口\",\n default: 3000,\n },\n })\n .help()\n .version(\"1.0.0\")\n .parseSync();\n\n const config: ServerConfig = {\n port: 3000,\n ossConfig: {},\n configSources: {\n port: \"default\",\n ossConfig: \"default\",\n },\n };\n\n // 处理端口配置\n if (argv.port) {\n config.port = argv.port;\n config.configSources.port = \"cli\";\n } else if (process.env.PORT) {\n config.port = parseInt(process.env.PORT, 10);\n config.configSources.port = \"env\";\n }\n\n // 处理OSS配置 - 首先检查命令行参数\n if (argv[\"oss-config\"]) {\n const allOssConfigs = JSON.parse(argv[\"oss-config\"] as string);\n\n if (allOssConfigs.region && allOssConfigs.accessKeyId) {\n config.ossConfig.default = OssConfigSchema.parse(allOssConfigs);\n } else {\n Object.entries(allOssConfigs).forEach(([name, cfg]) => {\n config.ossConfig[name.toLowerCase()] = OssConfigSchema.parse(cfg);\n });\n }\n config.configSources.ossConfig = \"cli\";\n } else if (process.env.OSS_CONFIG_DEFAULT) {\n const ossConfig = JSON.parse(process.env.OSS_CONFIG_DEFAULT)\n config.ossConfig.default = OssConfigSchema.parse(ossConfig);\n config.configSources.ossConfig = \"env\";\n }\n\n // 检查其他命名的OSS配置\n Object.entries(process.env).forEach(([key, value]) => {\n if (key.startsWith(\"OSS_CONFIG_\") && key !== \"OSS_CONFIG_DEFAULT\" && value) {\n try {\n const configName = key.replace(\"OSS_CONFIG_\", \"\").toLowerCase();\n const ossConfig = JSON.parse(value);\n config.ossConfig[configName] = OssConfigSchema.parse(ossConfig);\n } catch (error) {\n console.error(`解析环境变量${key}失败:`, error);\n }\n }\n });\n\n // 验证配置\n if (Object.keys(config.ossConfig).length === 0) {\n console.warn(\"未找到有效的OSS配置。服务器将启动,但上传功能将不可用。\");\n }\n\n // 打印配置信息(非stdio模式下)\n if (!isStdioMode) {\n console.log(\"\\n配置信息:\");\n console.log(`- 端口: ${config.port} (来源: ${config.configSources.port})`);\n\n if (Object.keys(config.ossConfig).length > 0) {\n console.log(\"- OSS配置:\");\n Object.entries(config.ossConfig).forEach(([name, cfg]) => {\n console.log(` - ${name}:`);\n console.log(` Region: ${cfg.region}`);\n console.log(` Endpoint: ${cfg.endpoint}`);\n console.log(` Bucket: ${cfg.bucket}`);\n console.log(` AccessKeyId: ${maskSecret(cfg.accessKeyId)}`);\n console.log(` AccessKeySecret: ${maskSecret(cfg.accessKeySecret)}`);\n });\n } else {\n console.log(\"- OSS配置: 未找到\");\n }\n console.log(); // 空行,增加可读性\n }\n\n return config;\n}\n\n// 获取所有OSS配置\nexport function getAllOssConfigs(): Record<string, OssConfig> {\n const { ossConfig } = getServerConfig(true);\n return ossConfig;\n}\n\n// 获取特定名称的OSS配置\nexport function getOssConfig(name: string = 'default'): OssConfig | null {\n const configs = getAllOssConfigs();\n const normalizedName = name.toLowerCase();\n return configs[normalizedName] || null;\n}\n\n// 获取可用的OSS配置名称列表\nexport function getAvailableOssConfigNames(): string[] {\n return Object.keys(getAllOssConfigs());\n}\n"],"mappings":"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","names":["z","config","z","config","fs","path","config","z","configs","configNames","resolve","fileStream","config"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/server.ts","../src/services/oss.service.ts","../src/config/oss.config.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * 实现阿里云OSS文件上传功能。\n * - 上传文件到阿里云OSS\n * - 获取可用的OSS配置\n */\n\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { OssMcpServer } from \"./server.js\";\nimport { getServerConfig } from \"./config/oss.config.js\";\nimport { resolve } from \"path\";\nimport { config } from \"dotenv\";\n\n// 加载当前工作目录中的.env文件\nconfig({ path: resolve(process.cwd(), \".env\") });\n\nexport async function startServer(): Promise<void> {\n // 检查是否在stdio模式下运行\n const isStdioMode = process.env.NODE_ENV === \"cli\" || process.argv.includes(\"--stdio\");\n\n // 获取服务器配置\n const serverConfig = getServerConfig(isStdioMode);\n\n // 创建OSS MCP服务器\n const server = new OssMcpServer();\n\n if (isStdioMode) {\n // 在stdio模式下运行\n const transport = new StdioServerTransport();\n await server.connect(transport);\n } else {\n // 在HTTP模式下运行\n console.log(`初始化OSS MCP服务器,HTTP模式,端口: ${serverConfig.port}...`);\n await server.startHttpServer(serverConfig.port);\n }\n}\n\n// 启动服务器\nstartServer().catch((error) => {\n console.error(\"启动服务器失败:\", error);\n process.exit(1);\n});\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { ossService } from \"./services/oss.service.js\";\nimport express, { Request, Response } from \"express\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport { IncomingMessage, ServerResponse } from \"http\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport fs from 'fs';\nimport path from 'path';\nimport https from 'https';\nimport http from 'http';\n\nexport const Logger = {\n log: (...args: any[]) => {\n console.log(...args);\n },\n error: (...args: any[]) => {\n console.error(...args);\n }\n};\n\nexport class OssMcpServer {\n private readonly server: McpServer;\n private sseTransport: SSEServerTransport | null = null;\n\n constructor() {\n this.server = new McpServer(\n {\n name: \"@yhy2001/oss-mcp\",\n version: \"1.0.0\",\n },\n // 使用正确格式的capabilities配置\n {\n capabilities: {\n tools: { listChanged: true },\n resources: { listChanged: true },\n prompts: { listChanged: true },\n logging: {}\n }\n }\n );\n\n this.registerTools();\n }\n\n private registerTools(): void {\n // 获取可用的OSS配置\n const configs = ossService.getConfigs();\n const configNames = configs.map(config => config.id);\n\n // 工具:上传文件到OSS\n this.server.tool(\n \"upload_to_oss\",\n \"将文件上传到阿里云OSS\",\n {\n filePath: z.string().describe(\"要上传的本地文件路径\"),\n targetDir: z.string().optional().describe(\"OSS中的目标目录路径(可选)\"),\n fileName: z.string().optional().describe(\"上传后的文件名(可选,默认使用原文件名)\"),\n configName: z.string().optional().describe(`OSS配置名称(可选,默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ filePath, targetDir, fileName, configName }) => {\n try {\n Logger.log(`准备上传: ${filePath} 到 ${targetDir || '根目录'}`);\n\n if (!filePath) {\n throw new Error(\"文件路径是必需的\");\n }\n\n // 检查文件是否存在\n if (!fs.existsSync(filePath)) {\n throw new Error(`文件不存在: ${filePath}`);\n }\n\n // 执行上传\n const result = await ossService.uploadFile({\n filePath,\n targetDir,\n fileName,\n configName\n });\n\n if (result.success) {\n Logger.log(`上传成功: ${result.url}`);\n return {\n content: [{\n type: \"text\",\n text: `文件上传成功!\\n文件名: ${path.basename(filePath)}\\n目标位置: ${targetDir || '根目录'}\\nURL: ${result.url}\\n配置名称: ${result.ossConfigName}`\n }]\n };\n } else {\n Logger.error(`上传失败: ${result.error}`);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `上传失败: ${result.error}`\n }]\n };\n }\n } catch (error) {\n Logger.error(`上传过程中出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `上传出错: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出可用的OSS配置\n this.server.tool(\n \"list_oss_configs\",\n \"列出可用的阿里云OSS配置\",\n {},\n async () => {\n try {\n const configs = ossService.getConfigs();\n const configNames = configs.map(config => config.id);\n\n if (configNames.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: \"未找到OSS配置。请检查环境变量设置。\"\n }]\n };\n }\n\n return {\n content: [{\n type: \"text\",\n text: `可用的OSS配置:\\n${configNames.map(name => `- ${name}`).join('\\n')}`\n }]\n };\n } catch (error) {\n Logger.error(`获取OSS配置列表时出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `获取配置列表失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:批量重命名OSS文件\n this.server.tool(\n \"batch_rename_files\",\n \"批量重命名阿里云OSS文件。通过copy+delete实现。【重要】首次调用必须使用dryRun=true预览,展示给用户确认后,用户同意才能用dryRun=false执行实际重命名。禁止跳过预览直接执行!\",\n {\n directory: z.string().describe(\"OSS中的目录路径(如 'images/icons',根目录传空字符串 '')\"),\n renameRules: z.array(z.object({\n oldName: z.string().describe(\"原文件名\"),\n newName: z.string().describe(\"新文件名\")\n })).describe(\"重命名规则数组,每项包含原文件名和新文件名\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`),\n dryRun: z.boolean().optional().describe(\"是否为预览模式(默认false)。为true时只返回将要执行的操作,不实际重命名\")\n },\n async ({ directory, renameRules, configName = 'default', dryRun = false }) => {\n try {\n Logger.log(`OSS批量重命名: 目录=${directory}, 规则数=${renameRules.length}, 配置=${configName}, 预览模式=${dryRun}`);\n\n let results: { oldName: string; newName: string; success: boolean; error?: string }[];\n\n if (dryRun) {\n // 预览模式:只返回将要执行的操作\n results = renameRules.map(rule => ({\n oldName: rule.oldName,\n newName: rule.newName,\n success: true\n }));\n } else {\n // 实际执行OSS重命名\n results = await ossService.batchRenameFiles(renameRules, directory, configName);\n }\n\n const successCount = results.filter(r => r.success).length;\n const failCount = results.filter(r => !r.success).length;\n\n let resultText = dryRun ? `【预览模式】以下是将要执行的OSS文件重命名操作:\\n\\n` : `OSS文件批量重命名完成:\\n\\n`;\n resultText += `配置: ${configName}\\n`;\n resultText += `目录: ${directory || '根目录'}\\n`;\n resultText += `成功: ${successCount} 个, 失败: ${failCount} 个\\n\\n`;\n\n if (results.length > 0) {\n resultText += '详细结果:\\n';\n for (const r of results) {\n if (r.success) {\n resultText += `✅ ${r.oldName} → ${r.newName}\\n`;\n } else {\n resultText += `❌ ${r.oldName} → ${r.newName} (${r.error})\\n`;\n }\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`OSS批量重命名出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `OSS批量重命名失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出本地目录文件\n this.server.tool(\n \"list_directory_files\",\n \"列出本地文件系统中指定目录下的所有文件。注意:此工具仅支持本地路径,如果要列出 OSS 中的文件,请使用 list_oss_files 工具。\",\n {\n directory: z.string().describe(\"要查看的目录路径\"),\n pattern: z.string().optional().describe(\"文件名过滤模式(可选),如 '*.png' 或 'icon_*'\")\n },\n async ({ directory, pattern }) => {\n try {\n Logger.log(`列出目录文件: ${directory}, 过滤: ${pattern || '无'}`);\n\n // 检查目录是否存在\n if (!fs.existsSync(directory)) {\n throw new Error(`目录不存在: ${directory}`);\n }\n\n const stat = fs.statSync(directory);\n if (!stat.isDirectory()) {\n throw new Error(`路径不是目录: ${directory}`);\n }\n\n let files = fs.readdirSync(directory);\n\n // 过滤掉隐藏文件\n files = files.filter(f => !f.startsWith('.'));\n\n // 如果有 pattern,进行简单的通配符匹配\n if (pattern) {\n const regex = new RegExp(\n '^' + pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.') + '$',\n 'i'\n );\n files = files.filter(f => regex.test(f));\n }\n\n // 获取文件信息\n const fileInfos = files.map(f => {\n const filePath = path.join(directory, f);\n const fileStat = fs.statSync(filePath);\n return {\n name: f,\n isDirectory: fileStat.isDirectory(),\n size: fileStat.size\n };\n });\n\n // 排序:目录在前,文件在后,按名称排序\n fileInfos.sort((a, b) => {\n if (a.isDirectory !== b.isDirectory) {\n return a.isDirectory ? -1 : 1;\n }\n return a.name.localeCompare(b.name);\n });\n\n if (fileInfos.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: `目录 ${directory} 下没有找到匹配的文件${pattern ? ` (过滤: ${pattern})` : ''}`\n }]\n };\n }\n\n let resultText = `目录: ${directory}\\n`;\n if (pattern) {\n resultText += `过滤: ${pattern}\\n`;\n }\n resultText += `共 ${fileInfos.length} 个项目:\\n\\n`;\n\n for (const f of fileInfos) {\n if (f.isDirectory) {\n resultText += `📁 ${f.name}/\\n`;\n } else {\n const sizeStr = f.size < 1024\n ? `${f.size}B`\n : f.size < 1024 * 1024\n ? `${(f.size / 1024).toFixed(1)}KB`\n : `${(f.size / 1024 / 1024).toFixed(1)}MB`;\n resultText += `📄 ${f.name} (${sizeStr})\\n`;\n }\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`列出目录文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出目录失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:列出OSS目录文件\n this.server.tool(\n \"list_oss_files\",\n \"列出阿里云OSS指定目录下的所有文件。用于查看 OSS 中的文件以便进行重命名或其他操作。注意:如果要列出本地文件,请使用 list_directory_files 工具。\",\n {\n directory: z.string().describe(\"OSS中的目录路径(如 'images/icons',根目录传空字符串 '')\"),\n pattern: z.string().optional().describe(\"文件名过滤模式(可选),如 '*.png' 或 'icon_*'\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ directory, pattern, configName = 'default' }) => {\n try {\n Logger.log(`列出OSS目录文件: ${directory || '根目录'}, 过滤: ${pattern || '无'}, 配置: ${configName}`);\n\n const result = await ossService.listFiles(directory, configName, pattern);\n\n if (!result.success) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出OSS文件失败: ${result.error}`\n }]\n };\n }\n\n const files = result.files || [];\n\n if (files.length === 0) {\n return {\n content: [{\n type: \"text\",\n text: `OSS目录 ${directory || '根目录'} 下没有找到匹配的文件${pattern ? ` (过滤: ${pattern})` : ''}\\n配置: ${configName}`\n }]\n };\n }\n\n const sizeStr = (size: number) => size < 1024\n ? `${size}B`\n : size < 1024 * 1024\n ? `${(size / 1024).toFixed(1)}KB`\n : `${(size / 1024 / 1024).toFixed(1)}MB`;\n\n let resultText = `OSS目录: ${directory || '根目录'}\\n`;\n resultText += `配置: ${configName}\\n`;\n if (pattern) {\n resultText += `过滤: ${pattern}\\n`;\n }\n resultText += `共 ${files.length} 个文件:\\n\\n`;\n\n for (const f of files) {\n resultText += `📄 ${f.name} (${sizeStr(f.size)})\\n`;\n }\n\n return {\n content: [{\n type: \"text\",\n text: resultText\n }]\n };\n } catch (error) {\n Logger.error(`列出OSS目录文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `列出OSS目录失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:下载文件\n this.server.tool(\n \"download_file\",\n \"从 URL 下载文件到本地目录。支持 HTTP/HTTPS 链接,可自定义保存文件名。\",\n {\n url: z.string().describe(\"要下载的文件 URL\"),\n targetDir: z.string().describe(\"保存文件的本地目录路径\"),\n fileName: z.string().optional().describe(\"保存的文件名(可选,默认从 URL 提取)\")\n },\n async ({ url, targetDir, fileName }) => {\n try {\n Logger.log(`下载文件: ${url} 到 ${targetDir}`);\n\n // 检查目录是否存在,不存在则创建\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n Logger.log(`创建目录: ${targetDir}`);\n }\n\n const stat = fs.statSync(targetDir);\n if (!stat.isDirectory()) {\n throw new Error(`路径不是目录: ${targetDir}`);\n }\n\n // 从 URL 提取文件名\n let finalFileName = fileName;\n if (!finalFileName) {\n const urlObj = new URL(url);\n finalFileName = path.basename(urlObj.pathname);\n // 如果 URL 没有文件名,生成一个\n if (!finalFileName || finalFileName === '/') {\n finalFileName = `download_${Date.now()}`;\n }\n }\n\n const filePath = path.join(targetDir, finalFileName);\n\n // 检查文件是否已存在\n if (fs.existsSync(filePath)) {\n throw new Error(`文件已存在: ${filePath}`);\n }\n\n // 下载文件\n await new Promise<void>((resolve, reject) => {\n const urlObj = new URL(url);\n const protocol = urlObj.protocol === 'https:' ? https : http;\n\n const request = protocol.get(url, (response) => {\n // 处理重定向\n if (response.statusCode === 301 || response.statusCode === 302) {\n const redirectUrl = response.headers.location;\n if (redirectUrl) {\n Logger.log(`重定向到: ${redirectUrl}`);\n const redirectProtocol = redirectUrl.startsWith('https:') ? https : http;\n redirectProtocol.get(redirectUrl, (redirectResponse) => {\n if (redirectResponse.statusCode !== 200) {\n reject(new Error(`下载失败,HTTP 状态码: ${redirectResponse.statusCode}`));\n return;\n }\n const fileStream = fs.createWriteStream(filePath);\n redirectResponse.pipe(fileStream);\n fileStream.on('finish', () => {\n fileStream.close();\n resolve();\n });\n fileStream.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n }).on('error', reject);\n return;\n }\n }\n\n if (response.statusCode !== 200) {\n reject(new Error(`下载失败,HTTP 状态码: ${response.statusCode}`));\n return;\n }\n\n const fileStream = fs.createWriteStream(filePath);\n response.pipe(fileStream);\n\n fileStream.on('finish', () => {\n fileStream.close();\n resolve();\n });\n\n fileStream.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n });\n\n request.on('error', (err) => {\n fs.unlink(filePath, () => {});\n reject(err);\n });\n\n request.setTimeout(60000, () => {\n request.destroy();\n fs.unlink(filePath, () => {});\n reject(new Error('下载超时(60秒)'));\n });\n });\n\n // 获取文件大小\n const downloadedStat = fs.statSync(filePath);\n const sizeStr = downloadedStat.size < 1024\n ? `${downloadedStat.size}B`\n : downloadedStat.size < 1024 * 1024\n ? `${(downloadedStat.size / 1024).toFixed(1)}KB`\n : `${(downloadedStat.size / 1024 / 1024).toFixed(1)}MB`;\n\n return {\n content: [{\n type: \"text\",\n text: `文件下载成功!\\n源URL: ${url}\\n保存路径: ${filePath}\\n文件大小: ${sizeStr}`\n }]\n };\n } catch (error) {\n Logger.error(`下载文件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `下载失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:检查压缩图片的前置条件\n this.server.tool(\n \"check_compress_prerequisites\",\n `检查图片压缩的前置条件并返回用户询问模板。\n\n【⚠️ 极其重要 - AI 必须严格按以下顺序执行】\n\n第 1 步:检查 Playwright MCP(必须在调用本工具之前完成!)\n- 调用 browser_snapshot 工具\n- 如果成功:继续执行\n- 如果失败/报错:立即停止,告知用户需要启用 Playwright MCP\n\n第 2 步:如果图片在 OSS 上(必须在调用本工具之前完成!)\n- 先使用 list_oss_files 列出文件\n- ⚠️ 重要:下载到【项目目录】下的 .tmp-compress/ 文件夹,不能用 /tmp/!\n (Playwright MCP 只能访问项目目录内的文件)\n- 使用 download_file 将图片下载到项目目录下\n- 只有下载到本地后才能调用本工具\n\n第 3 步:调用本工具\n- 传入本地图片路径数组\n- 获取用户询问模板\n\n第 4 步:询问用户\n- 使用 AskUserQuestion 询问压缩引擎、输出格式等\n\n第 5 步:执行压缩\n- 调用 compress_images 工具`,\n {\n images: z.array(z.string()).describe(\"要压缩的【本地】图片路径数组。如果图片在 OSS 上,必须先用 download_file 下载到本地!\")\n },\n async ({ images }) => {\n try {\n // 验证图片文件\n const validImages: { path: string; name: string; ext: string; size: number }[] = [];\n const errors: string[] = [];\n\n for (const imgPath of images) {\n if (!fs.existsSync(imgPath)) {\n errors.push(`文件不存在: ${imgPath}`);\n continue;\n }\n const stat = fs.statSync(imgPath);\n if (stat.size > 5 * 1024 * 1024) {\n errors.push(`文件超过 5MB 限制: ${imgPath}`);\n continue;\n }\n const ext = path.extname(imgPath).toLowerCase().slice(1);\n if (!['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext)) {\n errors.push(`不支持的格式: ${imgPath}`);\n continue;\n }\n validImages.push({\n path: imgPath,\n name: path.basename(imgPath, path.extname(imgPath)),\n ext: ext === 'jpg' ? 'jpeg' : ext,\n size: stat.size\n });\n }\n\n if (validImages.length === 0) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `没有有效的图片可处理:\\n${errors.join('\\n')}`\n }]\n };\n }\n\n // 构建需要询问用户的问题\n const questions = {\n playwrightCheck: {\n instruction: \"请先使用 browser_snapshot 工具测试 Playwright MCP 是否可用。如果报错说明未配置。\"\n },\n engineQuestion: {\n question: \"请选择压缩引擎\",\n header: \"压缩引擎\",\n options: [\n { label: \"TinyPNG (推荐)\", description: \"支持 PNG/JPEG/WebP 输出,压缩质量高,每批最多 3 个文件\" },\n { label: \"AnyWebP\", description: \"固定输出 WebP 格式,每批最多 20 个文件\" }\n ]\n },\n formatQuestion: {\n question: \"是否需要转换输出格式?\",\n header: \"输出格式\",\n options: [\n { label: \"保持原格式\", description: \"不转换格式,仅压缩\" },\n { label: \"转换为 WebP\", description: \"转换为 WebP 格式,体积更小\" },\n { label: \"转换为 JPEG\", description: \"转换为 JPEG 格式(仅 TinyPNG)\" },\n { label: \"转换为 PNG\", description: \"转换为 PNG 格式(仅 TinyPNG)\" }\n ]\n },\n deleteOriginalQuestion: {\n question: \"转换格式后是否删除原文件?\",\n header: \"删除原文件\",\n options: [\n { label: \"保留原文件\", description: \"在 OSS 上保留原格式文件\" },\n { label: \"删除原文件\", description: \"转换后删除 OSS 上的原格式文件\" }\n ],\n condition: \"仅当选择了转换格式时才需要询问\"\n }\n };\n\n const sizeStr = (size: number) => size < 1024\n ? `${size}B`\n : size < 1024 * 1024\n ? `${(size / 1024).toFixed(1)}KB`\n : `${(size / 1024 / 1024).toFixed(1)}MB`;\n\n let resultText = `## 图片压缩前置检查\\n\\n`;\n resultText += `### ✅ 有效图片 (${validImages.length} 个)\\n`;\n for (const img of validImages) {\n resultText += `- ${path.basename(img.path)} (${sizeStr(img.size)})\\n`;\n }\n\n if (errors.length > 0) {\n resultText += `\\n### ⚠️ 跳过的文件\\n`;\n for (const err of errors) {\n resultText += `- ${err}\\n`;\n }\n }\n\n resultText += `\\n### 📋 AI 执行步骤\\n\\n`;\n resultText += `1. **检查 Playwright**: 调用 \\`browser_snapshot\\` 测试是否可用\\n`;\n resultText += ` - 如果报错,提示用户需要配置 Playwright MCP\\n`;\n resultText += `2. **询问用户**: 使用 AskUserQuestion 一次性询问以下问题:\\n`;\n resultText += ` - 选择压缩引擎 (TinyPNG / AnyWebP)\\n`;\n resultText += ` - 是否转换格式 (保持原格式 / WebP / JPEG / PNG)\\n`;\n resultText += ` - 如果转格式,是否删除原文件\\n`;\n resultText += `3. **执行压缩**: 根据用户选择调用 \\`compress_images\\`\\n`;\n\n return {\n content: [\n {\n type: \"text\",\n text: resultText\n },\n {\n type: \"text\",\n text: `\\n---\\n**询问模板 (JSON)**:\\n\\`\\`\\`json\\n${JSON.stringify(questions, null, 2)}\\n\\`\\`\\``\n }\n ]\n };\n } catch (error) {\n Logger.error(`检查前置条件出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `检查失败: ${error}`\n }]\n };\n }\n }\n );\n\n // 工具:压缩图片(生成压缩指令,由 AI 调用 Playwright MCP 执行)\n this.server.tool(\n \"compress_images\",\n `压缩图片工具。生成 Playwright 自动化压缩指令。\n\n【⚠️ 禁止直接调用!必须先完成以下步骤】\n\n✅ 第 1 步:验证 Playwright MCP 可用\n → 调用 browser_snapshot,如果报错则停止并提示用户启用\n\n✅ 第 2 步:确保图片在项目目录内\n → OSS 图片必须先用 download_file 下载到【项目目录】下的 .tmp-compress/ 文件夹\n → ⚠️ 不能用 /tmp/,Playwright 无法访问项目外的路径!\n\n✅ 第 3 步:调用 check_compress_prerequisites\n → 验证文件并获取询问模板\n\n✅ 第 4 步:询问用户偏好\n → 使用 AskUserQuestion 询问引擎、格式、是否删除原文件\n\n✅ 第 5 步:调用本工具\n → 传入用户选择的参数\n\n【后续流程】\n1. 按返回的指令使用 Playwright MCP 执行网页自动化\n2. 下载压缩结果\n3. 使用 upload_to_oss 上传回 OSS`,\n {\n images: z.array(z.string()).describe(\"要压缩的本地图片路径数组\"),\n engine: z.enum(['tinypng', 'anywebp']).describe(\"压缩引擎 (必须先询问用户选择)\"),\n outputFormat: z.enum(['png', 'jpeg', 'webp']).optional().describe(\"输出格式 (必须先询问用户选择,仅 tinypng 支持多格式)\"),\n deleteOriginal: z.boolean().optional().describe(\"转格式时是否删除原文件 (必须先询问用户选择)\"),\n ossDirectory: z.string().optional().describe(\"OSS 目标目录 (用于上传压缩后的文件)\"),\n configName: z.string().optional().describe(`OSS配置名称(默认为'default')。可用配置: ${configNames.join(', ') || '无'}`)\n },\n async ({ images, engine, outputFormat, deleteOriginal = false, ossDirectory, configName = 'default' }) => {\n try {\n Logger.log(`压缩图片: 引擎=${engine}, 格式=${outputFormat || '原格式'}, 图片数=${images.length}`);\n\n // 验证图片文件存在\n const validImages: { path: string; name: string; ext: string; size: number }[] = [];\n const errors: string[] = [];\n\n for (const imgPath of images) {\n if (!fs.existsSync(imgPath)) {\n errors.push(`文件不存在: ${imgPath}`);\n continue;\n }\n const stat = fs.statSync(imgPath);\n if (stat.size > 5 * 1024 * 1024) {\n errors.push(`文件超过 5MB 限制: ${imgPath}`);\n continue;\n }\n const ext = path.extname(imgPath).toLowerCase().slice(1);\n if (!['png', 'jpg', 'jpeg', 'webp', 'gif', 'bmp', 'tiff'].includes(ext)) {\n errors.push(`不支持的格式: ${imgPath}`);\n continue;\n }\n validImages.push({\n path: imgPath,\n name: path.basename(imgPath, path.extname(imgPath)),\n ext: ext === 'jpg' ? 'jpeg' : ext,\n size: stat.size\n });\n }\n\n if (validImages.length === 0) {\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `没有有效的图片可处理:\\n${errors.join('\\n')}`\n }]\n };\n }\n\n // 生成压缩指令\n const actualOutputFormat = engine === 'anywebp' ? 'webp' : (outputFormat || null);\n const batchSize = engine === 'tinypng' ? 3 : 20;\n const batches: typeof validImages[] = [];\n\n for (let i = 0; i < validImages.length; i += batchSize) {\n batches.push(validImages.slice(i, i + batchSize));\n }\n\n // 构建指令文本\n let instructions = `## 图片压缩指令\\n\\n`;\n instructions += `**引擎**: ${engine === 'tinypng' ? 'TinyPNG (https://tinypng.com/)' : 'AnyWebP (https://anywebp.com/convert-to-webp)'}\\n`;\n instructions += `**输出格式**: ${actualOutputFormat || '保持原格式'}\\n`;\n instructions += `**总图片数**: ${validImages.length}\\n`;\n instructions += `**批次数**: ${batches.length} (每批最多 ${batchSize} 个)\\n\\n`;\n\n if (errors.length > 0) {\n instructions += `### ⚠️ 跳过的文件\\n`;\n for (const err of errors) {\n instructions += `- ${err}\\n`;\n }\n instructions += `\\n`;\n }\n\n instructions += `### 📋 执行步骤\\n\\n`;\n instructions += `**前置检查**: 请确认 Playwright MCP 已配置并可用\\n\\n`;\n\n if (engine === 'tinypng') {\n instructions += this.generateTinyPngInstructions(batches, actualOutputFormat);\n } else {\n instructions += this.generateAnyWebPInstructions(batches);\n }\n\n // 添加后续处理指令\n instructions += `\\n### 📤 后续处理\\n\\n`;\n instructions += `压缩完成后,请执行以下操作:\\n\\n`;\n\n for (const img of validImages) {\n const newExt = actualOutputFormat || img.ext;\n const isFormatChange = newExt !== img.ext;\n const newFileName = `${img.name}.${newExt}`;\n const downloadPath = path.join(path.dirname(img.path), `${img.name}-compressed.${newExt}`);\n\n instructions += `**${path.basename(img.path)}**:\\n`;\n instructions += `1. 下载压缩结果到: \\`${downloadPath}\\`\\n`;\n\n if (ossDirectory) {\n if (isFormatChange) {\n instructions += `2. 上传到 OSS: \\`upload_to_oss(\"${downloadPath}\", \"${ossDirectory}\", \"${newFileName}\", \"${configName}\")\\`\\n`;\n if (deleteOriginal) {\n instructions += `3. 删除原文件: 在 OSS 上删除 \\`${ossDirectory}/${path.basename(img.path)}\\`\\n`;\n }\n } else {\n instructions += `2. 覆盖上传到 OSS: \\`upload_to_oss(\"${downloadPath}\", \"${ossDirectory}\", \"${path.basename(img.path)}\", \"${configName}\")\\`\\n`;\n }\n }\n instructions += `\\n`;\n }\n\n // 返回信息\n const resultInfo = {\n engine,\n outputFormat: actualOutputFormat,\n deleteOriginal: actualOutputFormat ? deleteOriginal : false,\n ossDirectory,\n configName,\n totalImages: validImages.length,\n batches: batches.length,\n batchSize,\n images: validImages.map(img => ({\n originalPath: img.path,\n originalName: path.basename(img.path),\n originalExt: img.ext,\n originalSize: img.size,\n newExt: actualOutputFormat || img.ext,\n isFormatChange: (actualOutputFormat || img.ext) !== img.ext\n }))\n };\n\n return {\n content: [\n {\n type: \"text\",\n text: instructions\n },\n {\n type: \"text\",\n text: `\\n---\\n**压缩任务数据 (JSON)**:\\n\\`\\`\\`json\\n${JSON.stringify(resultInfo, null, 2)}\\n\\`\\`\\``\n }\n ]\n };\n } catch (error) {\n Logger.error(`生成压缩指令出错:`, error);\n return {\n isError: true,\n content: [{\n type: \"text\",\n text: `生成压缩指令失败: ${error}`\n }]\n };\n }\n }\n );\n }\n\n // 生成 TinyPNG 自动化指令\n private generateTinyPngInstructions(batches: { path: string; name: string; ext: string; size: number }[][], outputFormat: string | null): string {\n let instructions = '';\n\n // 添加重要提示\n instructions += `### ⚠️ 重要提示\\n\\n`;\n instructions += `1. **图片必须在项目目录内**:Playwright MCP 只能访问项目目录下的文件。\\n`;\n instructions += ` - 不能使用 \\`/tmp/\\` 等系统临时目录\\n`;\n instructions += ` - 请将图片下载到项目根目录下的 \\`.tmp-compress/\\` 文件夹\\n`;\n instructions += `2. **上传前必须先触发文件选择框**:先点击上传区域,等待 Modal state 显示 \"File chooser\" 后再调用 \\`browser_file_upload\\`\\n\\n`;\n\n const needsFormatConversion = outputFormat && outputFormat !== 'png';\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n instructions += `#### 批次 ${i + 1}/${batches.length}\\n\\n`;\n instructions += `**文件**: ${batch.map(img => path.basename(img.path)).join(', ')}\\n\\n`;\n\n let stepNum = 1;\n instructions += `${stepNum++}. **打开网站**: 使用 \\`browser_navigate\\` 访问 \\`https://tinypng.com/\\`\\n`;\n instructions += `${stepNum++}. **等待加载**: 使用 \\`browser_snapshot\\` 确认页面加载完成\\n`;\n\n // 如果需要转换格式(WebP/JPEG),先开启开关\n if (needsFormatConversion) {\n instructions += `${stepNum++}. **开启格式转换开关**: \\n`;\n instructions += ` - 在页面底部找到 \"Convert my images automatically\" 开关\\n`;\n instructions += ` - 使用 \\`browser_click\\` 点击开关开启它(如果是关闭状态)\\n`;\n instructions += ` - 开启后会出现格式选择选项\\n`;\n instructions += `${stepNum++}. **选择输出格式**: \\n`;\n instructions += ` - 点击选择 \"${outputFormat!.toUpperCase()}\" 格式\\n`;\n }\n\n instructions += `${stepNum++}. **触发文件选择框**: \\n`;\n instructions += ` - 使用 \\`browser_click\\` 点击上传区域(\"Drop your .webp, .png or .jpg files here!\" 文字区域)\\n`;\n instructions += ` - 等待 \\`browser_snapshot\\` 返回结果中 Modal state 显示 \"[File chooser]\"\\n`;\n instructions += `${stepNum++}. **上传文件**: 使用 \\`browser_file_upload\\` 上传以下文件:\\n`;\n for (const img of batch) {\n instructions += ` - \\`${img.path}\\`\\n`;\n }\n instructions += `${stepNum++}. **等待压缩**: 使用 \\`browser_wait_for\\` 等待 \"Download all\" 或各文件的 \"download\" 按钮出现\\n`;\n instructions += `${stepNum++}. **下载结果**: 点击 \"Download all\" 或逐个下载\\n`;\n\n if (i < batches.length - 1) {\n instructions += `${stepNum++}. **刷新页面**: 使用 \\`browser_navigate\\` 重新访问 \\`https://tinypng.com/\\` 准备下一批\\n`;\n }\n instructions += `\\n`;\n }\n\n return instructions;\n }\n\n // 生成 AnyWebP 自动化指令\n private generateAnyWebPInstructions(batches: { path: string; name: string; ext: string; size: number }[][]): string {\n let instructions = '';\n\n // 添加重要提示\n instructions += `### ⚠️ 重要提示\\n\\n`;\n instructions += `1. **图片必须在项目目录内**:Playwright MCP 只能访问项目目录下的文件。\\n`;\n instructions += ` - 不能使用 \\`/tmp/\\` 等系统临时目录\\n`;\n instructions += ` - 请将图片下载到项目根目录下的 \\`.tmp-compress/\\` 文件夹\\n`;\n instructions += `2. **上传前必须先触发文件选择框**:先点击上传区域,等待 Modal state 显示 \"File chooser\" 后再调用 \\`browser_file_upload\\`\\n\\n`;\n\n for (let i = 0; i < batches.length; i++) {\n const batch = batches[i];\n instructions += `#### 批次 ${i + 1}/${batches.length}\\n\\n`;\n instructions += `**文件**: ${batch.map(img => path.basename(img.path)).join(', ')}\\n\\n`;\n\n let stepNum = 1;\n instructions += `${stepNum++}. **打开网站**: 使用 \\`browser_navigate\\` 访问 \\`https://anywebp.com/convert-to-webp.html\\`\\n`;\n instructions += `${stepNum++}. **等待加载**: 使用 \\`browser_snapshot\\` 确认页面加载完成\\n`;\n instructions += `${stepNum++}. **触发文件选择框**: \\n`;\n instructions += ` - 使用 \\`browser_click\\` 点击 \"Drop your images here!\" 上传区域\\n`;\n instructions += ` - 等待 \\`browser_snapshot\\` 返回结果中 Modal state 显示 \"[File chooser]\"\\n`;\n instructions += `${stepNum++}. **上传文件**: 使用 \\`browser_file_upload\\` 上传以下文件:\\n`;\n for (const img of batch) {\n instructions += ` - \\`${img.path}\\`\\n`;\n }\n instructions += `${stepNum++}. **等待转换**: 使用 \\`browser_wait_for\\` 等待转换完成,出现 \"Download\" 按钮\\n`;\n instructions += `${stepNum++}. **下载结果**: 点击 \"Download All\" 或逐个下载 WebP 文件\\n`;\n\n if (i < batches.length - 1) {\n instructions += `${stepNum++}. **刷新页面**: 使用 \\`browser_navigate\\` 重新访问准备下一批\\n`;\n }\n instructions += `\\n`;\n }\n\n return instructions;\n }\n\n async connect(transport: Transport): Promise<void> {\n try {\n await this.server.connect(transport);\n\n Logger.log = (...args: any[]) => {\n try {\n this.server.server.sendLoggingMessage({\n level: \"info\",\n data: args,\n });\n } catch (error) {\n console.log(...args);\n }\n };\n\n Logger.error = (...args: any[]) => {\n try {\n this.server.server.sendLoggingMessage({\n level: \"error\",\n data: args,\n });\n } catch (error) {\n console.error(...args);\n }\n };\n\n Logger.log(\"OSS MCP服务器已连接并准备处理请求\");\n } catch (error) {\n console.error(\"连接到传输时出错:\", error);\n }\n }\n\n async startHttpServer(port: number): Promise<void> {\n const app = express();\n\n // SSE连接端点 - 修复头部发送冲突\n app.get(\"/sse\", (req: Request, res: Response) => {\n // 初始化SSE传输,不再自己设置头部,而是让SDK处理\n this.sseTransport = new SSEServerTransport(\n \"/messages\",\n res as unknown as ServerResponse<IncomingMessage>\n );\n\n try {\n // 连接到传输层\n this.server.connect(this.sseTransport)\n .catch((err) => {\n console.error(\"连接到SSE传输时出错:\", err);\n });\n\n // 处理客户端断开连接\n req.on('close', () => {\n console.log('SSE客户端断开连接');\n this.sseTransport = null;\n });\n } catch (error) {\n console.error(\"建立SSE连接时出错:\", error);\n // 如果连接失败,关闭响应\n if (!res.writableEnded) {\n res.status(500).end();\n }\n }\n });\n\n // 消息端点\n app.post(\"/messages\", async (req: Request, res: Response) => {\n if (!this.sseTransport) {\n console.log(\"尝试发送消息,但SSE传输未初始化\");\n res.status(400).json({\n error: 'SSE连接未建立',\n message: '请先连接到/sse端点'\n });\n return;\n }\n\n try {\n await this.sseTransport.handlePostMessage(\n req as unknown as IncomingMessage,\n res as unknown as ServerResponse<IncomingMessage>\n );\n } catch (error) {\n console.error(\"处理消息时出错:\", error);\n if (!res.writableEnded) {\n res.status(500).json({\n error: \"内部服务器错误\",\n message: String(error)\n });\n }\n }\n });\n\n // 启动服务器\n app.listen(port, () => {\n Logger.log = console.log;\n Logger.error = console.error;\n\n Logger.log(`HTTP服务器监听端口: ${port}`);\n Logger.log(`SSE端点: http://localhost:${port}/sse`);\n Logger.log(`消息端点: http://localhost:${port}/messages`);\n });\n }\n}\n","import OSS from 'ali-oss';\nimport fs from 'fs';\nimport path from 'path';\nimport { OssConfig, getOssConfig, getAllOssConfigs } from '../config/oss.config.js';\nimport { z } from 'zod';\n\n// 上传文件参数验证Schema\nexport const UploadFileParamsSchema = z.object({\n filePath: z.string(),\n targetDir: z.string().optional(),\n fileName: z.string().optional(),\n configName: z.string().optional(),\n});\n\n// 导出上传文件参数类型\nexport type UploadFileParams = z.infer<typeof UploadFileParamsSchema>;\n\n// 上传结果验证Schema\nexport const UploadResultSchema = z.object({\n success: z.boolean(),\n url: z.string().optional(),\n error: z.string().optional(),\n ossConfigName: z.string().optional(),\n});\n\n// 导出上传结果类型\nexport type UploadResult = z.infer<typeof UploadResultSchema>;\n\n/**\n * OSS配置接口(包含ID和名称)\n */\nexport interface OssConfigWithMeta extends OssConfig {\n id: string;\n name: string;\n}\n\n/**\n * 阿里云OSS服务类\n */\nexport class OssService {\n private clients: Map<string, OSS> = new Map();\n\n /**\n * 获取所有OSS配置\n * @returns OSS配置列表\n */\n getConfigs(): OssConfigWithMeta[] {\n const configs: OssConfigWithMeta[] = [];\n const allConfigs = getAllOssConfigs();\n\n for (const [id, config] of Object.entries(allConfigs)) {\n configs.push({\n id,\n name: `${id.charAt(0).toUpperCase()}${id.slice(1)} 配置`,\n ...config\n });\n }\n\n return configs;\n }\n\n /**\n * 获取OSS客户端\n * @param configName 配置名称\n * @returns OSS客户端实例\n */\n private getClient(configName: string = 'default'): OSS | null {\n // 检查缓存中是否已有客户端\n if (this.clients.has(configName)) {\n return this.clients.get(configName) as OSS;\n }\n\n // 获取配置并创建客户端\n const config = getOssConfig(configName);\n if (!config) {\n return null;\n }\n\n try {\n const client = new OSS({\n region: config.region,\n accessKeyId: config.accessKeyId,\n accessKeySecret: config.accessKeySecret,\n bucket: config.bucket,\n endpoint: config.endpoint\n });\n\n // 缓存客户端实例\n this.clients.set(configName, client);\n return client;\n } catch (error) {\n console.error(`Failed to create OSS client for ${configName}:`, error);\n return null;\n }\n }\n\n /**\n * 上传文件到OSS\n * @param params 上传参数\n * @returns 上传结果\n */\n async uploadFile(params: UploadFileParams): Promise<UploadResult> {\n // 验证并解析参数\n const validParams = UploadFileParamsSchema.parse(params);\n const { filePath, targetDir = '', fileName, configName = 'default' } = validParams;\n\n try {\n // 检查文件是否存在\n if (!fs.existsSync(filePath)) {\n return UploadResultSchema.parse({\n success: false,\n error: `File not found: ${filePath}`,\n ossConfigName: configName\n });\n }\n\n // 获取OSS客户端\n const client = this.getClient(configName);\n if (!client) {\n return UploadResultSchema.parse({\n success: false,\n error: `OSS config not found for: ${configName}`,\n ossConfigName: configName\n });\n }\n\n // 确定文件名\n const actualFileName = fileName || path.basename(filePath);\n\n // 构建OSS路径,确保正斜杠格式\n let ossPath = actualFileName;\n if (targetDir) {\n // 规范化目标目录:移除头尾斜杠,然后加上结尾斜杠\n const normalizedDir = targetDir.replace(/^\\/+|\\/+$/g, '');\n ossPath = normalizedDir ? `${normalizedDir}/${actualFileName}` : actualFileName;\n }\n\n // 上传文件\n const result = await client.put(ossPath, filePath);\n\n return UploadResultSchema.parse({\n success: true,\n url: result.url,\n ossConfigName: configName\n });\n } catch (error) {\n return UploadResultSchema.parse({\n success: false,\n error: `Upload failed: ${(error as Error).message}`,\n ossConfigName: configName\n });\n }\n }\n\n /**\n * 重命名OSS文件(通过 copy + delete 实现)\n * @param oldKey 原文件路径\n * @param newKey 新文件路径\n * @param configName 配置名称\n * @returns 重命名结果\n */\n async renameFile(oldKey: string, newKey: string, configName: string = 'default'): Promise<{ success: boolean; error?: string }> {\n try {\n const client = this.getClient(configName);\n if (!client) {\n return { success: false, error: `OSS config not found for: ${configName}` };\n }\n\n // 规范化路径:移除开头的斜杠\n const normalizedOldKey = oldKey.replace(/^\\/+/, '');\n const normalizedNewKey = newKey.replace(/^\\/+/, '');\n\n // 检查源文件是否存在\n try {\n await client.head(normalizedOldKey);\n } catch (_e) {\n return { success: false, error: `源文件不存在: ${normalizedOldKey}` };\n }\n\n // 检查目标文件是否已存在\n try {\n await client.head(normalizedNewKey);\n // 如果到这里说明文件存在\n if (normalizedOldKey !== normalizedNewKey) {\n return { success: false, error: `目标文件已存在: ${normalizedNewKey}` };\n }\n } catch (_e) {\n // 文件不存在,可以继续\n }\n\n // Step 1: 复制文件到新位置\n await client.copy(normalizedNewKey, normalizedOldKey);\n\n // Step 2: 删除原文件\n await client.delete(normalizedOldKey);\n\n return { success: true };\n } catch (error) {\n return { success: false, error: `重命名失败: ${(error as Error).message}` };\n }\n }\n\n /**\n * 列出OSS目录下的文件\n * @param directory OSS目录路径\n * @param configName 配置名称\n * @param pattern 文件名过滤模式(可选)\n * @returns 文件列表\n */\n async listFiles(\n directory: string = '',\n configName: string = 'default',\n pattern?: string\n ): Promise<{ success: boolean; files?: Array<{ name: string; size: number; lastModified: Date }>; error?: string }> {\n try {\n const client = this.getClient(configName);\n if (!client) {\n return { success: false, error: `OSS config not found for: ${configName}` };\n }\n\n // 规范化目录路径\n const normalizedDir = directory.replace(/^\\/+|\\/+$/g, '');\n const prefix = normalizedDir ? `${normalizedDir}/` : '';\n\n // 列出文件\n const result = await client.list({\n prefix,\n delimiter: '/',\n 'max-keys': 1000\n }, {});\n\n const files: Array<{ name: string; size: number; lastModified: Date }> = [];\n\n // 处理文件对象\n if (result.objects) {\n for (const obj of result.objects) {\n // 跳过目录本身(以 / 结尾的)\n if (obj.name.endsWith('/')) continue;\n\n // 提取文件名(去掉目录前缀)\n const fileName = obj.name.replace(prefix, '');\n if (!fileName) continue;\n\n // 如果有 pattern,进行简单的通配符匹配\n if (pattern) {\n const regex = new RegExp(\n '^' + pattern\n .replace(/\\./g, '\\\\.')\n .replace(/\\*/g, '.*')\n .replace(/\\?/g, '.') + '$',\n 'i'\n );\n if (!regex.test(fileName)) continue;\n }\n\n files.push({\n name: fileName,\n size: obj.size,\n lastModified: new Date(obj.lastModified)\n });\n }\n }\n\n // 按文件名排序\n files.sort((a, b) => a.name.localeCompare(b.name));\n\n return { success: true, files };\n } catch (error) {\n return { success: false, error: `列出文件失败: ${(error as Error).message}` };\n }\n }\n\n /**\n * 批量重命名OSS文件\n * @param rules 重命名规则数组\n * @param directory OSS目录路径\n * @param configName 配置名称\n * @returns 批量重命名结果\n */\n async batchRenameFiles(\n rules: Array<{ oldName: string; newName: string }>,\n directory: string = '',\n configName: string = 'default'\n ): Promise<Array<{ oldName: string; newName: string; success: boolean; error?: string }>> {\n const results: Array<{ oldName: string; newName: string; success: boolean; error?: string }> = [];\n\n // 规范化目录路径\n const normalizedDir = directory.replace(/^\\/+|\\/+$/g, '');\n const dirPrefix = normalizedDir ? `${normalizedDir}/` : '';\n\n for (const rule of rules) {\n const oldKey = `${dirPrefix}${rule.oldName}`;\n const newKey = `${dirPrefix}${rule.newName}`;\n\n const result = await this.renameFile(oldKey, newKey, configName);\n results.push({\n oldName: rule.oldName,\n newName: rule.newName,\n success: result.success,\n error: result.error\n });\n }\n\n return results;\n }\n}\n\n// 导出单例实例\nexport const ossService = new OssService();\n","import { config } from \"dotenv\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\nimport { z } from \"zod\";\n\nconfig();\n\n// OSS配置验证Schema\nexport const OssConfigSchema = z.object({\n region: z.string(),\n accessKeyId: z.string(),\n accessKeySecret: z.string(),\n bucket: z.string(),\n endpoint: z.string(),\n});\n\n// 导出OSS配置类型\nexport type OssConfig = z.infer<typeof OssConfigSchema>;\n\n// 服务器配置接口\nexport interface ServerConfig {\n port: number;\n ossConfig: Record<string, OssConfig>;\n configSources: {\n port: \"cli\" | \"env\" | \"default\";\n ossConfig: \"cli\" | \"env\" | \"default\";\n };\n}\n\n// 掩码函数,用于打印敏感信息\nfunction maskSecret(secret: string): string {\n if (secret.length <= 4) return \"****\";\n return `${secret.substring(0, 4)}****${secret.slice(-4)}`;\n}\n\n// 获取服务器配置\nexport function getServerConfig(isStdioMode: boolean = false): ServerConfig {\n // 解析命令行参数\n const argv = yargs(hideBin(process.argv))\n .options({\n \"oss-config\": {\n type: \"string\",\n description: \"OSS配置JSON字符串\",\n },\n port: {\n type: \"number\",\n description: \"服务器运行端口\",\n default: 3000,\n },\n })\n .help()\n .version(\"1.0.0\")\n .parseSync();\n\n const config: ServerConfig = {\n port: 3000,\n ossConfig: {},\n configSources: {\n port: \"default\",\n ossConfig: \"default\",\n },\n };\n\n // 处理端口配置\n if (argv.port) {\n config.port = argv.port;\n config.configSources.port = \"cli\";\n } else if (process.env.PORT) {\n config.port = parseInt(process.env.PORT, 10);\n config.configSources.port = \"env\";\n }\n\n // 处理OSS配置 - 首先检查命令行参数\n if (argv[\"oss-config\"]) {\n const allOssConfigs = JSON.parse(argv[\"oss-config\"] as string);\n\n if (allOssConfigs.region && allOssConfigs.accessKeyId) {\n config.ossConfig.default = OssConfigSchema.parse(allOssConfigs);\n } else {\n Object.entries(allOssConfigs).forEach(([name, cfg]) => {\n config.ossConfig[name.toLowerCase()] = OssConfigSchema.parse(cfg);\n });\n }\n config.configSources.ossConfig = \"cli\";\n } else if (process.env.OSS_CONFIG_DEFAULT) {\n const ossConfig = JSON.parse(process.env.OSS_CONFIG_DEFAULT)\n config.ossConfig.default = OssConfigSchema.parse(ossConfig);\n config.configSources.ossConfig = \"env\";\n }\n\n // 检查其他命名的OSS配置\n Object.entries(process.env).forEach(([key, value]) => {\n if (key.startsWith(\"OSS_CONFIG_\") && key !== \"OSS_CONFIG_DEFAULT\" && value) {\n try {\n const configName = key.replace(\"OSS_CONFIG_\", \"\").toLowerCase();\n const ossConfig = JSON.parse(value);\n config.ossConfig[configName] = OssConfigSchema.parse(ossConfig);\n } catch (error) {\n console.error(`解析环境变量${key}失败:`, error);\n }\n }\n });\n\n // 验证配置\n if (Object.keys(config.ossConfig).length === 0) {\n console.warn(\"未找到有效的OSS配置。服务器将启动,但上传功能将不可用。\");\n }\n\n // 打印配置信息(非stdio模式下)\n if (!isStdioMode) {\n console.log(\"\\n配置信息:\");\n console.log(`- 端口: ${config.port} (来源: ${config.configSources.port})`);\n\n if (Object.keys(config.ossConfig).length > 0) {\n console.log(\"- OSS配置:\");\n Object.entries(config.ossConfig).forEach(([name, cfg]) => {\n console.log(` - ${name}:`);\n console.log(` Region: ${cfg.region}`);\n console.log(` Endpoint: ${cfg.endpoint}`);\n console.log(` Bucket: ${cfg.bucket}`);\n console.log(` AccessKeyId: ${maskSecret(cfg.accessKeyId)}`);\n console.log(` AccessKeySecret: ${maskSecret(cfg.accessKeySecret)}`);\n });\n } else {\n console.log(\"- OSS配置: 未找到\");\n }\n console.log(); // 空行,增加可读性\n }\n\n return config;\n}\n\n// 获取所有OSS配置\nexport function getAllOssConfigs(): Record<string, OssConfig> {\n const { ossConfig } = getServerConfig(true);\n return ossConfig;\n}\n\n// 获取特定名称的OSS配置\nexport function getOssConfig(name: string = 'default'): OssConfig | null {\n const configs = getAllOssConfigs();\n const normalizedName = name.toLowerCase();\n return configs[normalizedName] || null;\n}\n\n// 获取可用的OSS配置名称列表\nexport function getAvailableOssConfigNames(): string[] {\n return Object.keys(getAllOssConfigs());\n}\n"],"mappings":"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","names":["z","config","z","config","fs","path","config","z","configs","configNames","resolve","fileStream","config"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oss-mcp-plus",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "本地MCP服务器,用于将文件上传到阿里云OSS,支持多配置和目录指定",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",