首先完成“构建你的第一个 MCP 服务器”即可解锁本课程。转到上一课

简介

MCP 原语是将 AI 应用连接到外部能力和上下文的主要设计单元。构建 MCP 服务器时,核心设计问题不是要暴露多少个端点,而是确定每项能力应表示为工具、资源还是提示。选择错误的原语可能导致智能体行为不安全、上下文难以发现,或迫使用户反复手动提供指令。

这三种原语具有不同的控制方式和交互模型。工具通常由模型控制:智能体可以在需要执行操作或进行计算时决定调用工具。资源通常由应用控制:宿主应用决定何时检索并向模型呈现其内容。提示通常由用户控制:用户选择或调用可复用的交互模板。这些是常见的 MCP 设计约定,而不仅仅是同一操作的不同名称。

本课将介绍一种实用的选择方法、契约设计规则以及一个小型决策辅助工具。目标是在开始实现之前,让原语选择变得可预测。

一个三列图,比较 MCP 工具、资源和提示,并分别显示从模型指向工具、从应用指向资源以及从用户指向提示的控制流箭头

三种原语

工具表示模型或智能体可以请求执行的一项操作。该操作可以读取数据、转换数据、调用服务或产生副作用。例如,搜索工单系统、计算运费、创建发票草稿或取消预订。工具应具有明确的名称、清晰的描述、定义完善的输入 schema,以及模型能够理解的输出。

资源表示由 URI 标识的、可寻址的信息。它适用于文档、配置、记录、schema、报告或其他应用可以加载并提供给模型的上下文。资源可以是静态的,例如策略文档;也可以是动态的,例如其 URI 标识当前实体的客户记录。读取资源应被视为检索上下文,而不是执行操作的指令。

提示是一种具有明确用途的可复用交互模板。它可以定义建议消息、参数以及任务的预期结构。例如,支持应用可以提供一个用于总结客户投诉的提示,而代码审查应用可以提供一个用于审查拉取请求的提示。提示不是工具的替代品,也不应隐藏会改变外部状态的操作。

选择合适的原语

首先确定用户或代理需要获取什么。如果需求是执行操作、进行计算、带参数查询或产生外部副作用,应从工具开始。某项操作仅读取数据这一事实,并不会自动使其成为资源。对当前订单进行参数化搜索通常属于工具,因为模型请求执行计算,并根据提供的参数接收结果。

当主要价值在于可检索且具有稳定标识的上下文时,应选择资源。退货政策等文档、数据库记录 URI 或生成的报告,在应用程序能够决定何时加载的情况下,都可以表示为资源。当用户需要独立于代理决策来浏览、附加、缓存、刷新或检查上下文时,资源尤其有用。

当需求是为用户封装一种可重复使用的对话模式时,应选择提示词。提示词可以告诉模型如何使用可用上下文,但不应伪装成可执行的业务操作。如果请求是“帮我准备退款申请”,提示词可以对对话进行组织;如果请求是“发起退款”,则必须由工具执行经过授权的操作。

一个实用的判断方法是补全这句话:“谁发起了这次交互?”如果应由模型决定何时调用某项操作,就使用工具。如果应由宿主应用程序检索或附加信息,就使用资源。如果应由用户选择一个预先准备好的工作流程,就使用提示词。有些工作流程确实会按顺序使用这三种原语。

设计强健的契约

良好的工具契约可以最大限度地减少歧义。名称应描述操作,而不是实现方式。描述应说明何时使用、何时不使用、需要哪些权限,以及有哪些重要约束适用。输入字段应尽可能具有明确的类型、有意义的描述、验证规则和范围受限的取值。每个请求都接受自由格式对象的工具,会使模型和服务器都更难发现错误。

工具输出应区分成功数据与失败信息。当客户端需要以编程方式检查字段时,应返回结构化结果;当结果将展示给模型或用户时,还应包含简洁、易读的内容。不要仅仅因为请求已到达服务器就报告成功。对于会产生副作用的工具,结果应明确说明操作是已完成、已拒绝、部分完成,还是仅已准备为草稿。

资源设计依赖稳定的标识符和可预测的内容。应使用能够标识领域对象或文档的 URI,同时避免嵌入偶然的实现细节。应确定资源是不可变、可刷新还是带版本的,并说明如何处理过时内容。包含敏感数据的资源还需要授权策略;URI 是标识符,并不等于读取底层数据的权限。

