MCP(Model Context Protocol)实战指南:从协议原理到动手构建 MCP Server 与 Client

如果你在 2025—2026 年做过大模型应用,大概率经历过这样的痛苦:每接一个外部工具(查数据库、读文件、调内部 API),就要手写一套专属的「函数描述 + 调用解析 + 结果回填」胶水代码。换个模型、换个前端,这套逻辑又得重写一遍。

MCP(Model Context Protocol,模型上下文协议) 的出现,就是为了解决这个问题。它由 Anthropic 在 2024 年底提出,并在 2025—2026 年迅速成为「大模型连接外部世界」的事实标准。一句话概括:MCP 是大模型与外部工具、数据源之间的 USB-C 接口——统一的协议,让任何 Server 能被任何支持 MCP 的 Client(Claude Desktop、Cursor、VS Code、各类 Agent 框架)即插即用。

本文从协议原理讲起,带你用官方 SDK 动手构建一个可用的 MCP Server 和 Client,并落到「把企业内部 API 封装成 MCP 服务」的真实场景。

一、为什么需要 MCP:Function Calling 的局限

大模型本身只能「对话」,要产生实际动作必须借助外部能力。早期的做法是 Function Calling(工具调用)

  • 开发者把每个函数的名称、参数 schema、描述写死在请求里;
  • 模型返回「要调用哪个函数 + 参数」;
  • 应用侧解析后执行,再把结果塞回上下文。

问题在于:这套约定是私有且碎片化的。OpenAI、Claude、通义千问各自的工具调用格式不同,参数描述风格不同,鉴权方式不同。每接一个工具、每换一个模型,都要重写适配层。当工具数量从几个涨到几十个、上百个时,维护成本指数级上升。

MCP 把这件事标准化了:

  • Server 用统一协议声明自己能提供什么(Tools / Resources / Prompts);
  • Client/Host 用统一协议发现、调用这些能力;
  • 工具的实现细节(怎么连数据库、怎么调 API)完全封装在 Server 内部,对模型和前端透明。

换模型不用改 Server,加工具不用改前端——这就是 MCP 的核心价值。

二、MCP 架构:Host、Client、Server 三层

一个典型的 MCP 部署包含三个角色:

角色是什么例子
**Host(宿主)**运行 LLM 的应用程序,负责编排Claude Desktop、Cursor、VS Code、自建 Agent
**Client(客户端)**Host 内部与某个 Server 一一对应的连接器每个 MCP Server 对应一个 Client 实例
**Server(服务端)**提供具体能力(工具、数据、提示模板)的进程或服务文件系统 Server、数据库 Server、天气 API Server

注意:一个 Host 可以有多个 Client,每个 Client 连接一个 Server,形成「一对多」的能力网络。Server 之间不直接通信,全部经由 Host 里的 LLM 进行「思考与编排」。

传输层(Transport)

MCP 支持多种传输方式,决定 Client 与 Server 怎么通信:

  • stdio(标准输入输出):Server 作为本地子进程启动,通过 stdin/stdout 交换 JSON-RPC 消息。最简单,适合本地工具(读文件、跑脚本)。
  • Streamable HTTP:2025-03-26 协议版本推荐的新远程传输,替代了旧的 SSE。支持有状态/无状态两种模式,适合把 Server 部署成远程服务。
  • SSE(Server-Sent Events):旧版远程传输,已被 Streamable HTTP 取代,新项目不建议使用。

三、三大核心原语:Tools、Resources、Prompts

MCP 把 Server 能提供的东西分成三类「原语」,分工非常清晰:

  1. Tools(工具):可被模型主动调用的函数,用于「执行动作」。比如「查询订单」「发送邮件」「运行测试」。由模型根据上下文决定是否调用(model-controlled)。
  2. Resources(资源):可被应用读取的数据源,用于「提供上下文」。比如「某个文件内容」「一条数据库记录」「一份配置」。通常由应用或用户决定何时加载(app-controlled)。
  3. Prompts(提示模板):预定义的、可复用的交互模板,由用户主动触发(user-controlled)。比如「代码审查模板」「周报生成模板」。

记住一句口诀:Tools 做事,Resources 给料,Prompts 引导

四、动手:用 Python 构建第一个 MCP Server

官方 Python SDK 名为 mcp。高层封装 FastMCP 让我们可以用装饰器快速声明能力。先安装:

pip install "mcp[cli]"

下面是一个最小可运行的 Server,包含 Tool、Resource、Prompt 三种原语:

from mcp.server.fastmcp import FastMCP

# 创建 Server 实例,名字可自定义
mcp = FastMCP("demo-server")


# 1) Tool:模型可调用的函数,docstring 会被当作工具描述
@mcp.tool()
def add(a: int, b: int) -> int:
    """计算两个整数的和。"""
    return a + b


# 2) Resource:可按 URI 读取的数据,支持路径参数
@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """根据名字返回一句问候语。"""
    return f"你好,{name}!欢迎使用 MCP。"


# 3) Prompt:可复用的提示模板
@mcp.prompt()
def review_code(code: str) -> str:
    """生成一段代码审查提示。"""
    return f"请审查下面这段代码的健壮性、性能与安全性:\n\n{code}"


if __name__ == "__main__":
    # 默认以 stdio 方式启动;远程部署可用 mcp.run(transport="streamable-http")
    mcp.run()

