MCP的个人理解

笔记概览

本笔记围绕 Model Context Protocol (MCP) 展开,覆盖以下核心模块:

  1. 协议本质:MCP 的定义、解决的痛点、与传统 Function Calling 的根本区别。
  2. 消息格式:基于 JSON-RPC 2.0 的请求、响应、通知结构。
  3. 实现方式:Host-Client-Server 三层架构的解耦机制。
  4. 项目集成:在 Python Web 应用中用 MCP 包装外部 API(附详细代码拆解)。
  5. 加载时机:工具列表的一次性加载 vs 动态发现。
  6. 隔离方案:多项目/多 Agent 场景下的命名空间、权限、进程隔离。
  7. 实战补充:Claude Code 本地配置实现项目级隔离的层层递进方案。

每一部分都包含技术原理、代码示例(主要针对 Python)、架构图解,并穿插扩展思考、追问方向和实践建议。


1. 协议本质:从函数调用到上下文协议

1.1 MCP 是什么?

MCP(Model Context Protocol)是 Anthropic 提出的开放协议,旨在标准化 AI 模型与外部工具、数据源的交互方式。类比为"AI 应用的 USB-C 接口"------不同工具只要遵循同一套协议,就可以被任何支持 MCP 的模型即插即用地连接。

1.2 要解决的核心痛点

传统 Function Calling 下,每接入一个新工具,开发者需要:

  • 手写适配函数、描述 JSON Schema;
  • 处理认证、错误重试;
  • 把函数签名硬编码为特定 AI 厂商的格式(如 OpenAI 与 Anthropic 不同)。

结果:工具集成与模型强绑定,复用性差

MCP 的解耦思路:工具按协议暴露一次,即可被所有 MCP 兼容的 AI 使用

1.3 MCP 与 Function Calling 的根本不同

|------|------------------|---------------------------------|
| 对比维度 | Function Calling | MCP |
| 定义位置 | 代码中一次性注入工具列表 | 工具定义在独立进程(MCP Server)中,通过协议动态获取 |
| 交互模式 | 单次请求-响应 | 持久化连接,支持工具发现、实时推送、资源订阅 |
| 标准化 | 各厂商格式不统一 | 开放协议,不绑定模型厂商 |
| 生命周期 | 函数在一次对话上下文中存活 | 工具服务器独立运行,启动/停止与模型无关 |

通俗比喻:Function Calling 是写在纸上的固定菜单;MCP 是一家可以随时更新菜单、开放厨房参观、接收实时订单的餐厅。

【延伸】

  • MCP 这种"协议驱动工具"的思想在微服务架构中早有先例(如 gRPC 服务定义)。但在 AI 领域,它可能成为类似"HTTP 之于 Web"的基础设施。
  • 协议标准化可能带来的生态效应:未来会出现 MCP 工具市场,开发者直接发布、复用工具服务器。

【追问】

  • 如果所有 AI 都通过 MCP 调用工具,那么工具的输入输出是否还需要适配不同模型的"偏好"?MCP 的描述规范足够消除差异吗?

2. 消息格式:基于 JSON-RPC 2.0 的统一通信

2.1 基础规范

MCP 底层使用 JSON-RPC 2.0,所有消息都是 JSON 对象,通过标准输入/输出(stdio)或 HTTP/SSE 传输。

三种消息类型:

  • 请求(Request) :含有 id,必须返回响应。
  • 响应(Response) :包含与请求相同的 id,携带 resulterror
  • 通知(Notification) :无 id,不需要响应,用于单向事件推送。

2.2 示例消息

工具列表请求与响应

复制代码
// 请求
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }

// 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather",
        "description": "获取指定城市的当前天气",
        "inputSchema": {
          "type": "object",
          "properties": { "city": { "type": "string" } },
          "required": ["city"]
        }
      }
    ]
  }
}

工具调用请求与响应

复制代码
// 请求
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "city": "Beijing" }
  }
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      { "type": "text", "text": "Beijing: 22°C, sunny." }
    ]
  }
}

资源更新通知(推送)

复制代码
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": { "uri": "file:///data/report.txt" }
}

通知机制是传统 Function Calling 不具备的,它允许工具主动向模型推送信息,而不必依赖轮询。

