mcp-universal-file-converter
Version:
MCP Universal File Converter - 支持压缩包、图片、PDF、Office文档等转换成可上传的 JPG (≤2MB)
150 lines (149 loc) • 5.59 kB
JavaScript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import fs from "fs";
import path from "path";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { processSubFolder, setApiConfig } from "./tools/convert_folder.js";
// 解析命令行参数
const args = process.argv.slice(2);
let apiKey = '';
let model = '';
// 解析参数格式: --apikey=xxx --model=xxx 或 apikey model
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--apikey=')) {
apiKey = arg.split('=')[1];
}
else if (arg.startsWith('--model=')) {
model = arg.split('=')[1];
}
else if (i === 0 && !arg.startsWith('--')) {
apiKey = arg;
}
else if (i === 1 && !arg.startsWith('--')) {
model = arg;
}
}
// 设置API配置
if (apiKey || model) {
setApiConfig({ apiKey, model });
console.log(`API配置已设置: apiKey=${apiKey ? '***' : '未设置'}, model=${model || '未设置'}`);
}
/**
* MCP 服务器设置
*/
const server = new Server({
name: "universal-file-converter",
version: "1.0.0"
}, {
capabilities: {
tools: {},
},
});
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "list_folders",
description: "【第一步】检查指定目录下的所有子文件夹,返回文件夹路径列表。使用流程:1.先调用此工具获取所有子文件夹路径 2.然后对每个文件夹路径逐个调用convert_folder工具",
inputSchema: zodToJsonSchema(z.object({
folderPath: z.string().describe("要检查的根目录路径"),
}))
},
{
name: "convert_folder",
description: "【第二步】将单个文件夹内所有可处理的文件转换为 JPG 格式(≤2MB),支持压缩包、图片、PDF、Office 文档等。注意:使用前必须先调用list_folders工具获取文件夹路径",
inputSchema: zodToJsonSchema(z.object({
folderPath: z.string().describe("要转换的单个文件夹路径(从list_folders工具获取)"),
}))
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { params } = request;
const { name, arguments: args } = params;
if (name === "list_folders") {
const { folderPath } = args;
console.log('检查目录--', folderPath);
if (!fs.existsSync(folderPath)) {
throw new Error(`文件夹不存在: ${folderPath}`);
}
const subFolders = fs.readdirSync(folderPath).filter(f => {
return fs.statSync(path.join(folderPath, f)).isDirectory();
});
if (subFolders.length === 0) {
return {
content: [
{
type: "text",
text: `目录 ${folderPath} 下没有找到子文件夹`
}
]
};
}
const folderPaths = subFolders.map(sub => path.join(folderPath, sub));
return {
content: [
{
type: "text",
text: `找到 ${subFolders.length} 个子文件夹:\n${folderPaths.map((p, i) => `${i + 1}. ${p}`).join('\n')}\n\n请使用 convert_folder 工具逐个处理这些文件夹。`
}
]
};
}
if (name === "convert_folder") {
const { folderPath } = args;
console.log('处理单个文件夹--', folderPath);
if (!fs.existsSync(folderPath)) {
throw new Error(`文件夹不存在: ${folderPath}`);
}
const allMessages = [];
allMessages.push(`=== 开始处理文件夹: ${path.basename(folderPath)} ===`);
try {
const generator = processSubFolder(folderPath);
let folderSuccess = true;
for await (const result of generator) {
// 实时输出处理进度
const statusIcon = result.type === 'success' ? '✅' :
result.type === 'error' ? '❌' :
result.type === 'warning' ? '⚠️' : 'ℹ️';
allMessages.push(`${statusIcon} ${result.message}`);
if (result.type === 'error') {
folderSuccess = false;
}
}
if (folderSuccess) {
allMessages.push(`✅ 文件夹处理成功`);
}
else {
allMessages.push(`❌ 文件夹处理失败`);
}
}
catch (error) {
allMessages.push(`❌ 文件夹处理异常: ${error}`);
}
return {
content: [
{
type: "text",
text: allMessages.join('\n')
}
]
};
}
throw new Error(`未知的工具: ${name}`);
});
// Start server
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.info("Universal File Converter Server running on stdio");
}
runServer().catch((error) => {
console.error("Fatal error running server:", error);
process.exit(1);
});