从零开发MCP Server:AI智能体工具调用实战教程
2026/9/2 5:52:47 网站建设 项目流程

最近准备 AI 智能体相关项目时,我发现一个很现实的痛点:大模型的外部工具调用几乎没有统一标准。不同模型对工具定义、参数格式、调用结果的定义各不相同,写智能体的时候,大量时间都花在“适配不同工具 API”和“处理胶水代码”上。

真正让我把思路理顺的,是系统学习《基于模型上下文协议的 AI 智能体专项课程》。这门课的核心就两个关键词:MCP(Model Context Protocol,模型上下文协议)和 AI 智能体。课程把协议原理、Server 开发、Client 接入、Agent 编排、工程化落地串成了一条完整链路。

本文结合该课程的主线,整理成可直接上手的教程。你会理解 MCP 到底解决什么问题,也能照着示例代码从零写一个 MCP Server,再通过 MCP Client 接入一个简单 AI 智能体。适合正在做 AI 应用开发、智能体平台接入、中间件封装的同学阅读。

1. 为什么 AI 智能体需要 MCP?

1.1 智能体的核心能力是“调用工具”

先看一个典型场景:你想让 AI 助手帮你查询本地文件、查数据库、发邮件。

如果只靠大模型自身,它只能根据训练数据生成文本,无法访问你的本地文件或企业数据库。所以我们必须给大模型“接上”外部能力。业界通常把这种能力叫 Function Calling 或 Tool Calling,也就是让模型在回答问题时,先输出“我想调用哪个工具、传什么参数”,再由程序真正执行工具,把结果交回给模型。

这个机制本身很成熟,但它有一个问题:工具的协议不统一。

  • 有的模型要求工具参数用 JSON Schema 描述,有的用简化结构。
  • 有的平台用 HTTP 回调,有的要求在函数名前加固定前缀。
  • 同样的“查天气”工具,在 A 模型接入和 B 模型接入,要写两套适配代码。
  • 当工具数量超过几十个时,每个工具都要自己管理鉴权、限流、错误码、重试逻辑,非常容易失控。

这也是为什么“AI 智能体开发人才需求增长很快”的原因之一:大家都发现智能体落地最花时间的地方不在模型本身,而在工具接入与编排层。

1.2 MCP 是什么

MCP 是 Model Context Protocol,模型上下文协议。它是由 Anthropic 提出并开源的一种开放协议,目标是为大模型应用与外部数据、工具之间建立统一连接标准。

你可以把它理解成 AI 世界的“USB-C 接口”。

  • 过去:每个外部系统有各自的数据格式和调用方式,大模型应用要逐个适配。
  • 现在:外部系统通过 MCP Server 暴露标准能力,AI 应用通过 MCP Client 统一访问。

不管这个 Server 背后是文件系统、数据库、搜索引擎还是企业内部系统,只要实现了 MCP 协议,AI 应用就能用同一套方式发现和调用它。

《基于模型上下文协议的 AI 智能体专项课程》里反复强调一个观点:MCP 并不是某个特定模型的私有功能,它是一层标准化协议。你可以让任意支持工具调用的大模型通过 MCP Client 连接到同一个 MCP Server。

1.3 MCP 与 Function Calling 的区别

很多初学者会把 MCP 和 Function Calling 混在一起,这里做一个明确区分。

Function Calling 是模型能力。它解决的核心问题是:模型如何识别外部函数、如何生成结构化的调用参数、如何解析工具返回结果。

MCP 是应用层协议。它解决的核心问题是:工具如何注册、如何被客户端发现、用什么传输方式通信、如何鉴权、多个工具如何统一管理。

在智能体项目中,两者通常是协作关系:

LLM 通过 Function Calling 能力决定调用哪个工具 ↓ MCP Client 把请求转发给对应的 MCP Server ↓ MCP Server 执行真实业务逻辑 ↓ 结果按协议返回给 MCP Client ↓ 最终交回给 LLM 继续推理

所以,MCP 并不替代 Function Calling,而是让工具调用的“连接层”更规范。

