Skip to main content
Glama
server.ts8.47 kB
/** * SiYuan MCP 服务器核心 */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { createSiyuanTools } from '../../src/index.js'; import type { ServerConfig, ExecutionContext, MCPTool } from './types.js'; import { DefaultToolRegistry } from './registry.js'; import { ConsoleLogger } from './logger.js'; import { createAllHandlers } from '../handlers/index.js'; /** * SiYuan MCP 服务器 */ export class SiyuanMCPServer { private mcpServer: Server; private registry = new DefaultToolRegistry(); private context: ExecutionContext; private logger = new ConsoleLogger(); constructor(config: ServerConfig) { // 初始化 SiYuan 工具 const siyuan = createSiyuanTools(config.baseUrl, config.token); // 创建执行上下文 this.context = { siyuan, config, logger: this.logger, }; // 注册所有工具处理器 this.registerHandlers(); // 创建 MCP 服务器实例 this.mcpServer = new Server( { name: config.name || 'siyuan-mcp-server', version: config.version || '0.1.0', }, { capabilities: { tools: {}, prompts: {}, }, } ); // 设置请求处理器 this.setupRequestHandlers(); } /** * 注册所有工具处理器 */ private registerHandlers(): void { const handlers = createAllHandlers(); for (const handler of handlers) { this.registry.register(handler); this.logger.debug(`Registered tool: ${handler.name}`); } } /** * 设置 MCP 请求处理器 */ private setupRequestHandlers(): void { // 处理工具列表请求 this.mcpServer.setRequestHandler(ListToolsRequestSchema, async () => { const tools: MCPTool[] = this.registry.getAll().map((handler) => ({ name: handler.name, description: handler.description, inputSchema: handler.inputSchema, })); this.logger.debug(`Listing ${tools.length} tools`); return { tools }; }); // 处理提示词列表请求 this.mcpServer.setRequestHandler(ListPromptsRequestSchema, async () => { return { prompts: [ { name: 'siyuan-usage-guide', description: 'SiYuan MCP 服务器的使用指南和最佳实践', }, ], }; }); // 处理获取提示词请求 this.mcpServer.setRequestHandler(GetPromptRequestSchema, async (request) => { const { name } = request.params; if (name === 'siyuan-usage-guide') { const guide = this.getUsageGuide(); return { messages: [ { role: 'user', content: { type: 'text', text: '请阅读 SiYuan MCP 服务器的使用指南', }, }, { role: 'assistant', content: { type: 'text', text: guide, }, }, ], }; } throw new Error(`Unknown prompt: ${name}`); }); // 处理工具调用请求 this.mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; this.logger.info(`Tool called: ${name}`); try { const handler = this.registry.get(name); if (!handler) { throw new Error(`Unknown tool: ${name}`); } // 执行工具 const result = await handler.execute(args || {}, this.context); // 格式化返回结果(符合 MCP 协议) // 处理 void 返回值(undefined) let text: string; if (result === undefined) { text = 'Success'; } else if (typeof result === 'string') { text = result; } else { text = JSON.stringify(result, null, 2); } return { content: [ { type: 'text' as const, text, }, ], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); this.logger.error(`Tool execution failed: ${errorMessage}`); return { content: [ { type: 'text' as const, text: `Error: ${errorMessage}`, }, ], isError: true, }; } }); } /** * 获取使用指南内容 */ private getUsageGuide(): string { return `# SiYuan MCP 服务器使用指南 ## 概述 SiYuan MCP 服务器提供了一套工具用于操作思源笔记,包括搜索、文档管理、快照备份等功能。 ## 重要提示 ### 数据安全 ⚠️ **在执行批量修改或删除操作前,请务必先创建快照!** \`\`\` 1. 使用 create_snapshot 创建快照(建议添加描述说明) 2. 执行修改操作 3. 如果出错,使用 list_snapshots 查看快照列表 4. 使用 rollback_snapshot 回滚到指定快照 \`\`\` ### 工作流程建议 1. **搜索文档**:使用 \`search_by_filename\` 或 \`search_by_content\` 查找目标文档 2. **获取内容**:使用 \`get_document_content\` 查看文档内容 3. **创建快照**:使用 \`create_snapshot\` 保存当前状态 4. **修改文档**:使用 \`update_document\`、\`append_to_document\` 等修改内容 5. **验证结果**:再次获取内容确认修改正确 6. **必要时回滚**:如果出错,使用 \`rollback_snapshot\` 恢复 ## 工具分类 ### 搜索工具(3个) - \`search_by_filename\`: 按文件名搜索文档 - \`search_by_content\`: 按内容搜索文档 - \`sql_query\`: 执行 SQL 查询(高级用法) ### 文档工具(6个) - \`get_document_content\`: 获取文档的 Markdown 内容 - \`create_document\`: 在指定笔记本创建新文档 - \`append_to_document\`: 向文档追加内容 - \`update_document\`: 更新(覆盖)文档内容 - \`append_to_daily_note\`: 追加内容到今日笔记 - \`move_document\`: 移动文档到其他位置 ### 笔记本工具(2个) - \`list_notebooks\`: 列出所有笔记本 - \`get_recently_updated_documents\`: 获取最近更新的文档 ### 快照工具(3个) - \`create_snapshot\`: 创建数据快照 - \`list_snapshots\`: 列出所有快照 - \`rollback_snapshot\`: 回滚到指定快照 ## 使用示例 ### 示例1:安全地批量修改文档 \`\`\` 1. create_snapshot(memo: "批量修改前的备份") 2. search_by_content(content: "需要修改的内容") 3. 对每个搜索结果: - get_document_content(document_id: "...") - 修改内容 - update_document(document_id: "...", content: "新内容") 4. 验证修改结果 5. 如有问题:rollback_snapshot(snapshot_id: "...") \`\`\` ### 示例2:创建每日记录 \`\`\` 1. list_notebooks() 获取笔记本列表 2. append_to_daily_note(notebook_id: "...", content: "今日总结...") \`\`\` ### 示例3:整理文档结构 \`\`\` 1. create_snapshot(memo: "整理文档结构前") 2. search_by_filename(filename: "待整理的文档") 3. move_document(from_ids: "文档ID", to_id: "目标文档ID") \`\`\` ## 注意事项 1. **文档 ID**:思源笔记中每个文档都有唯一的 ID(格式如 \`20240101120000-abc1234\`) 2. **路径格式**:创建文档时路径格式为 \`/folder/document\`(无需 .md 扩展名) 3. **Markdown 格式**:所有内容使用 Markdown 格式 4. **快照限制**:快照功能需要思源笔记开启数据仓库功能 5. **并发操作**:避免同时修改同一文档,可能导致冲突 ## 最佳实践 ✅ **推荐做法**: - 在批量操作前创建快照 - 先搜索确认目标文档,再进行修改 - 修改后验证结果 - 保持快照命名清晰(包含操作说明) ❌ **避免做法**: - 不创建快照就执行批量删除 - 不验证搜索结果就批量修改 - 对不熟悉的文档执行覆盖操作 - 忽略错误继续执行后续操作 `; } /** * 获取底层 MCP 服务器实例 */ getMCPServer(): Server { return this.mcpServer; } /** * 获取工具注册表 */ getRegistry(): DefaultToolRegistry { return this.registry; } /** * 获取日志记录器 */ getLogger(): ConsoleLogger { return this.logger; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/porkll/siyuan-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server