1. 先搞清楚:MCP 到底解决了什么问题
2024 年底到 2025 年,AI 圈子里几乎每个搞大模型应用的人都在聊 MCP。你要是只刷标题,可能会觉得这是又一个新出的模型或者什么神秘的算法框架。但实际上,MCP 的全称是 Model Context Protocol,翻译过来叫“模型上下文协议”,它不是一个具体的模型,而是一套给 AI 接外部世界的通用接口规范。
说人话就是:以前你想让 AI 帮你查天气、查数据库、操作 Figma、读文件、干活,你得给每个 AI 应用单独写一套对接代码。A 应用一套,B 应用一套,C 应用再来一套,而且这些代码几乎没法复用。今天你用 LangChain 写了一个查数据库的工具,明天换到另一个框架,基本等于推倒重来。MCP 想干的事情,就是把“AI 和外部工具之间怎么对话”这件事标准化,像 USB 接口一样——你做了一台支持 USB 的电脑,那你做的 U 盘、鼠标、键盘,插上去就能用,不用每家都单独设计一个专用插口。
那这套“USB 接口”到底是谁来定义的?是 Anthropic 在 2024 年 11 月开源的一个协议规范,后来在 2025 年 3 月捐赠给了 Linux 基金会,现在由 Linux 基金会的联合开发基金会来管理。这步很关键——它意味着 MCP 不再是某一家公司的私有接口,而是行业共同维护的开放标准。就像 HTTP 不是某家公司的私有协议一样,MCP 想要成为 AI 应用与外部工具之间的事实标准。
MCP 的价值定位非常清晰:大模型本身住在服务器里,它不知道你电脑里有什么文件,不知道你数据库里有什么表,不知道你今天要操作什么工具。MCP 就是给模型装上“手和眼睛”的那层桥梁。你可以把它拆成三个角色去看:MCP Host(宿主)、MCP Client(客户机)、MCP Server(服务器)。宿主是 AI 应用本身,比如 Claude Desktop、Cursor、Codex 这类工具;Client 是宿主内部负责跟外部通信的组件;Server 则是你提供具体能力的服务端程序,比如一个“查询天气”的服务、一个“读写数据库”的服务。
这套架构的好处在于,每个 MCP Server 都是独立部署、独立维护的。你想让 AI 新增一个能力,不需要改 AI 应用本身的代码,只需要起一个新的 MCP Server,然后在宿主里配置一行地址,就完事了。这种“插拔式”的设计,直接改变了 AI 应用开发的底层工作方式。
2. MCP 的核心架构拆解:Client、Server 与协议模型
2.1 三个角色各管什么
我先用一个来类比:假设 AI Agent 是一个大公司的老板,他不可能自己下场干活,他需要联系供应商。MCP Host 就是老板本人(AI 应用);MCP Client 是老板的秘书,负责拨打电话、传达指令;MCP Server 则是各个供应商——有快递公司(文件读写)、有调查公司(搜索查询)、有财务公司(数据库操作)。
技术上的分工大概是这样的:
- MCP Host:AI 应用本体,负责调用大模型、处理用户输入、展示结果。它要理解 MCP 的能力列表,然后在合适的时候把请求转给合适的 Server。
- MCP Client:Host 内部实现的一个协议客户端,负责与 Server 建立连接、发送请求、接收响应。一个 Host 可以同时连接多个 Client 实例,每个 Client 对应一个 Server。
- MCP Server:一个轻量级的服务程序,暴露出一系列“工具(Tools)”“资源(Resources)”“提示词(Prompts)”,底层可以对接任何外部系统——文件系统、数据库、HTTP API、搜索引擎、设计工具等。
连接方式上,MCP Server 有两种形态:一种是本地通过**标准输入输出(stdio)**与客户端通信,适合在用户自己电脑上运行的场景;另一种是通过HTTP + Server-Sent Events(SSE)进行远程通信,适合部署在服务器上,供多个客户端或远端 Agent 调用。
传输方式这块值得多说一句。本地场景用 stdio,本质上就是启动一个子进程,进程之间通过 stdin/stdout 来传 JSON 消息。这种方式的好处是稳、快、不走网络,没有端口冲突问题。而远程场景走 HTTP,MCP 协议把每个 Server 能力暴露成 URL 端点,然后用 JSON-RPC 2.0 格式来封装请求和响应。2025 年年中又推出了 Streamable HTTP 传输规范,逐渐取代早期以 SSE 为主的远程实现,让长连接和流式响应处理得更干净。
2.2 MCP 协议的数据模型:不只“工具”这一种能力
很多人一提到 MCP 就以为它只是“让 AI 能调用函数”,这个理解太窄了。MCP 的抽象对象一共分为三类:Tools(工具)、Resources(资源)、Prompts(提示词模板)。
Tools 是“动词”,是 AI 可以执行的操作。比如查询天气、提交订单、创建文件、发送邮件。Tools 通常需要入参,有明确的返回值。AI 在对话过程中,会根据你的问题自动判断该调用哪个 Tool,并填充参数。
Resources 是“名词”,是可供 AI 读取的上下文数据。比如一个文件的内容、一张数据表的记录、一个项目的说明文档。Resource 不强调“能不能做”,而强调“有没有、能不能读”。Host 启动时可以自动把某些 Resource 加载进上下文,让模型“天生就知道”某些领域信息。
Prompts 则是预定义的提示词模板。它们的目的是把常用的任务流程固定下来。比如你定义了一个“周报生成 Prompt”,里面写好了角色设定、输出格式、必须包含的模块,用户在宿主里一键调起,AI 就按这个模板去执行,省得每次重复打同样的话。
这三类对象加在一起,才构成了完整的“上下文接入”能力。工具让 AI 能动作,资源让 AI 有信息,提示词让 AI 有套路。你去看一个成熟的 MCP Server,往往不是只提供两三个 Tools 就算了,而是会同时暴露一组资源文件和一组提示词模板,这样接入方的使用体验才会完整。
2.3 从握手到调用:一次完整的 MCP 交互流程
MCP 的底层消息格式走的是 JSON-RPC 2.0,这是一套很经典的远程调用协议。JSON-RPC 2.0 的好处是它很轻、无状态、人类可读。MCP 在 JSON-RPC 之上定义了自己的方法名和参数语义,主要包括下面几个环节:
第一步是初始化握手。Client 发送initialize请求,带上自己支持的协议版本号、客户端标识、能力声明;Server 返回自己的协议版本、服务端能力、以及补充信息。这一步的作用是让两边对齐“都能听懂什么话”,规避版本不兼容的问题。
第二步是能力协商与枚举。初始化之后,Client 会调用tools/list、resources/list、prompts/list来获取 Server 暴露出来的能力清单。这个清单不是写在配置文件里写死的,而是通过协议动态获取的——这样 Host 就知道接下来可以调用哪些工具。有些 Host 还会同时读取每个 Tool 的输入 JSON Schema,用来约束大模型生成参数时的格式。
第三步是调用。当 AI 判断“此刻需要调用某个工具”,Client 发tools/call请求,带上工具名和参数。Server 执行具体的业务逻辑(可能是查表、调第三方 API、操作本地文件),然后把结果返回。结果通常包括内容片段(文本、图片)和可选的isError标记。如果执行过程中出了错,Server 要返回结构化错误信息,供模型判断下一步怎么处理。
第四步是通知与采样。MCP 还支持日志通知、进度通知、资源更新通知等。其中比较有意思的是“采样”机制——它允许 Server 反过来请求 Host 调用大模型来生成内容。这招在“需要 Agent 帮忙总结文件”的场景里特别有用:Server 发现自己手里的数据太散,没法直接给结果,就会返回一个“我去,请大模型帮我提炼一下”的请求。
整个流程走下来,你就会发现 MCP 本质上并不是什么高深莫测的新技术,它更像是一个为了 AI 应用场景重新组织的接口协议。它没有发明新的传输层,没有发明新的序列化格式,而是站在 JSON-RPC 和 HTTP 的肩膀上,把“AI 怎么发现能力、怎么调用能力、怎么理解结果”这件事系统地定义了一遍。
3. 手把手搭建一个 MCP Server:从零到被 AI 调用
讲完协议层面的东西,最关键的问题是:代码到底怎么写?我自己的学习路径是从一个极简的天气查询服务入手的,这个例子足够小,能覆盖一个 MCP Server 的核心要素,又不会让你陷入业务复杂度里出不来。下面给出完整的实操过程,建议你边看边敲。
3.1 环境准备与 Python SDK 选型
我用的是 Python 生态,MCP 官方 Python SDK 已经比较成熟,直接从 PyPI 安装即可:
pip install mcpSDK 本身依赖比较少,装好之后会有自带的一个命令行工具,方便联调。如果你用的是 Node.js 生态,官方也有对应的 TypeScript SDK,语法上大同小异。一般基础项目用 Python 就够了。
接下来我想搭一个“查询城市天气”的 MCP Server。这个服务内部其实是通过访问一个第三方的天气 HTTP API 拿数据,再把数据封装成 MCP 工具暴露出去。也就是说,MCP Server 不自己产生数据,它做的本质是“协议翻译”——把外面杂七杂八的 HTTP 接口,翻译成 AI 能理解、能调用的标准化工具。
3.2 核心代码实现:FastMCP 极简编写风格
MCP Python SDK 里提供了一个叫FastMCP的高层封装类,可以极大简化服务端开发。你不需要手写 JSON-RPC 的消息解析,只要注册几个函数,SDK 自动帮你把函数变成了 MCP Tools。
from mcp.server.fastmcp import FastMCP import httpx import json mcp = FastMCP("weather-server") @mcp.tool() def get_weather(city: str, days: int = 1) -> str: """获取指定城市的天气预报。 Args: city: 城市名称,例如 北京、上海、广州。 days: 获取未来几天的预报,默认 1 天。 """ # 这里以调用一个模拟的天气服务为例 # 实际项目里可以把 URL 换成任意第三方 HTTP API url = f"https://api.example.com/weather?city={city}&days={days}" resp = httpx.get(url, timeout=10) data = resp.json() return json.dumps(data, ensure_ascii=False) if __name__ == "__main__": mcp.run(transport="stdio")这段代码可以说是 MCP Server 的“最小可运行版本”——只用了三个关键要素:
mcp = FastMCP("weather-server"):声明一个 Server 实例,名字会显示在客户端的工具列表里。@mcp.tool()装饰器:把下面的普通函数暴露成一个 MCP Tool。函数的 docstring 会被自动解析成工具描述,参数类型和默认值也会被自动解析成 JSON Schema。所以你在写函数时,docstring 一定要认真写,因为模型理解这个工具能不能满足当前任务,靠的主要就是这段描述。mcp.run(transport="stdio"):以标准输入输出方式启动服务,供本地客户端连接。
有的读者会问:这里为什么要用 stdio 而不是 HTTP?原因是,用 Claude Desktop 这类本地桌面宿主连接 MCP Server 时,默认就是 spawn 一个子进程,通过 stdio 来通信。stdio 模式没有端口、没有鉴权问题,最省事。等你把 Server 调试通了,再部署到服务器上改用 HTTP 模式也不难。
3.3 服务端暴露多个工具与资源:扩展你的 Server
上面那个 Server 只做了一个工具,真实项目往往需要多个工具配合。你可以直接在同一个类里叠加注册,工具之间共享内部状态。假如我想再加一个“根据天气推荐穿衣”的功能,代码很简单:
@mcp.tool() def recommend_clothing(weather: str, temperature: float) -> str: """根据天气和温度推荐穿衣建议。 Args: weather: 天气描述,如 晴、雨、雪、阴。 temperature: 当前温度(摄氏度)。 """ if "雨" in weather or "雪" in weather: return "有降水,建议带伞,穿防水外套" if temperature < 5: return "寒冷,建议穿羽绒服、戴围巾手套" if temperature < 15: return "较凉,建议穿风衣或夹克" return "温暖,建议穿衬衫或薄外套"注意,MCP 工具跟普通 Python 函数最大的区别,在于它是给大模型“看得到”的。模型不会像人一样自己找函数说明,它完全依赖工具名、docstring、参数 Schema 来判断工具用途。你如果写一个名字含糊不清、描述也不明朗的工具,模型很可能永远不调用或者乱调。这件事我之前踩过不少坑。
另外,如果你想让 AI 能“读取”某些项目上下文,比如一个 README 内容、一个数据库的连接信息模板,可以暴露 Resources:
from mcp.server.fastmcp import FastMCP mcp = FastMCP("doc-server") @mcp.resource("docs://project-readme") def get_readme() -> str: """获取项目说明文档内容。""" with open("./README.md", "r", encoding="utf-8") as f: return f.read()定义好 Resource 之后,当客户端连接到这个 Server,宿主可以主动获取这份文档,放进模型上下文。这个机制在做“项目级 AI 助手”时特别好用,比如你把项目规范、代码结构说明作为 Resource 挂上,模型一开始就了解了整个项目背景,回答质量会明显提升。
3.4 本地联调:用官方调试工具验证你的 Server
写完了 Server,你不能直接说它就能用,得先联调。MCP SDK 内置了一个命令行调试工具,你可以把 Server 跑起来试试消息交互:
npx @modelcontextprotocol/inspector python weather_server.pyInspector 工具会打开一个本地 Web UI,你能在里面手动连接你的 Server,浏览 Tools 列表,填参试调,查看返回。这个工具特别适合开发期的快速验证——它能让你脱离 AI 宿主环境,直接测试 Server 本身是否工作正常。我在日常开发中习惯先把 Server 的每个工具都在 Inspector 里跑一遍,确认无误再接宿主,能省去很多“到底是工具问题还是模型调度问题”的排障时间。
如果你的 Server 已经被宿主连接,还可以直接看宿主日志。Claude Desktop 这类宿主有时会把 MCP 通信细节打印到日志里,方便你排查工具注册、参数传递等环节的问题。
接宿主时,配置方式是写一个 JSON 配置文件。以 Claude Desktop 为例,常见配置放在:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
配置内容大致如下:
{ "mcpServers": { "weather-server": { "command": "python", "args": ["/absolute/path/to/weather_server.py"] } } }配好之后重启宿主编译,就能在客户端设置里看到新接入的 Server。注意路径建议写绝对路径,Python 建议用虚拟环境里的绝对路径。我之前有几次接入失败,最后发现就是python命令指向了系统 Python,而依赖装在虚拟环境里,导致子进程启动时找不到包,直接崩溃。
3.5 用 Java 技术栈实现 MCP Server 的路径参考
如果你主要用 Java 后端,其实也有成熟的支持方式。2025 年之后,Spring AI 官方加入了 MCP 客户端和服务端支持,底层走的是io.modelcontextprotocol.sdk:mcp这个 Java SDK。你可以在服务端定义一个工具类(比如模拟一个查订单的接口),然后用ToolCallback暴露给 MCP 客户端。Solon AI 框架也对接了 MCP,启动时自动扫描并注册工具。Java 技术栈做 MCP Server 的好处在于:企业后端服务大都是 Java 写的,MCP Server 可以直接嵌在现有 Spring Boot 应用里,把那些已经存在的业务接口包装成 MCP 工具,不需要引入一套新的服务框架。
Spring AI 这边大致配置是:引入spring-ai-starter-model和 MCP Server Boot Starter,在配置里声明 Server 的 name 和 version,然后写一个普通的@Component,里面定义带@Tool注解的方法。项目启动后自动注册,宿主通过http://localhost:8080/mcp就能远程连接。这套方式对企业级落地非常友好,不过配置项比 Python 版多一点,需要先熟悉 Bean 的装配方式。
4. 围绕 MCP 的工具链生态:不只是“又一个接口规范”
4.1 热门 MCP Server 盘点:蓝湖、Figma 与浏览器自动化
MCP 能火,和它迅速长出来的生态有直接关系。光有协议没有工具,这个东西就是空壳。好在这两年各领域的客户端产品,都在积极做“MCP Server”作为自己能力的输出口。
把热搜词里出现频率比较高的几个梳理一下:
Figma MCP / 蓝湖 MCP。设计工具接入 MCP 之后,最大的价值场景是“设计稿一秒变前端代码”。以前设计师出 Figma 稿,前端工程师照着稿子手写 HTML/CSS。现在你让 AI 编程助手通过 MCP 连上 Figma,它可以直接读取设计稿的图层树、样式属性、组件信息,然后生成还原度极高的代码。蓝湖(Lanhu)做的 MCP 也一样,就是把设计稿的元素提取能力开放给 AI Agent。这个赛道本质上是“设计工程化”的又一次延伸——从切图工具到自动生成代码,再到 AI 直接理解设计意图,链路越来越短。
Playwright MCP。这是浏览器自动化领域的杀器。Playwright MCP Server 把浏览器操作封装成工具集合,比如
browser_navigate(打开页面)、browser_click(点击元素)、browser_type(输入文本)、browser_snapshot(获取页面可访问性快照)。AI Agent 接入之后,能自己打开网页、自己操作按钮、自己填写表单、自己验证结果。这不就是我们一直想要的那口“AI 帮你测网站”吗?很多做 E2E 测试的团队已经把它用在智能回归测试和自动化 bug 复现里了。Unity MCP / Cocos Creator MCP。游戏开发场景也在拥抱 MCP。Unity MCP 允许 AI 助手读取场景结构、查找游戏对象、修改组件属性、执行 C# 脚本;Cocos Creator 也有类似的 MCP 桥接方案。你用自然语言给 AI 下指令说“把主场景的主角移动速度调低 20%”,如果有 MCP 连着引擎,AI 真的能直接改场景里的数值。这块目前还在早期,但它代表了一个趋势:只要引擎愿意提供操作接口,AI 就能变成“能干活的生产力工具”,而不只是“写代码的建议器”。
Mobile MCP / 移动端设备控制。在移动端自动化上,MCP 也开始渗透,比如把 Android 的 adb 命令封装成 MCP Server,AI 就能自动操作模拟器甚至真机,安装 App、点击坐标、抓取截图。移动端 UI 测试自动化和 AI 兜底复测可以串起来了。
我建议新手选第一个自己接的 MCP Server 时,优先挑 Playwright MCP 或一个官方示例 Server,因为它们生态完整、文档多、踩坑概率低。如果你想看业务价值,就挑一个跟你日常工作强相关的(比如做前端的选 Figma MCP 或蓝湖 MCP,做后端的选数据库 MCP 或 HTTP 请求封装),直接把你手头最繁重的“信息搬运型”工作交出去,你会立刻体会到 MCP 的爽感。
4.2 Computer Use 与 MCP 有什么不同
很多文章会把“Computer Use”和 MCP 放在一起比较,还有人把概念搞混。这里我解释清楚。
Computer Use 指的是让 AI 像人一样操作电脑——看屏幕、移动鼠标、点击、敲键盘。它模仿的是“人类操作介面”的方式,也就是图形界面交互。如果 AI 要帮你写一封邮件,它不是调用 Mail API,而是像你一样打开邮件客户端、找到写信按钮、逐字敲进去。这种方式不需要对方系统定制接口,什么软件都能操作,但慢、不稳、需要视觉理解模型的参与。
MCP 不一样,它走的是结构化接口契约。AI 操作的不是像素,而是对方系统预先定义好的工具——比如“send_email(receiver, subject, body)”。它的前提是系统方必须开发一个 MCP Server 把能力暴露出来,但一旦暴露出来,调用极其稳定、速度快、返回结构化数据。
这两种方式的优劣很清楚:
| 维度 | Computer Use | MCP |
|---|---|---|
| 交互对象 | 屏幕图像(图形界面) | 结构化接口(工具函数) |
| 系统适配成本 | 无需定制,任何可看的界面都能操作 | 需要系统方提供 MCP Server |
| 稳定性 | 低,受界面变化、视觉识别影响 | 高,接口不变则稳定 |
| 速度 | 较慢,像人看屏幕一步步操作 | 较快,直接走协议执行 |
| 适用场景 | 老系统、无 API、无法改造的外部产品 | 自有系统、有开发能力的平台 |
真实生产中,二者不是二选一,而是互补的。MCP 能覆盖的,优先用 MCP;MCP 覆盖不到的(比如一个第三方老系统没有任何接口),再用 Computer Use 兜底。理论上未来的 Agent 既会调 MCP 也会操作电脑,“能上路的车走高速,上不了路的走省道”。
4.3 普通 REST API 与 MCP 的取舍,什么时候值得上
热搜词里“接口”一词反复出现,比如“接口是啥”“API 接口”“后端提供接口”“list 接口”“接口幂等性”“接口自动化”等,这些东西和 MCP 什么关系?这里我想专门掰扯一下。
普通 API 是“给程序用的接口”,MCP 是“给 AI 用的接口”——这是最本质的差异。后端团队提供一个 REST/orders?userId=123接口,是给前端页面调用的;页面代码写死了“点击按钮就请求这个 URL”。但当你面对 AI 时,它的输入是自然语言,它不知道你的 API 文档,不确定要传什么参数,也不清楚哪些接口能组合完成一个复杂任务。所以直接让 AI 去调你的 REST API,往往会失败。
MCP 的价值,在于给 API 加了一层“AI 友好的描述层”。你的 MCP Server 里,可以写清楚“这个接口是查订单的,用户 ID 是必填项,订单状态可选”“那个接口是发货的”,然后暴露成工具。AI 拿到这些描述之后,就能自己规划任务流程:先查订单,再调发货。
但这不意味着什么接口都要包一层 MCP。我的建议是:
- 无状态、简单的“查询类”单接口,没必要包 MCP——直接让 AI 框架调用普通 HTTP 工具就行。
- 涉及多步骤流程、需要决策分支、需要容错重试的“任务类”能力,才值得包成 MCP。
- 如果某个工具会被多个不同 AI 应用复用(比如多个 Agent 都要查你们公司的客户信息),就非常值得做 MCP Server,因为它一次对接,处处复用。
判断标准其实可以就一条:“能力的消费方是固定前端的,还是不确定的智能体?”如果是后者,用 MCP 的思路去暴露能力,能省很多将来往返协调的功夫。
5. 实战中会踩的坑:注册失败、鉴权紊乱和工具调不动
5.1 Figma MCP 在 Codex 里工具注册不上,怎么排查
热搜词里那条“Figma MCP 在 Codex 中总是工具注册不上”的词条,我猜是从某个真实求助问答里来的。这个问题的本质不是 MCP 协议本身的问题,而是 MCP Server 从启动到工具列表交付中间某个环节断了。我自己排查的思路固定在三个层面:
第一层,Server 是否启动成功。很多人配置了 MCP Server 地址,但它启动后报错退出。Figma MCP 要走 OAuth 令牌认证,如果你首次启动时没有正确粘贴访问令牌,Server 进程起来之后监听到错误,会直接卡住,或者返回一个空列表。排查办法:在 Codex 的 MCP 配置里找到 Server 的启动命令,手动在终端里跑一遍,看有无报错。
第二层,工具列表是否返回。MCP 客户端注册工具,靠的是tools/list这个请求。如果 Server 返回的是空数组,客户端界面自然什么都不显示。Figma MCP 返回空列表,常见的原因有两个:配置文件里没填 API Token;或者 Token 对应的 Figma 账号没有访问目标文件的权限。这个可以通过用 curl 去调用 Figma API 测试,看那个 Token 能不能取到文件数据,验证权限链路。
第三层,宿主软件配置与版本问题。Codex 这类 CLI 工具对 MCP 的配置文件格式要求可能不同,有些版本只支持本地 stdio Server,有些版本支持远程 HTTP Server。如果你把 HTTP URL 填到了不支持它的版本里,当然注册不上。这时候要么升级宿主,要么把 Figma MCP 换成本地启动的方式。
这种排查逻辑不只适用于 Figma MCP——只要你在任何宿主里遇到“工具注册不上”,都建议按照这个三步走:看服务有没有起来、看服务有没有返回能力、看宿主有没有正确读取配置。
5.2 本地 stdio 服务启动失败和处理办法
stdio 模式的 MCP Server 是宿主作为父进程 spawn 出来的子进程。宿主跟你平常在终端里手动运行程序不同,它的 PATH 环境、当前工作目录都由宿主进程决定。所以常见的两个坑是:
command写了python,但系统里同时存在多个 Python,选中的那个没有装 MCP SDK,子进程起来后立刻报ModuleNotFoundError。- Server 脚本里用了相对路径去读文件,但宿主启动子进程时的工作目录并不是你的项目目录,导致文件找不到。
解决办法非常朴素:command 写成虚拟环境中 Python 的绝对路径,比如/Users/me/.venv/bin/python;脚本内部涉及文件路径时,一律基于__file__算绝对路径。这个坑我在写自己的首个 MCP Server 时踩过,现象特别诡异——手动跑一切正常,一接宿主就报错,后来在日志里才发现是工作目录的问题。
排查这类问题,还有一个实用的工具——重定向 stdio 日志。MCP 通信走的是 stdin/stdout,你千万不能在 Server 里乱写print,否则会污染协议消息。如果你非要打日志,把日志写到 stderr 或者独立日志文件里,否则客户端解析 JSON-RPC 时会直接报错。
5.3 鉴权与安全:API 密钥、令牌不能出现在工具描述里
MCP Server 的本质是一个提供执行能力的服务,所以安全问题必须重点对待。最常见的反面教材是:有人把数据库连接串或者 API Token 硬编码进 MCP Server 代码里,然后配套的 Python 脚本随意分发给别人。一旦这个 Server 被其他人启动,等于他把你的数据库钥匙也一并拿走了。
建议做好这几件事:
- 敏感凭据放在环境变量里读取,不要提交到代码仓库。
- MCP Server 应明确给每个工具标注权限级别。比如“只读型工具”(查询数据)和“写操作型工具”(删除数据、提交订单)在描述中就要区分清楚。AI 一旦能理解这些注解,就不会乱调用写操作。
- 远程 MCP Server 一定要做鉴权,不能裸奔在公网。目前官方推荐在 HTTP 层引入 Bearer Token 或 OAuth。如果还没有统一的 MCP 鉴权规范,至少在网关层加一道访问控制,肯定没坏处。
从长期看,MCP 在安全方面还会演化出更细的授权模型。但现阶段,工具健壮性掌握在开发者手里。你自己写 Server 时,要把每个工具都当成“可能被任何恶意调用的人触发”来对待,输入校验、越权判断、频率限制这些后端基本功,一个都不能少。
5.4 工具被 AI 频繁调用出错:幂等性与上下文被撑爆
热搜词里提到了“接口幂等性”,这个词在做 MCP Server 时也重要。AI Agent 调工具,并不总是按人的预期来的,它可能失败后重试,也可能因为网络波动重复发请求。如果你的 MCP Server 里有一个“创建订单”的工具,它被执行了两次,用户就收到了两笔扣款——这就灾难了。所以写 MCP Server 时,凡是“会产生副作用”的工具,尽量做成了幂等设计:提供一个幂等键,服务端内存或数据库里保存处理记录,重复请求直接返回第一次的结果。
还有一个问题很隐蔽:上下文被撑爆。MCP 工具的返回结果会被原样塞给大模型,如果某个工具返回了一个几兆字节的大数据(比如查询了整张表),你的上下文长度马上被占光,后续对话质量骤降。更好的做法是:返回数据前先做截断或聚合,最多返回前几十条记录,再额外提供“加载更多”这类翻页工具。好用的 MCP Server,第一个素质就是“懂取舍”——不是把什么都一股脑给模型,而是给模型恰到好处的信息量。```