1.4 MCP 的典型应用场景

目前 MCP 在很多方向已经落地,常见场景包括:

  • 文件系统访问:让 AI 智能体读取本地文件、搜索项目代码、做批量统计。
  • 数据库查询:把 SQL 查询封装成 MCP Tool,智能体可以基于数据结构生成并执行查询。
  • 开发工具链:连接 Git、编译工具、构建系统,让 AI 协助完成开发任务。
  • 知识库检索:把 RAG 能力封装成 MCP Tool,智能体通过标准接口检索文档。
  • 浏览器自动化:通过 MCP Server 控制浏览器,执行信息采集、表单提交等操作。

这些场景有一个共同点:AI 智能体都需要“边思考边调用外部工具”,而 MCP 正好把外部能力统一抽象成了标准工具。

2. MCP 架构与核心概念

2.1 三层架构:Host、Client、Server

MCP 的架构分为三层:

角色作用对应示例
MCP Host用户直接交互的应用,通常是大模型桌面应用或 Web 应用Claude 客户端、自研智能体平台
MCP Client与 Server 建立一对一的连接,负责协议通信Python SDK 中的 ClientSession
MCP Server暴露工具、资源、提示词的外部程序文件系统 Server、数据库 Server

一个 Host 可以同时连接多个 MCP Server。例如智能体应用里,既连接文件系统 Server,又连接数据库 Server;每个 Server 可以单独开发、单独部署,也可以由不同团队维护。

在课程中,这个架构经常用一个句话概括:Host 负责交互,Client 负责连接,Server 负责被调用。

2.2 三大原语:Tools、Resources、Prompts

MCP 官方定义了三种基础能力原语。

Tools 工具:是让 AI 智能体主动执行操作的能力。工具通常代表“动作”,比如“发送邮件”“查询订单”“调用计算器”。工具由 Server 注册,由 Client 发起调用,结果返回给 AI 继续推理。

Resources 资源:是向外暴露数据的能力。资源通常代表“静态或半静态的数据”,比如“数据库 schema”“配置文件内容”“项目文档”。在 MCP 出现之前,这些内容通常靠拖拽文件或粘贴到提示词里;有了资源机制,客户端可以动态发现和读取。

Prompts 提示词:是可复用的提示模板。例如“代码审查”“需求分析”等固定流程,可以写成一个 Prompt 模板,由用户手动选中或自动触发。这样不同项目之间可以复用一套提示工程经验。

在智能体开发中,Tools 最受关注,因为绝大多数“干活”能力都要通过工具实现。

2.3 一次完整的调用过程

以“调用一个加法工具”为例,完整链路如下:

1. Client 启动后,与 Server 建立连接并完成初始化握手 2. Client 调用 list_tools 拉取 Server 的能力清单 3. LLM 根据用户问题,决定调用某个工具 4. Client 调用 call_tool,传入工具名和参数 5. Server 执行工具逻辑,返回结构化结果 6. Client 把结果交回给 LLM,LLM 生成最终回答

这个流程看起来简单,但协议层的价值就在这:无论工具是本地脚本还是远程 HTTP 服务,无论 Server 用什么语言开发,Client 侧的调用方式都是一致的。

2.4 传输方式与鉴权

MCP 支持多种传输方式,比较常见的有:

stdio 传输:Client 通过标准输入输出与本地子进程通信。这种方式适合开发阶段,因为它不需要启动独立服务,也不需要处理端口和网络权限。

Streamable HTTP 传输:Server 运行在远程服务器上,Client 通过 HTTP 请求访问。适合多个客户端共享同一个 Server,也适合部署到生产环境。

基于 WebSocket 的传输:适合双向实时通信场景,实际项目中根据环境选择。

鉴权方面,远程 MCP Server 通常需要 OAuth 2.0 或自定义 Token,本地 stdio 模式则更多依赖文件系统权限和进程启动用户权限。课程中特别提醒:生产环境一定要区分“可读工具”和“写操作工具”,并为高权限工具单独配置鉴权。

3. 环境准备与项目初始化

