从零接入 MCP:把任意工具变成 AI 的能力(协议级实践)

你有没有遇到过这种场景:AI 聊天很厉害,但它碰不到你的数据。让它「帮我看看这个目录里哪些文件超过 100MB」,它只能回答「我无法直接访问你的文件系统」。

MCP(Model Context Protocol,模型上下文协议)就是为了解决这个问题诞生的。它是 Anthropic 2024 年底开源的一个开放协议,现在已经是 AI 工具链的事实标准------Claude、Cursor、VS Code、各种 IDE 和 Agent 框架都原生支持。

这篇文章用最少的代码,带你从零起一个 MCP Server,再把它接进 AI Client,最后用一个真实场景展示「把工具变成 AI 能力」到底是什么意思。

一、MCP 是什么?用一句话说清楚

MCP 是「AI 应用和外部工具之间的统一接口协议」。它定义了三种核心能力:

  1. Tools(工具):AI 可以调用的函数,比如「查询数据库」「读写文件」「调用 HTTP API」
  2. Resources(资源):AI 可以读取的数据,比如「某个配置文件的当前内容」
  3. 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")

这里有两个关键设计:

  1. @mcp.resource():暴露一个「数据库 Schema」资源。AI 在写查询前会先读这个资源,了解有哪些表和字段,生成正确 SQL 的概率大幅提升。
  2. 安全护栏 :只允许 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 通用。

动手建议:

  1. 用本文的 file_size_server.py 跑通第一个闭环(15 分钟)
  2. 把你的一个业务工具做成 MCP Server(半天)
  3. 接进你日常用的 AI Client(10 分钟)

如果你在接入过程中遇到问题,欢迎在评论区留言,我看到都会回。也可以聊聊你想把什么工具接进 AI------说不定下一篇就写你的场景。

本文代码完整可运行,环境:Python 3.10+ / mcp SDK 1.x。如果你觉得有用,点个赞让更多人看到,谢谢!

相关推荐
冬哥聊AI1 小时前
字节面试官:RAG不就是给大模型挂个知识库?别把这题答浅了
人工智能
9i编程1 小时前
AI 只解决眼前那个坑【上篇】:来源、图片、鲁棒性,把能聊一处一处补齐
人工智能·openai·ai编程
晴天161 小时前
AgentLoop分享(上): 让 AI 真正“自主干活“-Day15
人工智能·python
phoenix@Capricornus1 小时前
从统计决策到贝叶斯估计
人工智能·算法·机器学习
NutShell Wang1 小时前
国产全模态开源潮:从语言模型到视频模型,中国开源生态再升级
人工智能·语言模型·开源·大模型·音视频·多模态·vibe coding
薛晓刚1 小时前
信息化、数字化:智能化的基础,还是历史包袱?
人工智能
Black蜡笔小新1 小时前
从智慧社区到雪亮工程:国标GB28181公网平台EasyCVR如何构建视频“一张网”?
人工智能·自动化·easycvr
一次旅行1 小时前
Agent面试题答案整理(一)
人工智能·microsoft
AICDragon1 小时前
1.8%就够了:K3的896个MoE专家,为什么激活率这么低反而是好事?
人工智能·算法