把这段代码保存为 server.py,用 mcp dev server.py 即可启动一个带调试界面的本地 Server;生产部署用 python server.py(stdio)或 mcp run(远程 HTTP)。

关键点:工具的 docstring 和类型注解就是模型的「说明书」add(a: int, b: int) -> int 会自动生成 JSON Schema 参数描述,模型据此知道该传什么、返回什么,无需你手写 schema。

五、真实案例:把企业内部 API 封装成 MCP Server

假设公司有一个订单查询接口 GET /api/orders?user_id=xxx,我们把它包装成模型可调用的 Tool:

import os
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("order-server")

API_BASE = os.getenv("ORDER_API_BASE", "https://internal.example.com")
API_TOKEN = os.getenv("ORDER_API_TOKEN", "")


@mcp.tool()
async def query_orders(user_id: str, status: str = "all", limit: int = 10) -> str:
    """查询指定用户的订单列表。

    Args:
        user_id: 用户唯一标识
        status: 订单状态,可选 paid / shipped / all
        limit: 返回条数上限
    """
    headers = {"Authorization": f"Bearer {API_TOKEN}"}
    params = {"user_id": user_id, "status": status, "limit": limit}
    async with httpx.AsyncClient() as client:
        resp = await client.get(f"{API_BASE}/api/orders", headers=headers, params=params)
        resp.raise_for_status()
        data = resp.json()
    # 把结构化结果转成模型易读的摘要文本
    lines = [f"共 {len(data)} 笔订单:"]

    for o in data:
        lines.append(f"- 订单 {o['id']} | 状态 {o['status']} | 金额 ¥{o['amount']}")
    return "\n".join(lines)


if __name__ == "__main__":
    mcp.run(transport="streamable-http")

这样,任何支持 MCP 的 Client 连上这个 Server 后,模型就能用自然语言「帮我查一下 user_123 最近的已付款订单」,而无需前端工程师为每个模型单独写对接代码

六、客户端:在 Agent 中接入 MCP Server

Host 侧通常已经内置 MCP Client(如 Claude Desktop、Cursor 通过配置文件声明要连哪些 Server)。如果你要自建 Agent,官方 SDK 也提供了 Client 能力。下面是用 Python 以 stdio 方式连上一个本地 Server 并调用工具的骨架:

import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client


async def main():
    # 声明要启动的 Server 进程
    server_params = StdioServerParameters(
        command="python",
        args=["server.py"],
    )
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            # 列出 Server 提供的工具
            tools = await session.list_tools()
            print([t.name for t in tools.tools])
            # 调用工具
            result = await session.call_tool("add", {"a": 1, "b": 2})
            print(result.content)


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

Client 拿到工具列表后,再结合 LLM 的 Function Calling 能力,就能让模型「见到」这些工具并自主决策调用——MCP 负责「统一接口」,LLM 负责「统一决策」,两者配合完成端到端的智能调用。

七、安全与最佳实践

MCP 把外部能力直接交给模型调用,安全是第一优先级

  • 最小权限:Server 只暴露必要的能力,数据库 Server 用只读账号,API Server 走最小 scope 的 token。
  • 密钥隔离:像上面的 ORDER_API_TOKEN 一律走环境变量,绝不写进代码或提交仓库。
  • 人工确认:对「写操作」类工具(发邮件、删数据、下单),Host 应设计审批/确认环节,避免模型误触发。
  • 输入校验:Server 侧对参数做严格类型与范围校验,防止越权查询(如 user_id 注入)。
  • 沙箱运行:本地 stdio Server 最好在受限环境中启动,限制文件系统与网络访问范围。

八、生态与未来

截至 2026 年,MCP 生态已经相当繁荣:

  • 客户端:Claude Desktop、Cursor、VS Code(Copilot + MCP)、Windsurf、各类 Agent 框架(LangChain、LlamaIndex)均已支持。
  • 服务端:官方维护 filesystem、fetch、git、postgres、slack、google-drive 等参考 Server;社区涌现大量第三方 Server。
  • 注册中心:出现了类似「MCP 市场」的 Server 目录,方便发现与复用。
  • 与 Agent 的关系:MCP 解决「模型怎么连工具」,Agent 框架解决「模型怎么思考与规划」,二者互补。可以认为 MCP 是 Agent 的「手脚标准接口」

协议本身也在演进:从最初的 stdio/SSE,到 2025 年引入 Streamable HTTP、支持远程无状态部署,再到对「可组合 Server」「权限协商」的持续完善。可以预见,MCP 正在成为 AI 应用基础设施里和 REST、gRPC 同等重要的存在。

九、总结

MCP 用一套统一协议,终结了「每个工具、每个模型各自适配」的混乱局面。回顾本文要点:

  • 本质:大模型与外部世界的「USB-C」统一接口。
  • 架构:Host 编排、Client 连接、Server 提供能力,一对多组网。
  • 原语:Tools 做事、Resources 给料、Prompts 引导。
  • 上手pip install mcp,用 @mcp.tool() 装饰器几行代码就能发布一个工具。
  • 落地:把内部 API 包成 MCP Server,即可被任意支持 MCP 的客户端即插即用地调用。
  • 安全:最小权限、密钥隔离、人工确认、输入校验、沙箱运行。

如果你正在构建大模型应用,现在正是把零散的工具调用迁移到 MCP 的最佳时机——一次标准化,长期受益。

本文示例代码基于 `mcp` Python SDK(协议版本 2025-03-26)。实际部署请以官方文档最新版为准。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部