你有没有遇到过这种场景:AI 聊天很厉害,但它碰不到你的数据。让它「帮我看看这个目录里哪些文件超过 100MB」,它只能回答「我无法直接访问你的文件系统」。
MCP(Model Context Protocol,模型上下文协议)就是为了解决这个问题诞生的。它是 Anthropic 2024 年底开源的一个开放协议,现在已经是 AI 工具链的事实标准------Claude、Cursor、VS Code、各种 IDE 和 Agent 框架都原生支持。
这篇文章用最少的代码,带你从零起一个 MCP Server,再把它接进 AI Client,最后用一个真实场景展示「把工具变成 AI 能力」到底是什么意思。
一、MCP 是什么?用一句话说清楚
MCP 是「AI 应用和外部工具之间的统一接口协议」。它定义了三种核心能力:
- Tools(工具):AI 可以调用的函数,比如「查询数据库」「读写文件」「调用 HTTP API」
- Resources(资源):AI 可以读取的数据,比如「某个配置文件的当前内容」
- Prompts(提示词模板):AI 可以复用的指令模板
你只需要把你的能力包成一个 MCP Server,任何支持 MCP 的 Client(Claude Desktop、Cursor、自建的 Agent)都能直接调用它。这就是「Write once, run everywhere」------一次开发,处处可用。
对比一下传统方式:
arduino
传统方式:每个 Client 都要单独写插件/适配器 → N 个 Client × M 个工具 = N*M 份代码
MCP 方式:每个工具做成 MCP Server → M 个 Server,所有 Client 通用
二、环境准备
本文示例用 Python,需要 Python 3.10+。
bash
# 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate
# 安装官方 SDK
pip install mcp
# 验证安装
python -c "import mcp; print(mcp.__version__)"
官方 SDK 现在支持两种传输方式:
- stdio:Client 启动 Server 进程,通过标准输入输出通信(适合本地工具)
- Streamable HTTP:Server 作为 HTTP 服务部署(适合远程服务、团队共享)
三、10 分钟起一个 MCP Server

