2026年最新MCP协议从原理到实战:手写一个MCP Server接入Claude Code全流程踩坑指南

📑 目录


摘要:2026 年 6 月微软 Build 大会宣布全面拥抱 MCP 协议,Copilot Studio 原生支持 MCP 工具注册。一时间,MCP 成了 AI 开发圈的"USB 接口"标准。但教程要么停在概念科普,要么一上来就堆 LangGraph + CrewAI 一堆框架,对只想"先跑通一个自己的工具"的开发者极不友好。本文不聊虚的,带你从零手写一个 MCP Server,接入 Claude Code,再把踩过的 7 个坑一次性讲透。读完你就能把自己的任何脚本变成大模型能调用的工具。

关键词:MCP 协议;Model Context Protocol;Claude Code;MCP Server;stdio / SSE 传输;Function Calling;AI Agent;工具调用

一、为什么 2026 年你必须搞懂 MCP 协议?

先说一个很多开发者都遇到过的痛点:

你给大模型接了一个"查询公司数据库"的能力,用 Function Calling 写得好好的。结果换了个 Agent 框架(从 LangChain 换到 CrewAI),接口全得重写;换了家模型(从 GPT 换到 Claude),参数格式又对不上;想让同事复用你的工具,发现他用的框架你压根没听过——工具写了一遍又一遍,像个永远调不通的转接头。

MCP(Model Context Protocol,模型上下文协议)就是来终结这个混乱的。

它由 Anthropic 在 2024 年底提出,核心目标用一句话讲清楚:

让大模型像浏览器访问网页一样,用统一协议安全地访问任何外部工具和数据源。写一次 Server,所有支持 MCP 的客户端都能用。

到 2026 年中,局面已经很明朗:

时间节点 事件
2024.11 Anthropic 发布 MCP 协议规范
2025 上半年 OpenAI、Google 相继表态支持
2025 下半年 Cursor、Claude Code、Cline 等 AI 编程工具原生集成
2026.06 微软 Build 大会宣布 Copilot Studio 全面拥抱 MCP

一句话:MCP 已经成了连接 AI 和外部工具的事实标准。学会它,等于拿到了 2026 年 AI 开发的入场券。

二、MCP 协议核心原理:5 分钟看懂

别被"协议"两个字吓到,MCP 的设计相当克制。底层就是 JSON-RPC 2.0,你发一段 JSON、收一段 JSON,仅此而已。

2.1 一句话理解 MCP

把大模型想象成一台电脑,MCP 就是它的 USB 接口。你不用关心接的是硬盘、网卡还是打印机——只要设备符合 USB 规范,插上就能用。MCP Server 就是那些"USB 设备",负责把你的数据库、文件系统、内部 API 包装成统一的接口。

2.2 三层架构:Host / Client / Server

MCP 的运行时由三个角色组成:

┌─────────────────────────────────┐
│   Host(宿主)                   │
│   如 Claude Code / Cursor / Cline │
│   ┌───────────┐  ┌───────────┐  │
│   │ MCP Client│  │ MCP Client│  │
│   └─────┬─────┘  └─────┬─────┘  │
└─────────┼──────────────┼────────┘
          │ JSON-RPC      │
          ▼               ▼
   ┌──────────────┐ ┌──────────────┐
   │ MCP Server A │ │ MCP Server B │
   │ (你的工具)    │ │ (别人的工具)  │
   └──────┬───────┘ └──────┬───────┘
          ▼                ▼
      数据库/文件         GitHub/邮件
  • Host(宿主):运行大模型的那个程序,比如 Claude Code。它负责把模型的工具调用请求转发给对应的 Server。
  • Client(客户端):嵌在 Host 里,每个 Server 对应一个 Client,负责协议通信。
  • Server(服务端):你写的那个程序,真正干活的人——读文件、查数据库、调 API 都在它里面。

2.3 三类能力:Tools / Resources / Prompts

一个 MCP Server 可以向外暴露三类东西:

能力 作用 谁主动 典型场景
Tools(工具) 可被模型调用的函数 模型决定何时调 查天气、发邮件、跑 SQL
Resources(资源) 可被读取的数据 客户端/用户主动拉 读文件内容、读配置
Prompts(提示模板) 预设的提示词模板 用户主动触发 代码审查模板、总结模板

90% 的实战场景你只需要 Tools。本文也以 Tools 为主线展开,资源和提示模板留作进阶。

2.4 两种传输方式:stdio vs SSE

Server 和 Client 之间怎么传 JSON-RPC 消息?MCP 规范定义了两种主流传输:

维度 stdio(标准输入输出) SSE(Server-Sent Events)
通信方式 子进程的标准输入/输出 HTTP 长连接 + 流式响应
部署形态 本地,Host 启动子进程 远程,独立 HTTP 服务
适用场景 本地工具、个人开发 团队共享、生产部署
配置复杂度 低,一行命令 中,需管端口/CORS
多客户端共享 不行,每个 Host 各起一份 可以,一个 Server 多端连
调试难度 print 会污染协议(见坑1) 可用浏览器/curl 直接测

新手建议:先用 stdio 跑通,再按需升级到 SSE。 本文两种都会手把手演示。

三、环境准备

3.1 Python 环境与 MCP SDK

MCP 官方提供了 Python 和 TypeScript 两套 SDK。本文用 Python,因为上手最快。

建议用 Python 3.10+,建个独立虚拟环境:

# 创建项目目录
mkdir my-mcp-server && cd my-mcp-server

# 创建虚拟环境(Windows 用 python,Linux/Mac 用 python3)
python -m venv .venv

# 激活虚拟环境
# Windows (Git Bash):
source .venv/Scripts/activate
# Linux/Mac:
source .venv/bin/activate

# 安装 MCP 官方 SDK
pip install mcp

踩坑预警:很多人图省事不建虚拟环境,直接全局 pip install。后面接入 Claude Code 时,command 字段要写 Python 解释器的绝对路径,全局环境的路径一旦变动(升级、重装)就全崩。永远用虚拟环境的绝对路径,别偷懒。

3.2 安装 Claude Code

Claude Code 是 Anthropic 官方的命令行 AI 编程助手,对 MCP 支持最完整,本文以它为接入对象。

# 需要 Node.js 18+
npm install -g @anthropic-ai/claude-code

# 验证安装
claude --version

安装后运行一次 claude 按提示登录即可。如果你用 Cursor,配置思路完全一致,只是配置文件位置不同,后文会提到。

四、实战第一步:手写一个 stdio 版 MCP Server

需求很实在:写一个"笔记管理"工具,让大模型能帮我们增删查改本地笔记。麻雀虽小,五脏俱全——查、增、改三种工具都有了,足够你举一反三。

4.1 用 FastMCP 五行代码起一个 Server

MCP Python SDK 提供了一个高层封装 FastMCP,用法类似 FastAPI,装饰器一挂就能把普通函数变成 MCP 工具。

新建 note_server.py

# note_server.py
import json
import os
from mcp.server.fastmcp import FastMCP

# 笔记存储文件
NOTE_FILE = "notes.json"

def _load_notes():
    if not os.path.exists(NOTE_FILE):
        return []
    with open(NOTE_FILE, "r", encoding="utf-8") as f:
        return json.load(f)

def _save_notes(notes):
    with open(NOTE_FILE, "w", encoding="utf-8") as f:
        json.dump(notes, f, ensure_ascii=False, indent=2)

# 创建 MCP Server 实例
mcp = FastMCP("note-server")

if __name__ == "__main__":
    mcp.run(transport="stdio")

跑起来什么都不干,但骨架已经有了。接下来加工具。

4.2 定义你的工具:增、查、搜索

@mcp.tool()
def list_notes() -> str:
    """列出所有笔记的标题和编号。无笔记时返回空列表提示。"""
    notes = _load_notes()
    if not notes:
        return "当前没有任何笔记。"
    return json.dumps(
        [{"id": i, "title": n["title"]} for i, n in enumerate(notes)],
        ensure_ascii=False
    )

