ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Dillinger MCP 服务器构建实战:基于 Model Context Protocol 的工具设计、资源模式与安全最佳实践

Dillinger MCP 服务器构建实战:基于 Model Context Protocol 的工具设计、资源模式与安全最佳实践 前端开发工具【免费下载链接】dillingerThe last Markdown editor, ever.项目地址https://gitcode.com/gh_mirrors/di/dillinger点击查看免费下载本指南以 Dillinger 仓库中的 MCP Builder 技能文档.agent/skills/mcp-builder/SKILL.md为核心骨架结合仓库内真实实现的 MCP 服务器packages/mcp/与后端 APIapp/api/v1/展开讲解。读完本文你将掌握 MCP 服务器的完整构建方法论——从工具Tools输入模式设计、资源ResourcesURI 规划、错误处理、多模态编码到环境变量配置与测试策略并能对照 Dillinger 的开源实现亲手构建一个可被 Claude Desktop 等客户端直接加载的 Stdio 型 MCP 服务器。1. MCP 概览让 AI 系统连接外部工具与数据1.1 什么是 MCPModel Context Protocol模型上下文协议简称 MCP是连接 AI 系统与外部工具、数据源的标准协议。它定义了一套统一的通信范式使 LLM 客户端如 Claude Desktop、各类 Agent无需针对每个集成方单独适配即可调用外部能力。Dillinger 对 MCP 的定位非常清晰——在其packages/mcp/README.md中写道MCP (Model Context Protocol) server for Dillinger. Lets LLMs use Dillinger as a native markdown tool.也就是说Dillinger 通过 MCP 服务器把自己的 Markdown 渲染、PDF/HTML 导出、HTML 转 Markdown 等能力开放给 LLM让大模型把 Dillinger 当作一个原生 Markdown 工具来使用。这正是 MCP 的典型应用场景把 AI 无法直接完成的确定性计算渲染、转换、导出交给外部服务完成。1.2 三大核心概念概念用途Dillinger 中的实例Tools工具AI 可以调用的函数有明确的名称、输入模式与返回结构render_markdown、export_pdf、export_html、convert_html_to_markdownResources资源AI 可以读取的数据通过 URI 寻址本仓库 MCP 服务器暂未暴露资源但资源 URI 设计范式见第 4 节Prompts提示模板预定义的提示词模板复用常见工作流可按需扩展如将这段 Markdown 转成会议纪要 PDFMCP 协议的价值在于工具是函数可执行资源是数据可读提示是模板可复用——三者边界清晰客户端AI与服务器能力提供方各司其职。2. 服务器架构从目录结构到传输方式2.1 项目结构MCP Builder 文档给出的最小项目结构如下my-mcp-server/ ├── src/ │ └── index.ts # Main entry ├── package.json └── tsconfig.jsonDillinger 仓库中的packages/mcp/完全遵循这一结构且每个文件都有明确职责packages/mcp/src/index.ts—— 唯一入口负责创建 Server、注册工具、连接传输层packages/mcp/package.json—— 声明dillinger/mcp包、bindillinger-mcp命令、build/start脚本与依赖modelcontextprotocol/sdkpackages/mcp/tsconfig.json—— 以strict: true、target: ES2022、module: Node16编译到dist/并开启declaration: true生成类型声明。编译产出与运行命令# 在 packages/mcp 目录下 npm install npm run build # tsc 编译到 dist/ npm start # node dist/index.js2.2 传输类型Transport类型适用场景Stdio本地、基于 CLI 的标准输入输出客户端以子进程方式启动服务器SSEServer-Sent Events基于 Web 的服务端事件流适合远程部署与流式推送WebSocket实时、双向通信适合需要持续双向交互的场景Dillinger 的 MCP 服务器采用Stdio传输实现于packages/mcp/src/index.tsasync function main() { const transport new StdioServerTransport(); await server.connect(transport); }选择 Stdio 的工程考量本地 MCP 客户端如 Claude Desktop可以零配置地以子进程方式拉起node dist/index.js无需端口监听、无需处理网络鉴权天然满足本地、CLI 化的使用场景。若未来需要把 Dillinger MCP 部署为远程服务则可替换为 SSE 或 WebSocket 传输业务逻辑工具实现无需改动。3. 工具设计原则让 AI 用得对、用得好3.1 优秀工具的四个原则原则说明正面示例 / 反面示例名称清晰动作导向动词开头见名知义get_weather✅ /w❌单一职责一个工具只做好一件事render_markdown只负责渲染输入校验用带类型和描述的 Schema 约束参数见 3.2 节结构化输出返回格式可预测便于 AI 解析统一返回{ content: [...] }Dillinger 的四个工具全部采用动词_名词命名法职责单一工具名职责render_markdown用完整插件管线把 Markdown 渲染为 HTMLexport_pdf把 Markdown 转换为 PDF返回 base64export_html把 Markdown 转换为可直接发布的样式化 HTML 文档convert_html_to_markdown把 HTML 内容转换为干净的 Markdown可用于抓取网页内容3.2 输入模式Input Schema设计MCP 工具通过 JSON Schema 声明输入Builder 文档要求以下字段字段是否必填说明type是顶层必须为objectproperties是逐个定义每个参数的类型与描述required是列出必填参数数组description是人类可读的参数说明供 AI 理解用途以 Dillinger 的export_html为例packages/mcp/src/index.ts{ name: export_html, description: Convert markdown to a complete, styled HTML document ready for publishing or sharing., inputSchema: { type: object, properties: { markdown: { type: string, description: Markdown content to convert }, title: { type: string, description: Document title }, styled: { type: boolean, description: Include CSS styling in the HTML document (default: true) }, }, required: [markdown], }, }设计要点只把真正必需的参数markdown放入required可选参数title、styled给出默认值与语义化描述。这让 AI 在调用时既能拿到最小可用约束又不会因未知的可选参数而困惑。description的价值不可低估——MCP 工具文档最后强调The AI relies on descriptions to use them correctlyAI 依赖描述来正确使用工具描述写得越精确AI 的调用成功率越高。3.3 工具注册与调用处理MCP SDK 要求服务器实现两个核心请求处理器ListToolsRequestSchema客户端询问你有哪些工具服务器返回工具清单含 SchemaCallToolRequestSchema客户端发起实际调用服务器按工具名分发并返回结果。Dillinger 的实现结构packages/mcp/src/index.tsconst server new Server( { name: dillinger, version: 0.1.0 }, { capabilities: { tools: {} } } ); server.setRequestHandler(ListToolsRequestSchema, async () ({ tools: [ /* 工具清单 */ ] })); server.setRequestHandler(CallToolRequestSchema, async (request) { const { name, arguments: args } request.params; switch (name) { case render_markdown: { /* ... */ } case export_pdf: { /* ... */ } case export_html: { /* ... */ } case convert_html_to_markdown: { /* ... */ } default: return { content: [{ type: text, text: Unknown tool: ${name} }], isError: true }; } });注意capabilities: { tools: {} }声明了该服务器仅提供工具能力无 resources/prompts这是对协议能力的显式声明。未知工具返回isError: true符合结构化错误的要求。4. 资源模式数据读取的 URI 设计4.1 资源类型类型用途静态Static固定数据如配置文件、文档动态Dynamic按请求即时生成的数据模板Template带参数的 URI参数化寻址4.2 URI 模式模式示例固定docs://readme参数化users://{userId}集合files://project/*设计建议资源的 URI 就是它的身份证应具备确定性同一 URI 永远指向同一资源与可读性scheme 表达来源域。Dillinger 当前 MCP 服务器以工具为中心未暴露资源端点但如果你要扩展一个自然的做法是暴露dillinger://documents/*之类模板资源让 AI 直接读取已保存的 Markdown 文档。5. 错误处理结构化、可操作、不泄露5.1 错误类型与响应策略场景响应策略参数无效返回校验错误信息Validation error资源/工具不存在明确返回 not found服务器内部错误返回通用错误细节写入日志5.2 最佳实践清单返回结构化错误结构化 JSON 而非裸字符串异常不向客户端暴露内部实现细节堆栈、内部变量记录日志以便调试提供可操作的错误信息告诉 AI 该怎么修正。Dillinger 的实现非常典型packages/mcp/src/index.tsserver.setRequestHandler(CallToolRequestSchema, async (request) { try { switch (name) { /* ... */ } } catch (error) { return { content: [{ type: text, text: Error: ${error instanceof Error ? error.message : String(error)} }], isError: true, }; } });同时其上游 API 层也遵循同样的分层错误策略参数缺失返回400与明确的error文案如markdown field is required未配置密钥返回503密钥无效返回403见lib/api-auth.ts。MCP 服务器只透传可操作的错误信息如API error 403: Invalid API key原始堆栈被吞掉内部细节不会暴露给 AI。6. 多模态处理文本、图片与文件的编码MCP 工具返回内容支持多模态Builder 文档列出的编码方式类型编码方式文本纯文本图片Base64 MIME 类型文件Base64 MIME 类型Dillinger 的export_pdf是文件以 Base64 返回的实例packages/mcp/src/index.tscase export_pdf: { const response await apiCall(/export/pdf, { markdown, title: title || document }); const buffer await response.arrayBuffer(); const base64 Buffer.from(buffer).toString(base64); return { content: [{ type: text, text: PDF generated successfully (${buffer.byteLength} bytes). Base64-encoded content follows:\n${base64}, }], }; }这里有一个工程上的务实取舍MCP 的content块统一以text形式承载PDF 二进制被转成 Base64 字符串放入text并在前面附加PDF generated successfully (N bytes)的说明文本。这样既绕开了对图片/文件 content 类型的额外协商又让 AI 明确知道返回的是什么、有多大。若返回图片则应使用{ type: image, data: base64, mimeType: image/png }结构。7. 安全原则输入校验、密钥与最小权限7.1 输入校验校验所有工具输入类型、必填、边界清洗用户提供的数据防止注入类问题限制资源访问范围最小权限。Dillinger 在后端 API 层做了双重校验MCP 服务器层校验参数存在性缺markdown时由上游返回 400后端路由层再校验typeof markdown ! string || !markdown.trim()见app/api/v1/render/route.ts。校验应该分层冗余靠近边界的每一层都假设自己是唯一防线。7.2 API 密钥管理使用环境变量不硬编码不记录密钥到日志校验权限最小权限原则。Dillinger 的密钥管理是环境变量贯穿全链路的教科书示例MCP 服务器侧packages/mcp/src/index.tsconst BASE_URL process.env.DILLINGER_URL || https://dillinger.io; const API_KEY process.env.DILLINGER_API_KEY || ;后端鉴权侧lib/api-auth.ts逐层检查未配置密钥503→ 缺少Authorization: Bearer头401→ 密钥不匹配403。每个分支都返回不同的状态码与可操作信息便于 AI 与运维人员区分配置问题与凭证问题。此外DILLINGER_URL提供默认值https://dillinger.ioDILLINGER_API_KEY无默认值强制显式配置——这正是安全默认原则的体现。8. 配置以 Claude Desktop 为例8.1 配置文件字段Claude Desktop 的 MCP 服务器配置位于~/Library/Application Support/Claude/claude_desktop_config.json其mcpServers条目字段如下字段用途command要执行的可执行文件args命令行参数env传递给子进程的环境变量8.2 Dillinger MCP 的完整配置示例Dillinger 官方 READMEpackages/mcp/README.md给出了可直接照用的配置{ mcpServers: { dillinger: { command: node, args: [/path/to/packages/mcp/dist/index.js], env: { DILLINGER_API_KEY: your-api-key, DILLINGER_URL: https://dillinger.io } } } }要点说明args指向编译产物dist/index.js而非src/index.ts因此配置前必须先执行npm run buildDILLINGER_URL指向后端 API 的根地址DILLINGER_API_KEY必须与后端部署时设置的环境变量一致否则调用会收到 401/403若将dillinger/mcp作为 npm 包安装package.json中的bin字段提供了dillinger-mcp命令可直接把command换成dillinger-mcp。9. 测试策略单元、集成与契约测试类型关注点单元测试单个工具的逻辑参数校验、输出格式集成测试完整服务器启动 → 连接 → 调用 → 返回契约测试Schema 校验输入输出是否符合声明Dillinger 仓库虽然尚未为 MCP 服务器编写独立测试但其后端 API 的测试模式可作为同构参考仓库的tests/routes/目录中如tests/routes/export-pdf.route.test.ts、tests/routes/import-html-to-markdown.route.test.ts等对每个 API 路由的鉴权、参数校验、成功/失败分支做了覆盖。为 MCP 服务器编写测试时可沿袭同样的思路为apiCall注入 mock 的fetch验证四种工具的分发逻辑、未知工具分支与错误兜底分支。10. 最佳实践检查清单按照 Builder 文档交付一个 MCP 服务器前应逐项确认工具命名清晰、动作导向动词开头输入 Schema 完整每个参数都有描述输出为结构化 JSON所有错误场景都有处理无效参数、未找到、服务器错误输入经过校验配置基于环境变量记录日志以便调试。Dillinger 的 MCP 服务器逐条对照检查项落点动作导向命名render_markdown、export_pdf等四个工具完整 Schema每个工具均声明properties与requiredpackages/mcp/src/index.ts结构化 JSON 输出统一{ content: [{ type: text, text }] }全场景错误处理未知工具分支 try/catch 兜底 isError: true输入校验MCP 层 后端路由层双重校验环境变量配置DILLINGER_URL/DILLINGER_API_KEY日志main().catch(console.error)兜底记录启动失败附Dillinger MCP 的调用链路全景为了让前面各节的知识形成闭环这里给出 Dillinger MCP 服务器一次完整调用的真实链路均有源码依据客户端Claude Desktop依据claude_desktop_config.json以 Stdio 方式启动node dist/index.js握手与清单客户端先通过ListToolsRequestSchema拿到四个工具的 Schemapackages/mcp/src/index.ts发起调用AI 选择某个工具通过CallToolRequestSchema传入参数代理转发MCP 服务器调用apiCall()向${BASE_URL}/api/v1${path}发起带Authorization: Bearer ${API_KEY}的 POST 请求packages/mcp/src/index.ts后端处理对应路由如app/api/v1/render/route.ts先过validateApiKey鉴权再执行真实逻辑——renderMarkdown会加载 markdown-it 及 11 个插件abbr、checkbox、deflist、footnote、ins、mark、sub、sup、texmathKaTeX、toc与 highlight.js 高亮见lib/markdown.ts结果回传后端返回 HTML/PDF/文本MCP 服务器封装为 MCP content 块返回给 AI其中 PDF 以 Base64 编码packages/mcp/src/index.ts。这条链路清晰地展示了 MCP 服务器的定位它不是业务实现者而是把后端能力翻译成 AI 可理解、可调用的协议接口。理解了这一点再回看 Builder 文档中的每一条原则——清晰命名、完整 Schema、结构化输出、分层错误、环境变量密钥——就都能找到它们在真实工程中的落点。赞分享前端开发工具【免费下载链接】dillingerThe last Markdown editor, ever.项目地址https://gitcode.com/gh_mirrors/di/dillinger点击查看免费下载相关推荐claude-skills 之 MCP Developer 实战基于 Model Context Protocol 构建、调试与部署 AI 工具服务claude skills 之 MCP Developer 实战基于 Model Context Protocol 构建、调试与部署 AI 工具服务 本篇技术AI 技能AI 插件后端前端DevOps基于 txtai API 的 Model Context ProtocolMCP服务接入实战指南基于 txtai API 的 Model Context ProtocolMCP服务接入实战指南 Model Context ProtocolMCP是人工智能大模型RAGAI Agent向量数据库NLP本地部署Spring AI MCP Server 实战指南基于 Model Context Protocol 暴露 AI 工具与资源Spring AI MCP Server 实战指南基于 Model Context Protocol 暴露 AI 工具与资源 本篇指南以 Spring AI人工智能大模型AI AgentRAG后端工具调用MCP 服务MCP Clients上一篇如何快速搭建开源电子签名平台OpenSign完整安装与使用指南下一篇Qwen3-4B-Instruct-2507震撼发布40亿参数模型实现超长上下文与多维度能力跃升创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表