oss-mcp-plus 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -2
- package/dist/index.js +403 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OSS MCP Plus 🚀
|
|
2
2
|
|
|
3
|
-
> Fork 自 [1yhy/oss-mcp](https://github.com/1yhy/oss-mcp)
|
|
3
|
+
> Fork 自 [1yhy/oss-mcp](https://github.com/1yhy/oss-mcp),新增批量重命名、目录列表、文件下载,以及图片批量压缩等实用重磅工具。
|
|
4
4
|
|
|
5
5
|
<img width="1280" height="2034" alt="image" src="https://github.com/user-attachments/assets/c03c3716-109b-49a5-ab7c-113a6777c868" />
|
|
6
6
|
|
|
@@ -29,6 +29,7 @@ OSS MCP服务器能够与其他MCP工具无缝集成,为您提供强大的工
|
|
|
29
29
|
- 📥 支持从 URL 下载文件到本地
|
|
30
30
|
- 📂 列出目录文件,支持通配符过滤
|
|
31
31
|
- ✏️ 批量重命名文件,支持预览模式
|
|
32
|
+
- 🗜️ 批量压缩图片(支持 TinyPNG / AnyWebP)
|
|
32
33
|
|
|
33
34
|
## 🔧 安装
|
|
34
35
|
|
|
@@ -132,7 +133,7 @@ pnpm start:http
|
|
|
132
133
|
pnpm inspect
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
## 🛠️ 与Claude/Cursor
|
|
136
|
+
## 🛠️ 与Claude/Cursor等AI工具集成
|
|
136
137
|
|
|
137
138
|
### Cursor配置方法
|
|
138
139
|
|
|
@@ -174,6 +175,12 @@ pnpm inspect
|
|
|
174
175
|
}
|
|
175
176
|
```
|
|
176
177
|
|
|
178
|
+
### 推荐方式:使用 MCP Switch 客户端
|
|
179
|
+
|
|
180
|
+
借助本作者的另一客户端软件 [MCP Switch](https://github.com/lovelyJason/mcp-switch),可以通过可视化界面轻松添加和管理 MCP 服务器:
|
|
181
|
+
|
|
182
|
+

|
|
183
|
+
|
|
177
184
|
## 🧰 可用工具
|
|
178
185
|
|
|
179
186
|
服务器提供以下工具:
|
|
@@ -217,6 +224,36 @@ pnpm inspect
|
|
|
217
224
|
- `targetDir`: 保存文件的本地目录路径(必需)
|
|
218
225
|
- `fileName`: 保存的文件名(可选,默认从 URL 提取)
|
|
219
226
|
|
|
227
|
+
### 6. 压缩图片 (`compress_images`) 🆕
|
|
228
|
+
|
|
229
|
+
批量压缩图片工具,支持 TinyPNG 和 AnyWebP 两个在线压缩引擎。需配合 Playwright MCP 使用。
|
|
230
|
+
|
|
231
|
+
**参数**:
|
|
232
|
+
- `images`: 要压缩的本地图片路径数组(必需)
|
|
233
|
+
- `engine`: 压缩引擎(必需),可选值:
|
|
234
|
+
- `tinypng`: 支持 PNG/JPEG/WebP 输出,每批最多 3 个文件
|
|
235
|
+
- `anywebp`: 固定输出 WebP,每批最多 20 个文件
|
|
236
|
+
- `outputFormat`: 输出格式(可选,仅 tinypng 有效),可选值: `png`/`jpeg`/`webp`
|
|
237
|
+
- `deleteOriginal`: 转格式时是否删除原文件(可选,默认 false)
|
|
238
|
+
- `ossDirectory`: OSS 目标目录(可选)
|
|
239
|
+
- `configName`: OSS 配置名称(可选,默认为 `default`)
|
|
240
|
+
|
|
241
|
+
**使用示例**:
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
用户: 帮我压缩这几张图片并上传到 OSS
|
|
245
|
+
AI:
|
|
246
|
+
1. 调用 compress_images 获取压缩指令
|
|
247
|
+
2. 使用 Playwright MCP 执行网页自动化压缩
|
|
248
|
+
3. 下载压缩结果
|
|
249
|
+
4. 使用 upload_to_oss 上传回 OSS
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**注意事项**:
|
|
253
|
+
- 需要同时配置 Playwright MCP 才能完成压缩
|
|
254
|
+
- TinyPNG 免费版每次最多上传 3 个文件,超过会自动分批处理
|
|
255
|
+
- 单个文件大小限制为 5MB
|
|
256
|
+
|
|
220
257
|
## 📦 发布
|
|
221
258
|
|
|
222
259
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -678,6 +678,409 @@ ${configNames2.map((name) => `- ${name}`).join("\n")}`
|
|
|
678
678
|
}
|
|
679
679
|
}
|
|
680
680
|
);
|
|
681
|
+
this.server.tool(
|
|
682
|
+
"check_compress_prerequisites",
|
|
683
|
+
`\u68C0\u67E5\u56FE\u7247\u538B\u7F29\u7684\u524D\u7F6E\u6761\u4EF6\u3002\u5728\u8C03\u7528 compress_images \u4E4B\u524D\u5FC5\u987B\u5148\u8C03\u7528\u6B64\u5DE5\u5177\uFF01
|
|
684
|
+
|
|
685
|
+
\u6B64\u5DE5\u5177\u4F1A\u68C0\u67E5\uFF1A
|
|
686
|
+
1. Playwright MCP \u662F\u5426\u53EF\u7528\uFF08\u901A\u8FC7\u5C1D\u8BD5\u8C03\u7528 browser_snapshot\uFF09
|
|
687
|
+
2. \u8FD4\u56DE\u9700\u8981 AI \u5411\u7528\u6237\u8BE2\u95EE\u7684\u95EE\u9898
|
|
688
|
+
|
|
689
|
+
\u3010\u91CD\u8981\u3011AI \u5FC5\u987B\u6309\u4EE5\u4E0B\u6D41\u7A0B\u64CD\u4F5C\uFF1A
|
|
690
|
+
1. \u5148\u8C03\u7528\u6B64\u5DE5\u5177\u68C0\u67E5\u524D\u7F6E\u6761\u4EF6
|
|
691
|
+
2. \u6839\u636E\u8FD4\u56DE\u7684 questions \u4F7F\u7528 AskUserQuestion \u8BE2\u95EE\u7528\u6237
|
|
692
|
+
3. \u6536\u96C6\u7528\u6237\u9009\u62E9\u540E\u518D\u8C03\u7528 compress_images`,
|
|
693
|
+
{
|
|
694
|
+
images: z3.array(z3.string()).describe("\u8981\u538B\u7F29\u7684\u672C\u5730\u56FE\u7247\u8DEF\u5F84\u6570\u7EC4\uFF08\u7528\u4E8E\u9A8C\u8BC1\u6587\u4EF6\u5B58\u5728\uFF09")
|
|
695
|
+
},
|
|
696
|
+
async ({ images }) => {
|
|
697
|
+
try {
|
|
698
|
+
const validImages = [];
|
|
699
|
+
const errors = [];
|
|
700
|
+
for (const imgPath of images) {
|
|
701
|
+
if (!fs2.existsSync(imgPath)) {
|
|
702
|
+
errors.push(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${imgPath}`);
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
const stat = fs2.statSync(imgPath);
|
|
706
|
+
if (stat.size > 5 * 1024 * 1024) {
|
|
707
|
+
errors.push(`\u6587\u4EF6\u8D85\u8FC7 5MB \u9650\u5236: ${imgPath}`);
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
const ext = path2.extname(imgPath).toLowerCase().slice(1);
|
|
711
|
+
if (!["png", "jpg", "jpeg", "webp", "gif", "bmp", "tiff"].includes(ext)) {
|
|
712
|
+
errors.push(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${imgPath}`);
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
validImages.push({
|
|
716
|
+
path: imgPath,
|
|
717
|
+
name: path2.basename(imgPath, path2.extname(imgPath)),
|
|
718
|
+
ext: ext === "jpg" ? "jpeg" : ext,
|
|
719
|
+
size: stat.size
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
if (validImages.length === 0) {
|
|
723
|
+
return {
|
|
724
|
+
isError: true,
|
|
725
|
+
content: [{
|
|
726
|
+
type: "text",
|
|
727
|
+
text: `\u6CA1\u6709\u6709\u6548\u7684\u56FE\u7247\u53EF\u5904\u7406:
|
|
728
|
+
${errors.join("\n")}`
|
|
729
|
+
}]
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
const questions = {
|
|
733
|
+
playwrightCheck: {
|
|
734
|
+
instruction: "\u8BF7\u5148\u4F7F\u7528 browser_snapshot \u5DE5\u5177\u6D4B\u8BD5 Playwright MCP \u662F\u5426\u53EF\u7528\u3002\u5982\u679C\u62A5\u9519\u8BF4\u660E\u672A\u914D\u7F6E\u3002"
|
|
735
|
+
},
|
|
736
|
+
engineQuestion: {
|
|
737
|
+
question: "\u8BF7\u9009\u62E9\u538B\u7F29\u5F15\u64CE",
|
|
738
|
+
header: "\u538B\u7F29\u5F15\u64CE",
|
|
739
|
+
options: [
|
|
740
|
+
{ label: "TinyPNG (\u63A8\u8350)", description: "\u652F\u6301 PNG/JPEG/WebP \u8F93\u51FA\uFF0C\u538B\u7F29\u8D28\u91CF\u9AD8\uFF0C\u6BCF\u6279\u6700\u591A 3 \u4E2A\u6587\u4EF6" },
|
|
741
|
+
{ label: "AnyWebP", description: "\u56FA\u5B9A\u8F93\u51FA WebP \u683C\u5F0F\uFF0C\u6BCF\u6279\u6700\u591A 20 \u4E2A\u6587\u4EF6" }
|
|
742
|
+
]
|
|
743
|
+
},
|
|
744
|
+
formatQuestion: {
|
|
745
|
+
question: "\u662F\u5426\u9700\u8981\u8F6C\u6362\u8F93\u51FA\u683C\u5F0F\uFF1F",
|
|
746
|
+
header: "\u8F93\u51FA\u683C\u5F0F",
|
|
747
|
+
options: [
|
|
748
|
+
{ label: "\u4FDD\u6301\u539F\u683C\u5F0F", description: "\u4E0D\u8F6C\u6362\u683C\u5F0F\uFF0C\u4EC5\u538B\u7F29" },
|
|
749
|
+
{ label: "\u8F6C\u6362\u4E3A WebP", description: "\u8F6C\u6362\u4E3A WebP \u683C\u5F0F\uFF0C\u4F53\u79EF\u66F4\u5C0F" },
|
|
750
|
+
{ label: "\u8F6C\u6362\u4E3A JPEG", description: "\u8F6C\u6362\u4E3A JPEG \u683C\u5F0F\uFF08\u4EC5 TinyPNG\uFF09" },
|
|
751
|
+
{ label: "\u8F6C\u6362\u4E3A PNG", description: "\u8F6C\u6362\u4E3A PNG \u683C\u5F0F\uFF08\u4EC5 TinyPNG\uFF09" }
|
|
752
|
+
]
|
|
753
|
+
},
|
|
754
|
+
deleteOriginalQuestion: {
|
|
755
|
+
question: "\u8F6C\u6362\u683C\u5F0F\u540E\u662F\u5426\u5220\u9664\u539F\u6587\u4EF6\uFF1F",
|
|
756
|
+
header: "\u5220\u9664\u539F\u6587\u4EF6",
|
|
757
|
+
options: [
|
|
758
|
+
{ label: "\u4FDD\u7559\u539F\u6587\u4EF6", description: "\u5728 OSS \u4E0A\u4FDD\u7559\u539F\u683C\u5F0F\u6587\u4EF6" },
|
|
759
|
+
{ label: "\u5220\u9664\u539F\u6587\u4EF6", description: "\u8F6C\u6362\u540E\u5220\u9664 OSS \u4E0A\u7684\u539F\u683C\u5F0F\u6587\u4EF6" }
|
|
760
|
+
],
|
|
761
|
+
condition: "\u4EC5\u5F53\u9009\u62E9\u4E86\u8F6C\u6362\u683C\u5F0F\u65F6\u624D\u9700\u8981\u8BE2\u95EE"
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
const sizeStr = (size) => size < 1024 ? `${size}B` : size < 1024 * 1024 ? `${(size / 1024).toFixed(1)}KB` : `${(size / 1024 / 1024).toFixed(1)}MB`;
|
|
765
|
+
let resultText = `## \u56FE\u7247\u538B\u7F29\u524D\u7F6E\u68C0\u67E5
|
|
766
|
+
|
|
767
|
+
`;
|
|
768
|
+
resultText += `### \u2705 \u6709\u6548\u56FE\u7247 (${validImages.length} \u4E2A)
|
|
769
|
+
`;
|
|
770
|
+
for (const img of validImages) {
|
|
771
|
+
resultText += `- ${path2.basename(img.path)} (${sizeStr(img.size)})
|
|
772
|
+
`;
|
|
773
|
+
}
|
|
774
|
+
if (errors.length > 0) {
|
|
775
|
+
resultText += `
|
|
776
|
+
### \u26A0\uFE0F \u8DF3\u8FC7\u7684\u6587\u4EF6
|
|
777
|
+
`;
|
|
778
|
+
for (const err of errors) {
|
|
779
|
+
resultText += `- ${err}
|
|
780
|
+
`;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
resultText += `
|
|
784
|
+
### \u{1F4CB} AI \u6267\u884C\u6B65\u9AA4
|
|
785
|
+
|
|
786
|
+
`;
|
|
787
|
+
resultText += `1. **\u68C0\u67E5 Playwright**: \u8C03\u7528 \`browser_snapshot\` \u6D4B\u8BD5\u662F\u5426\u53EF\u7528
|
|
788
|
+
`;
|
|
789
|
+
resultText += ` - \u5982\u679C\u62A5\u9519\uFF0C\u63D0\u793A\u7528\u6237\u9700\u8981\u914D\u7F6E Playwright MCP
|
|
790
|
+
`;
|
|
791
|
+
resultText += `2. **\u8BE2\u95EE\u7528\u6237**: \u4F7F\u7528 AskUserQuestion \u4E00\u6B21\u6027\u8BE2\u95EE\u4EE5\u4E0B\u95EE\u9898:
|
|
792
|
+
`;
|
|
793
|
+
resultText += ` - \u9009\u62E9\u538B\u7F29\u5F15\u64CE (TinyPNG / AnyWebP)
|
|
794
|
+
`;
|
|
795
|
+
resultText += ` - \u662F\u5426\u8F6C\u6362\u683C\u5F0F (\u4FDD\u6301\u539F\u683C\u5F0F / WebP / JPEG / PNG)
|
|
796
|
+
`;
|
|
797
|
+
resultText += ` - \u5982\u679C\u8F6C\u683C\u5F0F\uFF0C\u662F\u5426\u5220\u9664\u539F\u6587\u4EF6
|
|
798
|
+
`;
|
|
799
|
+
resultText += `3. **\u6267\u884C\u538B\u7F29**: \u6839\u636E\u7528\u6237\u9009\u62E9\u8C03\u7528 \`compress_images\`
|
|
800
|
+
`;
|
|
801
|
+
return {
|
|
802
|
+
content: [
|
|
803
|
+
{
|
|
804
|
+
type: "text",
|
|
805
|
+
text: resultText
|
|
806
|
+
},
|
|
807
|
+
{
|
|
808
|
+
type: "text",
|
|
809
|
+
text: `
|
|
810
|
+
---
|
|
811
|
+
**\u8BE2\u95EE\u6A21\u677F (JSON)**:
|
|
812
|
+
\`\`\`json
|
|
813
|
+
${JSON.stringify(questions, null, 2)}
|
|
814
|
+
\`\`\``
|
|
815
|
+
}
|
|
816
|
+
]
|
|
817
|
+
};
|
|
818
|
+
} catch (error) {
|
|
819
|
+
Logger.error(`\u68C0\u67E5\u524D\u7F6E\u6761\u4EF6\u51FA\u9519:`, error);
|
|
820
|
+
return {
|
|
821
|
+
isError: true,
|
|
822
|
+
content: [{
|
|
823
|
+
type: "text",
|
|
824
|
+
text: `\u68C0\u67E5\u5931\u8D25: ${error}`
|
|
825
|
+
}]
|
|
826
|
+
};
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
);
|
|
830
|
+
this.server.tool(
|
|
831
|
+
"compress_images",
|
|
832
|
+
`\u538B\u7F29\u56FE\u7247\u5DE5\u5177\u3002\u751F\u6210\u538B\u7F29\u6307\u4EE4\uFF0C\u9700\u914D\u5408 Playwright MCP \u6267\u884C\u3002
|
|
833
|
+
|
|
834
|
+
\u3010\u91CD\u8981\u3011\u8C03\u7528\u6B64\u5DE5\u5177\u524D\uFF0CAI \u5FC5\u987B\uFF1A
|
|
835
|
+
1. \u5148\u8C03\u7528 check_compress_prerequisites \u68C0\u67E5\u524D\u7F6E\u6761\u4EF6
|
|
836
|
+
2. \u4F7F\u7528 browser_snapshot \u786E\u8BA4 Playwright MCP \u53EF\u7528
|
|
837
|
+
3. \u4F7F\u7528 AskUserQuestion \u8BE2\u95EE\u7528\u6237\u9009\u62E9\u5F15\u64CE\u3001\u8F93\u51FA\u683C\u5F0F\u3001\u662F\u5426\u5220\u9664\u539F\u6587\u4EF6
|
|
838
|
+
4. \u5982\u679C\u56FE\u7247\u5728 OSS \u4E0A\uFF0C\u5148\u7528 download_file \u4E0B\u8F7D\u5230\u672C\u5730
|
|
839
|
+
|
|
840
|
+
\u3010\u5DE5\u4F5C\u6D41\u7A0B\u3011
|
|
841
|
+
1. \u8C03\u7528\u6B64\u5DE5\u5177\u83B7\u53D6\u538B\u7F29\u6307\u4EE4
|
|
842
|
+
2. \u6309\u6307\u4EE4\u4F7F\u7528 Playwright MCP \u6267\u884C\u7F51\u9875\u81EA\u52A8\u5316
|
|
843
|
+
3. \u4E0B\u8F7D\u538B\u7F29\u7ED3\u679C\u5230\u672C\u5730
|
|
844
|
+
4. \u4F7F\u7528 upload_to_oss \u4E0A\u4F20\u56DE OSS`,
|
|
845
|
+
{
|
|
846
|
+
images: z3.array(z3.string()).describe("\u8981\u538B\u7F29\u7684\u672C\u5730\u56FE\u7247\u8DEF\u5F84\u6570\u7EC4"),
|
|
847
|
+
engine: z3.enum(["tinypng", "anywebp"]).describe("\u538B\u7F29\u5F15\u64CE (\u5FC5\u987B\u5148\u8BE2\u95EE\u7528\u6237\u9009\u62E9)"),
|
|
848
|
+
outputFormat: z3.enum(["png", "jpeg", "webp"]).optional().describe("\u8F93\u51FA\u683C\u5F0F (\u5FC5\u987B\u5148\u8BE2\u95EE\u7528\u6237\u9009\u62E9\uFF0C\u4EC5 tinypng \u652F\u6301\u591A\u683C\u5F0F)"),
|
|
849
|
+
deleteOriginal: z3.boolean().optional().describe("\u8F6C\u683C\u5F0F\u65F6\u662F\u5426\u5220\u9664\u539F\u6587\u4EF6 (\u5FC5\u987B\u5148\u8BE2\u95EE\u7528\u6237\u9009\u62E9)"),
|
|
850
|
+
ossDirectory: z3.string().optional().describe("OSS \u76EE\u6807\u76EE\u5F55 (\u7528\u4E8E\u4E0A\u4F20\u538B\u7F29\u540E\u7684\u6587\u4EF6)"),
|
|
851
|
+
configName: z3.string().optional().describe(`OSS\u914D\u7F6E\u540D\u79F0\uFF08\u9ED8\u8BA4\u4E3A'default'\uFF09\u3002\u53EF\u7528\u914D\u7F6E: ${configNames.join(", ") || "\u65E0"}`)
|
|
852
|
+
},
|
|
853
|
+
async ({ images, engine, outputFormat, deleteOriginal = false, ossDirectory, configName = "default" }) => {
|
|
854
|
+
try {
|
|
855
|
+
Logger.log(`\u538B\u7F29\u56FE\u7247: \u5F15\u64CE=${engine}, \u683C\u5F0F=${outputFormat || "\u539F\u683C\u5F0F"}, \u56FE\u7247\u6570=${images.length}`);
|
|
856
|
+
const validImages = [];
|
|
857
|
+
const errors = [];
|
|
858
|
+
for (const imgPath of images) {
|
|
859
|
+
if (!fs2.existsSync(imgPath)) {
|
|
860
|
+
errors.push(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${imgPath}`);
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
863
|
+
const stat = fs2.statSync(imgPath);
|
|
864
|
+
if (stat.size > 5 * 1024 * 1024) {
|
|
865
|
+
errors.push(`\u6587\u4EF6\u8D85\u8FC7 5MB \u9650\u5236: ${imgPath}`);
|
|
866
|
+
continue;
|
|
867
|
+
}
|
|
868
|
+
const ext = path2.extname(imgPath).toLowerCase().slice(1);
|
|
869
|
+
if (!["png", "jpg", "jpeg", "webp", "gif", "bmp", "tiff"].includes(ext)) {
|
|
870
|
+
errors.push(`\u4E0D\u652F\u6301\u7684\u683C\u5F0F: ${imgPath}`);
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
validImages.push({
|
|
874
|
+
path: imgPath,
|
|
875
|
+
name: path2.basename(imgPath, path2.extname(imgPath)),
|
|
876
|
+
ext: ext === "jpg" ? "jpeg" : ext,
|
|
877
|
+
size: stat.size
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
if (validImages.length === 0) {
|
|
881
|
+
return {
|
|
882
|
+
isError: true,
|
|
883
|
+
content: [{
|
|
884
|
+
type: "text",
|
|
885
|
+
text: `\u6CA1\u6709\u6709\u6548\u7684\u56FE\u7247\u53EF\u5904\u7406:
|
|
886
|
+
${errors.join("\n")}`
|
|
887
|
+
}]
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
const actualOutputFormat = engine === "anywebp" ? "webp" : outputFormat || null;
|
|
891
|
+
const batchSize = engine === "tinypng" ? 3 : 20;
|
|
892
|
+
const batches = [];
|
|
893
|
+
for (let i = 0; i < validImages.length; i += batchSize) {
|
|
894
|
+
batches.push(validImages.slice(i, i + batchSize));
|
|
895
|
+
}
|
|
896
|
+
let instructions = `## \u56FE\u7247\u538B\u7F29\u6307\u4EE4
|
|
897
|
+
|
|
898
|
+
`;
|
|
899
|
+
instructions += `**\u5F15\u64CE**: ${engine === "tinypng" ? "TinyPNG (https://tinypng.com/)" : "AnyWebP (https://anywebp.com/convert-to-webp)"}
|
|
900
|
+
`;
|
|
901
|
+
instructions += `**\u8F93\u51FA\u683C\u5F0F**: ${actualOutputFormat || "\u4FDD\u6301\u539F\u683C\u5F0F"}
|
|
902
|
+
`;
|
|
903
|
+
instructions += `**\u603B\u56FE\u7247\u6570**: ${validImages.length}
|
|
904
|
+
`;
|
|
905
|
+
instructions += `**\u6279\u6B21\u6570**: ${batches.length} (\u6BCF\u6279\u6700\u591A ${batchSize} \u4E2A)
|
|
906
|
+
|
|
907
|
+
`;
|
|
908
|
+
if (errors.length > 0) {
|
|
909
|
+
instructions += `### \u26A0\uFE0F \u8DF3\u8FC7\u7684\u6587\u4EF6
|
|
910
|
+
`;
|
|
911
|
+
for (const err of errors) {
|
|
912
|
+
instructions += `- ${err}
|
|
913
|
+
`;
|
|
914
|
+
}
|
|
915
|
+
instructions += `
|
|
916
|
+
`;
|
|
917
|
+
}
|
|
918
|
+
instructions += `### \u{1F4CB} \u6267\u884C\u6B65\u9AA4
|
|
919
|
+
|
|
920
|
+
`;
|
|
921
|
+
instructions += `**\u524D\u7F6E\u68C0\u67E5**: \u8BF7\u786E\u8BA4 Playwright MCP \u5DF2\u914D\u7F6E\u5E76\u53EF\u7528
|
|
922
|
+
|
|
923
|
+
`;
|
|
924
|
+
if (engine === "tinypng") {
|
|
925
|
+
instructions += this.generateTinyPngInstructions(batches, actualOutputFormat);
|
|
926
|
+
} else {
|
|
927
|
+
instructions += this.generateAnyWebPInstructions(batches);
|
|
928
|
+
}
|
|
929
|
+
instructions += `
|
|
930
|
+
### \u{1F4E4} \u540E\u7EED\u5904\u7406
|
|
931
|
+
|
|
932
|
+
`;
|
|
933
|
+
instructions += `\u538B\u7F29\u5B8C\u6210\u540E\uFF0C\u8BF7\u6267\u884C\u4EE5\u4E0B\u64CD\u4F5C:
|
|
934
|
+
|
|
935
|
+
`;
|
|
936
|
+
for (const img of validImages) {
|
|
937
|
+
const newExt = actualOutputFormat || img.ext;
|
|
938
|
+
const isFormatChange = newExt !== img.ext;
|
|
939
|
+
const newFileName = `${img.name}.${newExt}`;
|
|
940
|
+
const downloadPath = path2.join(path2.dirname(img.path), `${img.name}-compressed.${newExt}`);
|
|
941
|
+
instructions += `**${path2.basename(img.path)}**:
|
|
942
|
+
`;
|
|
943
|
+
instructions += `1. \u4E0B\u8F7D\u538B\u7F29\u7ED3\u679C\u5230: \`${downloadPath}\`
|
|
944
|
+
`;
|
|
945
|
+
if (ossDirectory) {
|
|
946
|
+
if (isFormatChange) {
|
|
947
|
+
instructions += `2. \u4E0A\u4F20\u5230 OSS: \`upload_to_oss("${downloadPath}", "${ossDirectory}", "${newFileName}", "${configName}")\`
|
|
948
|
+
`;
|
|
949
|
+
if (deleteOriginal) {
|
|
950
|
+
instructions += `3. \u5220\u9664\u539F\u6587\u4EF6: \u5728 OSS \u4E0A\u5220\u9664 \`${ossDirectory}/${path2.basename(img.path)}\`
|
|
951
|
+
`;
|
|
952
|
+
}
|
|
953
|
+
} else {
|
|
954
|
+
instructions += `2. \u8986\u76D6\u4E0A\u4F20\u5230 OSS: \`upload_to_oss("${downloadPath}", "${ossDirectory}", "${path2.basename(img.path)}", "${configName}")\`
|
|
955
|
+
`;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
instructions += `
|
|
959
|
+
`;
|
|
960
|
+
}
|
|
961
|
+
const resultInfo = {
|
|
962
|
+
engine,
|
|
963
|
+
outputFormat: actualOutputFormat,
|
|
964
|
+
deleteOriginal: actualOutputFormat ? deleteOriginal : false,
|
|
965
|
+
ossDirectory,
|
|
966
|
+
configName,
|
|
967
|
+
totalImages: validImages.length,
|
|
968
|
+
batches: batches.length,
|
|
969
|
+
batchSize,
|
|
970
|
+
images: validImages.map((img) => ({
|
|
971
|
+
originalPath: img.path,
|
|
972
|
+
originalName: path2.basename(img.path),
|
|
973
|
+
originalExt: img.ext,
|
|
974
|
+
originalSize: img.size,
|
|
975
|
+
newExt: actualOutputFormat || img.ext,
|
|
976
|
+
isFormatChange: (actualOutputFormat || img.ext) !== img.ext
|
|
977
|
+
}))
|
|
978
|
+
};
|
|
979
|
+
return {
|
|
980
|
+
content: [
|
|
981
|
+
{
|
|
982
|
+
type: "text",
|
|
983
|
+
text: instructions
|
|
984
|
+
},
|
|
985
|
+
{
|
|
986
|
+
type: "text",
|
|
987
|
+
text: `
|
|
988
|
+
---
|
|
989
|
+
**\u538B\u7F29\u4EFB\u52A1\u6570\u636E (JSON)**:
|
|
990
|
+
\`\`\`json
|
|
991
|
+
${JSON.stringify(resultInfo, null, 2)}
|
|
992
|
+
\`\`\``
|
|
993
|
+
}
|
|
994
|
+
]
|
|
995
|
+
};
|
|
996
|
+
} catch (error) {
|
|
997
|
+
Logger.error(`\u751F\u6210\u538B\u7F29\u6307\u4EE4\u51FA\u9519:`, error);
|
|
998
|
+
return {
|
|
999
|
+
isError: true,
|
|
1000
|
+
content: [{
|
|
1001
|
+
type: "text",
|
|
1002
|
+
text: `\u751F\u6210\u538B\u7F29\u6307\u4EE4\u5931\u8D25: ${error}`
|
|
1003
|
+
}]
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
// 生成 TinyPNG 自动化指令
|
|
1010
|
+
generateTinyPngInstructions(batches, outputFormat) {
|
|
1011
|
+
let instructions = "";
|
|
1012
|
+
for (let i = 0; i < batches.length; i++) {
|
|
1013
|
+
const batch = batches[i];
|
|
1014
|
+
instructions += `#### \u6279\u6B21 ${i + 1}/${batches.length}
|
|
1015
|
+
|
|
1016
|
+
`;
|
|
1017
|
+
instructions += `**\u6587\u4EF6**: ${batch.map((img) => path2.basename(img.path)).join(", ")}
|
|
1018
|
+
|
|
1019
|
+
`;
|
|
1020
|
+
instructions += `1. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://tinypng.com/\`
|
|
1021
|
+
`;
|
|
1022
|
+
instructions += `2. **\u7B49\u5F85\u52A0\u8F7D**: \u4F7F\u7528 \`browser_snapshot\` \u786E\u8BA4\u9875\u9762\u52A0\u8F7D\u5B8C\u6210
|
|
1023
|
+
`;
|
|
1024
|
+
instructions += `3. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
|
|
1025
|
+
`;
|
|
1026
|
+
for (const img of batch) {
|
|
1027
|
+
instructions += ` - \`${img.path}\`
|
|
1028
|
+
`;
|
|
1029
|
+
}
|
|
1030
|
+
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
|
|
1031
|
+
`;
|
|
1032
|
+
if (outputFormat && outputFormat !== "png") {
|
|
1033
|
+
instructions += `5. **\u9009\u62E9\u8F93\u51FA\u683C\u5F0F**:
|
|
1034
|
+
`;
|
|
1035
|
+
instructions += ` - \u70B9\u51FB\u538B\u7F29\u7ED3\u679C\u53F3\u4FA7\u7684\u683C\u5F0F\u9009\u62E9\u4E0B\u62C9\u6846
|
|
1036
|
+
`;
|
|
1037
|
+
instructions += ` - \u9009\u62E9 "${outputFormat.toUpperCase()}"
|
|
1038
|
+
`;
|
|
1039
|
+
}
|
|
1040
|
+
instructions += `${outputFormat && outputFormat !== "png" ? "6" : "5"}. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download all" \u6216\u9010\u4E2A\u4E0B\u8F7D
|
|
1041
|
+
`;
|
|
1042
|
+
if (i < batches.length - 1) {
|
|
1043
|
+
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
|
|
1044
|
+
`;
|
|
1045
|
+
}
|
|
1046
|
+
instructions += `
|
|
1047
|
+
`;
|
|
1048
|
+
}
|
|
1049
|
+
return instructions;
|
|
1050
|
+
}
|
|
1051
|
+
// 生成 AnyWebP 自动化指令
|
|
1052
|
+
generateAnyWebPInstructions(batches) {
|
|
1053
|
+
let instructions = "";
|
|
1054
|
+
for (let i = 0; i < batches.length; i++) {
|
|
1055
|
+
const batch = batches[i];
|
|
1056
|
+
instructions += `#### \u6279\u6B21 ${i + 1}/${batches.length}
|
|
1057
|
+
|
|
1058
|
+
`;
|
|
1059
|
+
instructions += `**\u6587\u4EF6**: ${batch.map((img) => path2.basename(img.path)).join(", ")}
|
|
1060
|
+
|
|
1061
|
+
`;
|
|
1062
|
+
instructions += `1. **\u6253\u5F00\u7F51\u7AD9**: \u4F7F\u7528 \`browser_navigate\` \u8BBF\u95EE \`https://anywebp.com/convert-to-webp.html\`
|
|
1063
|
+
`;
|
|
1064
|
+
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
|
|
1065
|
+
`;
|
|
1066
|
+
instructions += `3. **\u4E0A\u4F20\u6587\u4EF6**: \u4F7F\u7528 \`browser_file_upload\` \u4E0A\u4F20\u4EE5\u4E0B\u6587\u4EF6:
|
|
1067
|
+
`;
|
|
1068
|
+
for (const img of batch) {
|
|
1069
|
+
instructions += ` - \`${img.path}\`
|
|
1070
|
+
`;
|
|
1071
|
+
}
|
|
1072
|
+
instructions += `4. **\u7B49\u5F85\u8F6C\u6362**: \u4F7F\u7528 \`browser_wait_for\` \u7B49\u5F85\u8F6C\u6362\u5B8C\u6210\uFF0C\u51FA\u73B0 "Download" \u6309\u94AE
|
|
1073
|
+
`;
|
|
1074
|
+
instructions += `5. **\u4E0B\u8F7D\u7ED3\u679C**: \u70B9\u51FB "Download All" \u6216\u9010\u4E2A\u4E0B\u8F7D WebP \u6587\u4EF6
|
|
1075
|
+
`;
|
|
1076
|
+
if (i < batches.length - 1) {
|
|
1077
|
+
instructions += `6. **\u5237\u65B0\u9875\u9762**: \u4F7F\u7528 \`browser_navigate\` \u91CD\u65B0\u8BBF\u95EE\u51C6\u5907\u4E0B\u4E00\u6279
|
|
1078
|
+
`;
|
|
1079
|
+
}
|
|
1080
|
+
instructions += `
|
|
1081
|
+
`;
|
|
1082
|
+
}
|
|
1083
|
+
return instructions;
|
|
681
1084
|
}
|
|
682
1085
|
async connect(transport) {
|
|
683
1086
|
try {
|
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 \"列出指定目录下的所有文件,用于查看当前文件名以便进行重命名操作\",\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 // 工具:下载文件\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 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 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 \"列出指定目录下的所有文件,用于查看当前文件名以便进行重命名操作\",\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 // 工具:下载文件\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 `检查图片压缩的前置条件。在调用 compress_images 之前必须先调用此工具!\n\n此工具会检查:\n1. Playwright MCP 是否可用(通过尝试调用 browser_snapshot)\n2. 返回需要 AI 向用户询问的问题\n\n【重要】AI 必须按以下流程操作:\n1. 先调用此工具检查前置条件\n2. 根据返回的 questions 使用 AskUserQuestion 询问用户\n3. 收集用户选择后再调用 compress_images`,\n {\n images: z.array(z.string()).describe(\"要压缩的本地图片路径数组(用于验证文件存在)\")\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 MCP 执行。\n\n【重要】调用此工具前,AI 必须:\n1. 先调用 check_compress_prerequisites 检查前置条件\n2. 使用 browser_snapshot 确认 Playwright MCP 可用\n3. 使用 AskUserQuestion 询问用户选择引擎、输出格式、是否删除原文件\n4. 如果图片在 OSS 上,先用 download_file 下载到本地\n\n【工作流程】\n1. 调用此工具获取压缩指令\n2. 按指令使用 Playwright MCP 执行网页自动化\n3. 下载压缩结果到本地\n4. 使用 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 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"]}
|