MCP 是什么:Agent 如何通过标准协议连接工具和外部服务

前言

前面我们已经学习了 Tool Calling。

Tool Calling 的基本思路是:模型决定要调用什么工具,后端负责校验参数、执行真实业务,然后把结果返回给模型。

但是当 Agent 项目逐渐变多时,会出现一个新问题:

text 复制代码
每个 Agent 都要重复接数据库工具吗?
每个 Agent 都要重复对接 Git、文件系统、接口文档吗?
不同模型、不同框架之间,工具定义能不能复用?

这时,MCP 就出现了。

MCP 全称是 Model Context Protocol,可以理解为一种让 AI 应用连接外部能力的标准协议。

它希望解决的问题不是"让模型变聪明",而是:

让 Agent 能以更统一的方式发现、调用和使用外部工具、资源与提示词模板。

对于 Java 后端开发者来说,MCP 可以先理解成:

text 复制代码
Agent 侧的标准化工具接入协议

它和我们平时做 REST API、RPC、消息队列一样,核心价值是降低系统之间的耦合。


一、没有 MCP 时,工具接入会遇到什么问题

假设我们开发了三个 Agent:

text 复制代码
项目知识库助手
代码审查助手
运维排障助手

它们都可能需要访问一些公共能力:

text 复制代码
查询 Git 提交记录
搜索项目文件
读取接口文档
查询发布记录
查询服务日志

如果每个 Agent 都自己封装一套工具,会变成下面这样:

text 复制代码
知识库助手 -> 自己实现 Git 查询工具
代码审查助手 -> 再实现一套 Git 查询工具
运维助手 -> 再实现一套日志查询工具

久而久之就会出现:

  • 工具定义不统一;
  • 参数格式不统一;
  • 权限校验逻辑分散;
  • 错误处理方式不一致;
  • 工具升级时需要改多个项目;
  • 很难让新的 Agent 快速复用已有能力。

MCP 的思路是把这些能力标准化。

text 复制代码
多个 Agent Client
        |
        | MCP 协议
        |
多个 MCP Server
        |
Git、数据库、文件、内部接口、日志系统

这样,Agent 不需要关心每个外部系统具体怎么实现,而是通过统一的工具描述和调用方式使用能力。


二、MCP 的核心角色

理解 MCP 时,可以先记住三个角色。

1. MCP Host

Host 是承载 AI 交互的应用。

例如:

  • 桌面 AI 客户端;
  • IDE 插件;
  • Agent 平台;
  • 企业内部智能助手;
  • Java 编写的聊天应用。

它负责管理用户交互、模型调用以及 MCP Client。

2. MCP Client

Client 负责连接具体的 MCP Server。

它通常会做这些事情:

  • 建立连接;
  • 获取工具列表;
  • 调用工具;
  • 获取资源;
  • 接收结果;
  • 处理异常和超时。

一个 Host 可以有多个 MCP Client,因为它可能要连接多个 MCP Server。

3. MCP Server

Server 是能力提供方。

它可以对外暴露:

  • Tools:可执行工具;
  • Resources:可读取资源;
  • Prompts:可复用提示词模板。

例如一个项目管理 MCP Server 可以提供:

text 复制代码
get_project_info
list_project_documents
search_issue
get_release_history

一个日志 MCP Server 可以提供:

text 复制代码
search_error_logs
get_service_health
get_trace_detail

三、MCP 中的 Tools、Resources、Prompts

1. Tools:可执行能力

Tool 是模型可以请求调用的动作。

例如:

text 复制代码
查询订单状态
搜索项目文件
获取服务健康状态
创建测试任务
查询发布记录

工具通常带有:

  • 工具名称;
  • 工具描述;
  • 参数定义;
  • 参数类型;
  • 返回结果;
  • 权限要求。

一个工具可以抽象成下面这个结构:

json 复制代码
{
  "name": "get_order_status",
  "description": "根据订单号查询订单当前状态,只能查询当前用户有权限访问的订单。",
  "inputSchema": {
    "type": "object",
    "properties": {
      "orderNo": {
        "type": "string",
        "description": "订单编号"
      }
    },
    "required": ["orderNo"]
  }
}

模型会根据工具描述判断是否需要调用它。

但请注意:

工具描述是给模型理解能力边界用的,不是权限控制。

