我做了几年LLM应用落地,最深的感触不是模型不够聪明,而是上下文接入的过程实在太碎。业务数据散落在数据库、文件、网页和内部API里,每种来源都有自己的鉴权方式和数据格式,每接一个数据源都要重写一遍胶水代码。后来MCP(Model Context Protocol,模型上下文协议)出现,我意识到这才是把上下文接入标准化的方向。这篇文章不打算照抄官方文档,我结合自己落地项目时的真实场景,把MCP解决什么问题、架构怎么运作、一个能用的MCP服务怎么搭起来、以及实际会踩的坑都讲一遍。不管你是正在做LLM应用、Agent、知识库问答,还是想把本地工具接入大模型,这篇应该都能帮你少走不少弯路。
1. MCP到底是什么:把“上下文接入”这件事标准化
1.1 为什么我会对这个协议这么上心
模型本身不会直接读数据库,不会直接操作浏览器,也不知道当前用户在哪个项目里。它看到的只有token组成的文本。所以“上下文”这个东西,本质上是要靠外部系统准备好再喂进去的。问题在于,这个“准备过程”过去毫无标准。
最开始的做法是“全塞进去”:PDF转文本、数据库导出成CSV、网页爬下来存成Markdown,一股脑拼进提示词。窗口小的时候塞不了多少,窗口大了以后(现在不少产品已经宣称1M上下文全量可用)反而出现新问题——模型在几千页的杂讯里翻找关键信息,推理质量和速度一起下降。再进阶一点,有人开始用Function Calling让模型自己决定调用哪些函数,但每个函数都要用JSON Schema描述、手动处理参数校验和鉴权,每换一个客户端或者换一种调用方式,这套东西就得跟着改。
MCP正好把这两件事统一了。它规定了模型应用这一端(Host)和外部工具、数据源那一端(Server)之间怎么发现能力、怎么传递消息、怎么执行工具、怎么返回结果。模型侧不需要关心数据源内部是什么数据库、哪家云服务、什么API协议,数据源也不需要关心模型是哪家的。两边只要都遵守同一个“上下文接入协议”,就能直接对话。就像给打印机装驱动,系统装好驱动,应用只管打印就行,不用自己去实现每个型号的指令集。
1.2 MCP的定位:不是模型,不是框架,而是上下文接入层
MCP是Anthropic在2024年底开源并推动的一套开放标准,现在已经有大量客户端、IDE、数据库、设计软件、安全工具在接入。它不负责推理,也不负责存储,它只负责“上下文接入”这一段。
我习惯用一个比喻:MCP像是USB-C接口。USB-C本身不是什么了不起的“功能”,但它规定了一套通用的物理接口和传输约定,让显示器、硬盘、手机充电器、扩展坞都能通过同一根线对接。MCP就是大模型世界里的USB-C——模型、Agent、IDE不需要为每个工具单独定制对接方案,工具方也不需要为每个模型各写一套SDK,两端对接MCP就够了。
有一段时间大家容易把MCP和“LLM框架”(比如LangChain、LlamaIndex、Swarm这类)搞混。我的理解是,框架解决的是上层编排问题,比如Agent怎么规划步骤、怎么在子Agent之间传递上下文变量、怎么Handoff;MCP解决的是下层接入问题,比如Agent想调用外部工具,工具怎么被发现、怎么被调用、结果怎么返回。框架可以内置MCP客户端,但MCP本身不包含编排逻辑。哪怕是本地用ONNX部署的轻量模型,只要能跑Function Calling、能兼容MCP客户端,同样可以接入MCP工具。这个认知想清楚,看后面的架构就不会乱。
1.3 一个生活化的类比:模型点餐,MCP Server在后厨
拿点外卖做类比。模型是食客,它不会做饭也不知道后厨在哪;MCP Client相当于送餐平台;MCP Server就是一家家餐厅,每家公开一份标准化菜单(能力列表)。
食客想吃什么,通过平台看菜单下单(模型通过Client发现Server提供的工具和资源);平台把订单转给合适的餐厅(Client把模型请求转发给Server);餐厅按订单做菜,做完由平台送回给食客(Server执行工具、查询资源,把结果注入模型上下文)。这个类比里最关键的一点是,食客不需要知道餐品是哪个厨房用什么灶做的,菜单格式是统一的,所以换一家餐厅只需要重新看菜单就行。这就是“标准化上下文接入”的含义——菜单写得好不好,直接决定食客点餐准不准。
2. MCP核心架构拆解:Host、Client与Server三角色
2.1 三个角色的职责边界
MCP规范把参与者分成三层:
| 角色 | 职责 | 典型实现 |
|---|---|---|
| Host | 上层应用或用户界面,负责统一调度模型 | Claude Desktop、Claude Code、IDE、自研Agent平台 |
| Client | 运行在Host内部的协议客户端,负责连接和消息收发 | Host内部的MCP客户端实例 |
| Server | 暴露能力的一方,把本地资源、脚本、API封装成标准原语 | 本地脚本、远程HTTP服务、数据库适配器 |
Host和Client的区别常让人困惑。我自己理解:Host是“主人”,负责决定模型做什么、什么时候调用工具;Client是“翻译”,负责把Host的需求翻译成MCP协议消息发给Server,再把Server的响应翻译回模型能用的文本。一个Host可以同时持有多个Client实例,分别连接到不同的Server上,也可以让模型在一个会话里混合调用多个Server的能力。
举个实际例子。我用Claude Code做代码审查时,挂了一个GitHub MCP Server拉取Issue,挂了一个本地文件系统MCP Server读取项目代码,还挂过一个数据库MCP Server查表结构。Claude Code作为Host统一调度,为每个Server启动一个Client进程,模型在对话里按需选择调用哪个工具。这种多Server共存的模式,就是Host和Client分层带来的好处。
2.2 一次完整调用的生命周期
一次MCP调用的完整流程,我拆成6步,每步都有对应的协议消息:
- 建立连接:Client和Server通过stdio(本地子进程)或Streamable HTTP/WebSocket(远程)建立双向通道。本地开发最常用stdio,远程服务常见wss://地址,连接时一般会携带身份令牌,这个token别写进公开配置模板。
- 初始化握手:Client发送initialize请求,两端协商协议版本号,服务端返回自身的能力列表(supported capabilities)。
- 能力发现:Client发送tools/list或resources/list,拿到Server暴露的能力清单。这一步很关键,因为模型实际看到的不是原始工具代码,而是清单说明和参数Schema。
- 模型决策:Host把能力清单连同对话内容交给LLM,LLM根据用户问题、上下文和工具描述,决定要不要调用某个工具,并生成参数。
- 工具执行:Client把模型生成的参数封装成tools/call请求发给Server,Server执行对应函数,把结果返回。
- 结果注入上下文:Client把返回结果追加到对话上下文,让模型继续推理。
这6步里最容易出问题的往往在3和5:能力清单描述写得不清晰,模型就不知道这个工具适用什么场景;参数Schema写得不严谨,模型生成的参数会被Server拒绝,出现类似“provider rejected the request schema or tool payload”的报错。这一块我后面第六节还会细讲。
2.3 协议层设计:为什么选JSON-RPC而不是REST
有些朋友第一反应是“现在不都流行REST API吗,怎么选了个老协议”。我实测下来,JSON-RPC在MCP这个场景里确实比REST合适。
REST是请求-响应模型,一问一答,天然适合同步查询;但MCP里有通知(Notifications)、有服务端主动推送(比如Server通知Client某个资源更新了)、有长时间运行的流式过程。这些用REST很难干净表达。JSON-RPC 2.0支持请求、响应、通知三种消息形态,配合长连接和ID配对,正好满足双向通道上的方法调用。
另一个原因是,MCP的消息本质是方法调用:有方法名(method)、参数(params)、结果(result)、错误(error)四个标准字段,语义非常贴近RPC。用JSON做载体是因为可读性好、生态好、调试方便。抓包看一条tools/call消息,里面就是标准的JSON-RPC结构,一眼能看懂。如果用REST,你还得定义一堆资源路径和HTTP状态码的映射,反而更繁琐。
关于传输方式,我补充一点:stdio适合本地启动子进程的场景,比如Claude Desktop拉起一个Python脚本;远程场景用Streamable HTTP或WebSocket,支持长连接和SSE流式推送。选择远程传输时,要额外处理鉴权、超时、重连和会话恢复,生产环境比本地stdio复杂不少。
3. 核心细节解析:三大原语与上下文工程的关系
3.1 资源(Resources)与提示(Prompts)
MCP定义了三种能力原语。资源(Resources)是“可以被读的数据”,类似文件或数据库记录,用URI标识,带MIME类型,可以是text/plain、application/json、image/png。模型或用户可以通过资源URI直接读取内容。我在一个Server里暴露过配置文件、知识库文档、数据库Schema、实时指标。协议本身允许资源携带图片等媒体类型,所以视觉模型也可以从资源里直接读图,这就是有些人说的“视觉内容上下文模型”在MCP这一层的落点。
提示(Prompts)是“可复用的用户指令模板”,类似带参数的提示词模板。可以定义成“代码审查提示词模板”,参数是仓库路径和PR编号;也可以定义成“周报生成模板”,参数是本周事项。客户端把这些模板展示给用户选择,用户选中后模板被填充,并作为上下文的一部分注入模型。
资源和提示的区别,我的理解是:资源回答“模型能查到什么”,提示回答“模型应该按什么套路做事”。资源是静态可查阅的信息,提示是动态可复用的指令。
3.2 工具(Tools)与函数调用的统一
工具(Tools)是MCP里最常用的原语,它对应一个可执行函数。模型看完工具名称和参数Schema后,决定调用;Server执行后返回结果。
需要区分的是,MCP的工具调用和各家LLM的Function Calling是两种层级的概念:Function Calling解决“怎么让模型输出结构化的调用意图”,MCP解决“怎么在模型与外部系统之间标准化地发现和执行这些调用”。可以理解为,LLM原生Function Calling是抽象接口,MCP是这个接口之外的一套具体协议标准,也是目前生态铺得最广的一套。
这一层往往还和“工具描述优化”绑定在一起。同一份工具,description写得宽泛,模型就容易误用;写得精确,模型召回的准确率明显提升。我的习惯是把每个工具的description写成“功能一句话 + 适用场景 + 示例问法”,比如“查询库存:当用户询问某商品是否有货、库存量时调用,示例:‘iphone 15还有货吗’”。这样LLM做意图匹配时准确率高很多,别小看这几行字,实测下来差别很大。
3.3 采样(Sampling)与上下文工程的扩展
MCP还有一个容易被忽略的原语是采样(Sampling),它允许Server反过来请求Host调用LLM补全内容。什么意思?就是工具执行过程中,Server可以调用模型:“帮我把这段文本总结一下”“从这份PDF里抽取出关键字段”。这相当于让模型在工具链里当“子模型”使用,做文本抽取、实体识别、摘要等预处理,再把结果返回给主模型。
有了采样,MCP就不只是外部数据单向输送,还具备一定双向智能协作能力。我在做一个知识库服务时,让MCP Server先读取原始法律文档,再用采样能力让模型抽取条款,最后把结构化条款返回给主模型回答用户问题。主模型上下文里只保留了小段抽取结果,而不是整篇法律原文,效果和成本都优化了。
这正好引出上下文工程的核心观点:不是所有数据都应该进上下文。MCP的价值在于让模型按需获取,而不是全量加载。模型的处理能力是有限的,上下文窗口再大,也经不住把无关信息都塞进去。
4. 实操上手:30分钟搭一个可用的MCP Server
4.1 环境准备与SDK选型
我建议新手用Python或Node.js起步。Python端官方SDK(mcp包)带一个FastMCP封装,用装饰器定义工具、资源和提示词,非常简洁;Node/TypeScript端适合和前端工程无缝对接。下面代码用Python演示。
环境准备:
- Python 3.10+
- 安装mcp库:pip install mcp
- 可选:安装mcp[cli],这样会带上mcp inspector调试工具
我一开始照着2024年底的老教程写,那个版本的Server需要手动new Server,然后注册一堆handler,比较绕。新版SDK里FastMCP把这一层封装掉了,直接pip install mcp就能用装饰器注册能力。如果你搜到的教程还在用旧写法,注意看一下版本,别照着过时代码抄。
4.2 最小Server实现:暴露一个数据库查询工具
下面这个例子,写了一个“库存查询Server”,它暴露一个工具,供LLM查询SQLite库中的商品库存:
from mcp.server.fastmcp import FastMCP import sqlite3 mcp = FastMCP("InventoryServer") @mcp.tool() def query_stock(product_id: str) -> str: """查询指定商品的最新库存。当用户询问商品是否有货、库存量时调用。 示例: 'iphone 15还有货吗' -> product_id='iphone-15' """ conn = sqlite3.connect("warehouse.db") cur = conn.cursor() cur.execute("SELECT stock FROM inventory WHERE id = ?", (product_id,)) row = cur.fetchone() conn.close() if row is None: return "未找到该商品" return f"当前库存: {row[0]} 件" @mcp.resource("sqlite://warehouse/schema") def get_schema() -> str: """返回数据库表结构信息。""" return "inventory(id TEXT, stock INTEGER, updated_at TEXT)" if __name__ == "__main__": mcp.run(transport="stdio")有几个关键点:
- 工具名称用蛇形命名,语义要清晰。query_stock比get_data好,模型能根据名称猜出用途。
- docstring就是工具描述,LLM会把它当作工具说明的一部分,所以要写清楚“什么场景用 + 示例输入”。示例问法不是装饰,实测能明显提升模型选择工具的准确率。
- 返回给模型的内容要精简。我这里返回“当前库存: X 件”,而不是把整个SQL执行结果或连接信息都扔回去。上下文里放太多无关日志,模型反而被干扰。
- transport="stdio"适合被Claude Desktop这类Host拉起子进程的场景;如果做成远程服务,改成mcp.run(transport="http"),并额外配好鉴权。
4.3 接入Claude Desktop或IDE
如果想在Claude Desktop里使用这个Server,去配置文件里添加:
{ "mcpServers": { "inventory": { "command": "python", "args": ["/path/to/inventory_server.py"] } } }macOS路径在 ~/Library/Application Support/Claude/claude_desktop_config.json,Windows在 %APPDATA%\Claude\claude_desktop_config.json。配置完成后重启Claude Desktop,对话里直接问“查一下iphone 15还有货吗”,模型就会自动调用query_stock。
同理,很多IDE(比如Trae、VS Code)都支持MCP Server列表配置。在IDE里配MCP,好处是模型能直接感知打开的工程文件、调试信息、构建日志,上下文贴合度一下子高很多。我见过有人把Burp Suite通过MCP接进IDE,让AI直接操作HTTP请求包做安全测试,确实能省不少重复劳动。
4.4 用MCP Inspector调试
官方提供了mcp inspector工具,格式是 npx @modelcontextprotocol/inspector。启动后它会打开一个网页,列出当前Server暴露的资源、工具、提示词,还能手动发起调用。
我踩过的坑是:工具能列出来,不代表参数能被正确解析。有时候docstring里写了参数说明,但MCP的工具Schema只认Python类型注解,docstring里的描述不一定自动进Schema。要让工具描述更丰富,可以直接给装饰器传description参数:
@mcp.tool(description="查询商品库存,当用户询问商品是否有货、库存量时调用。") def query_stock(product_id: str) -> str: ...如果Description和docstring都写了,以装饰器参数为准,这个细节文档里一般不会主动提醒。
5. 生态与应用场景:MCP真实落地用法盘点
5.1 开发与测试工具链
MCP在开发运维领域已经相当热闹。
- Playwright MCP:把浏览器自动化能力封装成MCP服务,模型可以直接打开网页、截图、点击元素、读取控制台日志。我做端到端回归测试时,让它跑一个完整用例流程,再把结果带回对话里,省去交叉拷贝的麻烦。
- Chrome DevTools MCP:让LLM直接读取页面调试信息、网络请求、控制台报错。调试前端问题时,模型能拿到真实运行现场,而不是瞎猜。
- Burp Suite MCP、Yakit MCP:安全测试工具接入MCP后,AI可以驱动抓包、重放请求、分析报文。提醒一句:这类工具接入后要格外注意授权范围,只在授权的测试环境里使用。
- WorkBuddy MCP Skill:把工作流技能封装成MCP Skill,让Agent按预设流程执行。
这些应用的共同点:把原来“只能人操作”的工具变成“模型可调用的服务”。人和模型在同一个工作台里协作,效率提升非常明显。还有一些Agent框架,例如Swarm,里面负责handoff、上下文变量的编排,也可以通过MCP把外部工具接进来,编排归编排、接入归接入,各管一层。
5.2 设计、创作与芯片设计
工程软件接入MCP的势头也很猛。
- Blender MCP:模型可以直接生成Python脚本操作Blender建模、渲染,3D艺术家可以把自己的创作流程教给LLM。
- Unity MCP:游戏开发中模型可以读取场景结构、修改对象属性、调用编辑器API。
- Vivado的MCP(FPGA开发工具):把硬件工程的项目状态、约束文件、综合报告暴露给模型,辅助分析时序问题。
我的观察是,这类专业工具接入MCP后,最大的价值不是“让AI替代工程师”,而是“让AI理解工程现场”。原来模型答得很泛,是因为它看不到现场;接入之后,它能读取真实报错、真实项目结构、真实配置,给的建议自然贴地气很多。
5.3 知识库与RAG:LLM Wiki、GraphRAG与本体RAG
知识库问答是MCP最常见的场景之一。很多人做企业知识库时的冲动,是把所有文档都塞给模型。但窗口再大也有限度,而且直接塞进去的检索精确度很差。更合理的架构是RAG + 检索工具:文档进入向量库或图数据库,MCP Server暴露检索工具,模型在需要时发起检索,拿到结果再回答。
在这个架构里,LLM Wiki这类项目开始出现,它把知识库建设成带结构的资料库,配合本体(Ontology)描述概念之间的关系。GraphRAG、本体RAG也在这个方向演进:用知识图谱方式组织信息,检索时按图结构关联扩散,比平面向量检索的信息更连贯。你可以把GraphRAG的查询接口封装成MCP工具,暴露“邻居扩散检索”“社区摘要检索”等能力,模型按需调用。
还有一个容易被忽略的联动点:上下文学习示例选择策略。给模型挑选什么示例放上下文,效果差异很大。与其随机塞几个样本,不如让MCP暴露一个“示例检索”工具,根据当前问题的语义相似度,动态选取最相关的示例注入上下文。这比固定模板好用很多,尤其在少样本场景下。
5.4 行业领域:金融、制造、办公
行业软件也陆续开放MCP接口。同花顺这类金融终端已经提供MCP服务,模型可以获取行情、财务指标等数据;制造业的NXOpen MCP可以把PLM/CAD系统的模型树、BOM、工程变更数据暴露给LLM;办公软件领域,大量MCP Server把邮件、日历、表格、IM消息接进来,让模型辅助处理日常事务。
说一点企业架构层面的观察:很多中大型公司会部署LLM网关,统一管理模型路由、限流、审计和权限控制。MCP Server作为工具接入时,通常会挂在网关后面,由网关负责鉴权和数据出域审核。这是我在真实项目里觉得最稳妥的做法,先管住权限,再谈效率。MCP解决了接入标准化,网关解决接入的安全管理,两者配合起来才完整。
6. 常见问题与排查技巧实录
6.1 “provider rejected the request schema or tool payload”怎么查
这类报错我遇到不止一次,常见原因有三个:
- 工具参数Schema与LLM生成的内容不一致。比如Python函数把参数定义为str,但模型生成了数字类型,Server端严格解析就崩了。对策:尽量用明确的类型注解,必要时自己加参数校验。
- 工具返回类型和响应要求的格式不匹配。MCP工具返回结果应该是字符串或结构化JSON,如果返回了None或者自定义对象,序列化时就会报错。
- 客户端缓存了旧的工具列表。Server端改了工具定义,但Host缓存没刷新,仍在按旧Schema调用。对策:重启Host进程,或重新拉取tools/list。
排查时先用MCP Inspector直接调用这个工具。如果Inspector里能正常执行,说明Server没问题,问题出在客户端模型生成参数的环节,那就看客户端日志里模型实际发出来的工具调用参数长什么样,比对Schema差异。
6.2 上下文溢出与1M上下文:不是越大越好
“1M上下文全量可用”是很多产品的卖点,窗口大了确实能容纳更多信息。但真正把100万token全塞进去,推理时间和成本会成倍增长,而且长文本里容易被无关信息干扰,关键信息反而被淹没。我见过有人把10万行的CSV直接塞给模型,结果模型在里面翻找某几行数据,又慢又容易算错。还有些产品没开这个功能时,会提示“请启用1M上下文后重试”,这只是去配置里开启窗口的功能开关,但开了以后也请克制。
正确做法是分层:高频关键信息进上下文;中低频信息走检索、走工具按需获取;明确无关的信息压根不进。MCP正是在这一层帮了大忙——模型需要什么,就从Server请求什么,把MCP查询工具当作“懒加载”式的上下文入口,比一股脑全塞进去靠谱得多。
如果确实需要一次性处理长文档,建议预处理:先让模型或工具抽取出章节、摘要、关键实体,只把结构化结果放上下文,再逐层深入查询细节。
6.3 客户端连接失败与远程鉴权
本地stdio模式最常见的失败原因是Python环境不一致。Claude Desktop通过配置文件里的command拉起脚本时,PATH环境可能和终端不一样,导致python命令找不到,或者sys.path不对。对策是用绝对路径,或者直接用虚拟环境里解释器的完整路径,别依赖系统PATH。
远程MCP Server要格外注意三件事。一是鉴权,很多服务用wss://地址,并让请求头或Query里携带token,配置时不要把token写进公开的配置模板,否则等于把访问凭证散出去了。二是超时设置,工具执行时间长的话,要给客户端配置合理超时,不然一个大查询跑到一半就被判定失败。三是重连和会话恢复机制,连接断开之后要能按会话ID恢复,否则用户对话到一半,工具状态就丢了。
6.4 切换账号之后对话上下文丢失
有些用户会通过第三方工具来管理多个账号,切换之后发现“之前对话的上下文不能加载了”。原理很简单:对话上下文与会话状态是和服务端账号绑定的,换账号等于开启全新会话;第三方工具切换时不会把历史一并带过去,所以对话加载不出来,这不是工具坏了,是机制本来就如此。
我的建议是,不要指望这种切换能自动延续历史。重要会话要么在切换前导出,把对话内容完整复制保存;要么把关键信息沉淀成独立的知识库或文档,之后作为新上下文喂给模型。更工程化的做法是用MCP把你的历史对话、项目档案做成一个可检索的Server,新会话里随时按需查询,这算是我目前觉得最正规的“上下文迁移”思路。
6.5 stdio模式下不要乱print
这是一个非常实战的坑。stdio模式下,Server的stdout就是协议通道,所有MCP消息都走这里。如果你在Server代码里写了print("hello"),这条消息会污染协议通道,导致客户端解析失败,表现形式就是连接正常但调用工具时莫名报错。要打日志,写到stderr或日志文件,千万别print到stdout。我一开始不知道这个,为了调试在代码里加了几个print,查了半天才发现是它。
| 报错/现象 | 常见原因 | 排查方法 |
|---|---|---|
| provider rejected the request schema or tool payload | 参数Schema不符、返回类型不正确、客户端缓存旧工具列表 | Inspector直连测试、查看模型实际传入参数 |
| 连接失败 | Python环境不一致、PATH不对、鉴权失败 | 配置绝对路径、校验token |
| 调用工具莫名报错 | stdio模式stdout被print污染 | 检查Server代码是否有print,日志写stderr |
| 对话上下文丢失 | 换账号、会话未持久化 | 导出会话、用MCP做历史检索 |
7. 最后这层:上下文工程才是MCP的上限
7.1 从提示词工程到上下文工程
过去大家聊的是提示词工程,怎么设计指令让模型输出更好。现在越来越多的人意识到,真正决定模型效果的,是它“看到了什么”,也就是上下文工程。提示词只是上下文的一部分,外部数据、工具结果、示例样本、对话历史,共同构成上下文。
公开榜单(比如open llm leaderboard这类)主要比较模型在基准测试集上的得分,但几乎不评价一个模型在真实项目里接入工具、组织上下文的能力。而实际落地时,决定成败的往往就是这一层。MCP只是上下文工程的基础设施,它解决“怎么拿到数据”的问题,但拿到之后如何组织、如何取舍,仍然影响最终体验。所以工具接得再多,内容组织烂,效果一样不行。
7.2 Token的三个点:我是谁、我在找什么、我能提供什么
关于上下文设计,我常用的一个框架是“Token的三个点”:Key——我是谁,决定回答角度;Query——我在找什么,决定要检索和处理的内容;Value——我能提供什么,决定覆盖范围和边界。拼进模型上下文的任何内容,先问自己这几句:它该让模型扮演什么角色?它要让模型产出什么?它给模型提供了哪些事实、工具和边界?
这个思路也适用于MCP工具描述。我写工具description的时候,会刻意把三个点都照顾到:说明工具能提供什么类型的数据(Value),它对什么用户意图生效(Query),以及调用这个工具后模型应该以什么视角使用结果(Key)。比写一句“能查询数据库”要管用太多了。
7.3 上下文窗口越大,越考验管理能力
最后说点个人体会。大窗口不是免死金牌,窗口越大,越考验内容取舍能力。复杂任务可以拆解成多个子任务,每个子任务携带独立的上下文片段,通过MCP按需取用,而不是用一个巨型上下文贯穿始终。这个思路和上下文数据流图的分解是相通的——把数据流拆细,让信息在正确的时间点出现在正确的位置。
MCP把接入标准统一了,但真正拉开差距的,还是接进来之后怎么组织这些内容。我接过越多MCP Server,越觉得上下文工程和MCP是相辅相成的:协议负责通道,内容工程负责血肉。两者都做好,LLM应用才能真正落地。如果你刚开始尝试MCP,我的建议是从一个小工具Server开始,把工具描述写细、把返回结果写精准,然后观察模型在真实对话里的调用表现,逐步调整。这个过程比看任何教程都管用。