MCP协议实战:从零开发AI Agent连接外部工具的完整教程(2026最新)

6 阅读7分钟

2026年,MCP(Model Context Protocol)已经成为 AI Agent 开发的事实标准。本文手把手教你用MCP协议开发一个能调用外部工具的AI Agent,附完整代码和踩坑记录。

为什么2026年的AI Agent必须掌握MCP?

如果你还在用"function calling + 手写adapter"的方式开发Agent,那你正在重复造轮子。

MCP是Anthropic在2024年底推出的开放协议,经过一年多的生态演进,2026年已经被主流框架全部支持。它解决的核心问题是:让AI Agent用统一的方式调用任意外部工具,不用为每个API写一套适配代码。

简单类比:MCP之于AI Agent,就像USB之于电脑外设。你不需要为每个鼠标键盘写驱动,插上就能用。

2026年的Agent开发现状:

  • Google A2A(Agent-to-Agent)协议让Agent之间可以协作
  • Anthropic MCP让Agent连接外部工具
  • OpenAI Function Calling仍然是最底层的能力
  • 三者不是竞争关系,而是不同层级的标准

MCP协议核心概念(5分钟搞懂)

架构三角

┌──────────┐     MCP协议     ┌──────────┐
│  AI Agent │ ◄──────────► │ MCP Server│
│ (Client)  │              │  (Tools)  │
└──────────┘              └──────────┘
                               │
                          ┌────┴────┐
                          │外部系统  │
                          │数据库/API│
                          └─────────┘

三个角色:

  1. Host:你的应用,负责发起Agent会话
  2. Client:Agent本体,理解用户意图并决定调用哪些工具
  3. Server:工具提供方,暴露能力给Agent

核心能力

能力说明典型场景
ToolsAgent可调用的函数查数据库、发邮件、调API
ResourcesAgent可读取的数据文件系统、知识库
Prompts预定义的提示模板代码审查、文档生成

传输方式

MCP支持两种传输:

  • stdio:适合本地工具,通过标准输入输出通信
  • HTTP SSE:适合远程服务,通过HTTP Server-Sent Events

实战:从零搭建MCP Agent

环境准备

# Python 3.10+
pip install mcp anthropic

# 或者用Node.js
npm install @modelcontextprotocol/sdk

我在腾讯云轻量服务器上开发(2核4G配置,跑Agent绰绰有余),推荐开发阶段用这个配置:

第一步:写一个MCP Server

先写一个最简单的天气查询工具:

# weather_server.py
from mcp.server import Server
from mcp.types import Tool, TextContent
import httpx

app = Server("weather-tool")

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="get_weather",
            description="查询指定城市的天气",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名"}
                },
                "required": ["city"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments["city"]
        # 调用真实天气API
        async with httpx.AsyncClient() as client:
            resp = await client.get(
                f"https://wttr.in/{city}?format=j1"
            )
            data = resp.json()
            current = data["current_condition"][0]
            return [TextContent(
                type="text",
                text=f"{city}天气:{current['weatherDesc'][0]['value']},"
                     f"温度{current['temp_C']}°C,"
                     f"湿度{current['humidity']}%"
            )]

if __name__ == "__main__":
    import asyncio
    from mcp.server.stdio import stdio_server
    asyncio.run(stdio_server(app))

第二步:配置MCP Client

{
  "mcpServers": {
    "weather": {
      "command": "python",
      "args": ["weather_server.py"],
      "transport": "stdio"
    }
  }
}

第三步:Agent调用逻辑

# agent.py
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from anthropic import Anthropic

async def run_agent():
    # 连接MCP Server
    server = StdioServerParameters(
        command="python",
        args=["weather_server.py"]
    )
    
    async with stdio_client(server) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            
            # 获取可用工具
            tools = await session.list_tools()
            print(f"可用工具: {[t.name for t in tools.tools]}")
            
            # Agent决策:是否需要调用工具
            client = Anthropic()
            response = client.messages.create(
                model="claude-sonnet-4-20250514",
                max_tokens=1024,
                messages=[{"role": "user", "content": "北京今天天气怎么样?"}],
                tools=[{
                    "name": t.name,
                    "description": t.description,
                    "input_schema": t.inputSchema
                } for t in tools.tools]
            )
            
            # 处理工具调用
            for block in response.content:
                if block.type == "tool_use":
                    result = await session.call_tool(
                        block.name, block.input
                    )
                    print(f"工具返回: {result.content[0].text}")

进阶:连接10个常用外部工具

基础跑通之后,实际项目中一个Agent通常需要连接多个工具。以下是我在生产环境中验证过的10个MCP Server配置:

工具用途传输方式复杂度
文件系统读写本地文件stdio
数据库查询MySQL/PGstdio⭐⭐
飞书/钉钉发消息、读文档HTTP SSE⭐⭐⭐
GitHubPR审查、Issue管理stdio⭐⭐
搜索引擎实时信息检索stdio
邮件收发邮件stdio⭐⭐
日历会议调度HTTP SSE⭐⭐
监控Prometheus/GrafanaHTTP SSE⭐⭐⭐
知识库RAG检索stdio⭐⭐
部署CI/CD触发HTTP SSE⭐⭐⭐

多工具配置示例:

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_TOKEN": "ghp_xxx" }
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://..."]
    }
  }
}

