想象一位从未进过这间厨房的新主厨。推开门,眼前是一间规划齐整的后厨:左手是食材储藏间,每份食材都贴着唯一的储位号;正面墙上挂满了厨具,每把都贴着操作说明;抽屉里码着一沓菜谱卡,标注着适合的场景。主厨要做的第一件事,不是闷头开火,而是先搞清楚“这里有什么、每样东西怎么用、哪些能组合”。这间后厨的秩序,恰恰就是 MCP 协议在数据层做的事。 AI Agent 面对一个 MCP Server 时,处境和这位主厨一模一样。MCP 协议把服务端的能力切成三种原语:Resources(数据源)是储藏间里的食材,只能被取用而不能被改变;Tools(可执行操作)是墙上的厨具,一经调用就产生真实动作;Prompts(提示模板)是菜谱卡,把常见任务的套路固化成可复用的模板。三类东西各归其位,Agent 才能按需取用、自由组合,最终端出一道完整的“菜”。 这篇文章就带你逛一遍这间后厨:先认三类原语的职责边界,再看数据格式规范(JSON Schema)与暴露机制(list/read),接着聊 Agent 如何按需组合,最后讲讲设计 MCP Server 时怎么避免“菜刀插进米缸”的混乱。
对 AI 从业者而言,理解 MCP 数据层是设计生产级 Agent 服务端的基本功——它决定了模型能否稳定、安全、高效地接入真实业务的数据与操作,是 Agent 架构师绕不开的必修课。
可视化演示
动态演示MCP数据层的核心机制,通过总览/传输/转换/输出四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
MCP数据层:Reso Resources与Tools JSON Schema数据格式 核心机制可视化 MCP数据层整体架构与关键组件
三大原语概览
一位新主厨第一次走进后厨,最怕的不是锅铲不顺手,而是“不知道东西在哪”。还好这间后厨有规矩:左手储藏间只放食材,墙上只挂厨具,抽屉里只摆菜谱卡。他环顾一圈,心里便有了底——做任何菜,无非是“取食材、动厨具、照菜谱”三件事的组合。
MCP 协议在设计数据层时做了完全相同的抽象。它把服务端能提供给 Agent 的能力,整齐地切成三种原语(Primitive):Resources、Tools、Prompts。所谓原语,就是最基础、不可再分的能力单元。一个 MCP Server 无论业务多复杂,它的能力都可以用这三类原语完整描述,不多不少。
从实现角度看,三类原语各管一摊:Resources 是数据源,负责“被读取”,例如数据库记录、文件内容、外部 API 返回的快照;Tools 是可执行操作,负责“被调用”,例如查余额、发通知、修改订单状态;Prompts 是模板,负责“被复用”,把高频任务的执行套路固化成可填参的文本模板。Agent 眼中看到的服务端全景,就是这三类原语的并集。
理解了这一点,再看任何 MCP Server 都不会慌:主厨心里有分类,出菜才快;Agent 心里有分类,任务才不乱。接下来要做的,就是把每一类原语的细节逐个摸清。
- R 集合(Resources)表示 MCP Server 上所有可读数据源的集合,包括数据库记录、文档内容等“可以被取用的食材”:
- T 集合(Tools)表示所有可执行操作的集合,每个元素都是一个带输入输出约束的函数:
- P 集合(Prompts)表示所有提示模板的集合,每个元素是一份可填入参数的消息模板:
- 并集 \cup把三类集合合成一个整体,形成 Agent 可发现、可调用、可复用的全部能力:
Resources数据源
储藏间管理的核心,是“货架标签”。每一份食材都有一个唯一的储位号:db://orders/2024 是指向订单库的坐标,file://reports/q3.pdf 是指向报告文件的坐标。主厨不关心食材是怎么进货的,他只需要知道“按这个号码就能拿到那样东西”。
在 MCP 中,Resources 就是这个储藏间:一种只读的数据源抽象。设计 Resources 要回答三个问题:数据放哪(URI)、数据长什么样(MIME 与结构)、怎么让 Agent 知道它存在(暴露)。URI 是资源的唯一地址,协议约定它必须能稳定定位同一份内容;mimeType 声明内容格式,告诉 Agent 该用 JSON 解析还是当作纯文本。
技术实现上,Server 通过 list_resources 返回资源清单(URI + 名称 + 描述 + MIME),通过 read_resource 接受 URI 并返回具体内容。数据量大的资源还可以分页读取。需要强调的是:Resources 不含任何“动作”。主厨打开储位号只能取出食材,不能顺手把食材加工成菜——那是厨具的事。
一间好储藏间的标准是“标签清晰、取用顺手”。同样,设计 Resources 时,给每个 URI 起一个可读的名字、写一句人能看懂的描述,比堆砌字段重要得多。Agent 是语言模型,它读清单时靠的就是这些描述来“猜”该取哪份食材。
- uri 资源坐标资源的唯一地址,相当于储藏间的储位号,Agent 凭它取货:
- mimeType 类型标签声明内容的媒体类型(如
application/json),决定 Agent 如何解析这份数据: - description 人话说明用一句自然语言描述资源用途,帮助 LLM 在清单里做出选择:
- 映射到 content三元组(uri、mimeType、description)共同决定最终读到的具体内容:
Tools工具设计
工具墙上的每把厨具都贴着一张说明书:名字、用途、怎么用、用了之后会发生什么。主厨拿起“高温喷枪”,知道它需要接燃气(输入),知道它能烤焦糖(输出),也知道它有烫伤风险(副作用)。知道这三件事,他才敢放心使用。
Tools 就是 MCP 里的“厨具说明书 + 厨具本身”。它是对可执行函数的封装,元数据包含四要素:name(动词开头的工具名)、description(用途说明)、inputSchema(输入参数的 JSON Schema)、outputSchema(返回结构的 JSON Schema)。Agent 看到这份说明书,就知道“这个工具解决什么问题、我该传什么参数”。
与 Resources 的“只读”不同,Tools 天然带有副作用的可能:写入数据库、发送通知、修改状态。因此设计 Tools 时要显式声明副作用,让 Agent 在调用前有能力评估风险。比如 query_balance 是无副作用的查询,send_notice 会真实发出消息——描述里写清楚,模型才能做负责任的选择。
工具命名也讲究:统一用动词开头,query_balance、update_address、restart_service,风格一致的工具清单能让 Agent 的“模式匹配”更快。想象一下,如果储藏间的储位号一会儿是数字一会儿是汉字,主厨找东西就得挨个翻——命名规范,本质上是降低 Agent 的选择成本。
- name 工具名动词短语命名,如
query_balance,一眼看出工具干什么: - inputSchema 输入契约用 JSON Schema 声明参数结构,标明字段类型与必填项:
- outputSchema 输出契约声明返回数据的结构,让 Agent 知道调用后能拿到什么:
- f 执行体被调用的实际函数,负责完成真实业务动作:
Prompts模板设计
菜谱卡是个神奇的东西:它不是食材(不能直接吃),也不是厨具(不能切菜),但主厨离不开它。一张“蒜蓉西兰花”的菜谱,把“焯水→炝锅→翻炒→调味”的套路写清楚,换掉主料就变成蒜蓉菠菜。菜谱的本质是可复用的套路。
Prompts 在 MCP 中扮演的正是菜谱卡的角色:一套可复用、可填参的提示模板。它由两部分组成:arguments(参数声明,如 {task}、{problem})和 messages(消息骨架,包含角色与带占位符的内容模板)。Agent 调用 get_prompt 拿到模板,填入实际参数,就得到一份高质量的任务指令或回复草稿。
Prompts 与 Tools 的根本区别在于:Tools 执行动作,Prompts 只产出文本。weekly_report 模板不会替你写周报,它只是把“写周报的正确姿势”固定下来。因此 Prompts 尤其适合高频、有固定结构的任务:客服回复、周报生成、代码审查清单、故障上报格式。它让团队的最佳实践沉淀为模板,而不是每次靠模型自由发挥。
值得注意的是,Prompts 常常与 Tools 配合:Agent 先 read 数据、call 工具拿到结果,再套用模板把结果组织成规范输出。菜谱提供了装盘的角度,但菜本身还是要靠食材和厨具做出来——模板负责“表达”,不负责“生产”。
- arguments 参数表声明模板中的占位参数,如
{task}、{question}: - messages 消息骨架定义角色(system/user)与带占位符的内容模板:
- 参数填充将实际值替换进占位符,得到具体内容:
- 合成结果填充完成后的消息集合就是可直接使用的完整提示:
数据格式规范
如果储藏间里每份食材的标签格式都不一样——有的写日期、有的写"fresh"、有的干脆不贴——主厨根本没法判断能不能用。标签的价值在于统一。在 MCP 世界里,这个统一标签就是 JSON Schema。
JSON Schema 是描述数据结构的标准格式,它声明字段名称、类型、是否必填、取值范围、默认值等信息。Tools 的 inputSchema、Resources 的内容结构、Prompts 的参数定义,都可以用 JSON Schema 来表达。有了它,参数校验就是一次确定性的运算,而不是靠“猜”。
校验流程在 Server 端执行:Agent 发起调用请求 → Server 按 Schema 逐字段校验 → 校验通过才进入业务逻辑,失败则立刻返回错误。错误返回也要遵循统一协议:isError: true 加上结构化错误信息,让 Agent 能读懂“哪里错了、怎么改”。想象后厨的食材变质会直接丢弃而不是硬炒——快速失败,是对 Agent 最大的保护。
Schema 里还要写好描述字段。LLM 不是普通程序,它通过阅读描述来理解“这个参数该填什么”。一个字段的 description 写得清晰,模型第一次就能填对;写得含糊,模型就开始瞎猜。好的 Schema 既是约束,也是说明书。
- x 输入值Agent 调用工具时传入的参数对象,如
{"user_id": 1}: - S 约束定义JSON Schema 描述的规则集合,包含类型、必填项、属性约束:
- D(S) 合法值域所有满足 Schema 约束的取值构成合法值域:
- validate 判定校验通过等价于参数落在合法值域内:
暴露方式机制
主厨不需要搬空储藏间才知道有哪些食材。他先看一眼门上的清单——“土豆 × 3、牛排 × 2、西兰花 × 1”——然后决定取哪一份。清单和取货是两道工序,先看单、再动手,省时又省力。
MCP 的暴露机制正是这个思路:list 与 read(或 call)分离。list_resources 返回轻量目录,只含 URI、名称、描述等元数据,不携带实际内容;read_resource 拿到具体 URI 后才返回完整数据。Tools 同理:list_tools 返回工具清单和参数 Schema,call_tool 才真正执行。Prompts 则是 list_prompts 与 get_prompt。
为什么非要拆成两步?首先是效率:把全量数据直接塞给模型,上下文会爆炸,而清单通常只有几百字节。其次是自主性:Agent 可以在运行时动态发现能力,而不是把工具列表硬编码在系统提示词里。Server 新增一个工具,Agent 下次 list 就能看到,无需重新部署——这就是动态发现的价值。
这种机制还天然支持权限控制:list 阶段给 Agent 看“有哪些能力”,read/call 阶段校验“这次操作是否被允许”。主厨能看清单,不代表能取走保险柜里的东西。两段式的暴露,让安全策略有了清晰的挂载点。
- list(S) 清单发现返回服务 S 的轻量目录,只含元信息:
- read(r) 内容读取对清单中的某个条目 r 发起读取,得到具体内容:
- 对全部清单项求和对清单中每个条目逐一执行读取,得到所有内容的并集:
- discover 总发现清单与内容相并,便是 Agent 对服务的完整认知:
Agent组合策略
今晚的主厨要做一道黑椒牛排。他先去储藏间取出牛排(read),再用平底锅煎制(call),最后对照摆盘手册装盘(fill)。三步缺一不可,顺序也不能乱。做菜如此,Agent 处理任务也一样——读数据 → 执行动作 → 套模板是最高频的组合链路。
Agent 组合策略的第一步是按需选择:根据用户任务判断需要哪类原语。查天气只需要 call 一个工具;生成周报则先 read 工作数据,再套用周报模板。选择的原则是“能读不写、能模板不自由发挥、能分工不包办”。数据取用走 Resources,动作执行走 Tools,表达组织走 Prompts。
第二步是多步编排。一个复杂任务往往需要串起多个原语:先 list_resources 发现订单表 → read_resource 读取用户订单 → call_tool 调用 check_overdue 判断状态 → fill 套用催单模板生成话术。前一步的输出作为后一步的输入,这就是上下文的流转与注入。
第三步是优先级判断。Agent 应该优先尝试显式的原语而非让模型凭空推理。Resoning(模型自己思考)成本低但不可靠,原语调用有确定语义但成本高。靠谱的 Agent 会先问:“这个信息服务端有没有?”——有,就 read;没有,才考虑让模型发挥。
- read(R\*) 数据获取从 Resources 中选出需要的资源子集并读取数据:
- call(T\*) 动作执行基于已读数据,从 Tools 中选出合适的工具执行:
- fill(P\*) 模板套用把执行结果填入 Prompts 模板,生成结构化输出:
- 串联执行三个阶段按序编排,前一步输出即后一步输入:
设计避坑指南
厨房的混乱,往往源于“东西放错地方”:菜刀插在米缸里,菜谱被垫了锅底,冰箱里存着没点着的煤气灶。每样东西只要离开自己的位置,整个流程就卡壳。MCP Server 设计的第一原则,就是别让三类原语互相越界。
最常见的越界是把数据塞进 Tools。比如把“查询订单”做成一个工具,表面上能用,但数据被锁死在工具内部:另一个工具想复用这批数据就只能重复调用,无法直接 read。反过来,把动作做成 Resources 更危险——Agent read 一个资源后以为“事情办完了”,实际上没产生任何效果。判断标准很简单:被取用的进 Resources,被执行的进 Tools,被复用的进 Prompts。
第二个坑是过度暴露。把内部函数全部注册成 Tool,Agent 的选择空间变大,但选错的概率和安全隐患也同步上升。一个订单服务没必要暴露“直接改数据库字段”的工具,暴露 update_order_status(带权限校验)就够了。最小权限原则在 MCP 世界里同样成立:能不开的门就不开。
此外还有命名与安全。Resources 用名词 URI(db://orders),Tools 用动词(query_balance),风格统一才能让模型快速理解。而对敏感数据,read 要有权限校验,Tools 要有操作审计,Prompts 要防止模板注入——食材再新鲜,食品安全出了问题,整间厨房都得关门。
- 交集为空之义任意两类原语之间没有共享成员,即每个能力条目只属于一个类别:
- 逻辑与联结三个“两两不相交”的条件必须同时成立,缺一不可:
- 边界清晰判定当数据、动作、模板三者互不越界时,服务端职责即达到清晰状态:
AI 应用场景
智能客服工单 Agent
阶段:Agent 编排与工具调用
解决的问题:传统客服需要人工查库、翻话术手册,响应慢且口径不一。通过 MCP 连接客服 Server,Resources 暴露用户档案与订单库,Tools 提供改地址、退差价等真实操作,Prompts 内置标准话术模板,Agent 端到端完成“查—判—答—办”全流程。
具体案例:用户问“我的订单 1234 什么时候到?”Agent 先 list_resources 发现订单库,read_resource 读取该订单状态,再套用 Prompts 的物流话术模板生成回复;若用户要求修改收货地址,则 call_tool 调用 update_address 完成变更并确认。全程无需人工介入,且动作类操作全部有权限校验和审计记录。
企业数据分析 Agent
阶段:数据接入与查询编排
解决的问题:分析师取数要写 SQL、等排期、手工核对口径,效率极低。MCP 数据层把表结构元数据放入 Resources(表名、字段、业务含义),把“执行只读查询”“导出报表”封装成 Tools,把“图表生成规范”做成 Prompts,业务人员用自然语言即可自助取数。
具体案例:销售总监问“华南区本月销售额”。Agent read 表结构资源确认字段语义,call 查询工具执行聚合 SQL,再套用报表模板生成结论和图表。所有查询只读、走统一权限网关,杜绝了业务人员直连生产库的裸 SQL 风险。
AIOps 运维 Agent
阶段:可观测与自动化操作
解决的问题:故障处置依赖运维专家经验,半夜告警往往人手不足。MCP 把监控指标放入 Resources,把重启、扩容、回滚等操作封装成 Tools(带审批流),把“故障排查手册”做成 Prompts,让 Agent 按预案自动处置常见故障。
具体案例:午夜告警“订单服务内存飙升”。Agent 先 read 监控指标定位进程,套用排查模板生成诊断步骤,确认是内存泄漏后 call_tool 执行灰度重启,并自动向值班群推送处置记录。预案在手,动作可控——这正是负责任地使用自动化。
Python 演示
# -*- coding: utf-8 -*-"""mini_mcp.py - 模拟 MCP 数据层:Resources / Tools / Prompts 三类原语的登记与调用。""" import jsonimport re class MiniMCPServer: """迷你 MCP 服务端:像一间后厨,分门别类管理食材、厨具和菜谱。""" def __init__(self): self.resource_map = {} # uri -> {"desc": "...", "content": ...} self.tool_map = {} # name -> {"desc": "...", "schema": ..., "fn": ...} self.prompt_map = {} # name -> {"desc": "...", "template": "..."} # ---------- Resources:食材储藏间 ---------- def add_resource(self, uri, desc, content): self.resource_map[uri] = {"desc": desc, "content": content} def list_resources(self): return [{"uri": u, "desc": v["desc"]} for u, v in self.resource_map.items()] def read_resource(self, uri): if uri not in self.resource_map: raise ValueError("Resource not found: %s" % uri) return self.resource_map[uri]["content"] # ---------- Tools:工具墙 ---------- def add_tool(self, name, desc, schema, fn): self.tool_map[name] = {"desc": desc, "schema": schema, "fn": fn} def list_tools(self): return [{"name": n, "desc": v["desc"]} for n, v in self.tool_map.items()] def call_tool(self, name, **args): if name not in self.tool_map: raise ValueError("Tool not found: %s" % name) tool = self.tool_map[name] for field, spec in tool["schema"].items(): if spec.get("required") and args.get(field) is None: raise ValueError("missing arg: %s" % field) return tool["fn"](**args) # ---------- Prompts:菜谱盒 ---------- def add_prompt(self, name, desc, template): self.prompt_map[name] = {"desc": desc, "template": template} def list_prompts(self): return [{"name": n, "desc": v["desc"]} for n, v in self.prompt_map.items()] def read_prompt(self, name, **kwargs): if name not in self.prompt_map: raise ValueError("Prompt not found: %s" % name) tpl = self.prompt_map[name]["template"] return re.sub(r"\{(\w+)\}", lambda m: str(kwargs.get(m.group(1), m.group(0))), tpl) def main(): server = MiniMCPServer() # 1. 登记 Resources:把数据放进储藏间 server.add_resource("db://orders", "最新订单表", [{"id": 1, "amount": 99.5}]) server.add_resource("db://users", "用户档案库", [{"id": 1, "name": "Alice"}]) # 2. 登记 Tools:把操作挂上工具墙 server.add_tool("query_balance", "查询账户余额", {"user_id": {"required": True}}, lambda user_id: {"user_id": user_id, "balance": 88.0}) server.add_tool("send_notice", "发送通知", {"target": {"required": True}, "content": {"required": True}}, lambda target, content: "sent -> %s: %s" % (target, content)) # 3. 登记 Prompts:把常用套路收进菜谱盒 server.add_prompt("weekly_report", "周报模板", "本周完成:{task};遇到的问题:{problem}") server.add_prompt("customer_service", "客服话术模板", "亲,您的问题我们已经收到:{question}") # 4. Agent 先"翻清单"再动手 print("== 发现阶段 ==") print(json.dumps(server.list_resources(), ensure_ascii=False)) print(json.dumps(server.list_tools(), ensure_ascii=False)) print(json.dumps(server.list_prompts(), ensure_ascii=False)) # 5. Agent 组合使用:读数据 + 调工具 + 套模板 print("== 组合阶段 ==") orders = server.read_resource("db://orders") balance = server.call_tool("query_balance", user_id=1) reply = server.read_prompt("customer_service", question="我的余额是多少?") print(orders) print(balance) print(reply) if __name__ == "__main__": main()
self.resource_map = {}用字典模拟储藏间,键是 URI 储位号,值是数据内容。def list_resources(self)翻清单操作,只返回 uri 和描述,不返回具体数据。def read_resource(self, uri)按储位号取货,URI 不存在时抛错,对应快速失败原则。def add_tool(self, name, desc, schema, fn)挂上工具墙:名字、说明、参数契约、执行函数四件套。for field, spec in tool["schema"].items()调用前按 Schema 校验必填参数,对应 JSON Schema 契约思想。def read_prompt(self, name, **kwargs)读取模板并用re.sub把{question}这类占位符替换成实际值。print(json.dumps(server.list_resources(), ...))Agent 的“发现阶段”输出,先看清单再动手。
常见误区
误区很多初学者觉得 Tools 最“万能”,把数据、动作、模板一股脑全注册成工具,例如把“查订单”和“订单数据”都做成 Tool,认为这样 Agent 什么都能干。
正解Tools 应该只承载可执行的动作。数据放进 Tools 会失去复用性——别的工具想读取同一份数据时,只能重复调用,无法直接 read。正确的划分是:数据进 Resources、动作进 Tools、套路进 Prompts。就像把食材全塞进烤箱,主厨想生吃沙拉时就没东西可用了。
为何常见:因为 Tools 在概念上最贴近“函数调用”,而函数在传统编程里什么都能干,容易让人忽略 MCP 对三类原语的职责切分。
误区看到"Prompts"这个词,就以为是用户输入框里的提示语,或者是写进系统提示词的 system prompt,觉得把它暴露给用户就行。
正解MCP 里的 Prompts 是服务端预置的任务模板,服务对象是 Agent 而非最终用户。它是“菜谱”而不是“菜单”:主厨(Agent)取走菜谱卡,填入参数,照着套路执行;食客(用户)只看到最后端上来的菜。模板的价值在于沉淀最佳实践,让 Agent 的高频任务不走样。
为何常见:"Prompt"一词在大模型领域太常用了,提示工程的概念先入为主,让人忽略了 MCP 场景下它是服务端复用的结构化资源。
误区有人觉得工具参数用自然语言描述清楚就够了,写 JSON Schema 是多余的负担,“反正 LLM 很聪明,能理解我的话”。
正解JSON Schema 是机器可校验的结构化契约。没有它,参数校验就只能靠运气,类型错误在运行时才暴露,而且每个客户端(不同模型、不同版本)猜的结果都不一样。就像食材标签缺保质期,主厨只能靠鼻子闻——闻错了就要出食品安全事故。Schema 让“能传什么、必须传什么”成为确定性的规则。
为何常见:LLM 对话接口的成功让很多人觉得“描述清楚就行”,忽视了生产系统对确定性校验的刚需。
误区倾向于把内部函数全部注册成 Tool,觉得能力越全,Agent 发挥空间越大,多暴露几个“备用工具”总没坏处。
正解过度暴露会带来三重风险:安全面扩大(内部操作可能被误调用)、选择混乱(工具太多导致模型选错)、上下文膨胀(工具清单占满上下文窗口)。正确做法是最小权限暴露,只开放业务允许的操作,并配上描述和权限校验。后厨的灭火器不会开放给顾客把玩,工具墙只挂今天用得上的厨具。
为何常见:功能枚举的思维惯性——把“提供更多选项”等同于“更强的能力”,而没有考虑 Agent 在大量工具中选错的概率会随数量上升。
面试题
Q1. MCP 数据层中,对应“厨房储藏间里食材”的原语是哪一类?
- A.Tools,负责可执行的操作
- B.Prompts,负责生成提示模板
- C.Resources,负责供应只读数据← 正确答案
- D.JSON Schema,负责约束参数格式
答案:C。Resources 就是数据源,像储藏间只存放食材一样,它只承载可被读取的数据、不产生任何动作。Tools 是厨具负责执行,Prompts 是菜谱负责模板,JSON Schema 只是描述规格的工具,并非原语本身。
Q2. Agent 想知道 MCP Server“有哪些数据可以读”,应该调用哪个操作?
- A.read_resource 读取具体数据
- B.list_resources 查看资源清单← 正确答案
- C.call_tool 执行某个业务工具
- D.read_prompt 读取提示模板
答案:B。list 系列操作返回的是轻量“目录”,只含 URI 和描述,不含实际内容——就像主厨先翻储藏清单,而不是把每份食材都拆开。A 是拿到清单后才做的事,C 属于 Tools 的执行操作,D 属于 Prompts 的模板操作。
Q3. Tools 工具的输入参数约束,通常用什么格式来描述?
- A.JSON Schema 结构化定义← 正确答案
- B.Markdown 文档描述段落
- C.自然语言自由文本描述
- D.私有二进制协议格式
答案:A。JSON Schema 是机器可读、可校验的结构化契约,定义字段类型、必填项、取值范围等。就像厨具标签写明功率和适用锅具,程序才能自动校验;而自然语言描述无法被程序确定性验证,容易在运行时出错。
Q4. Prompts 与 Tools 最根本的区别是什么?
- A.Prompts 有副作用而 Tools 没有
- B.Tools 执行动作而 Prompts 是模板← 正确答案
- C.Prompts 面向用户而 Tools 面向开发
- D.Tools 必须联网而 Prompts 离线可用
答案:B。Tools 被调用会产生真实动作(查余额、发通知、改状态),Prompts 只是文本模板,填入参数生成消息,本身不产生任何副作用。就像菜谱卡只是套路说明,下锅开火才是厨具(Tools)的事。副作用的有无,正是区分二者的关键。
Q5. 调用 read_resource("db://orders/1") 返回的是什么?
- A.资源的完整 JSON Schema 结构
- B.该 URI 对应的具体数据内容← 正确答案
- C.Server 上全部资源的清单列表
- D.该资源关联的可执行函数体
答案:B。read 操作按 URI 取出具体内容,对应“去储藏间把标好储位号的食材取出来”。A 是 Schema 定义的范畴,C 是 list 操作的返回值,D 属于 Tools 的信息。记住口诀:list 看目录,read 取内容。
Q6. 设计“查询用户余额”功能时,最合理的拆分方式是?
- A.全部封装进一个大而全的 Tool
- B.全部静态存进 Resources 数据里
- C.余额数据进 Resources,查询动作用 Tool← 正确答案
- D.用 Prompts 模板写死余额数值
答案:C。数据与动作分离是 MCP 的基本准则。余额数据由 Resources 提供,可被多个工具复用;“查询”这个动作用 Tool 封装以响应实时变化。全部塞进 Tool 会让数据失去复用性,静态存进 Resources 无法反映余额变化,写死在模板里更是荒谬。
Q7. 下列哪些属于 MCP 数据层的三大原语?
- A.Resources 数据源抽象← 正确答案
- B.Tools 可执行操作抽象← 正确答案
- C.Prompts 提示模板抽象← 正确答案
- D.Plugins 插件市场抽象
答案:ABC。MCP 协议只定义三类原语:Resources(读数据)、Tools(执行动作)、Prompts(套模板)。Plugins 是生态层面的扩展概念,不属于协议层原语。类比后厨:储藏间、工具墙、菜谱盒是三个固定区域,市场则是厨房之外的商业设施。
Q8. 以下哪些场景适合设计成 Resources?
- A.用户档案数据库内容← 正确答案
- B.发送邮件的通知动作
- C.商品文档与手册内容← 正确答案
- D.历史销售报表数据内容← 正确答案
答案:ACD。Resources 放“可以被读取的数据”:用户档案、文档、报表都是只读数据。B 是会产生副作用的动作,应封装成 Tools。判断标准一句话:主厨是“取用”还是“操作”?取用进储藏间,操作上工具墙。
Q9. 以下哪些做法有助于避免 MCP 的职责混乱?
- A.数据统一放进 Resources← 正确答案
- B.动作操作封装成 Tools← 正确答案
- C.通用套路做成 Prompts← 正确答案
- D.所有能力一律做成 Tools
答案:ABC。三类原语各司其职、两两交集为空,是避免混乱的唯一正解。数据归 Resources、动作归 Tools、套路归 Prompts。D 是典型反模式——把数据塞进工具会让数据失去复用性,也模糊了“读”与“做”的界限,就像把食材全塞进烤箱。
Q10. Agent 完成“读取订单→判断逾期→自动催单”全流程,最合理的组合是?
- A.只调用一个大而全的 Tool 完成所有步骤
- B.先 read 订单数据,再 call 催单工具← 正确答案
- C.只 read 订单数据,不做任何后续动作
- D.只套用 Prompts 模板,不读取真实数据
答案:B。按需组合是 Agent 的核心能力:先用 read_resource 取订单数据(取食材),判断逾期后调用 call_tool 发催单通知(开火),必要时再套模板组织话术。大而全 Tool 破坏职责边界,只读不做或只套模板都完不成业务闭环。