MCP(四):Python 实战 + MCP 调用原理(Java 开发者视角)
前面三篇,我已经把 MCP 的认知和底层原理拆清楚了:
- MCP 是什么
- MCP 的运行流程
- 为什么 LLM 会调用 MCP Tool
但如果只停留在理解层面,其实没有意义。
作为开发者,我必须真正写一个 MCP,才算真正掌握。
这一篇,我会做两件事:
- 用 Python 开发一个最小 MCP Server
- 用 Python 模拟 Client 调用 MCP
虽然我本身是 Java 开发者,但我发现:
只要理解了 Python 版本的运行机制,我就能很容易迁移到 Java。
因为:
MCP 的核心是协议思想,而不是语言。
一、这一篇到底要解决什么?
很多教程的问题是:
- 上来就贴代码
- 但根本不知道代码为什么这么写
所以这一篇,我不会只讲“怎么写”,还会讲:
每一行代码在 MCP 体系里到底对应什么角色。
二、先明确 MCP 开发的本质
一句话:
MCP 开发,本质就是“把普通函数暴露成 AI 可调用能力”
例如:
def get_weather(city):
return "晴天"
普通函数只能被程序调用。
但 MCP 做了一件事:
把它变成“LLM 可以发现和调用的 Tool”
三、MCP 的整体结构(必须先理解)
我先把完整链路画出来:
LLM
↓
MCP Client
↓
MCP Server
↓
Tool(Python函数)
每层在干什么?
| 层级 | 作用 |
|---|---|
| LLM | 决定调用什么 |
| MCP Client | 发送请求 |
| MCP Server | 管理 Tool |
| Tool | 真正执行逻辑 |
四、开始开发:安装 MCP SDK
先安装 Python SDK:
pip install mcp
五、开发第一个 MCP Server(核心)
1. 创建 server.py
from mcp.server import Server
server = Server("weather-server")
这一段在做什么?
这里不是简单创建对象。
而是在做:
启动一个“能力服务”
此时 Server 内部会维护:
- Tool 列表
- Tool Schema
- 请求路由
六、注册第一个 Tool
@server.tool()
def get_weather(city: str) -> str:
"""根据城市查询天气"""
return f"{city}今天晴天,25度"
七、这里到底发生了什么?(重点)
很多人会觉得:
“不就是一个装饰器吗?”
但实际上:
这一行是整个 MCP 的核心。
MCP 内部做了什么?
1. 收集函数信息
MCP 会自动读取:
- 函数名
- 参数类型
- 返回值类型
- docstring
2. 自动生成 Tool Schema
类似:
{
"name": "get_weather",
"description": "根据城市查询天气",
"parameters": {
"city": "string"
}
}
3. Tool 注册到 Server
Server 内部会维护:
Tool Name -> Python Function
类似:
get_weather -> 内存地址
八、为什么 LLM 后面能调用它?
这里终于进入核心。
注意:
LLM 从来没有“看到 Python 代码”
它看到的只有:
{
"name": "get_weather",
"description": "根据城市查询天气"
}
本质是什么?
Tool 被“翻译成文本描述”
然后:
- Client 会把这些 Tool 信息塞进 Prompt
- LLM 再决定是否调用
九、启动 MCP Server
if __name__ == "__main__":
server.run()
十、server.run() 到底干了什么?
很多教程不会讲这一层,但这一层非常关键。
本质上:
server.run() 启动了一个 MCP 通信服务
它会:
- 等待 Client 请求
- 接收 Tool 调用
- 分发到对应 Python 函数
类比 Java
如果我是 Java 开发者,我可以这样理解:
SpringBoot Controller
↓
接收 HTTP 请求
↓
调用 Service
MCP Server 本质类似:
MCP Request
↓
Tool Router
↓
Python Function
十一、开始开发 MCP Client
现在我再写一个 Client。
创建 client.py
from mcp.client import Client
client = Client("demo-client")
连接 MCP Server
client.connect("http://localhost:8000")
十二、连接时到底发生了什么?
这里不是简单 TCP 连接。
实际上:
Client 会开始“能力发现”
它会请求:
请告诉我你有哪些 Tool
Server 返回:
[
{
"name": "get_weather",
"description": "根据城市查询天气"
}
]
十三、LLM 为什么知道调用哪个 Tool?
现在:
- 用户输入:
帮我查一下北京天气
Client 会构造 Prompt:
你可以使用以下工具:
工具:
get_weather
作用:根据城市查询天气
然后 LLM 推理:
它发现:
- “天气”
- “get_weather”
高度匹配。
于是输出:
{
"tool": "get_weather",
"arguments": {
"city": "北京"
}
}
十四、为什么参数是 JSON?
因为:
Tool Schema 已经提前定义了参数结构。
例如:
{
"city": "string"
}
LLM 本质是在:
“按 Schema 填空”
而不是:
“凭空创造 JSON”
十五、Client 如何真正调用 Tool?
现在 Client 拿到:
{
"tool": "get_weather",
"arguments": {
"city": "北京"
}
}
Client 会做什么?
1. 解析 JSON
2. 发送 MCP 请求
类似:
调用 get_weather
参数 city=北京
Server 收到后:
根据:
get_weather -> Python函数
找到真实函数:
get_weather("北京")
十六、最终结果怎么回到 LLM?
Tool 返回:
北京今天晴天,25度
Client 再把结果塞回 Prompt:
工具返回:
北京今天晴天,25度
然后 LLM 再生成最终回答:
北京今天天气晴朗,气温25度。
十七、如果我是 Java 开发者,该怎么理解?
这一段非常重要。
很多 Java 开发者看到 Python 会慌。
但实际上:
MCP 和语言关系不大。
Java 对应关系
| MCP Python | Java 思维 |
|---|---|
| Tool | Service 方法 |
| Server | SpringBoot 服务 |
| Schema | DTO / JSON Schema |
| Client | Feign / SDK |
| Tool Router | Dispatcher |
本质上:
MCP 就是“AI 时代的 RPC/接口调用系统”
十八、真正重要的收获(不是代码)
这一篇最重要的不是:
- 会不会写 Python
而是:
我终于理解了 MCP 的本质机制。
MCP 真正做的事情
1. 把函数暴露成 Tool
2. 把 Tool 转成文本描述
3. 把文本描述交给 LLM
4. LLM 输出结构化调用
5. Client 转换成真实函数执行
十九、总结
我把这一篇压缩成一句话:
MCP 本质是“函数调用”和“自然语言”之间的翻译层
更多推荐


所有评论(0)