MCP协议原理与实战:让大模型真正「能动」起来

写了一个能「调用工具」的 Agent,结果每次加新工具都得改代码、重新部署、调参------这种痛苦,MCP 协议来解决。

一句话概括

MCP(Model Context Protocol)是大模型连接外部世界的「USB 接口」,有了它,你的 AI 不用再为每个工具单独写适配层,协议即标准,插上就能用。


为什么我们需要 MCP

说实话,早期做大模型应用的人都在重复造同一个轮子:怎么让 LLM 调用工具?

GPT-4 的 Function Calling 出来后,业界的主流方案是每个工具写一个 function_schema,LLM 返回函数名和参数,后端去调用。这套机制在场景简单时挺好用------三五个工具,靠 prompt engineering + function calling 勉强能跑。

但一旦工具数量超过 20 个、工具之间有依赖关系、需要跨 Agent 共享工具,你就发现这套方案的脆弱:

Prompt 膨胀。每个工具的描述塞进 system prompt,token 成本飙升,LLM 的推理质量反而下降。

协议碎片化。LangChain 有自己的 tool calling 格式,AutoGPT 有自己的,GPTs Actions 又是另一套。你写的工具没法跨平台复用。

版本管理混乱。工具的参数变了,prompt 里的描述也要同步更新,一不小心线上就「静默失败」。

MCP 就是 Anthropic 对这些问题的回答------一个开放协议,定义了 LLM 如何发现工具、调用工具、传递上下文。工具提供方只需要实现 MCP server,消费方只需要实现 MCP client,协议层统一,谁也不需要知道对方的具体实现。


MCP 核心原理

协议架构:三件事

MCP 协议本质上只做三件事:

第一,能力发现(Capability Discovery) 。Client 连接 server 后,server 通过 initialize 握手把自己能提供的所有能力(tools、resources、prompts)清单发给 client。这个清单是自描述的------每个 tool 有 name、description、input_schema,client 不需要提前知道 server 有什么,运行时动态发现。

