Agent 开发中,大模型本身通常只能处理输入、进行推理并生成结果。

而要处理实际业务,仅靠模型的能力并不能完成任务。

假设我们正在开发一个客户支持 Agent,用户给它一个任务:

帮我整理今天收到的客户问题,结合订单状态和产品知识库,找出最需要优先处理的三个问题,给出处理建议,并为负责人创建跟进任务。

这句话看起来很简单,背后却涉及几个完全不同的系统。

Agent 要先从客服系统读取今天的工单,再根据工单中的订单号查询订单状态;遇到退款、付款或者产品使用问题,还需要读取内部知识库;完成判断以后,可能还要在任务系统中创建跟进任务。

整个过程大致是:

Agent 连接客服系统、订单系统、产品知识库和任务管理系统的架构示意图放大查看 ↗
图示Agent 接收用户请求,并根据任务需要访问客服、订单、知识库和任务管理等外部系统。

这些系统通常都有自己的 API、SDK、认证方式和数据格式。

如果我们开发这样一个 Agent,就需要分别编写客服系统、订单系统、知识库和任务系统的集成代码。

以后又开发一个新的 Agent,这些能力可能还要重新接一次。

MCP 解决的正是这一层连接问题。

一、MCP 是什么

MCP 全称 Model Context Protocol,模型上下文协议。

它是一套开放协议,用于让 AI 应用以统一方式连接外部的数据和能力。

一个系统按照 MCP 暴露自己的能力之后,支持 MCP 的 AI 应用就能够发现并使用这些能力。

例如前面的客户支持系统,可以提供:

代码片段Text
search_tickets()
get_order()
create_followup_task()

知识库则可以提供:

代码片段Text
kb://policies/refund
kb://products/payment

Agent 不需要理解底层客服系统使用的是 REST API,订单系统连接的是 PostgreSQL,还是知识库来自某个内部搜索服务。

这些细节留在 MCP Server 内部。

从 Agent 一侧看到的是统一的 MCP 接口。

因此,MCP 更接近 AI 应用和外部系统之间的一层标准连接协议。

它没有让原来的 API、数据库或者 SDK 消失。

实际项目通常会变成:

代码片段Text
AI Application
       │
       │ MCP
       ▼
   MCP Server
       │
       ├── REST API
       ├── Database
       ├── SDK
       └── Internal Service

MCP Server 负责把已有系统的能力转换成 AI 应用更容易发现和使用的形式。

这也是理解 MCP 最重要的一点。

二、为什么需要 MCP

假设没有 MCP。

我们的客户支持 Agent 需要查询订单,于是直接在代码里调用订单 API:

代码片段Python
def get_order(order_id: str):
    return requests.get(
        f"https://order.example.com/orders/{order_id}"
    ).json()

需要读取客服工单,再写一个接口。

需要创建跟进任务,再接一个任务管理 API。

最终 Agent 内部可能出现大量这样的适配代码:

代码片段Text
Customer Support Agent
 ├── Support API Adapter
 ├── Order API Adapter
 ├── Knowledge Base Adapter
 └── Task API Adapter

对于一个应用,这种方式完全可行。

问题出现在能力开始复用以后。

例如公司后来又有:

代码片段Text
客户支持 Agent
销售 Agent
运营 Agent
内部知识助手
桌面 AI 客户端
IDE Agent

它们都可能需要读取订单或者访问知识库。

如果每个 AI 应用都自行实现一次集成,系统之间的连接会逐渐成为一张复杂的网。

MCP 希望把这种关系变成:

AI Application 通过 MCP 连接 Support、Order、Knowledge 和 Task MCP Server 的架构示意图放大查看 ↗
图示AI Application 通过统一的 MCP 协议接入多个 MCP Server,将客服、订单、知识库和任务管理等外部能力以一致的方式连接到应用中。

外部能力拥有相对统一的协议边界。

AI 应用重点处理模型、上下文和任务执行,MCP Server 负责具体系统的访问方式。

三、MCP 中的 Host、Client 和 Server

理解 MCP,需要先认识三个角色:

Host 内的 Agent 或 AI Application 通过 MCP Client 连接 MCP Server,并访问 Tools、Resources 和 Prompts 的架构示意图放大查看 ↗
图示在 MCP 架构中,Agent 或 AI Application 运行在 Host 内,通过 MCP Client 与 MCP Server 通信;Server 再向应用提供 Tools、Resources 和 Prompts 等能力。

Host

Host 是承载 AI 能力的应用。