3.1 开发环境清单

以下环境适合在 Windows、macOS 或 Linux 上搭建,本文示例以常见环境为例,版本需要根据你的项目实际情况调整。

组件说明
Python建议 3.9 及以上版本
MCP Python SDK通过 pip 安装,用于开发 Server 和 Client
Node.js可选,部分 MCP CLI 调试工具需要
IDEVS Code 或任意 Python IDE
LLM API支持 Function Calling / 工具调用的模型接口

建议在项目目录下创建独立的虚拟环境,避免依赖冲突。

3.2 创建项目目录

命令如下:

mkdir mcp-agent-demo cd mcp-agent-demo python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate

然后安装 MCP SDK:

pip install mcp

如果希望使用命令行工具辅助调试,可以安装 CLI 组件:

pip install "mcp[cli]"

如果安装速度慢,可以换成国内镜像源:

pip install mcp -i https://pypi.tuna.tsinghua.edu.cn/simple

安装完成后,可以检查版本:

pip show mcp

3.3 课程主线与本文对应关系

《基于模型上下文协议的 AI 智能体专项课程》通常围绕五条主线展开:

  1. 协议理解:MCP 是什么、为什么会出现。
  2. Server 开发:怎么把一个业务能力封装成 MCP Tool。
  3. Client 接入:怎么让大模型应用通过 Client 连接 Server。
  4. Agent 编排:怎么设计“推理 -> 调用工具 -> 观察结果”的循环。
  5. 工程化落地:鉴权、测试、日志、灰度发布。

本文接下来按照第 2、3、4 步做完整实战,第 5 步放在后面的最佳实践部分。

4. 实战:开发一个 MCP Server

4.1 编写 Server 入口

在项目目录下新建server.py。这个文件负责创建 MCP Server,并注册工具。

# server.py from mcp.server.fastmcp import FastMCP # 创建一个 MCP Server,名称可以自定义 mcp = FastMCP("AgentDemoServer")

这里的FastMCP是 MCP Python SDK 提供的高层封装,适合快速开发。如果你使用的是旧版 SDK,导入方式可能略有差异,需要以你安装的版本为准。

4.2 添加一个工具

工具函数通过@mcp.tool()注册,函数名就是工具名,docstring 会作为工具描述,供 LLM 判断是否调用。

# server.py @mcp.tool() def add(a: int, b: int) -> int: """计算两个整数的和。""" return a + b

这里的关键点是类型注解。MCP SDK 会根据类型注解自动生成 JSON Schema,所以a: intb: int必须写清楚。不要全部写成str或省略类型,否则 LLM 可能传入错误类型。

再添加一个稍微复杂的工具,比如获取指定时区的当前时间:

# server.py @mcp.tool() def get_current_time(timezone: str = "Asia/Shanghai") -> str: """获取指定时区的当前时间,默认返回东八区时间。""" from datetime import datetime from zoneinfo import ZoneInfo tz = ZoneInfo(timezone) return datetime.now(tz).isoformat()

这个工具演示了默认参数和“动态导入依赖”的用法。对于轻量工具,在函数内导入依赖可以减少 Server 启动时间;但如果是经常调用的工具,建议在模块顶部导入。

4.3 注册 Resources 和 Prompts

除了工具,MCP Server 还可以暴露资源。比如下面这个资源返回一段配置信息:

# server.py @mcp.resource("config://demo") def get_config() -> str: """返回 Demo 项目的示例配置。""" return "app_name=mcp-agent-demo\nmode=dev"

资源 URI 是自定义的,客户端可以通过read_resource读取。它适合暴露不常改动的元数据,比如数据库表结构、项目说明、权限说明等。

还可以注册 Prompt 模板:

# server.py @mcp.prompt() def review_code() -> str: """代码审查提示模板""" return "请以资深工程师视角,对以下代码做代码审查:{code}"

不过在实际智能体项目中,Resources 和 Prompts 的价值更多体现在“把上下文标准化”。如果你只需要工具调用能力,可以暂时不注册这两类资源。

4.4 启动 Server

