MCP详解

【基本介绍】

MCP 一般指 Model Context Protocol(模型上下文协议) :一种开源的标准通信协议,用来让大语言模型(LLM)以统一、可控、安全 的方式连接外部的数据源工具/服务。它常被形容为"AI 的 USB‑C 接口"

以查询位置、获取天气、数据计算为例子,在没有MCP前一般通过Function Calling的方式实现,将其与LLM做绑定,在LangChain中实现代码如下:

python 复制代码
import os
import json
from datetime import datetime

# 导入 LangChain 核心组件
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage, ToolMessage, SystemMessage

# ==========================================
# 1. 定义工具 (Tools)
# 使用 @tool 装饰器,docstring (注释) 对 LLM 非常重要,用于理解何时调用
# ==========================================

@tool
def calculate_expression(expression: str) -> str:
    """
    用于执行数学计算。
    参数 expression 是一个数学表达式字符串,例如 '23 * 4 + 10'。
    """
    return "计算结果"

@tool
def get_current_weather(location: str) -> str:
    """
    查询指定城市或地区的实时天气情况。
    参数 location 是城市名称,如 'Beijing', 'Shanghai'。
    """
    # 模拟 API 返回的数据
    print(f"--- 正在调用天气 API 查询: {location} ---")
    
    
    return "天气结果"
@tool
def get_user_location(user_id: str = "default") -> str:
    """
    获取当前用户的地理位置信息。
    """
    # 模拟定位服务
    print(f"--- 正在定位用户: {user_id} ---")
    return json.dumps({
        "city": "Shenzhen",
        "latitude": 22.5431,
        "longitude": 114.0579,
        "country": "China"
    })

# ==========================================
# 2. 初始化模型并绑定工具
# ==========================================

# 请确保环境变量 OPENAI_API_KEY 已设置,或者在下方直接传入 api_key 参数
# 这里使用 model="gpt-4o" 或 "gpt-3.5-turbo",它们对 tool calling 支持最好
llm = ChatOpenAI(
    model="gpt-4o", 
    temperature=0  # 工具调用场景建议温度设为0,更精准
)

# 将工具列表绑定到 LLM
tools = [calculate_expression, get_current_weather, get_user_location]
llm_with_tools = llm.bind_tools(tools)

# 创建工具映射字典,用于后续根据名称查找并执行函数
tool_map = {
    "calculate_expression": calculate_expression,
    "get_current_weather": get_current_weather,
    "get_user_location": get_user_location
}

# ==========================================
# 3. 定义执行循环 (模拟 Agent 流程)
# ==========================================

def run_conversation(query: str):
    print(f"\n====== 用户提问: {query} ======\n")
    
    # 1. 初始消息列表
    messages = [
        SystemMessage(content="你是一个智能助手。当前时间是 2026年3月19日。请根据用户需求调用相应工具。"),
        HumanMessage(content=query)
    ]

    # 2. 第一次调用 LLM,让它决定是否需要调用工具
    ai_msg = llm_with_tools.invoke(messages)
    messages.append(ai_msg) # 将 AI 的回复(包含工具调用请求)加入历史

    # 3. 检查 LLM 是否发起了工具调用 (tool_calls)
    if ai_msg.tool_calls:
        print(f"检测到 AI 需要调用 {len(ai_msg.tool_calls)} 个工具...")
        
        # 遍历所有需要调用的工具
        for tool_call in ai_msg.tool_calls:
            selected_tool_name = tool_call["name"]
            selected_tool_args = tool_call["args"]
            tool_call_id = tool_call["id"]
            
            print(f"-> 执行工具: {selected_tool_name} 参数: {selected_tool_args}")
            
            # 查找并执行对应的 Python 函数
            selected_tool = tool_map[selected_tool_name]
            tool_output = selected_tool.invoke(selected_tool_args)
            
            print(f"<- 工具返回结果: {tool_output}")

            # 4. 将工具执行结果封装为 ToolMessage 返回给 LLM
            messages.append(ToolMessage(
                content=str(tool_output),
                tool_call_id=tool_call_id
            ))
        
        # 5. 再次调用 LLM,让它根据工具的结果生成最终自然语言回复
        final_response = llm_with_tools.invoke(messages)
        print(f"\n====== AI 最终回复: ======\n{final_response.content}")
    else:
        # 如果不需要调用工具,直接打印回复
        print(f"\n====== AI 直接回复: ======\n{ai_msg.content}")

# ==========================================
# 4. 测试运行
# ==========================================