【延伸】

  • JSON-RPC 2.0 也常用于 WebSocket 通信。MCP 选择它,可能未来会考虑 WebSocket 传输层,以获得更好的双向实时能力。
  • 通知中的 resources/updated 暗示 MCP 不仅是"工具协议",还可能是"资源协议",有潜力构建 AI 可感知的文件系统或知识库。

【试一试】

可以尝试实现一个简单的 MCP Client 和 Server(用 Python 的 mcp 包),通过 stdio 传递上述 JSON 消息,观察初始化和工具调用流程。


3. 实现方式:客户端-主机-服务器的三层解耦

3.1 架构图

复制代码
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   MCP Host  │────▶│ MCP Client  │────▶│ MCP Server  │
│  (AI 应用)  │     │ (协议客户端) │     │ (工具实现)  │
└─────────────┘     └─────────────┘     └─────────────┘
  • MCP Host:真正发起调用的 AI 应用(如 Claude Desktop、你的 Web 后端)。
  • MCP Client:与一个 Server 1:1 映射,负责连接、收发消息、协议翻译。
  • MCP Server:轻量级服务,暴露工具、资源和能力。

3.2 解耦要点

  • Host 不接触 Server 的通信细节,Client 提供统一接口。
  • 一个 Host 可创建多个 Client,连接不同 Server,实现多工具组合。
  • Server 可用任何语言编写,只要通过 stdio 或 HTTP 产生 JSON-RPC 输出。

3.3 连接生命周期

  1. 初始化:Client 发送 initialize 请求,协商协议版本和能力。
  2. 正常操作:工具发现、调用、资源读取等。
  3. 关闭:连接断开,释放资源。

【延伸】

  • 这种架构与微服务中的 Service Mesh 相似:数据面(Client/Server)与控制面(Host 的策略)分离。
  • 可以预见到未来会出现"MCP 网关"产品,集中管理多个 Server 的认证、限流和监控。

【追问】

  • 三层架构中,如果 Client 崩溃,Host 能否自动恢复连接?MCP 本身未定义故障转移机制,这是否需要应用层自己实现?

4. 项目集成:在 Python Web 应用中包装外部 API(代码详解)

4.1 场景描述

智能助手 Web 应用需要接入天气查询。我们将外部天气 API 封装为一个 MCP Server,Web 后端通过 MCP Client 与之通信。

4.2 天气服务器(weather_server.py)逐段拆解

复制代码
import json, asyncio
from mcp.server import Server, NotificationOptions
from mcp.server.models import InitializationCapabilities
from mcp.server.stdio import stdio_server
import httpx

server = Server("weather-server")
  • asyncio:异步编程库,允许等待网络请求时不阻塞。
  • Server:创建 MCP 服务器实例。
  • stdio_server:基于标准输入输出的传输工具。

注册工具列表

复制代码
@server.list_tools()
async def list_tools():
    return [{
        "name": "get_weather",
        "description": "获取指定城市的当前天气",
        "inputSchema": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"]
        }
    }]
  • @server.list_tools() 装饰器:当客户端请求 tools/list 时调用此函数。
  • 返回一个工具定义列表,包含名称、描述和 JSON Schema 参数说明。

注册工具实现

复制代码
@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments["city"]
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"https://api.weather.com/v1/current?city={city}&key=KEY")
            data = resp.json()
        return {
            "content": [
                {"type": "text", "text": f"{city}: {data['temp']}°C, {data['condition']}"}
            ]
        }
  • @server.call_tool():处理 tools/call 请求。
  • 使用 httpx.AsyncClient 异步调用外部 API,await 等待结果。
  • 返回内容必须符合 MCP 规范:{"content": [...]}

启动服务器

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

if __name__ == "__main__":
    asyncio.run(main())
  • stdio_server() 建立 stdio 通信流。
  • server.run 进入事件循环,处理请求。

4.3 Web 应用集成(app.py)及常见陷阱

原始意图代码(有坑)

复制代码
from fastapi import FastAPI
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

app = FastAPI()
session = None

async def connect_to_weather_server():
    server_params = StdioServerParameters(command="python", args=["weather_server.py"])
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            return session  # ❌ 离开 async with 块后 session 就失效了!

@app.on_event("startup")
async def startup():
    global session
    session = await connect_to_weather_server()  # 拿到的 session 已关闭

问题剖析
async with 块退出时会自动关闭通信流和会话,返回的 session 对象已不可用。这是初学者极易犯的错误。

