[Ai Agent] 10 MCP基础:5分钟构建你的专属AI工具库(Server)

0 阅读11分钟

博客配套代码发布于github:10 MCP 基础

本系列所有博客均配套Gihub开源代码,开箱即用,仅需配置API_KEY。

如果该Agent教学系列帮到了你,欢迎给我个Star⭐

知识点Stdio传输 | Streamable HTTP | FastMCP框架 | Transport通信


序章:从“造轮子”到“插 USB”

在第 07 篇中,为了让 Agent 能查询天气,我们手写了一个 get_weather 函数,并用 @tool 装饰器将其注册为工具。

但现实需求远不止于此:

  • 想查高德地图的驾车路线?
  • 想通过 GitHub 自动创建 Issue?
  • 想用飞书机器人发送通知?

难道我们要为每一个服务去阅读 API 文档、处理认证、封装错误、维护版本,再手写几百个 @tool  函数吗?

这正是 “工具孤岛” 问题——每个 Agent 都在重复造轮子,无法共享、难以复用、维护成本极高。

Model Context Protocol(MCP)的诞生,就是为了解决这个问题。

MCP 把工具剥离出来,放到独立的Server里:

  • 它可以是个 USB 设备(支持 Stdio 插拔);
  • 也可以是个 Wifi 热点 (支持 HTTP 连接)。

有了MCP的Agent,才可以自由调用成百上千个工具,让Agent的能力飞速扩张。

对于MCP的基础篇与进阶篇,我们将逐个学习MCP的服务端客户端搭建。


一、为什么先学服务端

按常理,我们或许应该先学会“如何接入别人的 MCP 服务”(客户端),再学习“如何发布自己的服务”(服务端)。 但在 MCP 的学习路径中,这个顺序恰恰应该反过来。 原因很简单:

服务端适合“极速上手”,而客户端适合“深度进阶”。


服务端:极低门槛,所见即所得

得益于 FastMCP 这样高质量框架的存在,服务端的开发已经变得极其简单。你不需要处理复杂的协议握手,只需写一个带类型提示的普通 Python 函数,加个装饰器,它就立刻变成了一个标准工具。配合 CherryStudio 这样的可视化客户端,你能立刻看到自己的代码跑起来,获得极强的正反馈。

⚠️ 客户端:不仅是调用,更是架构

虽然社区已经出现了如 langchain-mcp-adapters 这样的封装库,能让你一键连接。但作为Agent 全栈工程师,如果只学会调用一个封装好的 load_tools() 函数,你永

远无法理解 MCP 的真正威力:

  • 它是如何跨越进程(Stdio)与 Node.js 服务对话的?
  • 它是如何通过 HTTP (SSE) 实现远程流式传输的?
  • 当连接断开或报错时,如何优雅地处理资源释放?

这些底层通信机制生命周期管理,被封装库完美地“隐藏”了。 正因如此,官方和主流工具(如 Cursor、Trae)都鼓励你先成为“工具提供者”。

因此,我们的策略是:

  1. 先攻服务端 (本章) :利用 FastMCP 的便利性,5分钟构建出可用的工具,建立信心,理解 MCP 的“双模”(Stdio/HTTP)形态。
  2. 后磨客户端 (下一章) :不满足于“调包”,我们将亲手拆解通信黑盒,手写一个生产级的双模客户端。只有造过一次轮子,你才有资格说自己“精通”了 MCP 架构。 (当然,在彻底理解原理后,我们也会介绍官方库作为生产环境的替代方案)。

二、极速上手:开发第一个基于FastMCP的Stdio Server

我们先从最简单的开始:本地管道模式(Stdio)

这是Cursor、Trae 等本地应用连接工具的标准方式。

在没有框架之前,我们写MCP Server需要处理各种复杂的协议格式。但借助FastMCP,我们只需会写Python函数即可:

# stdio_server.py
from mcp.server.fastmcp import FastMCP

# 初始化服务
# WeatherService 是服务的名字
mcp = FastMCP("WeatherService")

# 业务逻辑工具
@mcp.tool()
async def get_weather(city:str):
    """
    查询指定城市的实时天气。
    如果是此时此刻的天气请求,调用此工具。
    """
    # 模拟真实的网络请求(你可以换成自己的天气API)
    # 在MCP中,工具函数可以是async的,FastMCP会自动处理
    return f"{city}的天气是:晴,气温25℃,风力3级"


# 启动入口
if __name__ == '__main__':
    # 默认运行方式:Stdio(标准输入输出)
    # 这种模式下,程序启动后会“挂起”等待指令,不会有任何打印输出。
    mcp.run()