关键经验:工具数量控制在10-15个以内。超过15个工具,LLM选择工具的准确率会明显下降。

生产部署注意事项

1. 安全隔离

MCP Server运行在你的服务器上,对外部系统有真实的读写权限。务必做到:

# 白名单机制示例
ALLOWED_PATHS = ["/data/", "/tmp/agent-workspace/"]

@app.call_tool()
async def call_tool(name, arguments):
    if name == "read_file":
        path = arguments["path"]
        if not any(path.startswith(p) for p in ALLOWED_PATHS):
            raise ValueError(f"路径不在白名单内: {path}")

2. 超时和重试

import asyncio

async def safe_call_tool(session, name, args, timeout=30):
    try:
        return await asyncio.wait_for(
            session.call_tool(name, args),
            timeout=timeout
        )
    except asyncio.TimeoutError:
        return {"error": f"工具 {name} 调用超时({timeout}s)"}

3. 成本控制

Agent每次调用LLM都消耗token。在生产环境中,我建议:

  • 简单任务用Claude Haiku(便宜10倍),复杂推理用Sonnet
  • 工具调用结果做缓存(相同参数5分钟内不重复调用)
  • 设置每个session的最大tool call次数

如果需要部署到生产环境,推荐使用阿里云ECS,稳定性好,国内访问延迟低。

踩坑记录(真实经历)

坑1:stdio传输的进程管理

MCP的stdio模式下,Server是一个子进程。如果Agent崩溃,子进程不会自动清理,导致僵尸进程。

解决:用进程组管理,Agent退出时signal整个进程组。

坑2:并发工具调用的顺序问题

当Agent同时调用3个工具时,返回顺序不确定。如果工具之间有依赖(先查数据库,再发邮件),需要在Agent层面做编排。

解决:在system prompt中明确告诉Agent调用顺序,或者用chain-of-thought拆解步骤。

坑3:大模型的"幻觉工具调用"

LLM有时候会调用不存在的工具,或者给工具传错误的参数。

解决:在Client层做严格校验,参数不匹配直接返回错误信息让LLM重试。

FAQ

Q1:MCP和LangChain的Tool有什么区别?

MCP是协议层标准,LangChain的Tool是框架层封装。你可以在LangChain中使用MCP Server,两者是互补关系。LangChain 0.3+ 已经内置了MCP adapter。

Q2:MCP Server可以用什么语言写?

官方SDK支持Python和TypeScript。社区也有Go、Rust、Java的实现。选你团队最熟悉的语言。

Q3:一个Agent最多能连多少个MCP Server?

技术上没有限制,但实测超过15个工具后,LLM的工具选择准确率下降明显。建议按场景分组,每个场景5-8个工具。

Q4:MCP和Google A2A协议的关系?

MCP解决"Agent↔工具"的连接问题,A2A解决"Agent↔Agent"的协作问题。生产级系统两个都需要。

Q5:开发MCP Server需要什么级别的服务器?

开发阶段2核4G足够(腾讯云轻量服务器或阿里云ECS入门款)。生产环境取决于并发量,中等负载4核8G起步。

总结

MCP协议让AI Agent开发从"每个API写一遍adapter"变成了"统一协议、即插即用"。2026年入坑Agent开发,MCP是必修课。

完整项目代码我已整理成可运行的模板,包含上面提到的10个工具Server配置,可以直接clone到你的服务器上跑起来。

如果你对AI Agent开发感兴趣,推荐看看我整理的AI Agent开发实战手册,从架构设计到生产部署的完整路径。


作者:TechFind | AI产品架构师 | 专注AI Agent开发与落地