修正版:每次请求临时连接(可运行但不高效)

复制代码
@app.get("/ask")
async def ask(question: str):
    server_params = StdioServerParameters(command="python", args=["weather_server.py"])
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("get_weather", {"city": "Beijing"})
            return {"answer": result.content[0].text}
  • 每次请求启动一个子进程,用完立即关闭。逻辑正确,但开销大。

生产环境改进方向

  • 使用长连接(如 HTTP/SSE 传输),避免反复启动进程。
  • 用连接池维护一个持久的 session,并在 FastAPI 后台任务中维持。

4.4 通俗比喻

Web 应用就像餐厅服务员,客人问天气。服务员不会自己查,而是打电话(stdio)给专属气象员(天气服务器),通过一套标准问答(MCP 协议)获取结果,再转达给客人。气象员是独立的,更换他只需另一个懂协议的人即可,餐厅无需改造。

【延伸】

  • 这个模式本质上就是"工具即服务"(TaaS)。未来 AI 应用可以由多个这样的 MCP Server 微服务组合而成,类似"AI 原生微服务"。
  • 可以思考:是否可以在 Server 侧做结果缓存、限流?MCP 协议本身不限制,但应用层完全可以加上这些能力。

【试一试】

试着将天气服务器改为连接真实的 OpenWeatherMap API,并扩展一个 get_forecast 工具,体验增加工具的便捷性。


5. 加载时机:一次性加载 vs 动态发现

5.1 启动时一次性加载

Host 启动后,Client 连接 Server 并调用 tools/list,将全部工具注入到 AI 的 system prompt 或工具注册表。此后整个会话使用该固定列表。
适用场景:工具数量固定,如企业内部几个稳定的系统。

5.2 按需动态发现

MCP 支持运行时动态改变工具列表:

  • Server 可发送通知 notifications/tools/list_changed
  • Client 收到后可重新调用 tools/list 获取最新工具。
  • 高级用法:Host 可以根据 LLM 推理的需求,临时启动特定的 MCP Server 并查询其工具,实现"懒加载"。

比喻:固定菜单 vs 服务员告知"今日特供",你可随时追问更新。

【延伸】

  • 动态发现可用于插件系统:用户安装新插件时,Server 通知 Host,AI 立即获得新能力。
  • 在 Agent 协作中,子 Agent 的动态创建和销毁需要这种机制的支持。

【追问】

  • 动态发现增加了系统的复杂性,对 AI 的 prompt 管理提出了挑战:工具频繁变化时,如何保证模型能正确理解当前可用的工具集?

6. 隔离方案:多项目/多 Agent 的命名与权限

6.1 命名冲突

多个 MCP Server 可能拥有同名工具(如 search)。
解决方案 :命名空间前缀。例如 finance/search_transactionshr/search_employees

Client 端可以在聚合工具时自动添加来源前缀:

复制代码
for server_name, session in server_sessions.items():
    for tool in server_tools:
        tool["name"] = f"{server_name}/{tool['name']}"

6.2 权限隔离

  1. Agent 级隔离:不同 Agent 使用不同 Client 实例,连接各自的 Server 集合,天然隔离。
  2. 工具级访问控制:在 Server 内通过上下文(如认证令牌)检查权限。
  3. 进程/容器隔离:每个 Server 运行在独立进程或容器中,结合网络策略进一步加固。
  4. 传输层安全:HTTP/SSE 传输时使用 TLS 和身份验证头。

多租户架构示例

复制代码
 Agent A (Client A) ──── finance Server
 Agent B (Client B) ──── hr Server
 Agent C (Client C) ──── common Server (按需连接)

各个 Agent 仅能看到授权范围内的工具,权限不交叉。

【延伸】

  • 此类权限模型可以借鉴 AWS IAM 的策略语法,定义一个 MCP 权限策略语言,以声明式控制工具和资源的访问。
  • 在多 Agent 协作场景(如 AutoGen、CrewAI)中,Agent 之间的工具隔离成为安全基础。

【试一试】

尝试为你的 MCP Server 增加一个简单的认证:在 initialize 阶段传入 token,并在每个工具调用前验证。


7. 实战:Claude Code 中的项目级 MCP 配置与隔离

Claude Code 提供了一套层层递进的隔离方法,可以按需组合使用。

7.1 第一层:配置作用域隔离(划清边界)