例如一个 Agent 应用、桌面 AI 客户端、IDE,或者我们自己开发的 AI 系统。

Host 通常负责管理模型调用、用户交互、上下文、权限以及 MCP 连接。

Client

MCP Client 是 Host 中负责 MCP 通信的组件。

它知道如何向 Server 查询能力、读取 Resource、调用 Tool,并把结果交回 Host。

因此,MCP Client 和大模型是两个不同的角色。

模型负责判断和推理,Client 负责协议通信。

Server

MCP Server 对外提供具体能力。

例如:

代码片段Text
Order MCP Server
Support MCP Server
Database MCP Server
Filesystem MCP Server

Server 可以运行在用户电脑上,也可以部署成远程服务。

目前 MCP 官方提供了 Python SDK,可以直接用来开发 MCP Client 和 MCP Server,并支持 stdio、Streamable HTTP 等标准传输方式。

真正决定 MCP Server 能提供什么的,是接下来三个核心概念。

四、Tools、Resources 和 Prompts

MCP Server 最基础的三类能力是:

代码片段Text
Tools
Resources
Prompts

它们经常一起出现,但解决的问题并不相同。

官方对三者的控制方式也有明确区分:Tools 偏向模型选择,Resources 由应用读取,Prompts 通常由用户主动选择。

Tool:让 Agent 执行操作

回到客户支持 Agent。

如果它需要查询工单,MCP Server 可以提供:

代码片段Text
search_tickets()

查询订单:

代码片段Text
get_order()

创建任务:

代码片段Text
create_followup_task()

这些都属于 Tool。

Tool 可以理解为:模型能够选择并调用的函数。

例如:

代码片段Python
@mcp.tool()
def get_order(order_id: str) -> dict:
    """Get order information by order ID."""
    ...

MCP Client 能够发现这个 Tool 的名称、说明以及参数结构。

模型随后就有机会判断:

当前任务需要知道订单状态,因此应该调用 get_order。

在 MCP SDK 中,函数名会成为 Tool 名称,docstring 可以作为描述,而 Python 类型标注会用于生成输入 JSON Schema。

因此:

代码片段Python
def get_order(order_id: str)

不仅是普通的 Python 函数签名。

它最终还会帮助 Client 和模型知道:

代码片段Text
工具名称:get_order
参数:
  order_id: string

Tool 是 MCP 中使用频率最高的能力。

很多 Agent 接入 MCP,首先使用的也是 Tools。

五、Resource:给 AI 应用提供上下文

假设 Agent 正在处理一个退款问题。

除了订单状态,它还需要知道公司的退款规则。

我们当然也可以设计一个 Tool:

代码片段Text
get_refund_policy()

不过退款政策本身更接近一份可读取的数据。

MCP 为这种场景提供了 Resource。

例如:

代码片段Text
kb://policies/refund

它表示知识库中的退款政策。

还可以定义:

代码片段Text
kb://products/{product_id}/manual

表示某个产品的使用说明。

Resource 的核心特征是拥有一个 URI。

应用根据 URI 读取内容,然后将内容加入模型上下文。

官方 SDK 对 Resource 的定义也很直接:Tool 由模型决定调用,而 Resource 是应用选择加载的数据。

因此这两个操作虽然都可能返回数据,语义并不一样:

代码片段Text
get_order("A10248")

表达的是:

执行一次订单查询。

而:

代码片段Text
kb://policies/refund

表达的是:

这里有一份可以读取的退款政策资源。

六、Prompt:提供可复用的交互模板

第三类能力是 Prompt。

假设客户支持团队有一套固定的问题分析方法:

代码片段Text
判断问题类别
判断紧急程度
检查相关订单
确认适用规则
给出处理建议
指出仍需人工确认的信息

可以把这套方法定义为:

代码片段Text
analyze_customer_issue

MCP Server 将它作为 Prompt 提供。

用户或者 Host 可以选择这个 Prompt,再传入当前客户问题。

Prompt 更像服务端提供的一套可复用工作模板。

因此三者的职责可以归纳为:

代码片段Text
Tool      → 做什么
Resource  → 读取什么
Prompt    → 按什么模板处理

很多 MCP 系统实际上只需要 Tools。

Resources 和 Prompts 并不是为了凑齐 MCP 的三个概念而必须使用。只有当系统确实存在清晰的数据资源或者可复用交互模板时,引入它们才有意义。

七、一次 MCP Tool 调用到底发生了什么

理解 MCP 最容易混乱的地方,是“谁在调用谁”。

假设用户告诉 Agent:

