实战 SOP
实战 SOP

MCP Server 开发实战 SOP:从零写一个能跑的 MCP Server

结合 MCP 热点。MCP 不是框架是协议(Host/Client/Server 三角色),生态全景(微软/阿里/LangChain/Cherry Studio)。Python 实战 math-tutor Server(uv+server.py+Inspector+Claude Desktop),进阶 Grafana 对接,三避坑(工具描述/职责单一/传输层)。

发布于 2026年7月25日12 分钟阅读
<!-- mcp-server-dev-sop | sop | MCP Server 开发实战 SOP -->

别再给每个 AI 平台重复写相同的 API 胶水了。同一个查天气的函数,我给 Claude Desktop 封了一套 RESTful,Coze 要插件 JS,Dify 填 YAML,LangChain 还得自定义 Tool 类。参数名、返回格式、认证方式全不一样。上游模型一更新,又得逐行检查兼容性,感觉自己像个手工接线员,把各种 AI 工具用胶水粘在一起,维护成本指数级上升。

这不是能力问题,是协议碎片化。AI 工具大爆发,但彼此孤立,每个框架都发明了自己的"方言"。直到 Anthropic 把 MCP 协议推出来,局面才开始有实质改变。MCP 不搞框架,它要统一通信标准,让工具开发一次,能被任何支持 MCP 的客户端调用。

这篇文章不聊 5 分钟手搓玩具,直接从工程角度把 MCP 的架构、生态、实战和踩过的坑一次讲清楚。


一、MCP 不是框架,是协议

很多人刚接触 MCP,会拿它和 LangChain、Semantic Kernel 对比,这完全搞错了赛道。MCP 不管你怎么实现工具,也不定义业务逻辑,它只定义一件事:AI 客户端(Host)如何通过标准化的方式发现并调用远程工具(Server)。

整个流程拆成三个角色:

  • MCP Host:AI 应用本体,比如 Claude Desktop、Cherry Studio、Cline 等。发起用户指令,展示最终结果。
  • MCP Client:内嵌在 Host 里的协议客户端,和 Server 保持 1:1 连接,翻译请求。
  • MCP Server:你写的工具,封装了你的"独家能力",查数据库、调 API、操作文件等。

交互流程很清晰:Host 启动时,Client 通过配置找到 Server,获取能力列表(list_tools)。用户发指令,Host 把问题加工具列表发给 LLM。LLM 分析后,决定调用哪个工具,生成符合 Schema 的参数。Client 把调用请求发给 Server,拿到结果返回给 LLM。最后 LLM 整合结果展示给用户。这就是 MCP 的"解耦"和"复用"价值:你写一次工具,所有支持 MCP 的客户端都能用,不用给每个平台重写胶水代码。


二、生态全景:不只有 Claude,国内也已经开卷

很多人以为 MCP 只为 Claude 服务,其实它的野心远不止于此。到 2026 年,MCP 生态已经覆盖了主流大厂、开源框架和创意应用。

微软官方出了 MCP Server 合集,覆盖 Azure、GitHub、Teams 等产品。阿里云也在博客里展示了 Grafana MCP Server 开发实例,用 MCP 让大模型直接返回 Dashboard 实时图片和列表。LangChain 推出了 langchain-mcp-adapters,可以直接把 MCP Server 的 tools 转成 LangChain Tool 对象,老牌框架无缝接入新协议。客户端方面,Cherry Studio 1.1.2 已经内置 MCP 支持,Cline(VS Code 插件)可以充当 Host,甚至 Unity 引擎通过 Codex 配置 MCP,让 AI 在游戏里操作场景对象。

掘金上《2026 年最佳 MCP 服务器完全指南》 列出了从知识获取、代码生成到自动化运维的数十个生产级 Server,强调"不要把它们当玩具,这是给 Agent 提供结构化访问的生产工具"。找 Server 就去三个地方:GitHub 官方仓库、awesome-mcp-servers 列表、glama.ai 市场。

现在入局不算晚。你不需要再为每个大模型平台单独写插件,把核心能力封装成 MCP Server,就能一次性接入所有主流 Host。


三、实战:从零写一个能跑的 MCP Server

下面用 Python 实现一个极简的 MCP Server,叫 math-tutor,提供两个工具:addmultiply。代码基于官方 mcp Python 库,完整可运行,适合 3.10+ 环境。

1. 环境准备:用 uv 管理项目

uv 省心:

bash
# 安装 uv(如果没有)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 创建项目
uv init math-tutor
cd math-tutor
uv add mcp[cli]

2. 核心代码:server.py

python
import asyncio
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationCapabilities
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

server = Server("math-tutor")

@server.list_tools()
async def handle_list_tools() -> list[Tool]:
    """告诉 Host 我能干什么"""
    return [
        Tool(
            name="add",
            description="计算两个数字的和",
            inputSchema={
                "type": "object",
                "properties": {
                    "x": {"type": "number", "description": "第一个加数"},
                    "y": {"type": "number", "description": "第二个加数"}
                },
                "required": ["x", "y"]
            }
        ),
        Tool(
            name="multiply",
            description="计算两个数字的乘积",
            inputSchema={
                "type": "object",
                "properties": {
                    "a": {"type": "number", "description": "乘数"},
                    "b": {"type": "number", "description": "被乘数"}
                },
                "required": ["a", "b"]
            }
        )
    ]

