Tool 解决的是"把一个函数暴露给模型调用"。
MCP 解决的是更大一层的问题:把一组工具、资源和提示词,封装成一个标准服务,让不同 Agent 都能接入。
MCP 全称是 Model Context Protocol,可以理解成 Agent 使用外部能力的一套统一协议。

图里的关系可以这样理解:
txt
Agent / MCP Client -> MCP 协议 -> MCP Server -> Tools / Resources / Prompts
所以 MCP 不是单个 Tool,而是 Tool 的集合,也可以包含资料和提示词模板。
这一篇主要看这些内容:
txt
MCP 是什么
-> MCP 和 Tool 的关系
-> MCP Server 的结构
-> 注册 Tool
-> 注册 Resource
-> 注册 Prompt
-> stdio / HTTP 两种接入
-> 在 Agent 中使用 MCP
先记住一句话:Tool 是一个能力,MCP Server 是一组能力的标准化服务。
MCP 解决什么问题
如果每个 Agent 都用自己的方式接入工具,会出现很多重复工作:
- 工具参数格式不统一。
- 本地工具和远程工具接入方式不同。
- 不同语言写的工具难以复用。
- IDE、Agent、脚本都要单独适配一遍。
MCP 的价值就是把这些能力标准化。
只要一个服务遵守 MCP 协议,客户端就可以发现它提供了哪些工具、资源和提示词,并按统一方式调用。
txt
没有 MCP:每个 Agent 自己适配每个工具
有 MCP:工具封装成 MCP Server,Agent 按协议接入
这很像 AI 时代的"插件协议"。
MCP 和 Tool 的关系
普通 Tool 通常是在当前进程里定义,并直接绑定给模型。
MCP 则把工具放到一个独立服务里。
txt
Tool:一个可调用函数
MCP Server:一组 Tool / Resource / Prompt
MCP Client:连接 MCP Server,并把能力交给 Agent 使用
MCP 最大的特点是跨进程调用。
- 本地进程:通常用
stdio。 - 远程服务:通常用 HTTP / Streamable HTTP / SSE。
也就是说,Agent 不需要关心工具是用 TypeScript、Python 还是其他语言写的。
只要它是 MCP Server,就可以通过 MCP Client 接入。
MCP Server 的开发流程
开发一个 MCP Server,通常是这个顺序:
txt
1. 创建 MCP Server
2. 注册 Tool
3. 注册 Resource
4. 注册 Prompt
5. 选择传输方式
6. 启动服务
其中 Tool 最常用,Resource 和 Prompt 是可选能力。
创建 MCP Server
Python SDK 里可以用 FastMCP 快速创建 MCP Server。
python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("time-helper")
FastMCP 负责管理这个服务暴露出来的能力。
接下来要把工具、资源、提示词注册到这个 server 上。
注册 Tool
Tool 是 MCP 最核心的能力。
下面把"查询当前时间"这个普通工具,组装成 MCP Tool。
python
from datetime import datetime
from typing import Annotated
from zoneinfo import ZoneInfo
from pydantic import Field
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("time-helper")
@mcp.tool()
def get_current_time(
time_zone: Annotated[
str,
Field(description="IANA 时区名称,例如 Asia/Shanghai"),
],
) -> str:
"""查询指定时区的当前日期和时间。"""
# 真正执行的逻辑仍然是普通代码
current_time = datetime.now(ZoneInfo(time_zone))
return f"{time_zone} 当前时间:{current_time:%Y-%m-%d %H:%M:%S %Z}"
Tool 的关键点:
- 函数名通常会成为工具名。
- docstring 通常会成为工具描述,用来帮助模型判断什么时候调用这个工具。
- 类型标注和
Field(description=...)会帮助 MCP 生成参数 schema,用来约束模型怎么填写参数。 - 工具描述和参数 schema 都会影响模型判断,区别是前者更偏"要不要用",后者更偏"怎么用"。
- 函数体负责真正执行逻辑。
- 返回值会作为工具结果交给客户端。
注册 Resource
Resource 用来提供可读取的资料。
它不是让模型"执行动作",而是给模型一份内容。
python
@mcp.resource("docs://time-zone-guide")
def time_zone_guide() -> str:
"""常见时区名称说明。"""
# Resource 返回可读取内容
return "常见 IANA 时区:Asia/Shanghai、UTC、America/New_York、Europe/London。"
Resource 适合放:
- 使用指南。
- 配置说明。
- 项目规范。
- 不需要执行、只需要读取的上下文资料。
注册 Prompt
Prompt 是预设对话模板。
它可以让 MCP Server 给客户端提供一套可复用提示词。
python
@mcp.prompt()
def explain_current_time(time_zone: str) -> str:
"""生成当前时间查询提示词。"""
# Prompt 返回一段可复用任务说明
return f"请查询 {time_zone} 的当前时间,并用一句话说明这个时间属于哪个时区。"
Prompt 适合封装固定任务模板,例如:
- 代码解释模板。
- 文档生成模板。
- 查询报告模板。
- 业务问答模板。
Tool / Resource / Prompt 的区别
三者都能暴露给 MCP Client,但用途不同。
txt
Tool:执行动作,返回执行结果
Resource:提供资料,返回可读取内容
Prompt:提供提示词模板,返回消息模板
简单判断:
- 需要查数据库、调用接口、读文件:用 Tool。
- 需要提供文档、配置、规范:用 Resource。
- 需要复用一段任务说明:用 Prompt。
启动 stdio 服务
本地 MCP Server 通常使用 stdio。
stdio 的意思是:客户端启动这个进程,然后通过标准输入输出和它通信。
python
if __name__ == "__main__":
# stdio 适合本地 MCP Client 启动当前 Python 进程
mcp.run(transport="stdio")
本地开发工具、IDE、桌面 Agent 经常用这种方式接入 MCP。
在 IDE 中使用 MCP
MCP Server 启动后,可以被 IDE 或 Agent 客户端加载。
这里以 Cursor 为例。
打开 Cursor 设置,进入 Tools & MCPs,点击 New MCP Server。