通过不同优先级的配置文件,让不同项目使用不同的 MCP 服务器集。

配置优先级(由高到低)

  1. 命令行参数 --mcp-config <path> (仅当前会话)
  2. 项目根目录 .mcp.json (团队共享,可提交 Git)
  3. 项目本地 settings.local.json (个人敏感配置,不提交 Git)
  4. 全局 ~/.claude.json (兜底配置)

实战建议 :团队在项目根目录维护 .mcp.json,个人敏感连接字符串放在 .claude/settings.local.json

7.2 第二层:工具与权限隔离(能力限制)

如果多个项目必须共用同一个 MCP Server(如公司数据库),可通过代理和命名空间进行细粒度控制。

工具过滤示例(使用 mcproxy)

复制代码
// .mcp.json
{
  "mcpServers": {
    "secure-db": {
      "command": "npx",
      "args": ["-y", "@team-attention/mcproxy", "--", "npx", "-y", "@modelcontextprotocol/server-postgres", "postgresql://..."]
    }
  }
}

配合 .mcproxy.json 配置文件:

复制代码
{
  "servers": {
    "postgres@1.0.0": {
      "tools": {
        "query": true,
        "list_tables": true,
        "insert": false,
        "delete": false
      }
    }
  }
}

这样仅允许查询,禁止增删改。

命名空间 :当多个 Server 拥有同名工具时,MCP 防火墙可自动为工具添加前缀,如 github__create_issuejira__create_issue,避免冲突。

7.3 第三层:进程与运行环境隔离(硬隔离)

  • 进程隔离:每个 MCP Server 独立进程,拥有自己的内存空间。
  • 沙箱环境:限制网络访问、文件系统读写,通常用 Docker 容器或 AppArmor 实现。
  • scoped-mcp:一个为复杂场景设计的 Python 包,为每个 Agent 启动专属代理进程,内置凭据隔离、工具过滤和资源分区。

7.4 第四层:企业级纵深防御与审计

建议构建多层防线:

  1. 应用内开关(默认禁用外部工具)
  2. MCP 防火墙(流量过滤、脱敏、审计)
  3. 子 Agent 权限裁剪(最小权限原则)
  4. 系统级沙箱(容器、强制访问控制)

同时建立集中审计日志,记录每一次工具调用的详细信息(谁、时间、项目、工具、参数)。

7.5 总结选择指南

  • 简单省心 :用 .mcp.jsonsettings.local.json 划分项目。
  • 进阶限制 :通过 mcproxy 和命名空间过滤与区分工具。
  • 高安全要求 :采用沙箱和 scoped-mcp 创建安全泡泡。
  • 企业全面管控:部署多层防御 + 审计日志。

【延伸】

  • 审计日志可对接 SIEM 系统,实现对 AI 操作的安全监控和合规性检查。
  • 未来可能出现 MCP 安全标准(类似 OWASP API 安全 Top 10),专门针对 AI 工具调用的威胁建模。

【追问】

  • 在高度动态的 Agent 系统中,如何确保权限策略的实时更新和分发?
  • 代理方式的性能损耗有多大?是否适合高频工具调用场景?
相关推荐
填满你的记忆2 小时前
《RAG 完整工作流程详解》
java·ai·agent·rag
JaydenAI3 小时前
[MAF预定义ChatClient中间件-03]CachingChatClient——利用缓存省钱(Token)省时间
ai·c#·agent·caching·maf·chatclient中间件
爱听歌的周童鞋3 小时前
Learn-Claude-Code | 笔记 | Tools & Execution | s03_new Permission
llm·agent·tools·permission·execution·claude code
Cosolar3 小时前
2026 年 AI 开源生态全景图
人工智能·面试·大模型·agent·rag
雪碧聊技术3 小时前
AI通识一文详解(大模型应用、大模型服务、大模型API)
人工智能·大模型·agent
XLYcmy3 小时前
Agent身份与权限系统设计方案
windows·网络安全·ai·llm·飞书·api·agent
counterxing4 小时前
Reasonix 的设计哲学:不是在 Agent 上加缓存,而是把 Agent Loop 改造成可缓存的形状
agent·ai编程·claude
Terrence Shen12 小时前
Hermes agent的tools是怎么落地应用的系列
人工智能·llm·agent·hermes
Cosolar13 小时前
2026年AI Agent技术生态开源项目合集
人工智能·开源·agent·智能体