提示词设计应只暴露用户或应用程序能够合理提供的参数。提示词描述应说明预期结果和所需上下文。应将操作指令与用户数据分开,并避免嵌入模型必须视为权威的信息,除非应用程序能够对其进行维护。提示词可以建议调用工具,但授权和验证必须保留在工具层和服务器层。

示例

设想一个客户支持应用程序,它有三个需求:查找客户尚未关闭的订单、提供当前的退货政策,以及引导客服人员完成退货对话。第一个需求是针对实时系统的参数化查询,因此适合使用工具。第二个需求是一个可寻址的文档,应用程序可以在需要时加载,因此适合使用资源。第三个需求是一种可由用户选择的、可重复使用的对话模式,因此适合使用提示词。

下面这个本地 JavaScript 辅助函数表达了该决策规则。它不是 MCP 服务器,也不能替代协议注册。其用途是在实现之前,让设计评审过程明确化。结果包括所选的原语,以及支持该选择的理由。

javascript
function chooseMcpPrimitive(requirement) {
const text = requirement.toLowerCase();
if (text.includes("perform") || text.includes("create") || text.includes("update") ||
text.includes("delete") || text.includes("search") || text.includes("calculate") ||
text.includes("send") || text.includes("live")) {
return {
primitive: "tool",
reason: "The requirement describes an operation, computation, parameterized lookup, or side effect."
};
}
if (text.includes("document") || text.includes("policy") || text.includes("record") ||
text.includes("report") || text.includes("read") || text.includes("context")) {
return {
primitive: "resource",
reason: "The requirement describes addressable information that an application can retrieve and attach as context."
};
}
if (text.includes("guide") || text.includes("workflow") || text.includes("template") ||
text.includes("conversation") || text.includes("summarize")) {
return {
primitive: "prompt",
reason: "The requirement describes a reusable interaction pattern selected by a user or application."
};
}
return {
primitive: "review",
reason: "The requirement does not provide enough information to distinguish action, context, and interaction template."
};
}
console.log(chooseMcpPrimitive("search live open orders for a customer"));
console.log(chooseMcpPrimitive("read the current return policy document"));
console.log(chooseMcpPrimitive("guide an agent through a return conversation"));

第一次调用应生成工具决策,第二次调用应生成资源决策,第三次调用应生成提示词决策。该辅助函数在面对歧义时有意采取保守策略。实际的设计评审应在注册任何内容之前,检查授权、时效性、用户控制权,以及该操作是否会产生副作用。

常见失败模式

一个常见错误是将所有能力都暴露为工具,因为代理调用工具很方便。这会导致工具目录过于庞大,并促使模型通过本应可浏览或由应用控制的操作来获取文档。应将检索上下文与操作分开,尤其是在上下文稳定且可以缓存的情况下。

另一个错误是让工具描述过于模糊。像 process_request 这样的名称无法告诉模型该工具是用于搜索、审批、提交,还是删除某项内容。模糊的描述会增加错误调用,也会使授权评审更加困难。应直接说明操作、必需输入、重要排除项以及副作用行为。

资源的设计也可能不正确,例如其 URI 暴露了机密信息、依赖不稳定的数据库内部结构,或暗示拥有访问权限却未实际执行权限控制。应在适当情况下使用不透明标识符,在每次读取时验证授权,并定义如何报告内容缺失、过时或不可用的情况。对于提示词,不要将其视为安全边界。提示词中的指令不能替代服务器端验证。

最后,不要假设组合多个原语就会自动形成良好的工作流。应测试宿主是否在正确的时间暴露资源,用户是否能够理解提示词参数,以及工具是否会拒绝格式错误或未经授权的请求。可观测性应记录原语名称、验证结果、授权结果和失败类别,同时避免不必要地记录敏感值。

总结

工具适用于操作、计算、参数化查询和副作用。资源适用于可寻址的信息,应用可以检索这些信息并将其作为上下文提供。提示词适用于可复用的交互模式,用户可以选择或调用这些模式。它们之间的差异既涉及数据形态,也涉及控制权归属。

可靠的设计流程应从需求出发,确定由谁发起交互,检查结果属于操作还是上下文,然后定义精确且范围受限的契约。对于每种原语,都应明确说明描述、架构、权限、错误以及时效性行为。

当工作流跨越多个关注点时,应有意识地组合这些原语。用户可以选择提示词,应用可以附加资源,而模型可以调用工具。明确划分这些职责,可以带来更清晰的行为、更安全的授权,以及更易于测试和维护的 MCP 集成。

课后练习

课程检查点

巩固所学知识,获取作业反馈。

0/1
已回答 · 0/1