代码解析:

    1. 自动Schema生成:
    • 看代码中的city:str。FastMCP 会自动读取这些类型注释(Type Hints)。生成JSON Schema 告诉 LLM:“这个工具需要一个字符串类型的city参数’”。
    • 切记:写MCP工具,必须写 Type Hints,不然LLM不知道如何调用。
    1. Docstring 说明书:
    • 函数下方的注释("""查询指定...""")会被自动提取为文档描述。LLM 靠这个来决定什么情况下调用这个工具。
    1. Stdio 管道连接:
    • mcp.run() 默认开启 Stdio模式。此时 FastMCP 会接管标准输入/输出,将MCP消息通过JSON流处理。
    • 尽量不要在Server或工具函数中随意使用print()输出消息,因为Stdout 是 MCP协议通道,随意输出会破坏消息格式,导致客户端解析失败。

三、测试MCP链接:CherryStudio初体验

Server 代码写好了,写起来感觉非常简单,但我们怎么知道它能不能用?我们还没写 Client 测试代码(那是下一章的事)。这时候,现成的Cherry Studio作为目前对MCP支持最好的客户端之一,就是非常好的调试器:

1. 下载与安装

点开 www.cherry-ai.com/ ,

下载该文件并安装好(安装流程非常简易)。

 2. 配置MCP

下载好后,点击右上角设置:

点击MCP进到这里,再点击添加-快速创建:

在这里,我们把如下信息填充完整:

  • 类型 (Type):stdio  |  通信方式
  • 名称 (Name):Weather-Local  | MCP工具名
  • 命令 (Command): python.exe的绝对路径  |  启动py脚本的解释器 
  • 参数 (Args): 绝对路径/path/to/weather_server.py  |  你的服务器本地位置

⚠️ 如果你的python.exe解释器是在venv环境下,一定要明确指定。

如图,配置完成后,先按保存,并按确认:

 当看到有工具与小版本号时,意味着你已连接成功。

返回首页,我们测试下效果:

测试成功。

⚠️  推荐这里使用Qween3作为测试模型,默认的GLM-4.5对MCP支持有点小问题。

在这里,你可以尝试反复修改你的MCP服务器,并不断开关MCP按钮,来测试MCP的连接效果如何。

四、理解MCP的 Transport 通信机制

在上一节中,我们成功使用 Stdio 模式 启动了一个本地 MCP Server。你可能会疑惑:

“既然 Stdio 是本地通信,为什么我用 npx @amap/... 时,感觉像是‘远程调用了高德地图’?”

其实,这种“远程感”是一种部署层面的错觉通信本身仍是纯本地的。下面我们就来彻底厘清 Stdio 与 Streamable HTTP 的本质区别。

1. Stdio:真正的本地进程间通信(IPC)

Stdio(Standard Input/Output)的本质是 父子进程之间的匿名管道通信。它不经过网络协议栈,完全在操作系统内存中完成数据交换。

场景一:纯本地开发(前文所用的方法)

  • 运行 python weather_server.py 
  • 客户端(如 CherryStudio)通过subprocess 启动该脚本
  • 双方通过 stdin/stdout 交换 JSON-RPC 消息
  • ✅ 零网络开销,延迟极低(~0.01ms)
  • ❌ 仅限同一台机器

场景二:“伪远程”——通过 npx/uvx 临时执行

当你执行:

npx @amap/amap-maps-mcp-server YOUR_KEY

实际发生了三步:

  1. 联网下载(一次性):npx 从 npm 仓库拉取包并缓存到本地;
  2. 本地启动:在你的机器上立即运行这个 Node.js 脚本,生成一个子进程;
  3. Stdio 通信:客户端通过 stdin/stdout 与这个本地子进程对话。

🔑 关键点:无论代码来自哪里,只要用 Stdio 启动,服务端进程就一定运行在你的本地机器上。

因此,这仍然是 本地 IPC,只是“工具来源”是远程的,通信过程从未离开本机


2. Stdio 的局限:为何不能用于生产?

尽管 Stdio 简单高效,但它天生不适合生产环境:

问题说明
❌ 无法跨机器服务端必须与客户端同机运行,无法部署到云服务器供团队共享
❌ 无持久化每次调用都需重新启动进程,冷启动开销大
❌ 无并发支持一个 Stdio 连接 = 一个进程,难以支撑多用户或多 Agent 并发
❌ 可靠性差进程崩溃、环境变量错误、权限问题都会导致连接瞬间断裂

💡 Stdio 的定位很明确:快速验证、本地开发、桌面应用。
它是“造工具”的最佳起点,但不是“用工具”的终极形态。