if __name__ == "__main__":
    # 场景 A: 混合意图(先查位置,再查该位置天气,同时做个计算)
    # 注意:LLM 可能会分步思考,或者并行调用工具
    prompt = "我现在的城市在哪里?那里的天气怎么样?另外算一下 365 乘以 24 是多少。"
    
    run_conversation(prompt)

简单的数值计算可以硬编码或引入库放在代码本地,查询天气和位置需要在相应的函数中通过http调用。

如果没有mcp,每接入一个外部工具,都需要查询外部工具的API并做数据请求。这个过程会在无数项目中重复无数遍。

有了mcp,数据传输有了标准,外部工具自己做好传输协议解析,解析完数据自己调用自己的API接口,使用工具者只需要发送数据请求即可,节省大量工作。

因为有了协议标准,大模型获取外部工具提供的mcp能力,可以直接做隐式绑定,而不用在代码中显式绑定。

外部工具通常会有个mcpserver将来自各方的数据请求和自身API实现隔离,这样可以做到数据请求和API实现的解耦。

因此,一些不联网的外部工具,尤其是一些本地应用,例如unity、blender、photoshop、vs等,也可以通过mcp协议实现能力提供。

更宽泛来看,MCP和服务注册与发现的思想是类似的

【MCP的价值和作用】

  • 标准化集成、降低适配成本:不用每个模型都为每个工具写一套私有对接,改为"支持协议即可互通",更利于生态复用
  • 更可控的安全与权限边界:通过 Host/Server 的权限、白名单、审计、隔离等机制,减少模型越权访问风险。
  • **极大扩展模型能力和数据:**模型可按需读取本地文件、库表、内部系统数据、在线 API 等

【MCP核心概念和模块】

MCP 用一套标准把"模型/应用"和"外部能力"解耦,通常采用 Host--Client--Server 架构:

  • MCP Host(主机):承载并运行 LLM 的应用环境(如桌面助手、IDE、企业智能体平台、Claude Code、Cursor),负责会话管理与界面呈现。
  • MCP Client(客户端):在 Host 内,负责按协议与 MCP Server 通信(常见是 JSON-RPC 风格的请求/响应),做能力发现、路由与调用。
  • MCP Server(服务器):把某个外部系统封装成标准接口,向模型暴露能力

MCP由两层组成:

  • 数据层:定义了基于 JSON-RPC 的客户端-服务器通信协议,包括生命周期管理和核心原语,如工具、资源、提示和通知。
  • 传输层:定义了客户端和服务器之间进行数据交换的通信机制和通道,包括特定于传输的连接建立、消息帧和授权

数据层实现了基于JSON-RPC 2.0 的交换协议,该协议定义了消息结构和语义。该层包括:

  • 生命周期管理:处理客户端和服务器之间的连接初始化、能力协商和连接终止。
  • 服务器功能:使服务器能够提供核心功能,包括用于 AI 操作的工具、上下文数据资源以及与客户端交互的模板提示。
  • 客户端功能:使服务器能够请求客户端从主机LLM进行采样、获取用户输入以及向客户端记录消息。
  • 实用功能:支持实时更新通知和长时间运行操作的进度跟踪等附加功能

传输层管理客户端和服务器之间的通信通道和身份验证。它处理连接建立、消息帧构建以及MCP参与者之间的安全通信。MCP支持两种传输机制:

  • Stdio 传输:使用标准输入/输出流在同一台机器上的本地进程之间进行直接进程通信,提供最佳性能,且无网络开销。
  • 可流式 HTTP 传输:使用 HTTP POST 请求进行客户端到服务器的消息通信,并可选地使用服务器发送事件 (SENT) 来实现流式传输功能。此传输方式支持远程服务器通信,并支持包括持有者令牌、API 密钥和自定义标头在内的标准 HTTP 身份验证方法。MCP 建议使用 OAuth 获取身份验证令牌。

MCP Server 往往提供三类功能:

  • Resources:只读资源,提供对上下文信息的只读访问,例如文件内容、数据库模式或 API 文档
  • Tools:LLM 可以主动调用这些函数,并根据用户请求决定何时使用这些函数。工具可以写入数据库、调用外部 API、修改文件或触发其他逻辑。
  • Prompts:预先构建的指令模板,告诉模型如何使用特定的工具和资源。

在Claude Code中使用MCP Server】

根据传输机制,可以分为两种启动方式:STDIO(本地命令启动)、 SSE/HTTP(远程 URL)