真正的权限校验必须由 MCP Server 或业务后端完成。


2. Resources:可读取资料

Resource 更像"外部可读取内容"。

例如:

text 复制代码
项目 README
接口规范
数据库设计文档
部署手册
系统配置说明

资源可以理解为给 Agent 提供上下文的内容来源。

例如:

text 复制代码
resource://project/readme
resource://project/api-doc
resource://ops/deploy-guide

与 Tool 的区别在于:

  • Tool 偏向执行动作;
  • Resource 偏向读取内容;
  • Tool 可能产生副作用;
  • Resource 一般用于提供信息。

例如"查询实时订单状态"应该是 Tool,"读取订单状态枚举说明"更适合作为 Resource。


3. Prompts:可复用提示词模板

Prompts 用于提供标准化的提示词模板。

例如:

text 复制代码
代码审查模板
线上故障排查模板
接口设计模板
SQL 优化分析模板

一个"代码审查" Prompt 可能需要参数:

text 复制代码
language
diff
focus

调用时可以传入:

json 复制代码
{
  "language": "Java",
  "focus": "安全性和事务边界",
  "diff": "..."
}

对于团队来说,这种方式可以把高质量 Prompt 沉淀下来,而不是让每个用户都从零写一遍。


四、MCP 和 Tool Calling 有什么关系

很多同学第一次看到 MCP 时,会觉得它和 Tool Calling 很像。

确实,它们有关联,但不是同一个概念。

对比项 Tool Calling MCP
本质 模型调用工具的机制 工具、资源、提示词的标准协议
关注点 模型如何选择并发起调用 Agent 如何统一连接外部能力
工具定义 常由应用自行维护 可由 MCP Server 对外暴露
复用范围 单个应用内也可使用 更适合跨 Agent、跨客户端复用
权限控制 由业务后端实现 仍然由 MCP Server 和业务系统实现

可以这样理解:

text 复制代码
Tool Calling 解决"模型怎么发起工具调用"
MCP 解决"外部工具怎么以标准方式提供给 Agent"

它们完全可以配合使用。

text 复制代码
用户提问
-> Agent 判断需要工具
-> 通过 MCP Client 发现并调用 MCP Tool
-> MCP Server 校验权限并执行
-> 返回结果给 Agent
-> Agent 组织最终回答

五、一个项目查询 MCP Server 的设计示例

假设我们要做一个"项目研发助手",它需要查询项目文档、发布记录和接口信息。

可以先定义三个工具:

text 复制代码
search_project_document
get_release_history
get_api_detail

1. 工具定义

java 复制代码
@Data
public class McpToolDefinition {

    private String name;

    private String description;

    private Map<String, Object> inputSchema;
}

构造一个查询发布记录工具:

java 复制代码
public McpToolDefinition buildReleaseHistoryTool() {
    McpToolDefinition tool = new McpToolDefinition();
    tool.setName("get_release_history");
    tool.setDescription("""
            查询指定项目最近的发布记录。
            只能查询当前用户有权限访问的项目。
            返回发布时间、版本号、发布环境和发布状态。
            """);

    Map<String, Object> properties = Map.of(
            "projectId", Map.of(
                    "type", "string",
                    "description", "项目ID"
            ),
            "limit", Map.of(
                    "type", "integer",
                    "description", "返回数量,范围1到20"
            )
    );

    tool.setInputSchema(Map.of(
            "type", "object",
            "properties", properties,
            "required", List.of("projectId")
    ));

    return tool;
}

这段代码只是表达工具描述的思路。实际接入 MCP SDK 时,会按照 SDK 提供的方式注册工具。


六、工具执行的正确边界

假设模型请求调用:

json 复制代码
{
  "name": "get_release_history",
  "arguments": {
    "projectId": "project-a",
    "limit": 10
  }
}

后端不能直接拿参数执行查询,而应该完成以下步骤:

text 复制代码
1. 校验工具是否允许调用
2. 校验参数格式
3. 校验当前用户是否登录
4. 校验用户是否有项目权限
5. 执行受控业务查询
6. 过滤敏感字段
7. 记录审计日志
8. 返回结构化结果

1. 参数对象

java 复制代码
@Data
public class ReleaseHistoryQuery {

    @NotBlank(message = "项目ID不能为空")
    private String projectId;