我们从最简单的例子开始:做一个「文件大小统计工具」。它接收一个目录路径,返回目录下各文件的体积排行。
python
# file_size_server.py
from mcp.server.fastmcp import FastMCP
import os
# 创建一个 MCP Server,命名为 file-tools
mcp = FastMCP("file-tools")
@mcp.tool()
def list_large_files(directory: str, min_size_mb: float = 10) -> str:
"""列出目录下超过指定大小(MB)的文件,按大小降序排列。
Args:
directory: 要扫描的目录绝对路径
min_size_mb: 最小文件大小阈值,单位 MB,默认 10
"""
results = []
for root, dirs, files in os.walk(directory):
# 跳过常见的无关目录
dirs[:] = [d for d in dirs if d not in {".git", "node_modules", ".venv", "__pycache__", "venv"}]
for name in files:
path = os.path.join(root, name)
try:
size = os.path.getsize(path)
except OSError:
continue
if size >= min_size_mb * 1024 * 1024:
results.append((size, path))
results.sort(reverse=True)
if not results:
return "没有找到超过阈值的大文件。"
lines = [f"共找到 {len(results)} 个超过 {min_size_mb}MB 的文件:"]
for size, path in results[:20]:
lines.append(f" {size / 1024 / 1024:.1f} MB {path}")
return "\n".join(lines)
if __name__ == "__main__":
mcp.run(transport="stdio")
就这么多。核心是 @mcp.tool() 装饰器------你的函数签名(参数名、类型、docstring)会自动变成 AI 可以理解的工具描述。这也体现了 MCP 的设计哲学:函数即工具,文档即提示词。
跑起来试试:
bash
python file_size_server.py
程序会阻塞等待输入,说明 Server 已经就绪。
四、写一个 Client 调用它
现在写一个 Client,通过 MCP 协议和这个 Server 通信:
python
# client.py
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def main():
# 指定要启动的 Server
server_params = StdioServerParameters(
command="python",
args=["file_size_server.py"],
cwd=".", # Server 的工作目录
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 1. 初始化握手
await session.initialize()
# 2. 列出 Server 暴露的工具
tools = await session.list_tools()
print("可用工具:", [t.name for t in tools.tools])
# 3. 调用工具
result = await session.call_tool(
"list_large_files",
{"directory": "/path/to/your/project", "min_size_mb": 5},
)
# 解析返回
for content in result.content:
if content.type == "text":
print(content.text)
asyncio.run(main())
运行:
bash
python client.py
你会看到输出:
lua
可用工具: ['list_large_files']
共找到 3 个超过 5MB 的文件:
128.4 MB /path/to/your/project/backup.sql
56.2 MB /path/to/your/project/logs/app.log
12.7 MB /path/to/your/project/model.bin
到这里,一个完整的 MCP 闭环就跑通了:Client 通过协议发现工具 → 根据 AI 生成参数调用工具 → 拿到结构化结果。
五、真实场景:把「数据库查询」变成 AI 能力

文件操作只是热身。MCP 真正的价值在于把你的业务系统接进 AI。我们做一个「只读数据库查询」工具------注意加权限边界,只暴露 SELECT,杜绝 AI 乱写库的风险:
python
# db_server.py
from mcp.server.fastmcp import FastMCP
import sqlite3
mcp = FastMCP("readonly-db")
DB_PATH = "app.db"
@mcp.tool()
def query_database(sql: str, limit: int = 20) -> str:
"""对业务数据库执行只读查询。只允许 SELECT 开头的语句,自动限制返回行数。
Args:
sql: 要执行的 SQL 语句,必须以 SELECT 开头
limit: 最多返回的行数,默认 20
"""
sql = sql.strip().rstrip(";")
if not sql.upper().startswith("SELECT"):
return "错误:只允许 SELECT 查询,拒绝执行。"
# 强制加 LIMIT,防止 AI 拉全表
if "LIMIT" not in sql.upper():
sql += f" LIMIT {int(limit)}"
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
try:
rows = conn.execute(sql).fetchall()
if not rows:
return "查询无结果。"
cols = list(rows[0].keys())
header = " | ".join(cols)
lines = [header, "-" * len(header)]
for row in rows:
lines.append(" | ".join(str(row[c]) for c in cols))
return "\n".join(lines)
except Exception as e:
return f"查询失败: {e}"
finally:
conn.close()
@mcp.resource("db://schema")
def db_schema() -> str:
"""返回数据库全部表结构,帮助 AI 生成正确的查询。"""
conn = sqlite3.connect(DB_PATH)
try:
tables = conn.execute(
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
).fetchall()
parts = []
for (tname,) in tables:
cols = conn.execute(f"PRAGMA table_info({tname})").fetchall()
parts.append(
f"表 {tname}: " + ", ".join(f"{c[1]} ({c[2]})" for c in cols)
)
return "\n".join(parts)
finally:
conn.close()
if __name__ == "__main__":
mcp.run(transport="stdio")
这里有两个关键设计:
@mcp.resource():暴露一个「数据库 Schema」资源。AI 在写查询前会先读这个资源,了解有哪些表和字段,生成正确 SQL 的概率大幅提升。- 安全护栏 :只允许 SELECT、强制 LIMIT、异常兜底。让 AI 有权限之前,先想清楚它做错事的后果。
接进 Claude Desktop 的配置文件(claude_desktop_config.json):
json
{
"mcpServers": {
"readonly-db": {
"command": "python",
"args": ["/absolute/path/to/db_server.py"]
}
}
}
配置好后,你可以在对话里直接说:「帮我看看这个月新增了多少用户」「按地区统计一下订单量」,AI 会自己读 Schema、写 SQL、执行查询、把结果整理成自然语言回复。
六、进阶:Streamable HTTP 部署

如果工具要被多个 Agent 或团队共享,用 stdio 就不够了。改成 HTTP 部署只需要一行:
python
if __name__ == "__main__":
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)
启动后,任何远程 Client 都可以通过 http://your-server:8000/mcp 端点接入。适合把「公司内部 API」「统一知识库」这类服务做成 MCP,让不同 Agent 复用同一套工具。
七、踩坑与调试经验
我在接入过程中踩了不少坑,挑几个有代表性的:
坑 1:docstring 就是工具说明书
MCP 会把函数的 docstring 作为工具描述传给 AI。参数说明写得越清楚,AI 调对的概率越高。我一开始写的是 directory: 目录,AI 经常传相对路径导致找不到文件。改成「目录绝对路径」之后,几乎没再错过。
坑 2:streaming 模式下输出别乱 print
stdio 模式下,print() 会污染和 Client 的通信通道。调试信息要用 logging 模块输出到 stderr,不要直接 print 到 stdout。血泪教训:曾经有个 Server 一切正常但 Client 一直报协议错误,查了半天是残留的 print。
坑 3:权限边界不是可选项
只读工具(SELECT/GET)和只写工具(INSERT/POST)要分开成不同的 Server。给 AI 最小权限,出问题时损失也最小。我见过直接把「删除文件」工具暴露给 Agent 的配置,只能说胆大。
坑 4:Windows 路径注意转义
在 Windows 上配 claude_desktop_config.json 时,路径里的反斜杠要写成双反斜杠,否则 JSON 解析直接失败。
坑 5:超时和重试要设计好
MCP 调用是网络交互,AI 生成参数、传输、执行、返回,每一步都可能慢。如果你的工具本身要跑几十秒(比如大数据量查询),Client 侧要设置合理超时,Server 侧要支持幂等重试。我第一次做「批量文件处理」工具时没考虑这一点,AI 连续三次调用都超时,用户以为工具坏了------其实只是单次执行太久。后来我把长任务拆成「提交任务 + 查询状态」两步,问题就解决了。
坑 6:工具数量和调用顺序
工具不是越多越好。MCP Server 暴露 20 个工具,AI 的「选择困难症」会明显加重,调用出错率上升。我的经验是:一个 Server 聚焦一类能力,暴露 3~5 个精心设计的工具,比塞进去 20 个「能用但边界模糊」的工具效果好得多。这和写代码是一样的道理------接口越小,越不容易用错。
坑 7:日志和可观测性
MCP Server 跑在后台,出问题时你往往看不到现场。建议从一开始就接入日志:记录每次工具调用的入参、出参、耗时、错误。这不仅是排查问题的依据,也是你优化工具描述(让 AI 更少出错)的数据来源。我现在每个 Server 都带一个 @mcp.tool() 的 health_check,AI 或者运维随时可以确认服务状态。
八、MCP 生态:现在能做什么
截至 2026 年中,MCP 生态已经非常丰富:
- 官方参考实现:Filesystem、Git、SQLite、Memory、Fetch、Sequential Thinking 等
- 社区生态:GitHub 上已有数千个 MCP Server,覆盖数据库、浏览器、邮件、Slack、Jira、设计工具
- 框架支持:Claude Desktop、Cursor、VS Code、OpenAI Agents SDK、LangChain、自建 Agent 全部支持
我的建议:先从一个「每天都要手动作的小工具」开始(文件清理、日报生成、数据查询),把它做成 MCP Server,然后让 AI 每天帮你跑。用起来之后你会直观感受到「AI 从聊天助手变成数字员工」的差别。
从更宏观的视角看,MCP 正在成为 AI 时代的「USB-C 接口」------它统一了 AI 与外部世界的连接标准。以前每个 AI 产品都有一套自己的插件体系,开发者要为不同平台重复适配;现在只要实现一次 MCP 协议,就能被所有主流 AI 客户端识别和调用。这种「协议层的标准化」,带来的不只是开发效率的提升,更是整个 AI 工具生态的互联互通。对企业来说,这意味着你积累的工具资产不会因为换一个 AI 平台而作废;对开发者来说,这意味着你的技能可以沉淀成一套可复用的「能力库」,而不是绑定在某一家厂商的私有格式上。
九、总结
MCP 的核心价值不是「又一个新协议」,而是把工具接入成本从 N×M 降到了 M。一次开发,所有 AI Client 通用。
动手建议:
- 用本文的
file_size_server.py跑通第一个闭环(15 分钟) - 把你的一个业务工具做成 MCP Server(半天)
- 接进你日常用的 AI Client(10 分钟)
如果你在接入过程中遇到问题,欢迎在评论区留言,我看到都会回。也可以聊聊你想把什么工具接进 AI------说不定下一篇就写你的场景。
本文代码完整可运行,环境:Python 3.10+ / mcp SDK 1.x。如果你觉得有用,点个赞让更多人看到,谢谢!