在文件末尾添加启动入口:

# server.py if __name__ == "__main__": # 使用 stdio 传输,适合客户端通过子进程启动 mcp.run(transport="stdio")

直接运行:

python server.py

程序会等待标准输入,不会直接打印内容。这是因为 stdio 模式下,Server 与 Client 通过标准输入输出通信,我们需要通过客户端来验证。

5. 实战:编写 MCP Client 并调用工具

5.1 编写 Client

在项目目录下新建client.py,创建一个连接到本地server.py的客户端。

# client.py import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client # 通过 stdio 启动 server.py 子进程 server_params = StdioServerParameters( command="python", args=["server.py"], ) async def main(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 1. 初始化握手 await session.initialize() # 2. 获取工具列表 tools = await session.list_tools() print("MCP Server 暴露的工具:") for tool in tools.tools: print(f"- {tool.name}: {tool.description}") # 3. 调用工具 result = await session.call_tool("add", {"a": 3, "b": 4}) print("调用 add(3, 4) 的返回结果:", result.content) asyncio.run(main())

这段代码做了三件事:

  1. 通过stdio_client启动server.py进程。
  2. 通过ClientSession完成 MCP 握手并获取工具列表。
  3. 调用add工具验证真实调用。

需要注意,不同版本的 Python SDK 在导入路径上可能有区别。如果遇到No module named 'mcp.client.stdio',可以查一下该版本 SDK 的文档,有时客户端模块位于mcp.client.stdio,有时位于顶层。

5.2 运行与预期结果

在虚拟环境中执行:

python client.py

预期输出类似:

MCP Server 暴露的工具: - add: 计算两个整数的和。 - get_current_time: 获取指定时区的当前时间,默认返回东八区时间。 调用 add(3, 4) 的返回结果: [TextContent(text='7', type='text')]

这里result.content是一个列表,具体输出结构因 SDK 版本而异。如果你打印出来的类型不同,也不要慌,先查看官方文档或打印result的完整结构。

到这里,你已经完成了最基础的 MCP Server + Client 闭环。

5.3 在支持 MCP 的客户端产品中接入

除了自己写 Python Client,很多 AI 客户端产品也支持直接配置 MCP Server。它们通常会读取一个配置文件,内容类似:

{ "mcpServers": { "agent-demo": { "command": "python", "args": ["/absolute/path/to/server.py"] } } }

注意,这里的路径建议写成绝对路径,因为客户端进程的启动目录不一定是你执行命令的目录。

接入后,用户可以在对话框里直接让 AI “使用工具”,客户端会自动完成 MCP 的握手、工具发现和调用。对产品验证阶段来说,这种接入方式效率很高。

6. 实战:构建基于 MCP 的 AI 智能体

6.1 智能体主循环设计

有了 MCP Server 和 Client 之后,下一步就是把 LLM 加入进来,组成“能思考、能调用工具”的智能体。

一个基础智能体主循环可以拆成四步:

  1. 将用户问题放入消息列表。
  2. 让 LLM 基于当前对话和可用工具生成响应。
  3. 如果 LLM 决定调用工具,就通过 MCP Client 执行,并把结果追加到消息列表。
  4. 重复第 2 步,直到 LLM 不再调用工具,输出最终答案。

下面是一个不绑定具体 LLM SDK 的示意代码,重点是讲清楚编排逻辑:

# agent_loop.py —— 示意代码,需要结合具体 LLM SDK 调整 MAX_STEPS = 5 def run_agent(query: str, llm, mcp_client, system_prompt: str = "你是一个智能助手,必要时可以调用工具。"): messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": query}, ] # 1. 从 MCP Server 拉取工具列表,并转换成 LLM 可识别的工具 Schema tools_meta = mcp_client.list_tools() tools_schema = [tool.to_schema() for tool in tools_meta.tools] for step in range(MAX_STEPS): # 2. 调用 LLM response = llm.chat(messages=messages, tools=tools_schema) # 3. 如果没有工具调用请求,说明推理结束 if not response.tool_calls: return response.content # 4. 执行工具调用(这里假设只处理第一个工具调用) call = response.tool_calls[0] tool_result = mcp_client.call_tool(call.name, call.arguments) # 5. 把工具结果追加到历史消息中 messages.append({"role": "assistant", "content": response.content}) messages.append({ "role": "tool", "tool_call_id": call.id, "content": tool_result, }) raise RuntimeError("智能体执行步骤超过上限,请检查多轮工具调用逻辑。")