@server.call_tool()
async def handle_call_tool(name: str, arguments: dict) -> list[TextContent]:
    """执行具体工具"""
    if name == "add":
        result = arguments["x"] + arguments["y"]
        return [TextContent(type="text", text=f"结果是 {result}")]
    elif name == "multiply":
        result = arguments["a"] * arguments["b"]
        return [TextContent(type="text", text=f"结果是 {result}")]
    else:
        raise ValueError(f"未知工具: {name}")

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationCapabilities(
                sampling={},
                experimental={},
            ),
            notification_options=NotificationOptions()
        )

if __name__ == "__main__":
    asyncio.run(main())

3. 配置启动

修改 pyproject.toml,添加执行入口:

toml
[project.scripts]
math-tutor = "server:main"

然后 uv run math-tutor 就可以跑起来。现在需要一个 Host 来测试。

4. 用 MCP Inspector 测试

官方提供了调试工具 Inspector,不需要自己写客户端:

bash
npx @anthropic-ai/mcp-inspector uv run math-tutor

浏览器打开给出的地址,就能看到 Server 暴露的工具列表,点 add 输入参数,立刻看到返回结果。这比在 Claude Desktop 里反复重启调试高效得多。

5. 接入 Claude Desktop(或其他 Host)

编辑 claude_desktop_config.json(通常在 ~/Library/Application Support/Claude/ 下):

json
{
  "mcpServers": {
    "math-tutor": {
      "command": "uv",
      "args": ["run", "math-tutor"]
    }
  }
}

重启 Claude Desktop,在对话框输入"用数学助手帮我算 3.14 乘以 2.5",它就会自动调用你的 Server 并返回结果。

你不需要写任何 HTTP 路由、JSON 解析、认证逻辑,MCP 框架把通信层全包了,你只需要专注在 call_tool 里实现业务逻辑。


四、进阶:对接真实业务,以 Grafana 为例

写一个玩具 Server 只是第一步,真正有用的是把企业内部系统封装成 MCP Server,让 AI 能直接操作。阿里云云原生团队的文章 MCP Server 开发实战|大模型无缝对接 Grafana 给出了一个好示范:让大模型通过 MCP 返回 Grafana 的 Dashboard 列表和实时曲线图。

核心思路:你的 call_tool 里调用 Grafana API(用 API Key 认证),获取 JSON 数据,然后按需处理。比如 list_dashboards 工具返回面板列表,get_dashboard_image 工具调用 Grafana 的渲染 API 返回图片 URL。当用户说"显示应用监控大盘",AI 就能直接拿出图片,而不是只给一串 ID。

实战要点

  • 工具描述(description)一定要写得足够详细,因为 LLM 靠它来决定什么时候调用你。比如:"获取指定 Grafana 面板的实时截图,需要提供 dashboardUid、panelId 和时间范围。"
  • 参数 Schema 严格定义,required 字段要准确,否则 LLM 可能会漏传关键参数。
  • 安全性:如果涉及敏感数据,考虑使用只读 API Key,并限定作用域(如仅允许查看指定 Dashboard)。建议分三步走:第一步只读服务,第二步狭窄范围,第三步完整日志,逐步放开权限。

五、避坑与选型:别让 MCP 变成新累赘

工具描述是写给 LLM 看的。 很多开发者习惯在描述里写"这是一个加法工具",这等于没写。LLM 需要足够多的上下文来判断何时调用你。正确的写法:"计算两个数字的和,适用于需要算术运算的场景,比如用户问'1+2 等于几'或'把 3 和 5 加起来'。"

一个 Server 一个职责。 别把数据库查询、文件操作、邮件发送全塞到一个 Server 里。MCP 的每个 Server 应该是正交的,职责单一,方便组合,也方便权限控制。

不要忽略传输层选择。 MCP 支持多种传输:stdio(适用于本地进程)、HTTP(Streamable HTTP,支持流式输出)。本地开发调试用 stdio 最方便,要暴露给远程团队或生产环境,就需要用 HTTP 模式,并加上认证。新规范已经在推进更安全的流式传输,值得关注。


参考来源

本文由 AI 辅助生成,经人工审核编辑。最后更新:2026-07-25

常见问题

MCP Server 和 LangChain Tool 有什么区别?
MCP 是协议(定义 Host 如何发现调用 Server),不是框架。LangChain Tool 是框架内工具类。MCP Server 写一次,所有 MCP 客户端(Claude/Cline/Cherry Studio)都能调;LangChain Tool 只在 LangChain 内用。MCP 解决跨平台复用。
开发 MCP Server 要什么环境?
Python 3.10+ + uv 包管理 + mcp[cli] 库。单文件 server.py(@server.list_tools + @server.call_tool 装饰器),stdio 传输本地调试,MCP Inspector 测试,claude_desktop_config.json 接入 Host。
MCP Server 怎么调试?
用官方 MCP Inspector(npx @anthropic-ai/mcp-inspector uv run server),浏览器看工具列表+测试参数返回,比在 Claude Desktop 反复重启高效。

相关文章