@mcp.tool()
def add_note(title: str, content: str) -> str:
    """添加一条新笔记。
    
    Args:
        title: 笔记标题,简短概括
        content: 笔记正文内容
    """
    notes = _load_notes()
    notes.append({"title": title, "content": content})
    _save_notes(notes)
    return f"已添加笔记《{title}》,当前共 {len(notes)} 条。"

@mcp.tool()
def search_notes(keyword: str) -> str:
    """按关键词搜索笔记标题和正文,返回匹配结果。
    
    Args:
        keyword: 搜索关键词
    """
    notes = _load_notes()
    results = [
        {"id": i, "title": n["title"], "content": n["content"]}
        for i, n in enumerate(notes)
        if keyword in n["title"] or keyword in n["content"]
    ]
    if not results:
        return f"没有找到包含「{keyword}」的笔记。"
    return json.dumps(results, ensure_ascii=False)

注意几个细节,这些是新手最容易忽略、却直接决定工具能不能被模型正确调用的关键:

  1. 函数名要语义化:模型靠名字猜用途,list_notesget_data 好一万倍。
  2. docstring 是命根子:模型决定"要不要调这个工具"时,主要看 docstring。写得越清楚,调用越准。
  3. 参数要有类型注解title: strtitle 多了类型信息,SDK 会自动转成 JSON Schema 喂给模型。
  4. 返回值统一用字符串:复杂结构用 json.dumps,别直接返回 dict,不同客户端兼容性参差。

完整文件保存后,本地先验证语法没问题:

python note_server.py
# 没报错、阻塞等待输入,说明 stdio 服务已就绪(Ctrl+C 退出)

4.3 本地调试:MCP Inspector 可视化

MCP 官方提供了一个调试神器 Inspector,能在浏览器里直接测试你的工具,不用每次都启动 Claude Code。

# 一行命令启动(会自动拉起一个 Web 界面)
npx @modelcontextprotocol/inspector python note_server.py

浏览器打开 http://localhost:5173,能看到:

  • 左侧列出所有已注册的 Tools
  • 点一个工具,右侧填参数,点 “Run” 直接调用
  • 底部显示完整的 JSON-RPC 请求/响应

强烈建议:每次改完代码先在 Inspector 里测一遍,确认工具行为正常,再去接 Claude Code。 这能帮你把"是 Server 的 bug"还是"模型没调用对"区分开,省下大量排查时间。

五、接入 Claude Code 实战

Server 写好了,怎么让 Claude Code 用上它?有两种方式,任选其一。

5.1 方式一:配置文件(推荐,可版本化)

在项目根目录(或用户家目录 ~/.claude/)创建 .mcp.json

{
  "mcpServers": {
    "note-server": {
      "command": "C:\\\\项目路径\\\\my-mcp-server\\\\.venv\\\\Scripts\\\\python.exe",
      "args": ["C:\\\\项目路径\\\\my-mcp-server\\\\note_server.py"]
    }
  }
}

Windows 路径坑:JSON 里反斜杠要转义成 \\\\。更省心的做法是用正斜杠 /,Windows 也认:"C:/项目路径/my-mcp-server/.venv/Scripts/python.exe"。Mac/Linux 用户写正常路径即可。

5.2 方式二:命令行添加(适合临时调试)

claude mcp add note-server -- C:/项目路径/my-mcp-server/.venv/Scripts/python.exe C:/项目路径/my-mcp-server/note_server.py

-- 后面跟的就是启动命令和参数,和配置文件里的 command + args 完全对应。

5.3 验证:工具是否被识别

在项目目录下启动 Claude Code:

claude

进入交互界面后,输入:

/mcp

会列出所有已连接的 MCP Server 及其状态。看到 note-server: connected 且下面列出 list_notesadd_notesearch_notes 三个工具,说明接入成功。

然后直接用自然语言测试:

> 帮我加一条笔记,标题"MCP学习计划",内容"本周跑通stdio版本,下周升级SSE"
> 我现在有哪些笔记?
> 搜一下有没有关于"SSE"的笔记