这个代码的核心思路是“把 MCP 的工具调用结果当作一条新消息喂回 LLM”。这也是当前主流 Agent 框架普遍采用的模式。

6.2 工具 Schema 的转换

不同 LLM SDK 对工具 Schema 的字段命名并不完全一致。有的要求如下结构:

{ "type": "function", "function": { "name": "add", "description": "计算两个整数的和", "parameters": { "type": "object", "properties": { "a": { "type": "integer" }, "b": { "type": "integer" } }, "required": ["a", "b"] } } }

而 MCP 返回的工具定义格式可能略有不同,所以实际开发时要做一层转换。你可以把tools_meta.tools遍历出来,提取namedescriptioninputSchema,再组装成目标 LLM 需要的格式。

这一步虽然简单,但却是最容易踩坑的地方。课程里建议:把 Schema 转换单独封装成一个函数,并补充单测。

6.3 多工具调用编排

真实场景中,智能体经常需要连续调用多个工具。例如用户问“对比 A 文件和 B 文件的字数”,智能体可能需要:

  1. 调用文件读取工具,读取 A 文件。
  2. 调用文件读取工具,读取 B 文件。
  3. 调用统计工具,计算字数。
  4. 生成对比结论。

这个流程如果交给 LLM 自动编排,主循环里需要支持“一次响应返回多个工具调用”。你的循环不能只处理tool_calls[0],而应遍历所有工具调用结果,再一次性追加到消息里。

此外,还要设置最大步数,防止智能体在复杂任务中无限循环。上面代码里的MAX_STEPS就是最小保护。

6.4 日志与可观测性

智能体的调试难度明显高于普通后端接口。建议在工具调用前后都记录日志:

[step 1] LLM 决定调用 add,参数 {"a": 3, "b": 4} [step 1] MCP 返回结果 7 [step 2] LLM 生成最终回答

这样的日志是整个链路调试的基础。后续如果要接入链路追踪、成本统计、质量评估,也需要先有结构化日志。

7. 常见问题与排查思路

下面整理了一些 MCP + AI 智能体开发中的高频问题,方便你对照排查。

问题现象常见原因排查与解决思路
工具列表为空Server 未正确注册工具,或注册代码没有执行检查@mcp.tool()装饰器,确认 Server 启动日志正常
启动client.py后没有输出stdio 模式下 Server 等待输入,或路径配置错误使用绝对路径,并手动运行python server.py验证进程不报错
调用工具提示参数解析失败函数签名未写类型注解,或参数名与 LLM 传入不一致给函数参数补全类型注解,保持参数名简洁准确
工具执行报错但客户端无感知工具内部异常被 SDK 包装,日志未打印在工具函数内捕获异常并记录日志,或先做最小复现
通过 HTTP 连接远程 Server 时鉴权失败Token 过期、Scope 不足、OAuth 配置错误检查 Token 有效期,查看 Server 日志中的鉴权信息
Agent 多轮调用后陷入死循环工具返回结果不满足 LLM 停止条件,或上下文过长设置最大步数,精简工具返回内容,增加终止判断
版本升级后原有代码不可用MCP Python SDK 版本快速迭代,接口变化阅读当前版本 changelog,锁定依赖版本

遇到问题时,优先看两个地方:一是 Server 进程的终端输出,二是 Client 打印的原始返回结构。MCP 的链路不长,大多数问题都能通过这两步定位。

8. 最佳实践与工程建议

8.1 工具设计原则

工具是智能体能力的放大器,也是风险入口。设计工具时,我建议遵循以下原则。

