Activepieces MCP Server 最佳实践指南:命名、工具设计、分页、传输与安全规范
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
导读
本文是 Activepieces 仓库中 MCP 服务器最佳实践文档 的深度展开版。它面向需要为 LLM(如 Claude、Cursor、Windsurf)构建高质量 MCP(Model Context Protocol)服务器的开发者,系统讲解服务器与工具的命名约定、JSON/Markdown 双格式响应、分页元数据、stdio 与 Streamable HTTP 传输选型、安全加固、工具注解、错误处理、测试与文档要求。读完本文,你将掌握一套可直接落地、可被 Agent 顺畅发现与调用的 MCP 服务器设计与实现规范,并理解 Activepieces 内部托管 MCP 服务器(mcp-server-builder.ts)是如何将这些最佳实践固化为代码的。
一、速查卡(Quick Reference)
原文档首先给出了一页纸式的速查条目,它们是后续所有章节的浓缩,开发时应当时刻对照:
| 维度 | 规范 |
|---|---|
| Python 服务器命名 | {service}_mcp,例如slack_mcp |
| Node/TypeScript 服务器命名 | {service}-mcp-server,例如slack-mcp-server |
| 工具命名 | snake_case 且带服务前缀,格式{service}_{action}_{resource} |
| 工具命名示例 | slack_send_message、github_create_issue |
| 响应格式 | 同时支持 JSON 与 Markdown:JSON 面向程序化处理,Markdown 面向人类可读 |
| 分页 | 始终尊重limit参数,返回has_more、next_offset、total_count,默认每页 20–50 条 |
| 传输层 | 远程/多客户端场景用 Streamable HTTP;本地/命令行工具用 stdio;避免 SSE(已被 Streamable HTTP 取代) |
这些约定并非空谈。在 Activepieces 中,McpToolDefinition类型(packages/core/shared/src/lib/automation/mcp/mcp.ts)就为每个工具定义了title、description、inputSchema与annotations,而服务器侧在注册工具时正是把工具名作为 LLM 可见的唯一标识符(mcp-server-builder.ts),因此命名是否清晰、是否有前缀,直接影响 Agent 能否在众多工具中快速命中正确的那一个。
二、服务器命名规范(Server Naming Conventions)
Python:{service}_mcp
- 全小写、下划线分隔;
- 示例:
slack_mcp、github_mcp、jira_mcp。
Node/TypeScript:{service}-mcp-server
- 全小写、连字符分隔;
- 示例:
slack-mcp-server、github-mcp-server、jira-mcp-server。
命名要点
- 名称应当通用且能准确描述被集成的服务;
- 应当能从任务描述中轻易推断出该服务器是干什么的;
- 不要带版本号(版本信息应交给包管理或 manifest,而不是包名);
- 保持一致的前缀体系,便于在工具列表中按服务归类。
仓库中的托管服务器也遵循同样的精神:buildMcpServer创建的服务器实例名为Activepieces,版本号1.0.0独立于名称之外(mcp-server-builder.ts),名称只承担"描述服务"的职责。
三、工具命名与设计(Tool Naming and Design)
工具命名四原则
- 使用 snake_case:
search_users、create_project、get_channel_info; - 包含服务前缀:要预见到你的 MCP 服务器可能与其他服务器并存于同一个客户端。用
slack_send_message而非send_message,用github_create_issue而非create_issue,避免与其他服务器的工具重名冲突; - 动作导向(action-oriented):以动词开头(get、list、search、create、update、delete 等),让 Agent 一眼看出工具行为;
- 具体明确:避免宽泛名称,越具体越不容易产生歧义。
工具设计要点
- 描述必须窄而明确:工具描述要"无歧义"地说明功能,不能模棱两可;
- 描述必须与真实功能精确一致:描述是 LLM 决定何时调用该工具的唯一依据,夸大或含糊都会导致错误调用;
- 提供工具注解(annotations):
readOnlyHint、destructiveHint、idempotentHint、openWorldHint四类注解帮助客户端理解工具行为(详见第七章); - 保持操作聚焦与原子化:一个工具只做一件事,避免"大而全"的万能工具。
仓库中的落地方式
Activepieces 的流式 MCP 工具在注册时由服务器自动生成名称:
const baseName = (mcpToolNameInput ?? flow.version.displayName) + '_' + flow.id.substring(0, 4) const toolName = mcpToolNameUtils.createToolName(baseName)(见 mcp-server-builder.ts,工具名规范化工具由 mcp-tool-name-util.ts 从@activepieces/core-piece-types导出。)
同时在 MCP Tool 触发器 中,toolName与toolDescription是必填属性——后者即"描述必须精确匹配功能"这一要求在可视化搭建场景下的直接体现:
toolName: Property.ShortText({ displayName: 'Name', description: 'Used to call this tool from MCP clients like Claude Desktop, Cursor, or Windsurf', required: true, }), toolDescription: Property.LongText({ displayName: 'Description', description: 'Used to describe what this tool does and when to use it', required: true, }),四、响应格式(Response Formats)
所有返回数据的工具都应支持多种格式,以兼顾程序化处理与人类阅读:
JSON 格式(response_format="json")
- 机器可读的结构化数据;
- 包含全部可用字段与元数据;
- 字段名与类型保持一致;
- 供程序化处理使用。
Markdown 格式(response_format="markdown",通常为默认)
- 人类可读的格式化文本;
- 善用标题、列表与排版提升清晰度;
- 将时间戳转换为人类可读格式;
- 展示显示名称,并在括号中附带 ID;
- 省略冗长的元数据。
仓库佐证
Activepieces 的runFlowAsTool返回值同时携带人类可读文本与结构化 JSON:成功时输出✅ Successfully executed flow ...加 JSON 块,失败时输出❌ Error executing flow ...加错误详情 JSON(mcp-server-builder.ts)。McpToolResult类型同样同时包含content(text 数组)与可选的structuredContent(mcp.ts),这正是"Markdown 给人看、JSON 给机器用"的双轨设计。
五、分页(Pagination)
对于会列出资源的工具:
- 始终尊重
limit参数; - 实现分页:使用
offset或基于游标(cursor)的分页; - 返回分页元数据:
has_more、next_offset/next_cursor、total_count; - 绝不一次性把所有结果载入内存:对大数据集尤其重要;
- 默认设置合理上限:每页 20–50 条是常见取值。
示例分页响应
{ "total": 150, "count": 20, "offset": 0, "items": [...], "has_more": true, "next_offset": 20 }设计意图:LLM 的上下文窗口有限,一次返回数千条记录既浪费 token 又降低回答质量。分页元数据让 Agent 可以"按需翻页",先看第一页判断是否值得继续,而不是被迫一次性拉全量数据——这对应了 SKILL.md 中"上下文管理:让工具返回聚焦、相关的数据"的原则(见 SKILL.md)。
六、传输层选项(Transport Options)
Streamable HTTP
- 适用场景:远程服务器、Web 服务、多客户端并发场景;
- 特性:
- 基于 HTTP 的双向通信;
- 支持多个客户端同时连接;
- 可作为 Web 服务部署;
- 支持服务器到客户端的通知(server-to-client notifications);
- 使用时机:同时服务多个客户端、以云服务形态部署、与 Web 应用集成。
stdio
- 适用场景:本地集成、命令行工具;
- 特性:
- 通过标准输入/输出流通信;
- 设置简单,无需网络配置;
- 作为客户端子进程运行;
- 使用时机:构建本地开发环境工具、与桌面应用集成、单用户单会话场景;
- 注意:stdio 服务器不应向 stdout 打日志(会污染协议数据流),应使用 stderr 记录日志。
传输选型对比
| 标准 | stdio | Streamable HTTP |
|---|---|---|
| 部署方式 | 本地 | 远程 |
| 客户端 | 单个 | 多个 |
| 复杂度 | 低 | 中等 |
| 实时性 | 无 | 有 |
仓库中的工程化佐证
Activepieces 自身的托管 MCP 服务器即采用 HTTP 形态对外服务:服务器基于@modelcontextprotocol/sdk/server/mcp.js的McpServer构建(mcp-server-builder.ts),并注册了占位资源与空 prompt(registerEmptyResourcesAndPrompts,mcp-server-builder.ts)。这意味着即便你的服务器以流式 HTTP 提供主要工具能力,也建议补齐资源(Resource)与提示词(Prompt)的注册,使协议面保持完整,客户端枚举能力时不会落空。
七、安全最佳实践(Security Best Practices)
认证与授权(Authentication & Authorization)
OAuth 2.1:
- 使用来自权威 CA 的证书,启用安全的 OAuth 2.1;
- 处理请求前先校验访问令牌;
- 只接受明确指定给本服务器的令牌(防止令牌混淆攻击)。
API Keys:
- API Key 存放在环境变量中,绝不写进代码;
- 在服务器启动时校验 Key;
- 认证失败时给出清晰、可操作的错误信息。
输入校验(Input Validation)
- 净化文件路径,防止目录遍历攻击;
- 校验 URL 与外部标识符;
- 检查参数的大小与取值范围;
- 在系统调用中防止命令注入;
- 对所有输入使用 schema 校验(Pydantic / Zod)。
错误处理(安全视角)
- 不向客户端暴露内部错误细节;
- 安全相关错误在服务端记录日志;
- 提供"有帮助但不过度泄露"的错误信息;
- 出错后正确清理资源。
DNS Rebinding 防护(针对本地 Streamable HTTP 服务器)
- 开启 DNS rebinding 防护;
- 校验所有入站连接的
Origin头; - 绑定
127.0.0.1而不是0.0.0.0。
DNS rebinding 的威胁模型:浏览器中的恶意页面可先解析到合法域名,再在 DNS 层面将域名解析回
127.0.0.1,从而绕过同源策略访问你本机的 MCP 服务。校验 Origin + 只绑回环地址可以显著缩小攻击面。
仓库佐证:权限不是注解,而是强制检查
Activepieces 的托管服务器在注册每个工具前,都会通过PermissionChecker做权限校验,并将检查结果作为工具执行的守卫(mcp-server-builder.ts):
const flowPermissionError = permissionChecker.check(Permission.WRITE_RUN, toolName) server.registerTool(toolName, {...}, async (args) => { if (flowPermissionError) { return flowPermissionError } const result = await runFlowAsTool({...}) return result })这印证了下一章的核心结论:注解只是"提示",真正的安全必须依赖服务端的强制校验。
八、工具注解(Tool Annotations)
为帮助客户端(尤其是 LLM 客户端)理解工具行为,应为每个工具提供四类注解:
| 注解 | 类型 | 默认值 | 描述 |
|---|---|---|---|
readOnlyHint | boolean | false | 工具不会修改其运行环境 |
destructiveHint | boolean | true | 工具可能执行破坏性更新 |
idempotentHint | boolean | false | 相同参数重复调用不产生额外效果 |
openWorldHint | boolean | true | 工具与外部实体交互 |
重要:注解是提示(hints),不是安全保证。客户端不应仅凭注解做安全攸关的决策——是否允许执行某个破坏性操作,必须由服务端授权体系裁决。
仓库中的注解实践
McpToolDefinition类型把注解建模为可选字段(mcp.ts):
annotations?: { readOnlyHint?: boolean destructiveHint?: boolean idempotentHint?: boolean openWorldHint?: boolean }而在 mcp-server-builder.ts 中,不同类别的工具使用了差异化的注解组合,可作为参考样板:
// 流式工具:会触发现有流执行、与外部世界交互、非只读 const FLOW_TOOL_ANNOTATIONS = { readOnlyHint: false, destructiveHint: false, openWorldHint: true } // 锁定占位工具:纯只读、不触达外部 const LOCKED_PLACEHOLDER_ANNOTATIONS = { readOnlyHint: true, destructiveHint: false, openWorldHint: false } // 可控制占位工具:可能破坏性、触达外部 const CONTROLLABLE_PLACEHOLDER_ANNOTATIONS = { readOnlyHint: false, destructiveHint: true, openWorldHint: true }九、错误处理(Error Handling)
- 使用标准 JSON-RPC 错误码;
- 工具错误应放在结果对象内报告(通过
isError标记),而不是协议级错误——协议级错误会中断会话,结果级错误则允许客户端读取错误内容并继续推理; - 提供有帮助、具体、带下一步建议的错误信息;
- 不暴露内部实现细节;
- 出错时正确清理资源。
示例:结果内错误报告
try { const result = performOperation(); return { content: [{ type: "text", text: result }] }; } catch (error) { return { isError: true, content: [{ type: "text", text: `Error: ${error.message}. Try using filter='active_only' to reduce results.` }] }; }注意错误文案的写法:Try using filter='active_only'直接给出了可执行的下一步,这正是"可操作错误信息"的范式——告诉 Agent 怎么修,而不是只告诉它坏了。
仓库中的一致实现
Activepieces 的runFlowAsTool在流程执行失败时返回isError: true并附带可读的错误 JSON(mcp-server-builder.ts):
const isOkay = Math.floor(response.status / 100) === 2 const text = isOkay ? `✅ Successfully executed flow ${flowDisplayName}\n\nOutput:\n\`\`\`json\n${JSON.stringify(response, null, 2)}\n\`\`\`` : `❌ Error executing flow ${flowDisplayName}\n\nError details:\n\`\`\`json\n${JSON.stringify(response, null, 2) || 'Unknown error occurred'}\n\`\`\`` return { content: [{ type: 'text', text }], ...(isOkay ? {} : { isError: true }) }McpToolResult类型同样显式声明了可选的isError字段(mcp.ts),从类型层面保证"错误即结果"这一约定贯穿全链路。
十、测试要求(Testing Requirements)
全面的测试应覆盖以下五个维度:
- 功能测试:以合法/非法输入验证工具是否正确执行;
- 集成测试:测试与外部系统的真实交互;
- 安全测试:验证认证、输入净化、速率限制;
- 性能测试:检查负载下的行为、超时表现;
- 错误处理测试:确保错误报告正确、资源清理到位。
补充工程实践(对应 SKILL.md 的 Review & Test 阶段):
- TypeScript:运行
npm run build验证编译;用 MCP Inspector 交互式调试:npx @modelcontextprotocol/inspector; - Python:运行
python -m py_compile your_server.py校验语法;同样用 MCP Inspector 验证工具行为。
此外,SKILL.md 的 Phase 4 还要求在实现完成后创建评测集(evaluations):针对你的 MCP 服务器设计 10 个独立、只读、复杂、真实、可验证、稳定的问题,用 XML 格式组织成qa_pair,检验 LLM 是否真的能借助你的服务器完成现实任务——这是"功能测试"之上更高一层的"Agent 可用性测试"。
十一、文档要求(Documentation Requirements)
- 为所有工具与能力提供清晰的文档;
- 每个主要功能至少给出3 个可运行示例;
- 记录安全考量;
- 说明所需的权限与访问级别;
- 记录速率限制与性能特征。
为什么文档是 MCP 服务器质量的一部分:MCP 服务器没有传统意义上的"UI",它的用户界面就是工具描述与文档。Agent 依据描述决定调用哪个工具、填什么参数;人类开发者依据文档决定如何部署、如何授权、预期什么性能。toolDescription之于工具,正如 README 之于仓库——MCP Tool 触发器 将描述设为必填项,正是这一原则在 Activepieces 产品化场景中的强制落地。
结语
MCP 服务器的质量不取决于代码多炫,而取决于"LLM 能否用它顺畅地完成真实任务"(SKILL.md 开宗明义)。本文覆盖的命名、双格式响应、分页、传输选型、安全、注解、错误处理、测试与文档九大规范,正是从工具可发现性、可组合性、健壮性与安全性四个维度支撑这一目标的完整 checklist。开发者可以对照 mcp_best_practices.md 原文逐项自查,也可参考本仓库的 TypeScript 实现指南 与 Python 实现指南 获取具体语言的项目结构与代码样板,再结合 评测指南 验证最终效果。
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考