以百度地图为例:

百度地图提供了MCP SDK,就可以用本地命令启动。

直接在配置文件添加如下配置

(配置文件可以是~/.claude.json 或者 <项目目录>/.claude/settings.json 或者 用户目录.claude/settings.json 或者项目级的.mcp.json文件)

python 复制代码
{
  "mcpServers": {
    "baidu-maps": {
      "command": "uvx",
      "args": ["mcp-server-baidu-maps"],
      "env": {
        "BAIDU_MAPS_API_KEY": "<YOUR_API_KEY>"
      }
    }
  }
}

参数含义如下,实际相当于调用命令行的参数

  • command:要执行的可执行文件/命令本体
  • args :传给这个命令的参数列表(按顺序逐个传递,每个参数一个数组元素)
  • env:把 AK 这种敏感信息放环境变量(不要硬编码在代码仓库里)

有些是通过URL连接的,例如UnityMCP,配置形式如下:

python 复制代码
      "mcpServers": {
        "UnityMCP": {
          "type": "http",
          "url": "http://localhost:8080/mcp"
        }
      }

也可以用命令行来添加,形式如下:

python 复制代码
claude mcp add MCP的名字 -- 命令行应该输入的命令

配置完成后重新启动Claude Code,输入/mcp,可以看到当前配置了哪些mcp以及该mcp是否连接上了

【Claude Code如何使用MCP Server】

  • 启动阶段:建立连接

    • Claude Code 启动时,会读取各类配置文件,获取mcpServers的相关配置
    • 有些可以通过命令行启动的MCP Server,会直接通过命名行启动MCP Server子进程;有些需要手动启动
    • 建立通信连接
  • 能力发现阶段:获取工具列表

    • Claude Code 会向每个 MCP Server 查询其提供的工具(Tools)列表,例如

      python 复制代码
      Claude Code 询问: "你能做什么?"
      Unity MCP 返回: [
        - create_gameobject(创建游戏对象)
        - run_script(执行脚本)
        - get_scene_info(获取场景信息)
        ...
      ]
    • 获取到tools列表转换成tool的元描述并绑定,类似在LangChain中绑定tool一样,最终这些tools的信息被放入系统提示中

      • 因此MCP Server最好放在项目级,不要配置过多MCP Server,否则仅仅是tools的描述就会占用大量的token
  • 执行阶段:理解意图并调用工具

    • 模型理解用户意图找到需要调用什么工具

    • 执行Function Calling

    • 通过MCP协议发送给MCP Server

    • MCP Server再调用API获取结果

    • 再将执行结果返回

    • 将执行结果放入上下文

    • 汇总分析回复用户

【获取MCP Server】

官方MCP列表 https://github.com/modelcontextprotocol/servers

社区MCP聚合https://glama.ai/mcp/servers https://mcp.so/ https://cursor.directory/plugins

钉钉MCP广场

【创建自己的MCP服务器】

参考官方示例

https://modelcontextprotocol.io/docs/develop/build-server

【参考】

https://modelcontextprotocol.io/docs/getting-started/intro

相关推荐
ServBay11 小时前
Laravel Herd MCP 的替代,多语言与跨平台的 AI 本地开发选择
后端·ai编程·mcp
码哥字节12 小时前
我把整个代码库喂给 Claude Code,工具超 50 个就静默丢失,这个坑太阴了
mcp·claude code·ai编程工具
ServBay4 天前
打通 AI 编程本地运维边界,利用 MCP 协议简化环境与服务管理
后端·ai编程·mcp
Solis程序员6 天前
MCP (Model Context Protocol):AI应用连接外部世界的标准协议
人工智能·microsoft·agent·skill·mcp
-星空下无敌6 天前
Skills详解(2万字详细教程),Skills是什么,如何安装并使用Skills
人工智能·ai·提示词·codex·mcp·skills·agent skills
老H科研技术6 天前
第 07 篇:OAuth 2.1 与授权架构 —— AS/RS 分离的正确姿势
人工智能·mcp
海天一色y6 天前
深入理解 Function Calling、MCP 与 Skills:AI Agent 的三层能力架构
人工智能·mcp·skills
未秃头的程序猿6 天前
别再重复适配了!用MCP给AI配个"万能工具箱",Java项目接入新能力再也不改代码
后端·ai编程·mcp
宋哥转AI7 天前
Spring AI Alibaba实战:通过MCP协议串联Graph编排与RAG检索
agent·mcp