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。

相关推荐
Captain_Data2 小时前
AI 12小时设计CPU完整解析:从219字到RISC-V内核的技术突破
人工智能·python·ai·大模型·芯片设计·risc-v
AI砖家2 小时前
解剖 Claude Code:如何搭建一个企业级的私有化 AI 编程助手
前端·人工智能·ai编程
数智化精益手记局2 小时前
仓库安灯管理系统的异常响应机制:破解仓库安灯管理系统的跨部门协同难题
大数据·数据结构·人工智能·制造·精益工程
每日综合2 小时前
燕之屋“国家绿色工厂”隆重揭牌,以绿色智造赋能行业发展
人工智能
互联科技报2 小时前
矩阵头部产品源码泄露超级编导超级智剪筷子科技拆解对比分享
人工智能
zhangshuang-peta2 小时前
MCP 的终局形态:它会成为 AI 系统的“操作系统层”吗?
人工智能·ai agent·mcp·peta
qq_411262422 小时前
四博 AI 智能拍学机 / AI 智能音箱技术方案
人工智能·智能音箱
Gh0st_Lx2 小时前
【6】持续学习方法概述:在数据集 B 上变强了,在数据集 A 上却暴跌?
人工智能·语言模型·transformer
前端摸鱼匠2 小时前
【AI大模型春招面试题27】字节对编码(BPE)的分词过程?如何处理未登录词(OOV)?
人工智能·ai·面试·大模型·求职招聘