找出今天最需要优先处理的三个客户问题。

一个简化后的执行过程可能是:

代码片段Text
User
 │
 ▼
Host
 │
 │ 获取 Server 能力
 ▼
MCP Client
 │
 │ tools/list
 ▼
MCP Server
 │
 │ 返回 Tool 定义
 ▼
Host
 │
 ▼
LLM
 │
 │ 判断需要 search_tickets
 ▼
Host
 │
 ▼
MCP Client
 │
 │ tools/call
 ▼
MCP Server
 │
 ▼
客服系统
 │
 │ 返回工单
 ▼
MCP Server
 │
 ▼
Host / LLM

模型拿到工单后,可能发现其中一个问题涉及订单:

代码片段Text
“付款成功,但订单一直显示未支付。”

模型再次判断需要调用:

代码片段Text
get_order(order_id="A10251")

订单信息返回以后,模型继续分析。

如果问题涉及退款规则,Host 还可以读取:

代码片段Text
kb://policies/refund

最终模型得到足够的信息,再给出处理建议。

如果需要人工跟进,模型可能继续请求:

代码片段Text
create_followup_task(...)

整个 Agent Loop 就是这样逐步向前推进。

MCP 处在其中负责外部能力发现与通信的位置。

八、实现一个 MCP Server

理解概念以后,可以写一个最小但具有实际意义的 MCP Server。

本文使用当前官方 Python SDK v2。

安装:

代码片段Bash
pip install "mcp[cli]"

创建:

代码片段Text
server.py

代码如下:

代码片段Python
from mcp.server import MCPServer
 
 
mcp = MCPServer("Customer Support")
 
 
TICKETS = [
    {
        "id": "T-1024",
        "title": "退款五天后仍未到账",
        "order_id": "A10248",
        "status": "open",
    },
    {
        "id": "T-1025",
        "title": "付款成功但订单仍显示未支付",
        "order_id": "A10251",
        "status": "open",
    },
]
 
 
ORDERS = {
    "A10248": {
        "id": "A10248",
        "status": "refunded",
        "refund_status": "processing",
    },
    "A10251": {
        "id": "A10251",
        "status": "payment_review",
        "refund_status": None,
    },
}
 
 
@mcp.tool()
def search_tickets(status: str = "open") -> list[dict]:
    """Search customer support tickets by status."""
    return [
        ticket
        for ticket in TICKETS
        if ticket["status"] == status
    ]
 
 
@mcp.tool()
def get_order(order_id: str) -> dict:
    """Get order information by order ID."""
    return ORDERS.get(
        order_id,
        {"error": "Order not found"},
    )
 
 
@mcp.tool()
def create_followup_task(
    ticket_id: str,
    title: str,
    priority: str,
) -> dict:
    """Create a follow-up task for a support ticket."""
    return {
        "success": True,
        "ticket_id": ticket_id,
        "title": title,
        "priority": priority,
    }
 
 
@mcp.resource("kb://policies/{topic}")
def get_policy(topic: str) -> str:
    """Read a customer support policy."""
    policies = {
        "refund": (
            "退款通常会在 3-5 个工作日内到账。"
            "超过该时间仍未到账,需要进入人工审核。"
        ),
        "payment": (
            "付款成功但订单状态未更新时,"
            "应先检查支付回调和订单同步状态。"
        ),
    }
 
    return policies.get(topic, "Policy not found.")
 
 
@mcp.prompt()
def analyze_customer_issue(
    issue: str,
    order_status: str,
) -> str:
    """Generate a prompt for customer issue analysis."""
    return f"""
分析下面的客户问题。
 
客户问题:
{issue}
 
订单状态:
{order_status}
 
请完成:
1. 判断问题类别
2. 判断紧急程度
3. 分析可能原因
4. 给出处理建议
5. 指出需要人工确认的信息
"""
 
 
if __name__ == "__main__":
    mcp.run(
        transport="streamable-http",
        json_response=True,
    )

这个例子虽然很短,实际上已经包含了 MCP Server 的三个核心能力。

search_tickets、get_order 和 create_followup_task 是 Tools。

kb://policies/{topic} 是 Resource Template。

analyze_customer_issue 是 Prompt。

SDK 会根据 Python 函数签名生成工具 Schema,因此我们没有手工编写 JSON Schema,也没有自己实现 tools/list、tools/call 或 resources/read 等协议处理逻辑。

这也是使用 MCP SDK 的主要意义之一。

九、使用 MCP Server

安装 mcp[cli] 后,可以使用开发工具启动:

代码片段Bash
mcp dev server.py

