1. 引言
TL;DR:面向 Python 开发者,从零掌握 MCP 协议,手把手搭建 MCP Server 与 Agent 客户端,完成「智能运维助手」实战,快速落地可复用的 AI Agent 工具链。
关键词:MCP AI Agent Python Streamable HTTP 工具链
随着大语言模型能力的快速提升,AI Agent 的应用场景越来越广泛。然而,模型本身无法直接访问外部数据源、调用业务系统或操作本地文件,这成为 Agent 落地的核心瓶颈。MCP(Model Context Protocol,模型上下文协议)正是为解决这一问题而诞生的开放标准。
MCP 的价值在于统一了 Agent 与外部工具、数据源的接入方式,避免为每个数据源单独开发定制化集成,让工具能力可复用、可共享、可跨平台迁移。基于这套标准,开发者只需实现一次工具接入,即可被任意支持 MCP 的 AI 应用复用,大幅降低集成成本。
本文将从零开始,手把手带你搭建一套基于 MCP 的 AI Agent 工具链,涵盖协议原理、服务端开发、客户端接入与实战案例,帮助你快速掌握这一关键技术的落地方法。
2. MCP 协议核心概念
2.1 什么是 MCP
MCP 是一种基于 JSON-RPC 2.0 的开放协议,定义了 AI 应用(Host)与外部工具/数据源(Server)之间的标准化通信方式。
2.2 核心角色
-
Host:AI 应用主体,如 Claude Desktop、自研 Agent 框架
-
Client:与 Server 建立连接的协议客户端
-
Server:暴露工具、资源和提示词的服务端### 2.3 三大核心原语
-
Tools(工具):可被模型调用的函数,如查询天气、操作数据库
-
Resources(资源):可被读取的数据,如文件内容、API 返回
-
Prompts(提示词):可复用的提示模板
2.4 通信机制
- 基于 JSON-RPC 2.0 的消息格式
- 支持 stdio 与 Streamable HTTP 两种传输方式
- 会话初始化与能力协商流程
3. 开发环境准备
3.1 技术栈选型
- 语言:Python 3.10+(本文以 Python 为例)
- 官方 SDK:mcp Python SDK
- 框架:FastAPI(用于 HTTP 传输)
3.2 环境搭建
# 创建虚拟环境
python -m venv .venv
source .venv/bin/activate
# 安装 MCP SDK
pip install mcp
# 安装 FastAPI(HTTP 传输需要)
pip install "mcp[fastapi]"
3.3 项目结构规划
mcp-agent-toolchain/
├── server/
│ ├── __init__.py
│ ├── main.py # 服务端入口
│ ├── tools/ # 工具定义
│ └── resources/ # 资源定义
├── client/
│ ├── __init__.py
│ └── agent.py # Agent 客户端
└── tests/
4. 开发第一个 MCP Server
4.1 最小服务端实现
# 导入 MCP Server 核心类,用于创建服务端实例
from mcp.server import Server
# 导入 stdio 传输层,负责通过标准输入/输出与客户端通信
from mcp.server.stdio import stdio_server
# 创建 MCP Server 实例,参数 "demo-server" 是服务端名称,用于标识和日志记录
app = Server("demo-server")
# @app.list_tools() 装饰器注册"工具列表"处理器
# 当客户端调用 list_tools 请求时,MCP 框架会自动调用此函数
@app.list_tools()
async def list_tools():
# 返回工具定义列表,每个工具是一个字典,包含三个关键字段:
return [
{
"name": "get_time", # 工具名称,客户端通过它来调用
"description": "获取当前时间", # 工具描述,LLM 据此判断何时调用
"inputSchema": { # 输入参数 Schema,定义工具接受的参数结构
"type": "object", # 参数必须是 JSON 对象
"properties": {}, # 该工具无参数,所以属性为空
},
}
]
# @app.call_tool() 装饰器注册"工具调用"处理器
# 当客户端请求调用某个工具时,MCP 框架会调用此函数
@app.call_tool()
async def call_tool(name: str, arguments: dict):
# name 参数:客户端请求调用的工具名称
# arguments 参数:客户端传入的工具参数(字典形式)
if name == "get_time":
# 延迟导入 datetime,避免模块加载时的额外开销
from datetime import datetime
# 返回 MCP 标准格式的结果,content 是内容列表
# 每个内容项需指定 type(text 表示文本)和 text(实际内容)
return {"content": [{"type": "text", "text": str(datetime.now())}]}
# 定义服务端主入口函数
async def main():
# 使用 async with 打开 stdio 传输通道
# read 是读取客户端消息的流,write 是向客户端发送消息的流
async with stdio_server() as (read, write):
# 启动 MCP Server 主循环,监听并处理来自客户端的请求
await app.run(read, write)
# 当脚本被直接执行时(而非被导入),运行主函数
if __name__ == "__main__":
import asyncio
# 使用 asyncio.run 启动异步事件循环,运行 main() 协程
asyncio.run(main())
4.2 运行与验证
python server/main.py
4.3 工具注册进阶
- 使用 @app.tool() 装饰器简化注册
- 定义带参数的复杂工具
- 返回结构化数据
5. 构建 Agent 客户端
5.1 客户端连接
from mcp.client.stdio import stdio_client
from mcp import ClientSession
async def connect_to_server():
server_params = {"command": "python", "args": ["server/main.py"]}
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
return session
5.2 工具发现与调用
- 通过 session.list_tools() 获取工具列表
- 通过 session.call_tool() 调用工具
- 处理工具返回结果
5.3 与 LLM 集成
- 将工具列表转换为 LLM 可识别的 function calling 格式
- 模型决策 → 工具调用 → 结果回填的完整循环
6. 实战:搭建完整工具链
6.1 场景设计
构建一个「智能运维助手」,集成以下能力:
- 查询服务器状态
- 读取日志文件
- 执行简单运维命令
6.2 服务端实现
# @app.tool() 装饰器是 MCP 框架提供的便捷注册方式
# 它会自动将函数转换为 MCP 工具,并根据函数签名生成 inputSchema
@app.tool()
async def check_server_status(host: str) –> str:
"""检查服务器状态"""
# 模拟检查逻辑:实际项目中可替换为真实的 SSH 连接、ping 或 API 调用
# 返回字符串会被 MCP 自动包装为标准响应格式
return f"服务器 {host} 运行正常,CPU 使用率 23%"
# 注册第二个工具:读取日志文件
# 函数参数 file_path 和 lines 会自动映射为工具的输入 Schema
@app.tool()
async def read_log(file_path: str, lines: int = 50) –> str:
"""读取日志文件末尾 N 行"""
# 使用 with 语句安全打开文件,确保文件使用后自动关闭
with open(file_path, "r") as f:
# readlines() 读取所有行,[-lines:] 切片取最后 N 行
content = f.readlines()[–lines:]
# 将行列表拼接为单个字符串返回
return "".join(content)
6.3 客户端 Agent 实现
async def run_agent(session: ClientSession, query: str):
tools = await session.list_tools()
# 将 MCP 工具转换为 LLM function calling 格式
functions = [
{
"name": t.name,
"description": t.description,
"parameters": t.inputSchema,
}
for t in tools.tools
]
# 调用 LLM 进行决策(此处以伪代码示意)
response = await llm.chat(query, functions=functions)
# 执行工具调用
if response.tool_calls:
for call in response.tool_calls:
result = await session.call_tool(call.name, call.arguments)
print(f"工具 {call.name} 返回: {result}")
6.4 完整流程演示
#mermaid-svg-KPH2JaN1a5EblGYQ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-KPH2JaN1a5EblGYQ .error-icon{fill:#552222;}#mermaid-svg-KPH2JaN1a5EblGYQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-KPH2JaN1a5EblGYQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-KPH2JaN1a5EblGYQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-KPH2JaN1a5EblGYQ .marker.cross{stroke:#333333;}#mermaid-svg-KPH2JaN1a5EblGYQ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-KPH2JaN1a5EblGYQ p{margin:0;}#mermaid-svg-KPH2JaN1a5EblGYQ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster-label text{fill:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster-label span{color:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster-label span p{background-color:transparent;}#mermaid-svg-KPH2JaN1a5EblGYQ .label text,#mermaid-svg-KPH2JaN1a5EblGYQ span{fill:#333;color:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ .node rect,#mermaid-svg-KPH2JaN1a5EblGYQ .node circle,#mermaid-svg-KPH2JaN1a5EblGYQ .node ellipse,#mermaid-svg-KPH2JaN1a5EblGYQ .node polygon,#mermaid-svg-KPH2JaN1a5EblGYQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-KPH2JaN1a5EblGYQ .rough-node .label text,#mermaid-svg-KPH2JaN1a5EblGYQ .node .label text,#mermaid-svg-KPH2JaN1a5EblGYQ .image-shape .label,#mermaid-svg-KPH2JaN1a5EblGYQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-KPH2JaN1a5EblGYQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-KPH2JaN1a5EblGYQ .rough-node .label,#mermaid-svg-KPH2JaN1a5EblGYQ .node .label,#mermaid-svg-KPH2JaN1a5EblGYQ .image-shape .label,#mermaid-svg-KPH2JaN1a5EblGYQ .icon-shape .label{text-align:center;}#mermaid-svg-KPH2JaN1a5EblGYQ .node.clickable{cursor:pointer;}#mermaid-svg-KPH2JaN1a5EblGYQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-KPH2JaN1a5EblGYQ .arrowheadPath{fill:#333333;}#mermaid-svg-KPH2JaN1a5EblGYQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-KPH2JaN1a5EblGYQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-KPH2JaN1a5EblGYQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KPH2JaN1a5EblGYQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-KPH2JaN1a5EblGYQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KPH2JaN1a5EblGYQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster text{fill:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ .cluster span{color:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-KPH2JaN1a5EblGYQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-KPH2JaN1a5EblGYQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-KPH2JaN1a5EblGYQ .icon-shape,#mermaid-svg-KPH2JaN1a5EblGYQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-KPH2JaN1a5EblGYQ .icon-shape p,#mermaid-svg-KPH2JaN1a5EblGYQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-KPH2JaN1a5EblGYQ .icon-shape .label rect,#mermaid-svg-KPH2JaN1a5EblGYQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-KPH2JaN1a5EblGYQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-KPH2JaN1a5EblGYQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-KPH2JaN1a5EblGYQ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
是
否
用户输入问题
LLM 决策
需要调用工具?
MCP Client 调用 Server
工具执行并返回结果
结果回填给 LLM
生成最终回答
7. 进阶:Streamable HTTP 传输
7.1 为什么需要 HTTP 传输
- 支持远程部署与跨网络调用
- 便于与现有 Web 服务集成
- 支持多客户端并发访问
7.2 服务端改造
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("remote-server")
@mcp.tool()
def get_weather(city: str) –> str:
"""查询城市天气"""
return f"{city} 今天晴,25°C"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
7.3 客户端连接
from mcp.client.streamable_http import streamable_http_client
async with streamable_http_client("http://localhost:8000/mcp") as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
8. 安全与最佳实践
8.1 安全注意事项
- 工具权限最小化原则
- 输入校验与参数白名单
- 敏感操作需二次确认
- 日志脱敏处理
8.2 开发最佳实践
- 工具命名规范统一
- 为每个工具编写清晰描述
- 合理设计输入 Schema
- 做好错误处理与超时控制
8.3 性能优化
- 连接复用与长连接
- 工具结果缓存
- 异步并发调用
9. 总结与展望
9.1 本文回顾
- 理解了 MCP 协议的核心概念与通信机制
- 从零实现了 MCP Server 与 Client
- 搭建了完整的 AI Agent 工具链
- 掌握了 HTTP 传输与安全实践
9.2 未来方向
- 探索 MCP 在更多场景的应用
- 关注协议版本演进与新特性
- 构建更复杂的多 Server 协作架构
10. 参考资料
- MCP 官方文档:MCP 协议的官方站点,包含协议规范、架构说明与各语言 SDK 的权威指南。
- MCP Python SDK 文档:MCP 官方 Python SDK 源码与使用说明,覆盖 Server、Client 及多种传输方式的实现细节。
- JSON-RPC 2.0 规范:MCP 底层消息格式所遵循的 JSON-RPC 2.0 官方规范,帮助理解请求、响应与错误对象的结构。
- Anthropic MCP 介绍:MCP 协议发布时的官方技术博客,阐述其设计动机与生态愿景。
- Model Context Protocol 入门指南:面向初学者的快速上手教程,从概念到第一个 Server 的完整引导。
网硕互联帮助中心





评论前必须登录!
注册