然后在配置文件里加入自己的 MCP Server。
我们前面写的 time-helper 是一个本地 MCP Server,所以配置里不是写 URL,而是告诉 Cursor:用什么命令启动这个本地进程。
json
{
"mcpServers": {
"time-helper": {
"command": "uv",
"args": [
"--directory",
"/Users/copyer/Documents/copyer_code/project/python/python-agent",
"run",
"python",
"-m",
"app.mcp_examples.time_server"
]
}
}
}
这段配置的意思是:
txt
time-helper:MCP Server 的名字
command:用什么命令启动
args:启动命令的参数
--directory:进入项目目录
python -m app.mcp_examples.time_server:启动 MCP Server 模块

上面采用 uv 启动 Python 项目。也可以根据项目形态换成其他命令:
txt
Python 文件:command 可以是 python
uv 项目:command 可以是 uv
Node.js 文件:command 可以是 node
npm 包:command 可以是 npx
远程服务:通常配置 url 和 headers

从图里可以看到,Cursor 不只是识别到了一个工具,还识别到了这个 MCP Server 暴露的 prompt 和 resource。
这也是 MCP 比单个 Tool 更像"能力包"的原因。
使用远程 MCP
除了本地 stdio,MCP 也可以连接远程服务。
先区分两个容易混淆的概念:
txt
第三方 MCP:别人提供的 MCP Server
远程 MCP:通过 URL 连接的 MCP Server
第三方 MCP 不一定是远程 MCP。
比如截图里的 amap-maps,虽然它是高德提供的第三方 MCP,但配置方式是 npx,本质上还是 Cursor 启动了一个本地进程。
而 context7 这种配置里直接写 url 和 headers 的,才是典型的远程 MCP。
远程 MCP 的配置通常长这样:
json
{
"mcpServers": {
"context7": {
"url": "https://mcp.context7.com/mcp",
"headers": {
"CONTEXT7_API_KEY": "你的 API Key"
}
}
}
}
这类配置不需要 Cursor 在本地启动脚本,而是直接通过 HTTP 连接已经部署好的 MCP Server。
本地和远程的区别主要在传输层:
txt
stdio:启动本地进程,适合本地文件、脚本、数据库
HTTP:连接远程服务,适合云端 API、托管服务、团队共享服务
Python SDK 的 FastMCP 也可以用 HTTP 方式启动:
python
if __name__ == "__main__":
# streamable-http 适合把 MCP Server 作为远程服务暴露
mcp.run(transport="streamable-http")
实际项目里,如果 MCP Server 需要被多人或多个 IDE 共用,才更适合部署成远程服务。
如果只是本机开发、读取本地文件、调用本地脚本,stdio 会更简单。
用 Python Client 调用 MCP
也可以直接在 Python 代码里连接 MCP Server,列出工具、资源、提示词并调用。
python
import asyncio
from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client
async def main() -> None:
server_params = StdioServerParameters(
command="uv",
args=[
"--directory",
"/Users/copyer/Documents/copyer_code/project/python/python-agent",
"run",
"python",
"-m",
"app.mcp_examples.time_server",
],
)
# 1. 通过 stdio 启动并连接 MCP Server
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 2. 初始化会话
await session.initialize()
# 3. 查看服务提供了哪些工具
tools = await session.list_tools()
print([tool.name for tool in tools.tools])
# 4. 调用工具
result = await session.call_tool(
"get_current_time",
arguments={"time": "Asia/Shanghai"},
)
print(result.content)
asyncio.run(main())
这段代码里,Python 程序扮演的是 MCP Client。
它通过 stdio 启动 MCP Server,然后按协议调用工具。
小结
这一篇要记住几个核心点:
- MCP 是 Agent 使用外部能力的统一协议。
- Tool 是单个能力,MCP Server 是一组能力的标准化服务。
- MCP Server 可以暴露 Tool、Resource、Prompt。
- Tool 用来执行动作,Resource 用来提供资料,Prompt 用来提供模板。
- 本地 MCP 常用 stdio,远程 MCP 常用 HTTP。
- Python 里可以用
FastMCP快速创建 MCP Server。 - MCP 的价值是复用和标准化,让不同 Agent 都能接入同一组能力。