    @Min(value = 1, message = "limit不能小于1")
    @Max(value = 20, message = "limit不能大于20")
    private Integer limit = 10;
}

2. 工具执行 Service

java 复制代码
@Service
@RequiredArgsConstructor
public class ReleaseHistoryToolService {

    private final ProjectPermissionService projectPermissionService;
    private final ReleaseRecordMapper releaseRecordMapper;
    private final AgentAuditLogService agentAuditLogService;

    public ToolExecuteResult execute(
            Long userId,
            ReleaseHistoryQuery query
    ) {
        projectPermissionService.checkReadPermission(userId, query.getProjectId());

        List<ReleaseRecord> records = releaseRecordMapper.selectRecent(
                query.getProjectId(),
                query.getLimit()
        );

        List<ReleaseRecordVO> result = records.stream()
                .map(this::convertToSafeView)
                .toList();

        agentAuditLogService.record(
                userId,
                "get_release_history",
                query.getProjectId(),
                "SUCCESS"
        );

        return ToolExecuteResult.success(result);
    }

    private ReleaseRecordVO convertToSafeView(ReleaseRecord record) {
        ReleaseRecordVO vo = new ReleaseRecordVO();
        vo.setVersion(record.getVersion());
        vo.setEnvironment(record.getEnvironment());
        vo.setStatus(record.getStatus());
        vo.setReleaseTime(record.getReleaseTime());
        return vo;
    }
}

文字说明:

  • 工具调用之前必须做项目权限校验;
  • 不要把数据库实体原样返回给模型;
  • 应该通过 VO 过滤内部字段;
  • 每次工具执行都应记录审计日志;
  • 工具失败时应该返回可控错误信息,而不是数据库异常堆栈。

七、为什么不要让 MCP Server 直接暴露数据库能力

有些人会想:

text 复制代码
既然 Agent 要查数据,那我干脆提供一个 execute_sql 工具。

例如:

json 复制代码
{
  "name": "execute_sql",
  "arguments": {
    "sql": "SELECT * FROM user"
  }
}

这在生产环境中风险非常高。

模型可能因为理解偏差、提示词注入或参数构造错误,生成危险 SQL:

sql 复制代码
DELETE FROM user;

或者越权查询:

sql 复制代码
SELECT * FROM employee_salary;

更合理的方式是提供业务语义明确的工具:

text 复制代码
get_order_status
list_user_orders
get_project_release_history
search_error_logs
get_api_detail

这样可以让后端控制:

  • 查询范围;
  • 可返回字段;
  • 分页上限;
  • 权限逻辑;
  • 敏感字段脱敏;
  • 操作审计。

核心原则是:

模型负责表达意图,后端负责执行受控业务能力。


八、MCP Server 中的安全设计

1. 工具白名单

不要让客户端随意调用任意内部能力。

java 复制代码
private static final Set<String> ALLOWED_TOOLS = Set.of(
        "search_project_document",
        "get_release_history",
        "get_api_detail"
);

当收到工具调用时:

java 复制代码
public void checkToolAllowed(String toolName) {
    if (!ALLOWED_TOOLS.contains(toolName)) {
        throw new BusinessException("不允许调用该工具");
    }
}

2. 参数校验

模型生成的参数并不可靠。

例如它可能传:

json 复制代码
{
  "limit": 999999
}

所以必须做:

  • 类型校验;
  • 必填校验;
  • 长度校验;
  • 枚举校验;
  • 数值范围校验;
  • 业务规则校验。

3. 高风险操作必须确认

以下操作不能因为模型调用了工具就立即执行:

  • 删除数据;
  • 修改权限;
  • 发布生产环境;
  • 发起支付;
  • 发送批量通知;
  • 调整库存;
  • 执行退款。

推荐的流程:

text 复制代码
Agent 生成操作计划
-> 后端返回待确认信息
-> 用户确认
-> 后端执行
-> 返回执行结果

例如:

text 复制代码
即将发布项目 project-a 到测试环境,版本为 v1.2.0。
本次操作会重启 2 个服务实例,是否确认?

4. 审计日志

建议至少记录:

text 复制代码
用户ID
会话ID
工具名称
请求参数摘要
执行结果
耗时
时间
失败原因

但日志中不要记录完整 Token、密码、密钥和敏感业务字段。


