document-conversion-mcp
Version:
MCP server for document format conversion
396 lines (355 loc) • 12.9 kB
JavaScript
/**
* MCP文档转换工具集成器
* 将所有文档转换工具整合在一个统一的接口中
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { DocumentConverter } from './src/converter.js';
import { validateFile, getSupportedFormats, formatFileSize, normalizePath } from './src/utils.js';
import fs from 'fs/promises';
import path from 'path';
class UnifiedMCPToolsServer {
constructor() {
this.server = new Server(
{
name: 'unified-document-conversion-mcp',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.converter = new DocumentConverter();
this.setupAllTools();
}
setupAllTools() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'document_converter',
description: '统一的文档转换工具,支持格式转换、信息获取、批量处理、文件验证等所有功能',
inputSchema: {
type: 'object',
properties: {
operation: {
type: 'string',
description: '操作类型',
enum: [
'convert',
'get_info',
'list_formats',
'batch_convert',
'validate_file',
'scan_directory',
'preview_conversion',
'check_status'
],
},
// 文件路径参数
input_path: {
type: 'string',
description: '输入文档的文件路径(convert, get_info, validate_file, preview_conversion操作需要)',
},
output_path: {
type: 'string',
description: '输出文档的文件路径(convert操作需要)',
},
file_path: {
type: 'string',
description: '文档文件路径(get_info, validate_file操作的别名)',
},
// 目录参数
input_directory: {
type: 'string',
description: '输入目录路径(batch_convert操作需要)',
},
output_directory: {
type: 'string',
description: '输出目录路径(batch_convert操作需要)',
},
directory_path: {
type: 'string',
description: '要扫描的目录路径(scan_directory操作需要)',
},
// 格式参数
target_format: {
type: 'string',
description: '目标格式 (pdf, docx, xlsx, pptx, md, html, txt, png, jpg)',
},
// 其他参数
file_pattern: {
type: 'string',
description: '文件匹配模式(batch_convert操作可选)',
},
file_extensions: {
type: 'array',
description: '要扫描的文件扩展名(scan_directory操作可选)',
items: {
type: 'string',
},
},
options: {
type: 'object',
description: '转换选项(convert操作可选)',
properties: {
quality: {
type: 'number',
description: '图片质量 (0-100)',
minimum: 0,
maximum: 100,
},
page_range: {
type: 'string',
description: 'PDF页面范围,如 "1-5" 或 "1,3,5"',
},
extract_images: {
type: 'boolean',
description: '是否提取图片',
},
},
},
},
required: ['operation'],
},
},
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'document_converter':
return await this.handleDocumentConverter(args);
default:
throw new McpError(
ErrorCode.MethodNotFound,
`未知工具: ${name}`
);
}
} catch (error) {
throw new McpError(
ErrorCode.InternalError,
`工具执行错误: ${error.message}`
);
}
});
}
// 统一文档转换处理器
async handleDocumentConverter(args) {
// 参数验证
if (!args || typeof args !== 'object') {
throw new Error('参数不能为空且必须是对象类型');
}
const { operation } = args;
if (!operation) {
throw new Error('operation参数是必需的');
}
switch (operation) {
case 'convert':
return await this.handleConvertDocument(args);
case 'get_info':
// 支持input_path作为file_path的别名
const infoArgs = { ...args, file_path: args.file_path || args.input_path };
return await this.handleGetDocumentInfo(infoArgs);
case 'list_formats':
return await this.handleListSupportedFormats();
case 'batch_convert':
return await this.handleBatchConvert(args);
case 'validate_file':
// 支持input_path作为file_path的别名
const validateArgs = { ...args, file_path: args.file_path || args.input_path };
return await this.handleValidateFile(validateArgs);
case 'scan_directory':
return await this.handleScanDirectory(args);
case 'preview_conversion':
return await this.handlePreviewConversion(args);
case 'check_status':
return await this.handleCheckToolStatus();
default:
throw new Error(`不支持的操作类型: ${operation}`);
}
}
// 核心转换功能
async handleConvertDocument(args) {
const { input_path, output_path, target_format, options = {} } = args;
// 标准化输入和输出路径,支持单斜杠
const normalizedInputPath = normalizePath(input_path);
const normalizedOutputPath = normalizePath(output_path);
const validation = await validateFile(normalizedInputPath);
if (!validation.valid) {
throw new Error(validation.error);
}
const result = await this.converter.convert(
normalizedInputPath,
normalizedOutputPath,
target_format,
options
);
return {
content: [
{
type: 'text',
text: `✅ 文档转换成功!\n📁 输入: ${normalizedInputPath}\n📄 输出: ${normalizedOutputPath}\n🔄 格式: ${target_format}\n${result.message || ''}`,
},
],
};
}
// 获取文档信息
async handleGetDocumentInfo(args) {
const { file_path } = args;
const info = await this.converter.getDocumentInfo(file_path);
return {
content: [
{
type: 'text',
text: `📋 文档信息:\n${JSON.stringify(info, null, 2)}`,
},
],
};
}
// 列出支持的格式
async handleListSupportedFormats() {
const formats = getSupportedFormats();
return {
content: [
{
type: 'text',
text: `📚 支持的文档格式:\n${JSON.stringify(formats, null, 2)}`,
},
],
};
}
// 批量转换
async handleBatchConvert(args) {
const { input_directory, output_directory, target_format, file_pattern } = args;
const results = await this.converter.batchConvert(
input_directory,
output_directory,
target_format,
file_pattern
);
// 验证results结构
const details = results.details && Array.isArray(results.details) ? results.details : [];
return {
content: [
{
type: 'text',
text: `🔄 批量转换完成!\n✅ 成功: ${results.success || 0}\n❌ 失败: ${results.failed || 0}\n📝 详情:\n${details.join('\n')}`,
},
],
};
}
// 验证文件
async handleValidateFile(args) {
const { file_path } = args;
const validation = await validateFile(file_path);
return {
content: [
{
type: 'text',
text: validation.valid
? `✅ 文件验证通过: ${file_path}\n📊 大小: ${formatFileSize(validation.size)}\n📅 修改时间: ${validation.lastModified}`
: `❌ 文件验证失败: ${validation.error}`,
},
],
};
}
// 扫描目录
async handleScanDirectory(args) {
const { directory_path, file_extensions = [] } = args;
// 验证file_extensions参数
if (file_extensions && !Array.isArray(file_extensions)) {
throw new Error('file_extensions参数必须是数组类型');
}
try {
const files = await fs.readdir(directory_path, { withFileTypes: true });
const documentFiles = [];
for (const file of files) {
if (file.isFile()) {
const filePath = path.join(directory_path, file.name);
const ext = path.extname(file.name).toLowerCase();
if (file_extensions.length === 0 || file_extensions.includes(ext)) {
const stats = await fs.stat(filePath);
documentFiles.push({
name: file.name,
path: filePath,
extension: ext,
size: formatFileSize(stats.size),
lastModified: stats.mtime.toISOString(),
});
}
}
}
return {
content: [
{
type: 'text',
text: `📁 目录扫描结果: ${directory_path}\n📄 找到 ${documentFiles.length} 个文件:\n${JSON.stringify(documentFiles, null, 2)}`,
},
],
};
} catch (error) {
throw new Error(`目录扫描失败: ${error.message}`);
}
}
// 预览转换
async handlePreviewConversion(args) {
const { input_path, target_format } = args;
const validation = await validateFile(input_path);
if (!validation.valid) {
throw new Error(validation.error);
}
const inputFormat = path.extname(input_path).toLowerCase().slice(1);
const formats = getSupportedFormats();
const isSupported = formats.input.includes(inputFormat) && formats.output.includes(target_format);
return {
content: [
{
type: 'text',
text: `🔍 转换预览:\n📁 输入文件: ${input_path}\n📊 文件大小: ${formatFileSize(validation.size)}\n🔄 输入格式: ${inputFormat}\n🎯 目标格式: ${target_format}\n${isSupported ? '✅ 支持此转换' : '❌ 不支持此转换'}`,
},
],
};
}
// 检查工具状态
async handleCheckToolStatus() {
const formats = getSupportedFormats();
console.log('Debug - formats:', JSON.stringify(formats, null, 2));
const status = {
server: 'running',
version: '1.0.0',
supportedInputFormats: formats.inputFormats ? formats.inputFormats.length : 0,
supportedOutputFormats: formats.outputFormats ? formats.outputFormats.length : 0,
availableTools: 8,
timestamp: new Date().toISOString(),
};
return {
content: [
{
type: 'text',
text: `🚀 MCP工具服务器状态:\n${JSON.stringify(status, null, 2)}`,
},
],
};
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('🚀 Unified Document Conversion MCP Tools Server running on stdio');
console.error('📚 Available tool: document_converter (支持8种操作: convert, get_info, list_formats, batch_convert, validate_file, scan_directory, preview_conversion, check_status)');
}
}
// 启动统一工具服务器
const server = new UnifiedMCPToolsServer();
server.run().catch(console.error);