3. 升级到生产:为什么必须用 Streamable HTTP?

当我们要将 MCP 工具部署到云端、供多人或多个 Agent 共享时,必须切换到 Streamable HTTP

⚠️ 注意:这里的“Streamable HTTP”不是老的 HTTP/1.1,而是一种支持真正双向实时通信的现代协议(基于 HTTP/2 或 HTTP/3),用起来跟 WebSocket 差不多,但部署更简单。

为什么不用常规 HTTP?

特性常规 HTTP/1.1Streamable HTTP(MCP 推荐)
连接模型短连接(请求-响应后关闭)持久长连接,作为通信隧道
通信方向半双工(客户端问 → 服务端答)全双工,双方可随时主动发消息
状态管理无状态(每次请求独立)强有状态,可追踪任务上下文
效率高并发但高开销(重复建连、头部冗余)多路复用,单连接承载多 RPC 流
适用场景静态资源、简单 API实时协作、Agent 控制、流式推理

Streamable HTTP 的三大核心优势

  1. 持续的状态追踪
    Agent 的推理常是多步的(Plan → Act → Observe → Reflect)。Streamable HTTP 通过长连接维持上下文,避免反复传输冗余历史。
  2. 原生全双工 JSON-RPC
    服务端可在执行中主动推送日志、中间结果、权限请求(如“请授权访问你的日历”),无需等待客户端轮询。
  3. 流式反馈与控制
    不仅返回最终结果,还能实时输出思考链(Chain-of-Thought)、函数调用轨迹、进度条等,极大提升用户体验与可调试性。

4. 两种 Transport 对比

维度StdioStreamable HTTP
通信机制父子进程 + 匿名管道全双工 JSON-RPC over HTTP/2
延迟~0.01ms~1–10ms
安全性⭐⭐⭐⭐⭐(进程隔离,无网络暴露)⭐⭐⭐⭐(需配合 TLS、认证)
部署场景本地开发、桌面应用云服务、团队共享、生产环境
是否占用端口❌ 否✅ 是
典型启动方式python server.py 或 npx pkguvicorn server:app --host 0.0.0.0 --port 8000

📌 一句话总结
Stdio 是“插 USB”,即插即用,但只能在自己电脑上用;
Streamable HTTP 是“连 WiFi”,稍复杂,但能让全世界的 Agent 都用上你的工具。

前文我们已经讲了Stdio的生产实现,下一小节我们将继续针对 Streamable HTTP 的实际实现。

注:本文针对工程细节并不会讲的过深,诸如父子进程、JSON-RPC、Schema等各种术语,会在下一章进行详细拆解。此处仅做简单了解即可。

⚠️ 另外,针对Transport的另一种通讯机制sse,因为它只支持单向限制,已被官方弃用,正逐步淘汰,故此处不做过多提及。

五、架构升级 —— 一键开启 Streamable HTTP 远程模式

既然要支持远程调用,代码会不会变得复杂?

完全不会!FastMCP 已将底层细节全部封装,你只需改动两行配置。

# streamable_http_server.py

# ...

# 创建服务实例,指定监听地址和端口
mcp = FastMCP("WeatherService",host="0.0.0.0",port=8001)

# ...


# 启动入口
if __name__ == '__main__':
    # 运行方式:Streamable HTTP
    # 这会自动启动 uvicorn 服务器,支持远程调用  
    mcp.run('streamable-http')

在mcp初始化处,我们为其填上host与port的主机与端口,再在末尾run内指定streamable-http即可。

运行查看控制台:

服务启动,再去CherryStudio里验证:

MCP链接成功,再去对话:

没有问题,Agent 成功调用你的远程服务,并返回结果。

💡 更棒的是:得益于 Streamable HTTP 的流式特性,工具调用过程支持实时日志输出与中间状态反馈,体验比 Stdio 模式更丰富(尤其在复杂工具场景下)。

总结、

本章我们彻底掌握了 MCP 服务端 (Server) 的开发。

  • 我们使用 FastMCP,仅用装饰器就将 Python 函数变成了 AI 工具。
  • 我们理解了 Stdio(本地管道)和 HTTP/SSE(远程网络)两种暴露方式的区别。
  • 我们证明了:业务逻辑(查天气)和 传输协议(Stdio/HTTP)是完全解耦的

预告:11 篇《MCP 进阶篇

现在工具造好了,CherryStudio也能连上了。但是,如果我们自己的py代码想连接这个Server,该怎么写代码?下一篇,我们将深入 客户端(Client)开发,手写代码去对接我们造出来的这个双模传输 Server,完成最后的闭环