MCP Inspector 可以帮助我们查看 Server 暴露出来的 Tool、Resource 和 Prompt,并直接进行调用测试。

例如调用:

代码片段Text
search_tickets

参数:

代码片段JSON
{
  "status": "open"
}

Server 会返回当前开放工单。

调用:

代码片段Text
get_order

参数:

代码片段JSON
{
  "order_id": "A10248"
}

则会得到对应订单状态。

在真正的项目中,只需要把示例里的内存数据替换成真实业务系统:

代码片段Text
search_tickets()
        │
        ▼
Customer Support API

get_order()
        │
        ▼
Order Service

create_followup_task()
        │
        ▼
Task System

kb://policies/*
        │
        ▼
Knowledge Base

MCP Server 对 Agent 暴露的接口基本可以保持稳定。

底层实现则可以独立变化。

十、MCP 和 Function Calling 有什么区别

这是理解 MCP 时最常见的疑问之一。

因为看到:

代码片段Python
@mcp.tool()
def get_order(...):
    ...

很容易觉得:

这不就是 Function Calling 吗?

二者确实经常一起工作,但负责的环节不同。

Function Calling 主要解决:

模型如何表达“我想调用这个函数”。

例如 Host 给模型提供:

代码片段Text
get_order(order_id)
search_tickets(status)

模型根据当前上下文返回:

代码片段Text
调用 get_order
order_id = A10248

这属于模型与 Host 之间的工具调用机制。

MCP 解决的是另一层问题:

Host 去哪里发现这些工具,又怎样以统一方式调用它们。

完整关系更接近:

代码片段Text
MCP Server
    │
    │ tools/list
    ▼
MCP Client
    │
    │ Tool definitions
    ▼
Host
    │
    ▼
LLM
    │
    │ 选择 get_order
    ▼
Host
    │
    ▼
MCP Client
    │
    │ tools/call
    ▼
MCP Server

因此在实际 Agent 中,两者经常共同出现。

MCP 把 Tool 定义交给 Host,Host 再按照具体模型供应商支持的 Tool Calling / Function Calling 格式提供给模型。

模型决定要调用哪个 Tool。

Host 再通过 MCP Client 完成真实调用。

十一、MCP 和 API 有什么区别

MCP 出现以后,还有一种说法是:

有了 MCP,以后是不是不需要 API 了?

现实恰恰相反。

绝大多数 MCP Server 背后仍然依赖 API。

例如:

代码片段Text
Agent
  │
  │ MCP
  ▼
Order MCP Server
  │
  │ REST API
  ▼
Order Service

订单系统已经有稳定 API,就没有必要为了 MCP 重写订单系统。

我们只需要在 MCP Server 中调用原来的 API:

代码片段Python
@mcp.tool()
def get_order(order_id: str):
    return order_api.get_order(order_id)

API 主要解决系统与系统之间的接口问题。

MCP 在此基础上增加了一套面向 AI 应用的能力描述、发现和调用方式。

所以更准确的关系是:

代码片段Text
MCP
 │
 ▼
API / SDK / Database / File System

MCP 经常建立在现有基础设施之上。

十二、MCP 和 RAG 有什么关系

RAG 也是 Agent 开发中经常和 MCP 一起出现的概念。

例如公司有十万份内部文档。

用户问:

我们企业版退款有什么特殊规则?

RAG 系统可能执行:

代码片段Text
Question
   │
   ▼
Retrieval
   │
   ▼
Relevant Documents
   │
   ▼
LLM

它解决的是:

怎样从大量知识中找到与当前问题相关的内容。

MCP 关注的是:

AI 应用怎样连接并使用这种能力。

因此完全可以构建:

代码片段Text
Agent
  │
  │ MCP
  ▼
Knowledge MCP Server
  │
  ▼
RAG Service
  │
  ├── Embedding
  ├── Vector Database
  └── Reranker

然后向 Agent 暴露:

代码片段Text
search_knowledge(query)

RAG 成为 Tool 背后的实现。

也可以把确定的文档通过 Resource 暴露:

代码片段Text
kb://policies/refund

MCP 和 RAG解决的是不同层次的问题,因此经常组合使用。

十三、本地 MCP 和远程 MCP

MCP Server 并不一定部署在服务器上。

一个常见场景是本地进程:

代码片段Text
AI Application
      │
      │ stdio
      ▼
Local MCP Server
      │
      ▼
Local Files / Git / CLI

这类方式适合访问本地文件、开发工具或者操作系统能力。

另一种是远程服务:

代码片段Text
AI Application
      │
      │ HTTP
      ▼
Remote MCP Server
      │
      ▼
Business Service

例如:

代码片段Text
CRM
订单系统
企业知识库
数据平台
内部 SaaS

可以统一部署为 Remote MCP Server。

当前 SDK 支持 stdio、Streamable HTTP 等标准传输方式。

对于刚开始学习 MCP 的开发者,不需要马上深入这些协议细节。

先掌握:

代码片段Text
本地能力 → stdio MCP Server

远程业务能力 → HTTP MCP Server

已足够可以设计实际系统。

十四、什么时候值得使用 MCP

MCP 很有价值,但它并不意味着每个 Agent 都需要增加一个 MCP Server。

例如只有一个简单应用,而且只有两个内部函数:

代码片段Python
search_database()
calculate_price()

这些函数只服务当前 Agent,也没有复用需求。

直接通过模型的 Tool Calling 使用它们,结构通常更简单。

当下面的情况出现时,MCP 的价值会明显增加:

同一种能力开始被多个 Agent 或 AI 应用共享;外部系统越来越多;工具需要独立开发和部署;希望模型供应商与业务能力之间保持较弱耦合;需要把内部系统提供给不同 AI Client;或者准备把某项能力作为标准化 Agent 接口提供给其他团队。

所以判断是否需要 MCP 时,可以思考一个很实际的问题:

我是在给当前 Agent 写一个函数,还是在提供一种可以被多个 AI 应用使用的能力?

如果答案接近后者,MCP 通常会更加合适。

十五、MCP 的真正难点往往不是写 Tool

写一个 Tool 很简单:

代码片段Python
@mcp.tool()
def get_order(order_id: str):
    ...

真正进入生产环境以后,问题会很快转向:

代码片段Text
谁可以调用这个 Tool?
模型能否直接执行删除操作?
不同用户看到的数据是否应该不同?
API Token 放在哪里?
读取到恶意内容怎么办?
敏感操作是否需要用户确认?

这些问题比装饰器本身重要得多。

例如:

代码片段Text
get_order()

通常只是读取数据。

而:

代码片段Text
refund_order()
delete_customer()
send_email()

已经会修改外部世界。

这类 Tool 应该设置更严格的权限边界,很多场景还需要用户确认。

同时,MCP Server 的凭据应该保留在 Server 侧:

代码片段Text
Agent
 │
 │ MCP
 ▼
MCP Server
 │
 │ API Token
 ▼
Business API

模型不需要知道真正的数据库密码或者业务系统 Token。

还要考虑 Prompt Injection。

Agent 从工单、网页、邮件或者文档中读取的内容都属于外部数据,其中可能包含恶意指令。

MCP 解决的是连接标准,并不会自动让模型免疫 Prompt Injection。

官方 MCP 资料也明确提醒,Tool annotations 等元数据只能给 Host 提供风险信息,真正的安全边界仍需要权限控制、网络限制、沙箱和人工确认等机制落实。

因此,生产 MCP Server 至少应把“最小权限”“凭据隔离”“敏感操作确认”和“不可信数据边界”作为基础设计。

十六、重新理解 MCP

回到文章开始的客户支持 Agent。

用户只说了一句话:

帮我整理今天收到的客户问题,结合订单状态和产品知识库,找出最需要优先处理的三个问题,给出处理建议,并为负责人创建跟进任务。

真正执行时可能经过:

代码片段Text
用户
 │
 ▼
Agent
 │
 ├── search_tickets()
 │
 ├── get_order()
 │
 ├── kb://policies/refund
 │
 └── create_followup_task()
 │
 ▼
最终结果

模型负责理解任务、判断下一步和生成结果。

Host 负责运行 Agent、管理上下文和安全策略。

MCP Client 负责协议通信。

MCP Server 负责向 AI 应用暴露外部数据和能力。

底层仍然可以是:

代码片段Text
REST API
Database
File System
SDK
Search Engine
RAG
Internal Service

MCP 的意义就在这些层之间建立了一个统一边界。

当 Agent 只调用一两个内部函数时,这层协议可能没有必要。

当系统逐渐需要连接更多工具、更多数据源,并且这些能力需要被多个 AI 应用重复使用时,MCP 的价值才会真正显现出来。

理解到这里,MCP 就不再只是:

代码片段Text
@mcp.tool()

这样的几个装饰器。

它解决的是一个更加基础的工程问题:

当 Agent 开始真正连接外部世界,我们应该用什么方式定义、发现和调用这些能力。