工具职责单一。一个工具只做一件事,不要搞“超级工具”。比如把“查询用户”“修改用户”“删除用户”写成三个工具,LLM 的选型准确率会更高。

描述尽量具体。LLM 通过描述决定是否调用工具,所以docstring要写清楚“什么时候用、会有什么副作用”。例如:

@mcp.tool() def delete_user(user_id: int) -> bool: """根据用户 ID 删除用户。请谨慎使用,执行后无法恢复。"""

参数校验要在工具内部做。不能只依赖 LLM 生成参数,工具内部必须校验边界条件。

8.2 配置与密钥管理

关于 API Key、数据库密码、Token 等敏感信息,绝对不要硬编码在server.py中。推荐使用环境变量或专门的配置中心。

# 启动前设置环境变量 export AGENT_API_KEY=your_api_key export DATABASE_URL=postgres://...

在 Server 代码里读取:

import os api_key = os.environ.get("AGENT_API_KEY") if not api_key: raise RuntimeError("AGENT_API_KEY 未设置")

涉及生产环境变更时,要坚持最小权限原则:普通查询工具只给只读权限;删除、修改、写数据库这类工单高危险操作,必须有独立的鉴权、审批和记录。

8.3 错误恢复与幂等

智能体与用户交互时,工具调用可能反复失败。你需要考虑错误恢复:

  • 工具内部捕获异常后,返回一个“结构化的错误消息”,让 LLM 知道下一步怎么办。
  • 对于发送邮件、创建订单这类操作,要设计幂等参数,比如request_id,避免重复调用产生重复数据。
  • 对耗时较长的工具,设置超时时间,避免 LLM 同步等待过久。

8.4 测试与灰度

MCP Server 本质上是一个独立服务,测试策略要跟上。

最小测试集建议覆盖:

  • 工具注册是否完整。
  • 每个工具的正常路径与异常路径。
  • 参数校验是否生效。
  • 在 Agent 循环中,工具返回结果能否被 LLM 正确理解。

上线 MCP Server 时,先在一个小范围用户群灰度,观察工具调用成功率、响应延迟和错误日志,再逐步放量。不要一上来就把所有高权限工具暴露给所有客户端。

8.5 版本锁定

MCP 生态还处于快速发展期,SDK 版本更新很快。项目里建议使用requirements.txtpoetry.lock锁定依赖版本,并定期评估升级影响。否则今天还能运行的代码,下周可能因为一个接口变更而失效。

mcp==1.0.0

等到你确认新版本兼容后,再统一升级。

9. 总结与学习路线

这篇教程从中背景讲到实战,主要覆盖了以下内容。

首先是概念层:理解了 MCP 是模型上下文协议,它和 Function Calling 是协作关系,MCP 负责统一连接和工具管理,Function Calling 负责模型侧的工具决策。

其次是实战层:从零编写了一个 MCP Server,注册了工具、资源和 Prompt;又编写了 MCP Client,完成握手、拉取工具列表、调用工具;最后设计了一个最简单的 AI 智能体主循环,让 LLM 能基于工具调用结果继续推理。

如果你准备进一步深入,可以按这个顺序拓展:

  1. 学习更多 MCP 原语:Resources 和 Prompts 的高级用法。
  2. 尝试远程 MCP Server:用 Streamable HTTP 方式部署一个远程服务,并补充鉴权。
  3. 学习 Agent 编排框架:LangGraph、Dify、Coze 等,它们已经内置了 MCP 支持。
  4. 研究 RAG 与 MCP 结合:把知识库检索封装成 MCP Tool,让智能体具备专业知识。
  5. 关注工程化落地:日志、链路追踪、测试、灰度发布、成本控制。

AI 智能体的开发方式还远没有定型,MCP 是当前最有可能成为“标配”的连接层协议。如果你也在搭建自己的智能体,建议先从小工具、小闭环开始,把 MCP Server、Agent 主循环、日志体系跑通,再逐步扩展能力。

这篇笔记就先写到这里。接下来我会继续整理 MCP 远程部署和鉴权相关的内容,如果期间遇到有代表性的问题,再来和大家分享。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询