工具优先思维
在 Apps SDK 中,工具是 MCP 服务器与模型之间的契约。它们描述了连接器可以做什么、如何调用以及返回什么数据。良好的工具设计使发现过程更准确、调用更可靠,且下游的用户体验 (UX) 更具预测性。
在触及 SDK 之前,请使用以下检查清单将您的用例转化为范围明确的工具。
起草工具表面积
从您在用例研究中定义的用户旅程开始
- 每个工具仅做一件事 —— 保持每个工具专注于单一的读或写操作(如“fetch_board”、“create_ticket”),而不是一个大而全的终点。这有助于模型在多个选项中做出准确选择。
- 显式输入 —— 现在就定义
inputSchema的格式,包括参数名称、数据类型和枚举值。记录默认值和可空字段,以便模型了解哪些是可选的。 - 可预测的输出 —— 列出您将返回的结构化字段,在
outputSchema中进行声明,并包含模型可以在后续调用中重复使用的机器可读标识符。
如果您需要读取和写入行为,请创建单独的工具,以便 ChatGPT 可以在写入操作时执行确认流程。
分离数据处理与 UI 渲染
如果一个工作流既需要可重用的数据又需要一个组件,请将其规划为两个工具,而不是一个负载过重的工具。
- 数据工具:返回完整的
structuredContent以供模型推理和后续调用,不含 UI 模板。 - 渲染工具:接受已准备好的数据,附上组件模板,并专注于展示。
模型应首先调用数据工具,使用返回的 structuredContent,然后使用准备好的数据调用渲染工具,从而确保组件在模型校验后的最终上下文中只渲染一次。在渲染工具的描述中说明这种依赖关系。
对于需要即时数据交互的本地 UI,让组件直接调用数据工具,而不是重新挂载自身。有关更完整的实现模式,请参阅构建您的 ChatGPT UI。
捕获元数据以优化发现
工具的发现几乎完全由元数据驱动。对于每个工具,请草拟:
- 名称 —— 面向操作且在您的连接器内唯一(例如
kanban.move_task)。 - 描述 —— 以“Use this when…”(在此情况下使用……)开头的一两句话,以便模型准确知道何时选择该工具。
- 参数注释 —— 描述每个参数并标出安全范围或枚举值。当用户提示模糊时,这种上下文可以防止格式错误的调用。
- 全局元数据 —— 确认您已准备好应用层级的名称、图标和描述,以用于目录和启动器。
稍后,将这些集成到您的 MCP 服务器中,并使用优化元数据工作流进行迭代。
模型侧的防护栏
思考工具链接后模型应如何表现:
-
预链接与需要链接 (Prelinked vs. link-required) —— 如果您的应用可以在匿名状态下工作,请将工具标记为无需授权即可使用。否则,请确保您的连接器通过身份验证中描述的引导流程强制执行链接。
-
只读提示 —— 设置
readOnlyHint注释以指定无法更改状态的工具。 -
破坏性提示 —— 设置
destructiveHint注释以指定哪些工具会删除或覆盖用户数据。 -
开放世界提示 —— 设置
openWorldHint注释以指定哪些工具会发布内容或触达用户账户之外的资源。 -
结果组件 —— 决定每个工具是应渲染组件、仅返回 JSON 还是两者皆有。在工具描述符上设置
_meta.ui.resourceUri以公示 UI 模板,从而使相同的 UI 能够在多个 MCP 应用宿主中运行(ChatGPT 将_meta["openai/outputTemplate"]视为一个可选的兼容性别名)。
黄金提示词预演
在实现之前,根据您之前捕获的提示列表对工具集进行完整性检查:
- 对于每个直接提示,确认您拥有一个能够清晰响应请求的工具。
- 对于间接提示,确保工具描述为模型提供了足够的上下文,使其能够选择您的连接器而不是内置选项。
- 对于否定提示,验证您的元数据是否能使工具保持隐藏状态,除非用户明确选择(例如,通过提及您的产品名称)。
现在就捕获任何差距或歧义并调整计划——在发布前更改元数据比事后重构代码成本低得多。
移交至实现阶段
准备好进行实现时,请将以下内容整理成一份移交文档:
- 工具名称、描述、
inputSchema和outputSchema。 - 工具是否应返回组件,如果应返回,则确定由哪个 UI 组件进行渲染。
- 身份验证要求、速率限制以及错误处理预期。
- 应该成功的测试提示(以及应该失败的测试提示)。
将此计划带入设置您的服务器指南,使用您选择的 MCP SDK 将其转换为代码。