2026年最新MCP协议从原理到实战:手写一个MCP Server接入Claude Code全流程踩坑指南
2026/6/26 6:55:54 网站建设 项目流程

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

📑 目录

  • 一、为什么 2026 年你必须搞懂 MCP 协议?
  • 二、MCP 协议核心原理:5 分钟看懂
    • 2.1 一句话理解 MCP
    • 2.2 三层架构:Host / Client / Server
    • 2.3 三类能力:Tools / Resources / Prompts
    • 2.4 两种传输方式:stdio vs SSE
  • 三、环境准备
    • 3.1 Python 环境与 MCP SDK
    • 3.2 安装 Claude Code
  • 四、实战第一步:手写一个 stdio 版 MCP Server
    • 4.1 用 FastMCP 五行代码起一个 Server
    • 4.2 定义你的工具:增、查、搜索
    • 4.3 本地调试:MCP Inspector 可视化
  • 五、接入 Claude Code 实战
    • 5.1 方式一:配置文件(推荐,可版本化)
    • 5.2 方式二:命令行添加(适合临时调试)
    • 5.3 验证:工具是否被识别
  • 六、进阶:升级到 SSE 远程传输
    • 6.1 改造代码:从 stdio 到 SSE
    • 6.2 客户端连接 SSE Server
  • 七、踩坑实录:我踩过的 7 个坑(建议收藏)
  • 八、MCP vs 传统 Function Calling 横向对比
  • 九、总结与互动
    • 9.1 本文核心回顾
    • 9.2 给你的下一步建议
    • 9.3 互动

摘要: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.11Anthropic 发布 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+,建个独立虚拟环境:

# 创建项目目录mkdirmy-mcp-server&&cdmy-mcp-server# 创建虚拟环境(Windows 用 python,Linux/Mac 用 python3)python-mvenv .venv# 激活虚拟环境# Windows (Git Bash):source.venv/Scripts/activate# Linux/Mac:source.venv/bin/activate# 安装 MCP 官方 SDKpipinstallmcp

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

3.2 安装 Claude Code

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

# 需要 Node.js 18+npminstall-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.pyimportjsonimportosfrommcp.server.fastmcpimportFastMCP# 笔记存储文件NOTE_FILE="notes.json"def_load_notes():ifnotos.path.exists(NOTE_FILE):return[]withopen(NOTE_FILE,"r",encoding="utf-8")asf:returnjson.load(f)def_save_notes(notes):withopen(NOTE_FILE,"w",encoding="utf-8")asf: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()deflist_notes()->str:"""列出所有笔记的标题和编号。无笔记时返回空列表提示。"""notes=_load_notes()ifnotnotes:return"当前没有任何笔记。"returnjson.dumps([{"id":i,"title":n["title"]}fori,ninenumerate(notes)],ensure_ascii=False)@mcp.tool()defadd_note(title:str,content:str)->str:"""添加一条新笔记。 Args: title: 笔记标题,简短概括 content: 笔记正文内容 """notes=_load_notes()notes.append({"title":title,"content":content})_save_notes(notes)returnf"已添加笔记《{title}》,当前共{len(notes)}条。"@mcp.tool()defsearch_notes(keyword:str)->str:"""按关键词搜索笔记标题和正文,返回匹配结果。 Args: keyword: 搜索关键词 """notes=_load_notes()results=[{"id":i,"title":n["title"],"content":n["content"]}fori,ninenumerate(notes)ifkeywordinn["title"]orkeywordinn["content"]]ifnotresults:returnf"没有找到包含「{keyword}」的笔记。"returnjson.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 mcpaddnote-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 mcpaddnote-server-remote--transportsse http://localhost:8765/sse

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

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

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

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

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

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

坑 1 的正确调试姿势:

importsysimportlogging# 关键:输出到 stderr,不污染 stdout(stdout 是协议通道)logging.basicConfig(level=logging.DEBUG,stream=sys.stderr,format="%(asctime)s [%(levelname)s] %(message)s")@mcp.tool()defadd_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()defsearch(keyword):"""搜索"""...# ✅ 模型能准确判断何时调用、怎么传参@mcp.tool()defsearch_notes(keyword:str)->str:"""按关键词搜索笔记标题和正文,返回所有匹配的笔记。 当用户想查找"包含某内容的笔记""有没有关于XX的记录"时使用。 Args: keyword: 要搜索的关键词,单个词或短语 """...

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

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

维度传统 Function CallingMCP 协议
标准化程度各家模型接口不一,参数格式各异开放标准,模型无关,一套规范通吃
工具复用换个框架/模型基本要重写写一次 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 可能有细微差异,以官方文档为准。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询