第二,工具调用(Tool Invocation) 。Client 告诉 LLM 有哪些工具可用,LLM 决定调用哪个工具及参数。MCP 用 JSON-RPC 2.0 作为传输层,调用请求结构是 {"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "...", "arguments": {...}}, "id": 1}。简单、明确、可扩展。

第三,上下文注入(Context Injection) 。工具调用返回的结果,通过 rootssampling 机制回流给 LLM,作为下一轮推理的上下文。这解决了「工具返回结果 LLM 看不到」的问题。

Transport 层:不止一种

MCP 的设计是 transport-agnostic,官方默认实现了两套:

  • stdio:通过标准输入输出通信,适合本地进程、子进程调用。Claude Desktop 用这套。
  • HTTP + SSE:Server 通过 HTTP 响应发送 events(Server-Sent Events),client 通过另一个 HTTP POST 发送请求。适合远程服务,Browsermcp 用这套。

选哪种取决于你的部署场景------本地工具链用 stdio,远程服务用 SSE,没有谁比谁更好。

资源与提示词:不只是工具

MCP 设计了一个比「工具调用」更宽的抽象------ResourcesPrompts

Resources 是「LLM 可以读取的数据」。比如一个文件、一段数据库查询结果、一个 API 响应的 JSON。Resources 有 URI,LLM 可以按需请求具体某个 resource,而不需要把所有数据都塞进 prompt。

Prompts 是「预定义的 prompt 模板」。Server 可以暴露一系列已封装好的 prompt,client 通过 prompts/list 发现它们,在合适的时候调用。这比在代码里写死的 system prompt 灵活得多。


实战:手写一个 MCP Server

说原理容易,上手才难。我来手写一个真实可用的 MCP server------一个能搜索 Wikipedia 并返回摘要的工具。

环境准备

bash 复制代码
pip install mcp[cli] httpx
# 或用 uv
uv add mcp httpx

定义 Server

python 复制代码
# wiki_mcp_server.py
from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("Wikipedia Search")

@mcp.tool()
async def search_wikipedia(query: str, lang: str = "en") -> str:
    """
    Search Wikipedia and return article summaries.
    
    Args:
        query: Search query
        lang: Language code (en, zh, ja, etc.)
    """
    async with httpx.AsyncClient() as client:
        # Step 1: Search for articles
        search_url = f"https://{lang}.wikipedia.org/w/api.php"
        search_params = {
            "action": "opensearch",
            "search": query,
            "limit": 5,
            "format": "json"
        }
        search_resp = await client.get(search_url, params=search_params)
        search_data = search_resp.json()
        
        if not search_data[1]:
            return f"No results found for '{query}'"
        
        # Step 2: Get article extracts
        results = []
        for title, url in zip(search_data[1], search_data[3]):
            extract_params = {
                "action": "query",
                "titles": title,
                "prop": "extracts",
                "exintro": True,
                "format": "json"
            }
            extract_resp = await client.get(search_url, params=extract_params)
            pages = extract_resp.json()["query"]["pages"]
            page = list(pages.values())[0]
            extract = page.get("extract", "No summary available.")
            results.append(f"## {title}\n{extract}\nSource: {url}\n")
        
        return "\n---\n".join(results)

if __name__ == "__main__":
    mcp.run(transport="stdio")

客户端调用

python 复制代码
# client_example.py
from mcp import ClientSession
from mcp.client.stdio import stdio_client
import asyncio

async def main():
    async with stdio_client() as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            
            # 动态发现工具
            tools = await session.list_tools()
            print("Available tools:", [t.name for t in tools])
            
            # 调用工具
            result = await session.call_tool(
                "search_wikipedia",
                {"query": "Large Language Model", "lang": "en"}
            )
            print(result.content[0].text)

asyncio.run(main())

整个过程没有硬编码任何 tool description------description 来自 @mcp.tool() 装饰器,input_schema 来自类型注解。MCP 客户端连接后自动拿到这些元信息。


我踩过的坑

stdio 模式的编码问题

MCP stdio 传输层对 stdin/stdout 的编码非常敏感。在 macOS 上默认是 UTF-8,没问题,但在某些 Linux 发行版上,如果 locale 设置不对,中文字符会变成乱码,导致 JSON-RPC 消息解析失败。

解法 :运行 server 前设置 export LANG=en_US.UTF-8

SSE 模式下的 CORS

如果你的 MCP server 暴露为 HTTP+SSE,前端直接调用会遇到 CORS 问题。Browsermcp 的做法是在浏览器扩展层做了 CORS 代理,生产环境建议用 nginx 反向代理 + 明确设置 Access-Control-Allow-Origin

工具返回结果的大小

MCP 协议本身对返回结果大小没有硬限制,但 LLM 的 context window 是有限的。我曾经写了个 MCP server 返回了整本 Wikipedia 文章,结果 LLM 看到的是超长的 context,性能严重下降。

解法:在 server 端做截断,返回「足够 LLM 做决策」的信息量,而不是「完整信息」。


进阶:MCP 在 Multi-Agent 场景的应用

MCP 最有潜力的场景不是单 Agent 单 server,而是 Multi-Agent 共享工具

假设你有三个 Agent:搜索 Agent、分析 Agent、写作 Agent。它们都需要访问同一个「企业内部知识库」。没有 MCP 之前,你得在三个 Agent 的 prompt 里都塞一份知识库的 API 调用说明,重复且难以维护。

有了 MCP,你可以:

  1. 部署一个 knowledge-base-mcp-server,暴露 searchget_documentlist_collections 三个工具
  2. 三个 Agent 的 client 都连接这个 server
  3. 当 LLM 判断「我需要查一下 Q3 财报数据」时,它看到的工具列表里自然有这个知识库的能力,不需要任何额外配置

这才是 MCP 的真正价值:让工具成为可共享的基础设施,而不是绑定在某个 Agent 里的私有能力


写在最后

MCP 协议目前还处于早期阶段,生态还在建设,但它解决的是一个真实的工程问题:大模型应用的可扩展性。

我现在写任何新的 AI 应用,第一件事就是看有没有现成的 MCP server 能用。Anthropic 官方维护的 aws-mcp、filesystem-mcp、github-mcp 已经覆盖了常见场景,Supabase、Figma、Slack 这些第三方 server 也在快速跟进。

协议的魅力在于:一旦建立标准,生态就会自运转。你不需要说服任何人用你的工具------只要你的工具实现了 MCP,就能被任何 MCP client 发现和使用。

这才是真正的「解耦」。

讨论问题:你觉得 MCP 协议会像 USB 一样成为 AI 时代的标配,还是会因为各大厂商的利益博弈而分裂成多个阵营?欢迎留言区Battle。

相关推荐
2zcode几秒前
基于改进YOLOv8与BiLSTM的智能安防盗窃行为识别系统-融合CBAM注意力机制与ByteTrack多目标跟踪
人工智能·yolo·目标跟踪
AI周红伟1 分钟前
All in Token,移动,电信和联通,华为,阿里,百度,字节,卖Token Plan,卖算力时代结束,卖智力时代来了:Token经济万亿赛道全景解码
大数据·人工智能·机器学习·百度·华为·copilot·openclaw
SuAluvfy2 分钟前
不存在“全能第一模型”,存在“任务空间中的局部最优模型”
人工智能·chatgpt·agent
workflower3 分钟前
AI能源智慧生产与绿色开发核心场景
大数据·人工智能·设计模式·机器人·软件工程·能源
染指11107 分钟前
4.AI大模型-幻觉、记忆、参数-大模型底层运行机制
人工智能
晓蓝WQuiet10 分钟前
GAN生成对抗网络
人工智能·神经网络·生成对抗网络
闵孚龙11 分钟前
Claude Code 权限系统全解析:AI Agent 安全治理、权限模式、规则匹配、沙箱防护与企业落地实战
人工智能·安全
测试员周周11 分钟前
【Appium 系列】第10节-手势操作实战 — 滑动、拖拽、缩放与轻拂
linux·服务器·开发语言·人工智能·python·appium·pytest
耕烟煮云12 分钟前
一篇文章讲清大语言模型发展史
人工智能·语言模型·自然语言处理
硅谷秋水15 分钟前
ARIS:基于对抗性多智体协作的自主研究
人工智能·科技·机器学习·语言模型·软件工程