九、MCP 与 RAG 如何配合

MCP 不等于 RAG。

RAG 主要解决"从文档中检索知识",MCP 主要解决"以标准协议连接工具与资源"。

但它们可以结合。

例如用户问:

text 复制代码
测试环境最近一次发布是什么时候?发布后错误率有没有升高?

Agent 可以拆成两个步骤:

text 复制代码
步骤1:通过 MCP Tool 查询最近发布记录。
步骤2:通过 MCP Tool 查询发布前后的错误日志或监控指标。
步骤3:结合结果生成分析结论。

如果用户问:

text 复制代码
项目的灰度发布流程是什么?

这更适合使用 RAG,从发布规范文档中检索答案。

简单记忆:

text 复制代码
稳定说明文档 -> RAG
实时系统数据 -> MCP Tool
用户历史偏好 -> Memory
固定高风险流程 -> Workflow

十、实际开发建议

1. 先从只读工具开始

第一次做 MCP Server,建议先提供只读能力:

text 复制代码
查询项目文档
查询接口说明
查询发布记录
查询日志摘要
查询服务健康状态

只读工具的风险更低,也更容易调试。

2. 工具粒度不要太粗

不推荐:

text 复制代码
manage_project
operate_system
execute_database_command

推荐:

text 复制代码
get_project_info
get_release_history
search_project_document
get_service_health
search_error_logs

工具名称越清晰,模型选择工具越稳定,后端也越容易控制权限。

3. 工具返回要简洁、结构化

不要把几百 KB 原始日志直接返回给模型。

推荐返回:

json 复制代码
{
  "serviceName": "order-service",
  "timeRange": "2026-07-18 10:00:00 ~ 2026-07-18 10:10:00",
  "errorCount": 12,
  "topErrors": [
    {
      "type": "DatabaseTimeoutException",
      "count": 8
    }
  ]
}

模型需要的是能用于推理和回答的信息,不是无限量原始数据。


十一、总结

这一篇我们认识了 MCP 的基本作用和开发边界。

重点可以记住:

  1. MCP 是 Agent 连接外部工具、资源和提示词模板的标准协议。
  2. MCP 包含 Host、Client、Server 三类角色。
  3. Tool 用于执行受控能力,Resource 用于读取资料,Prompt 用于复用提示词模板。
  4. MCP 与 Tool Calling 可以配合,但两者不是同一个概念。
  5. MCP Server 不应该直接暴露任意 SQL、Shell 或内部高危操作。
  6. 权限校验、参数校验、脱敏、审计日志必须由后端负责。
  7. 高风险操作需要显式确认,不能只靠模型判断。
  8. 初学阶段建议先实现只读、业务语义明确的工具。

下一篇我们继续学习多智能体协作:一个 Agent 不够用时,如何把规划、执行、审核等职责拆开。

相关推荐
丨白色风车丨2 小时前
MCP 入门指南:大模型时代的“USB-C”接口
python·mcp
阿图灵2 小时前
Agentic AI 架构完整学习手册(课程精华全收录)
架构设计·ai agent·智能体·agentic ai·完整手册
阿图灵3 小时前
Agentic AI 架构入门(十二·完结):ADLC、AgentOps 与企业级平台蓝图
人工智能·架构·ai agent·智能体·agentops·agentic ai·adlc
Python私教5 小时前
MCP 工具安全设计:为什么 stdio 也要做最小权限与输出过滤
后端·mcp
VIP_CQCRE6 小时前
用 Ace Data Cloud Studio,把内容营销变成自动运行的 AI 工作流
ai·自动化·内容营销·mcp·acedatacloud
小田学Python16 小时前
100行Python代码,搭一个能干活的AI Agent
python·langchain·大模型·ai agent
jufeng130721 小时前
【系列:手搓自主 AI Agent:Hermes 架构原理剖析 · 第 6 篇】
python·ai agent·记忆系统
Joy T1 天前
Agent 开源项目全景解析(下):LlamaIndex、Dify、FastGPT 与真实工程选型
langchain·开源·框架·agent·springai·langgraph·mcp
鱼日先生1 天前
办公聊天软件接入 Hermes Agent 实录(一):企业微信 WebSocket 长连接 + Dify 知识库问答
企业微信·dify·ai agent·大模型应用·hermes agent