如果模型自主决定调用对应工具并返回正确结果,恭喜,你已经拥有了一个能被大模型驱动的自定义工具系统。

六、进阶:升级到 SSE 远程传输

stdio 模式有个硬伤:每台机器都要装一份 Server,没法团队共享。 当你想让整个团队用同一个"公司内部知识库查询工具"时,就需要 SSE 模式——把 Server 部署成 HTTP 服务,大家远程连。

6.1 改造代码:从 stdio 到 SSE

改动极小,FastMCP 帮你屏蔽了传输层差异:

# note_server_sse.py
# ... 上面的工具定义完全不变 ...

if __name__ == "__main__":
    # 只需把 transport 从 "stdio" 改成 "sse",并指定端口
    mcp.run(transport="sse", port=8765)

运行:

python note_server_sse.py
# 输出类似:Uvicorn running on http://0.0.0.0:8765

6.2 客户端连接 SSE Server

Claude Code 的 .mcp.json 配置改为 URL 形式:

{
  "mcpServers": {
    "note-server-remote": {
      "url": "http://your-server-ip:8765/sse"
    }
  }
}

或命令行:

claude mcp add note-server-remote --transport sse http://localhost:8765/sse

这样你的 Server 就能被团队任意成员、任意支持 MCP 的客户端连接了。部署到云服务器后,还能配合 nginx 做反向代理和 HTTPS。

新协议提醒:MCP 规范在 2025 年下半年引入了 Streamable HTTP 传输,逐步取代纯 SSE。它对无状态部署更友好。如果你的 SDK 版本较新,可尝试 transport="streamable-http"。过渡期 SSE 仍广泛兼容,本文以 SSE 为例。

七、踩坑实录:我踩过的 7 个坑(建议收藏)

理论和实战都有了,但真正写的时候,坑往往在细节里。下面这 7 个坑,每一个都让我或社区同学掉过头发。

# 坑点 现象 根因 解决方案
1 stdio 下用 print 调试 Claude Code 连接后卡死、报协议解析错误 stdio 传输靠标准输入输出传 JSON-RPC,print 的内容会被当成协议消息,直接污染通道 永远用 logging 输出到 stderr:import logging; logging.basicConfig(stream=sys.stderr)
2 Windows 中文编码乱码 工具返回的中文变成 ??? 或抛 UnicodeDecodeError Windows 默认控制台编码是 GBK,Python 写文件/输出时编码不一致 文件操作显式指定 encoding="utf-8";脚本开头加 sys.stdout.reconfigure(encoding="utf-8")
3 command 写了相对路径 换个目录启动 Claude Code 就报 “command not found” Host 启动子进程时的工作目录不固定,相对路径解析失败 commandargs 一律写绝对路径,包括 python.exe 和脚本文件
4 docstring 太简略 模型明明有合适工具却死活不调用,或者乱传参数 模型选工具主要靠 docstring 理解语义,写得太短它不知道这工具干嘛 docstring 写清"做什么 + 参数含义 + 返回什么",像给新人写接口文档一样
5 参数没写类型注解 模型把数字传成字符串,或参数顺序混乱 没有类型注解,SDK 生成的 JSON Schema 缺类型信息,模型只能猜 每个参数都加类型注解 name: strcount: int,复杂结构用 Pydantic Model
6 SSE 部署后连不上 本机 localhost 能连,远程/容器内死活连不上 默认监听 127.0.0.1 只接受本机;或防火墙没开端口;或跨域被拦 监听地址设为 0.0.0.0;开放对应端口;跨域时配置 CORS
7 工具能干危险操作却没护栏 模型自作主张删了数据 / 改了不该改的文件 给了工具全部权限,模型在"自主"执行时可能越界 危险操作(删除/覆盖)加二次确认参数;用 Resources 的只读特性隔离;生产环境加操作日志和回滚

重点展开坑 1 和坑 4,这俩是高频翻车点:

坑 1 的正确调试姿势:

import sys
import logging

# 关键:输出到 stderr,不污染 stdout(stdout 是协议通道)
logging.basicConfig(
    level=logging.DEBUG,
    stream=sys.stderr,
    format="%(asctime)s [%(levelname)s] %(message)s"
)

