#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ReadResourceRequestSchema,
ListResourcesRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fs from 'fs-extra';
import path from 'path';
import mammoth from 'mammoth';
const server = new Server(
{
name: "word-doc-reader",
version: "1.0.0",
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// 内存存储用于保存读取的文档内容
const documentMemory = new Map();
const uiComponentMemory = new Map();
// 工具定义
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "read_word_document",
description: "读取Word文档内容并存储到内存中",
inputSchema: {
type: "object",
properties: {
filePath: {
type: "string",
description: "Word文档的文件路径"
},
memoryKey: {
type: "string",
description: "用于存储的内存键名,便于后续检索",
default: "default"
},
documentType: {
type: "string",
description: "文档类型,如 'ui-component', 'api-doc', 'common-doc'",
enum: ["ui-component", "api-doc", "common-doc", "other"],
default: "common-doc"
}
},
required: ["filePath"]
}
},
{
name: "list_stored_documents",
description: "列出所有已存储到内存的文档",
inputSchema: {
type: "object",
properties: {
documentType: {
type: "string",
description: "筛选特定类型的文档",
enum: ["ui-component", "api-doc", "common-doc", "other"]
}
}
}
},
{
name: "get_stored_document",
description: "获取已存储的文档内容",
inputSchema: {
type: "object",
properties: {
memoryKey: {
type: "string",
description: "要获取的文档内存键名"
}
},
required: ["memoryKey"]
}
},
{
name: "search_in_documents",
description: "在已存储的文档中搜索内容",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "搜索关键词"
},
documentType: {
type: "string",
description: "限制搜索的文档类型",
enum: ["ui-component", "api-doc", "common-doc", "other"]
}
},
required: ["query"]
}
},
{
name: "clear_memory",
description: "清除指定的内存内容",
inputSchema: {
type: "object",
properties: {
memoryKey: {
type: "string",
description: "要清除的内存键名,如果不提供则清除所有"
}
}
}
}
]
};
});
// 工具执行
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "read_word_document": {
const { filePath, memoryKey = "default", documentType = "common-doc" } = args;
if (!fs.existsSync(filePath)) {
throw new Error(`文件不存在: ${filePath}`);
}
const fileExt = path.extname(filePath).toLowerCase();
if (fileExt !== '.docx' && fileExt !== '.doc') {
throw new Error(`不支持的文件格式: ${fileExt}。仅支持 .docx 和 .doc 文件`);
}
const result = await mammoth.extractRawText({ path: filePath });
const documentData = {
content: result.value,
filePath,
documentType,
timestamp: new Date().toISOString(),
memoryKey
};
// 根据文档类型存储到不同的内存区域
if (documentType === 'ui-component') {
uiComponentMemory.set(memoryKey, documentData);
} else {
documentMemory.set(memoryKey, documentData);
}
return {
content: [
{
type: "text",
text: `成功读取并存储Word文档:\n文件路径: ${filePath}\n文档类型: ${documentType}\n内存键: ${memoryKey}\n内容长度: ${result.value.length} 字符\n\n文档内容预览:\n${result.value.substring(0, 500)}...`
}
]
};
}
case "list_stored_documents": {
const { documentType } = args;
let docs = [];
if (!documentType || documentType === "ui-component") {
for (const [key, doc] of uiComponentMemory.entries()) {
docs.push({ ...doc, memoryKey: key, storage: "ui-component" });
}
}
if (!documentType || documentType !== "ui-component") {
for (const [key, doc] of documentMemory.entries()) {
if (!documentType || doc.documentType === documentType) {
docs.push({ ...doc, memoryKey: key, storage: "document" });
}
}
}
const docList = docs.map(doc =>
`- 内存键: ${doc.memoryKey}\n 文件路径: ${doc.filePath}\n 文档类型: ${doc.documentType}\n 存储时间: ${doc.timestamp}\n 内容长度: ${doc.content.length} 字符`
).join('\n\n');
return {
content: [
{
type: "text",
text: `已存储的文档 (${docs.length} 个):\n\n${docList || "暂无存储的文档"}`
}
]
};
}
case "get_stored_document": {
const { memoryKey } = args;
let doc = uiComponentMemory.get(memoryKey) || documentMemory.get(memoryKey);
if (!doc) {
throw new Error(`未找到内存键为 "${memoryKey}" 的文档`);
}
return {
content: [
{
type: "text",
text: `文档内容 (内存键: ${memoryKey}):\n\n${doc.content}`
}
]
};
}
case "search_in_documents": {
const { query, documentType } = args;
const queryLower = query.toLowerCase();
const results = [];
// 搜索UI组件文档
if (!documentType || documentType === "ui-component") {
for (const [key, doc] of uiComponentMemory.entries()) {
const contentLower = doc.content.toLowerCase();
if (contentLower.includes(queryLower)) {
results.push({
memoryKey: key,
filePath: doc.filePath,
documentType: doc.documentType,
matches: extractMatches(doc.content, query)
});
}
}
}
// 搜索其他文档
if (!documentType || documentType !== "ui-component") {
for (const [key, doc] of documentMemory.entries()) {
if (!documentType || doc.documentType === documentType) {
const contentLower = doc.content.toLowerCase();
if (contentLower.includes(queryLower)) {
results.push({
memoryKey: key,
filePath: doc.filePath,
documentType: doc.documentType,
matches: extractMatches(doc.content, query)
});
}
}
}
}
const resultsText = results.map(result =>
`- 内存键: ${result.memoryKey}\n 文件: ${result.filePath}\n 类型: ${result.documentType}\n 匹配内容: ${result.matches.slice(0, 3).join('; ')}...`
).join('\n\n');
return {
content: [
{
type: "text",
text: `搜索结果 "${query}" (找到 ${results.length} 个匹配):\n\n${resultsText || "未找到匹配的内容"}`
}
]
};
}
case "clear_memory": {
const { memoryKey } = args;
if (memoryKey) {
const removedFromUI = uiComponentMemory.delete(memoryKey);
const removedFromDoc = documentMemory.delete(memoryKey);
if (removedFromUI || removedFromDoc) {
return {
content: [
{
type: "text",
text: `已清除内存键 "${memoryKey}" 的内容`
}
]
};
} else {
throw new Error(`未找到内存键 "${memoryKey}" 的内容`);
}
} else {
// 清除所有内存
const count = uiComponentMemory.size + documentMemory.size;
uiComponentMemory.clear();
documentMemory.clear();
return {
content: [
{
type: "text",
text: `已清除所有内存内容 (共 ${count} 个文档)`
}
]
};
}
}
default:
throw new Error(`未知工具: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `错误: ${error.message}`
}
],
isError: true
};
}
});
// 辅助函数:提取匹配的内容片段
function extractMatches(content, query, maxMatches = 5) {
const lines = content.split('\n');
const matches = [];
const queryLower = query.toLowerCase();
for (let i = 0; i < lines.length && matches.length < maxMatches; i++) {
if (lines[i].toLowerCase().includes(queryLower)) {
const context = lines[i].trim();
if (context.length > 0) {
matches.push(context.substring(0, 100));
}
}
}
return matches.length > 0 ? matches : [`包含关键词 "${query}"`];
}
// 启动服务器
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Word Document Reader MCP server running on stdio");
}
main().catch((error) => {
console.error("服务器启动失败:", error);
process.exit(1);
});