@mcp.tool()
def add_note(title: str, content: str) -> str:
    logging.debug(f"调用 add_note: title={title}")
    # ... 业务逻辑 ...
    return "ok"

Claude Code 启动 Server 时可以把 stderr 重定向到文件查看:在 .mcp.json 里没法直接重定向,但可以在 Python 脚本里把日志写到文件。

坑 4 的 docstring 对比:

# ❌ 模型大概率不会调用,或乱传参
@mcp.tool()
def search(keyword):
    """搜索"""
    ...

# ✅ 模型能准确判断何时调用、怎么传参
@mcp.tool()
def search_notes(keyword: str) -> str:
    """按关键词搜索笔记标题和正文,返回所有匹配的笔记。
    当用户想查找"包含某内容的笔记""有没有关于XX的记录"时使用。
    
    Args:
        keyword: 要搜索的关键词,单个词或短语
    """
    ...

八、MCP vs 传统 Function Calling 横向对比

写到这里你可能会问:我之前用 Function Calling 用得好好的,凭什么要换 MCP?这张表给你答案:

维度 传统 Function Calling MCP 协议
标准化程度 各家模型接口不一,参数格式各异 开放标准,模型无关,一套规范通吃
工具复用 换个框架/模型基本要重写 写一次 Server,所有 MCP 客户端通用
工具发现 手动在代码里注册每个工具 自动发现,连上 Server 即可用
本地数据访问 需自己处理本地文件/数据库对接 Server 跑在本地,天然能访问本地资源
安全控制 基本裸奔,全靠 prompt 自觉 Server 侧可做鉴权、审计、权限隔离
调试体验 只能看日志,黑盒 MCP Inspector 可视化调试
生态 各自为政 MCP 工具市场逐渐成型,官方/社区 Server 越来越多
学习成本 低,直接写函数 中,需理解协议和传输
适用场景 单一模型、简单工具、快速原型 多模型/多框架、团队共享、生产级 Agent

结论:如果你只是个人小打小闹、只用一个模型,Function Calling 够用;但只要涉及工具复用、团队共享、生产部署,MCP 的标准化红利会越来越值。2026 年的趋势已经很明确——新工具按 MCP 规范写,老工具逐步迁移。

九、总结与互动

9.1 本文核心回顾

  • MCP 是什么:连接大模型和外部工具的"USB 协议",2026 年已成事实标准。
  • 三层架构:Host(宿主)→ Client(客户端)→ Server(你写的工具服务)。
  • 三类能力:Tools(最常用)、Resources、Prompts。
  • 两种传输:stdio(本地起步)、SSE/Streamable HTTP(远程共享)。
  • 实战路径:FastMCP 写工具 → Inspector 调试 → 接入 Claude Code → 按需升级 SSE。
  • 7 个坑:print 污染、中文编码、相对路径、docstring、类型注解、SSE 监听、安全护栏。

9.2 给你的下一步建议

  1. 本周:照着本文把 stdio 版 Note Server 跑通,接上 Claude Code。
  2. 下周:把你自己工作中的一个真实脚本(比如查日志、跑 SQL、生成报表)改造成 MCP Server。
  3. 进阶:研究 Resources 和 Prompts 能力,做只读知识库和提示模板。
  4. 生产化:升级到 Streamable HTTP,加上鉴权和操作审计。

9.3 互动

MCP 这套东西还在快速演进,坑也还在不断被发现。你在实操中遇到过什么离谱的问题?或者有什么好玩的 Server 想法?欢迎在评论区交流,我会逐条回复。

如果这篇对你有帮助,点赞 + 收藏 + 关注三连是对原创最大的鼓励——下一篇我会写 「MCP Server 生产部署:鉴权、审计与高可用实战」,把这套东西从"能跑"推进到"敢上线",别错过。


本文所有代码均基于 MCP Python SDK 实测,环境为 Windows 11 + Python 3.13 + Claude Code 最新版。不同版本 SDK API 可能有细微差异,以官方文档为准。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