首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >MCP 在实际 Agent 业务中的实现方案

MCP 在实际 Agent 业务中的实现方案

作者头像
tunsuy
发布2026-04-09 11:39:40
发布2026-04-09 11:39:40
1710
举报

1. MCP 简介

1.1 什么是 MCP?

「MCP(Model Context Protocol)」 是 Anthropic 于 2024 年 11 月发布的一个开放协议,旨在标准化 AI 模型与外部工具、数据源之间的通信方式。

简单来说,MCP 定义了一套 「"AI 应用如何调用外部能力"」 的标准协议,就像 HTTP 定义了 Web 通信标准一样。

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                            MCP 在 AI 应用中的位置                              │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   传统方式(各家自定义):                                                      │
│   ┌────────────┐      各种私有协议      ┌────────────┐                        │
│   │  AI 应用 A  │ ──────────────────────► │  工具服务1  │                        │
│   │            │ ◄────────────────────── │            │                        │
│   └────────────┘                        └────────────┘                        │
│                                                                              │
│   ┌────────────┐      另一种私有协议    ┌────────────┐                        │
│   │  AI 应用 B  │ ──────────────────────► │  工具服务2  │                        │
│   │            │ ◄────────────────────── │            │                        │
│   └────────────┘                        └────────────┘                        │
│                                                                              │
│   ────────────────────────────────────────────────────────────────────────   │
│                                                                              │
│   MCP 方式(统一标准):                                                        │
│   ┌────────────┐                        ┌────────────┐                        │
│   │  AI 应用 A  │ ────┐                  │ MCP Server1│                        │
│   └────────────┘     │    MCP 协议      │ (天气服务)  │                        │
│                      ├─────────────────►├────────────┤                        │
│   ┌────────────┐     │                  │ MCP Server2│                        │
│   │  AI 应用 B  │ ────┘                  │ (数据库)   │                        │
│   └────────────┘                        └────────────┘                        │
│                                                                              │
│   任何 MCP Client 都能连接任何 MCP Server,无需定制适配                         │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

1.2 MCP 核心概念

概念

说明

类比

「MCP Server」

提供工具能力的服务端,暴露工具列表和执行接口

类似 REST API 服务

「MCP Client」

调用 MCP Server 的客户端,集成在 AI 应用中

类似 HTTP Client

「Tool」

MCP Server 暴露的具体能力(如查天气、搜索文档)

类似 API 接口

「Resource」

MCP Server 暴露的只读数据(如文件内容、数据库 Schema)

类似静态资源

「Prompt」

MCP Server 提供的预定义提示词模板

类似模板文件

「Transport」

底层传输方式(STDIO、HTTP SSE、Streamable HTTP)

类似 TCP/WebSocket

1.3 MCP 三大核心能力

MCP 协议定义了三种核心能力,满足 AI 应用的不同需求:

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                         MCP 三大核心能力                                      │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐          │
│   │      Tools       │  │    Resources     │  │     Prompts      │          │
│   │     (工具)      │  │    (资源)       │  │   (提示词)      │          │
│   ├──────────────────┤  ├──────────────────┤  ├──────────────────┤          │
│   │                  │  │                  │  │                  │          │
│   │  可执行的动作     │  │  只读的数据       │  │  预定义的模板     │          │
│   │                  │  │                  │  │                  │          │
│   │  • 调用 API      │  │  • 文件内容       │  │  • 对话模板      │          │
│   │  • 执行命令      │  │  • DB Schema     │  │  • 指令模板      │          │
│   │  • 发送消息      │  │  • 配置信息       │  │  • 常用提示      │          │
│   │  • 修改数据      │  │  • 日志/监控      │  │                  │          │
│   │                  │  │                  │  │                  │          │
│   ├──────────────────┤  ├──────────────────┤  ├──────────────────┤          │
│   │  有副作用        │  │  无副作用(安全)  │  │  无副作用        │          │
│   │  需要审批/确认   │  │  可自动授权       │  │  辅助生成        │          │
│   └──────────────────┘  └──────────────────┘  └──────────────────┘          │
│                                                                              │
│   典型协作流程:                                                               │
│   ┌──────────────────────────────────────────────────────────────────────┐  │
│   │  1. 读取 Resource(获取上下文)→ 2. AI 分析决策 → 3. 调用 Tool(执行) │  │
│   └──────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
│   例如:"修复 user 表索引"                                                    │
│   1. Resource: 读取 db://schema/users(获取表结构)                           │
│   2. AI 分析:需要在 email 字段加索引                                         │
│   3. Tool: 执行 CREATE INDEX 语句                                            │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
Resource vs Tool 对比

维度

Resource(资源)

Tool(工具)

「操作类型」

只读

可读可写

「副作用」

「权限控制」

可默认放行

通常需审批

「使用场景」

获取上下文信息

执行具体动作

「协议方法」

resources/list、resources/read

tools/list、tools/call

「特有能力」

支持订阅变化、缓存友好

支持动态参数

Resource 典型场景

场景

Resource URI 示例

说明

文件系统

file:///project/README.md

读取项目文件作为上下文

数据库 Schema

db://mysql/schema/users

让 AI 了解表结构以生成 SQL

配置信息

config://env/current

获取当前环境配置

日志/监控

logs://app/error/recent

分析最近的错误日志

知识库

wiki://api/authentication

访问企业文档

Prompt 的作用

「Prompt 与 Tool/Resource 的核心区别」:Tool 和 Resource 是给 「LLM」 用的,而 Prompt 是给 「人/应用」 用的。

维度

Tool/Resource

Prompt

「使用者」

LLM 决定调用

用户主动选择

「用途」

AI 执行任务

快捷指令、标准化模板

「协议方法」

tools/*、resources/*

prompts/list、prompts/get

「典型场景」

  • 「UI 快捷菜单」:IDE 显示 [代码审查] [SQL优化] 按钮,用户点击后直接调用预定义 Prompt
  • 「企业标准模板」:统一的"安全审计"、"代码规范检查"等提示词模板
  • 「参数化模板」:填入语言、代码等参数,生成完整的结构化 Prompt

「为什么不用 Tool?」 Prompt 用于 UI 展示和用户直接选择,不需要经过 LLM 理解意图,更直接、准确、省 Token。

1.5 MCP 协议核心方法

MCP 协议定义了几个关键的 RPC 方法:

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                          MCP 协议核心方法                                      │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   1. initialize(初始化握手)                                                  │
│      Client → Server: 协议版本、客户端能力                                     │
│      Server → Client: 服务端能力、支持的功能                                   │
│                                                                              │
│   2. tools/list(获取工具列表)                                                │
│      Client → Server: ListToolsRequest                                       │
│      Server → Client: ListToolsResponse                                      │
│                        [                                                     │
│                          {name: "get_weather", description: "...",          │
│                           inputSchema: {type: "object", properties: {...}}} │
│                        ]                                                     │
│                                                                              │
│   3. tools/call(调用工具)                                                    │
│      Client → Server: CallToolRequest {name: "get_weather", args: {...}}    │
│      Server → Client: CallToolResponse {content: [...]}                     │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

1.6 MCP 支持的传输方式

传输方式

特点

适用场景

「STDIO」

通过标准输入输出通信,启动子进程

本地工具、CLI 集成

「HTTP SSE」

基于 Server-Sent Events,单向流

Web 服务、远程调用

「Streamable HTTP」

基于 HTTP,支持双向流式传输

云服务、高性能场景(推荐)

协议来源说明

技术

来源

说明

「SSE」

W3C 标准

Server-Sent Events,浏览器原生支持 EventSource API

「HTTP/JSON-RPC」

行业标准

IETF RFC / jsonrpc.org 定义

「Streamable HTTP」

MCP 定义

基于 HTTP + SSE + JSON-RPC 的「组合使用方式」,非独立标准

「理解要点」:Streamable HTTP 不是新的网络协议,而是 MCP 规范定义的一种使用模式——用 HTTP POST 发送请求、用 SSE 接收响应和通知、消息格式为 JSON-RPC 2.0。类似于 REST 是使用 HTTP 的一种约定风格。 ❞

关于"Streamable"的澄清

「常见误解」:MCP 支持 Streamable HTTP,是不是工具调用支持流式输出?

「答案:不是。」 MCP 的 "Streamable" 是「消息流」,不是「内容流」

概念

含义

类比

「消息流」(MCP Streamable)

多个完整的 JSON-RPC 消息在连接上流动

快递车持续送多个完整包裹

「内容流」(LLM 流式输出)

单个响应边生成边返回(delta)

一个包裹边打包边送

「Streamable HTTP 的真正目的」

  • 「双向通信」:Server 可以主动推送通知给 Client(如资源变化、工具列表更新)
  • 「长连接复用」:一个连接上发送多个请求/响应,减少握手开销
  • 「会话管理」:支持 session-id,维护会话状态

「tools/call 的响应特性」

  • 协议规范中是「一次性完整返回」,没有定义增量/delta 格式
  • 即使 Tool 内部调用了 LLM 流式输出,也必须拼接完整后才能返回给 Client
  • 这与 LLM API 的 stream=true(边生成 Token 边返回)是不同的

2. trpc-agent-go 的 MCP 实现架构

2.1 整体架构

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                    trpc-agent-go MCP 实现架构                                 │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   ┌─────────────────────────────────────────────────────────────────────┐   │
│   │                           Agent 层                                   │   │
│   │                                                                     │   │
│   │   LLMAgent / Graph Node                                             │   │
│   │       │                                                             │   │
│   │       │ 统一工具接口: tool.Tool / tool.ToolSet                       │   │
│   │       ▼                                                             │   │
│   └───────┼─────────────────────────────────────────────────────────────┘   │
│           │                                                                  │
│   ┌───────┼─────────────────────────────────────────────────────────────┐   │
│   │       ▼         工具层                                               │   │
│   │   ┌─────────────────┐    ┌─────────────────┐    ┌────────────────┐  │   │
│   │   │   本地工具       │    │   Agent 工具     │    │   MCP 工具集    │  │   │
│   │   │   (Function)    │    │   (AgentTool)   │    │   (MCPToolSet) │  │   │
│   │   └─────────────────┘    └─────────────────┘    └───────┬────────┘  │   │
│   │                                                         │           │   │
│   └─────────────────────────────────────────────────────────┼───────────┘   │
│                                                             │               │
│   ┌─────────────────────────────────────────────────────────┼───────────┐   │
│   │                      MCP 会话层                          │           │   │
│   │                                                         ▼           │   │
│   │   ┌─────────────────────────────────────────────────────────────┐   │   │
│   │   │                  mcpSessionManager                          │   │   │
│   │   │                                                             │   │   │
│   │   │  • connect()     - 建立连接                                  │   │   │
│   │   │  • initialize()  - MCP 协议握手                              │   │   │
│   │   │  • listTools()   - 获取工具列表                              │   │   │
│   │   │  • callTool()    - 调用工具                                  │   │   │
│   │   │  • close()       - 关闭连接                                  │   │   │
│   │   │                                                             │   │   │
│   │   └──────────────────────────┬──────────────────────────────────┘   │   │
│   │                              │                                      │   │
│   └──────────────────────────────┼──────────────────────────────────────┘   │
│                                  │                                          │
│   ┌──────────────────────────────┼──────────────────────────────────────┐   │
│   │                      MCP 传输层                                      │   │
│   │                              ▼                                      │   │
│   │   ┌─────────────┐   ┌─────────────┐   ┌─────────────────────────┐   │   │
│   │   │    STDIO    │   │   HTTP SSE  │   │   Streamable HTTP       │   │   │
│   │   │  Transport  │   │  Transport  │   │      Transport          │   │   │
│   │   └──────┬──────┘   └──────┬──────┘   └───────────┬─────────────┘   │   │
│   │          │                 │                      │                 │   │
│   └──────────┼─────────────────┼──────────────────────┼─────────────────┘   │
│              │                 │                      │                     │
│              ▼                 ▼                      ▼                     │
│   ┌──────────────────────────────────────────────────────────────────────┐  │
│   │                         MCP Server                                   │  │
│   └──────────────────────────────────────────────────────────────────────┘  │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

2.2 核心组件

组件

职责

文件位置

MCPToolSet

实现 ToolSet 接口,管理 MCP 工具集合

tool/mcp/toolset.go

mcpTool

实现 Tool 接口,封装单个 MCP 工具

tool/mcp/tool.go

mcpSessionManager

管理 MCP 连接、重连、协议交互

tool/mcp/toolset.go

ConnectionConfig

MCP 连接配置(地址、传输方式、超时等)

tool/mcp/config.go


3. 四个核心问题详解

接下来,我们聚焦四个核心问题:

  1. 「LLM 怎么知道有哪些 MCP 工具?」
  2. 「工具是怎么执行的?」
  3. 「连接什么时候建立、什么时候关闭?」
  4. 「MCP Server 有新工具了,Agent 怎么感知?」

3.1 LLM 怎么知道有哪些 MCP 工具?

流程图
代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                        LLM 获取 MCP 工具列表流程                               │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   Agent.Run("查询天气")                                                       │
│         │                                                                    │
│         ▼                                                                    │
│   收集所有工具 ◄─────────────────────────────────────────────────────┐       │
│         │                                                            │       │
│         ├─► 本地工具: localTool1, localTool2                         │       │
│         │                                                            │       │
│         └─► mcpToolSet.Tools(ctx) ─────────────────────────────────► │       │
│                   │                                                  │       │
│                   │  MCP 协议: tools/list                            │       │
│                   ▼                                                  │       │
│             ┌────────────────┐                                       │       │
│             │   MCP Server   │                                       │       │
│             │                │                                       │       │
│             │  ListToolsResponse:                                    │       │
│             │  [                                                     │       │
│             │    {name: "get_weather", desc: "...", schema: {...}},  │       │
│             │    {name: "search_docs", desc: "...", schema: {...}}   │       │
│             │  ]                                                     │       │
│             └────────────────┘                                       │       │
│                   │                                                  │       │
│                   │ 转换为 tool.Tool 接口                             │       │
│                   ▼                                                  │       │
│             返回: [get_weather, search_docs] ─────────────────────────┘       │
│                                                                              │
│         │                                                                    │
│         ▼                                                                    │
│   构建 System Prompt(包含所有工具的名称、描述、参数 Schema)                   │
│         │                                                                    │
│         ▼                                                                    │
│   发送给 LLM                                                                  │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
核心代码
代码语言:javascript
复制
// tool/mcp/toolset.go

// Tools 实现 ToolSet 接口,返回 MCP Server 的工具列表
func (ts *ToolSet) Tools(ctx context.Context) []tool.Tool {
    if err := ts.listTools(ctx); err != nil {
        log.ErrorContext(ctx, "Failed to refresh tools", err)
    }
    return ts.tools
}

// listTools 从 MCP Server 获取工具列表
func (ts *ToolSet) listTools(ctx context.Context) error {
    // 1. 确保已连接
    if !ts.sessionManager.isConnected() {
        if err := ts.sessionManager.connect(ctx); err != nil {
            return err
        }
    }

    // 2. 调用 MCP 协议的 ListTools 方法
    mcpTools, err := ts.sessionManager.listTools(ctx)
    if err != nil {
        return err
    }

    // 3. 转换为框架统一的 tool.Tool 接口
    tools := make([]tool.Tool, 0, len(mcpTools))
    for _, mcpTool := range mcpTools {
        tools = append(tools, newMCPTool(mcpTool, ts.sessionManager))
    }

    ts.tools = tools
    returnnil
}
关键点
代码语言:javascript
复制
MCP 工具实现 tool.Tool 接口,LLM 看到的和本地工具一模一样

3.2 工具是怎么执行的?

流程图
代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                           MCP 工具执行流程                                    │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   LLM 决定调用工具: tool_calls: [{name: "get_weather", args: {city: "北京"}}] │
│         │                                                                    │
│         ▼                                                                    │
│   Agent 解析 tool_calls,找到对应的 Tool                                      │
│         │                                                                    │
│         │ 调用: tool.Call(ctx, `{"city": "北京"}`)                            │
│         ▼                                                                    │
│   ┌─────────────────────────────────────────────────────────────────────┐    │
│   │                          mcpTool.Call()                              │    │
│   │                                                                     │    │
│   │   1. 解析 JSON 参数                                                  │    │
│   │   2. 调用 sessionManager.callTool(ctx, "get_weather", args)         │    │
│   │                                                                     │    │
│   └─────────────────────────────────────────────────────────────────────┘    │
│         │                                                                    │
│         │ MCP 协议: tools/call                                               │
│         │ {method: "tools/call", params: {name: "get_weather", args: {...}}} │
│         ▼                                                                    │
│   ┌─────────────────────────────────────────────────────────────────────┐    │
│   │                          MCP Server                                  │    │
│   │                                                                     │    │
│   │   执行 get_weather("北京")                                           │    │
│   │   返回: {temperature: 22, weather: "晴"}                             │    │
│   │                                                                     │    │
│   └─────────────────────────────────────────────────────────────────────┘    │
│         │                                                                    │
│         │ MCP 协议: CallToolResponse                                         │
│         ▼                                                                    │
│   返回结果给 Agent,Agent 再发给 LLM 进行下一轮对话                            │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
核心代码
代码语言:javascript
复制
// tool/mcp/tool.go

type mcpTool struct {
    mcpToolRef     *mcp.Tool           // MCP 工具元数据(名称、描述、Schema)
    sessionManager *mcpSessionManager  // 会话管理器(用于发起 MCP 调用)
}

// Call 实现 CallableTool 接口
func (t *mcpTool) Call(ctx context.Context, jsonArgs []byte) (any, error) {
    // 1. 解析 JSON 参数
    var args map[string]any
    iflen(jsonArgs) > 0 {
        json.Unmarshal(jsonArgs, &args)
    }

    // 2. 通过 MCP 协议调用远程工具
    return t.sessionManager.callTool(ctx, t.mcpToolRef.Name, args)
}

// tool/mcp/toolset.go

// callTool 发起 MCP 工具调用
func (m *mcpSessionManager) callTool(ctx context.Context, name string, args map[string]any) (any, error) {
    var result any
    err := m.executeWithSessionReconnect(ctx, func() error {
        // MCP 协议调用
        resp, err := m.client.CallTool(ctx, mcp.CallToolParams{
            Name:      name,
            Arguments: args,
        })
        if err != nil {
            return err
        }
        result = resp.Content
        returnnil
    })
    return result, err
}
关键点
代码语言:javascript
复制
mcpTool
 实现 CallableTool 接口,Agent 不知道这是远程调用

3.3 连接什么时候建立、什么时候关闭?

连接生命周期
代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                           连接生命周期                                        │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   方式一:懒加载(默认)                                                       │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   创建时:NewMCPToolSet(config)                                    │    │
│   │           │                                                        │    │
│   │           └──► 只保存配置,不建立连接                               │    │
│   │                                                                    │    │
│   │   首次使用:toolSet.Tools(ctx)  或  tool.Call()                    │    │
│   │           │                                                        │    │
│   │           └──► 建立连接 + MCP 初始化握手                           │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   方式二:显式初始化(推荐)                                                   │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   创建时:toolSet := NewMCPToolSet(config)                         │    │
│   │                                                                    │    │
│   │   显式初始化:err := toolSet.Init(ctx)  ← 此时建立连接              │    │
│   │           │                                                        │    │
│   │           └──► 连接失败立即报错(Fail Fast)                        │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   关闭时机:                                                                  │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   toolSet.Close()  ← 显式调用,释放连接资源                         │    │
│   │                                                                    │    │
│   │   推荐写法:                                                        │    │
│   │   toolSet := mcp.NewMCPToolSet(config)                             │    │
│   │   if err := toolSet.Init(ctx); err != nil {                        │    │
│   │       log.Fatal(err)                                               │    │
│   │   }                                                                │    │
│   │   defer toolSet.Close()  // 程序退出时关闭                          │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
核心代码
代码语言:javascript
复制
// tool/mcp/toolset.go

// 创建时:只保存配置,不连接
func NewMCPToolSet(config ConnectionConfig, opts ...ToolSetOption) *ToolSet {
    sessionManager := newMCPSessionManager(config, ...)
    return &ToolSet{
        sessionManager: sessionManager,
        tools:          nil,  // 工具列表为空,懒加载
    }
}

// 显式初始化:立即连接
func (ts *ToolSet) Init(ctx context.Context) error {
    return ts.listTools(ctx)  // 内部会触发连接
}

// 首次使用时触发连接
func (m *mcpSessionManager) connect(ctx context.Context) error {
    m.mu.Lock()
    defer m.mu.Unlock()

    // 1. 创建客户端(建立传输层连接)
    client, err := m.createClient()
    if err != nil {
        return err
    }
    m.client = client
    m.connected = true

    // 2. MCP 协议初始化握手
    if err := m.initialize(ctx); err != nil {
        m.client.Close()
        return err
    }
    m.initialized = true

    returnnil
}

// 关闭连接
func (ts *ToolSet) Close() error {
    return ts.sessionManager.close()
}
关键点
代码语言:javascript
复制
懒加载:首次 Tools() 或 Call() 时;显式:调用 Init() 时

3.4 MCP Server 有新工具了,Agent 怎么感知?

工具刷新机制
代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                        新工具感知机制                                         │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   MCP Server 工具列表变化:                                                    │
│   初始:[get_weather, search_docs]                                            │
│   新增:[get_weather, search_docs, translate]  ← 新增了 translate             │
│                                                                              │
│   ────────────────────────────────────────────────────────────────────────   │
│                                                                              │
│   方式一:每次 Run 时自动刷新(推荐)                                           │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   import "trpc.group/trpc-go/trpc-agent-go/agent/llmagent"         │    │
│   │                                                                    │    │
│   │   agent := llmagent.New("assistant",                               │    │
│   │       llmagent.WithToolSets([]tool.ToolSet{mcpToolSet}),           │    │
│   │       llmagent.WithRefreshToolSetsOnRun(true),  // 关键配置         │    │
│   │   )                                                                │    │
│   │                                                                    │    │
│   │   // 配置位置: agent/llmagent/option.go:383                         │    │
│   │                                                                    │    │
│   │   每次 agent.Run() 时:                                             │    │
│   │   1. 调用 mcpToolSet.Tools(ctx)                                    │    │
│   │   2. 内部重新调用 MCP Server 的 ListTools                           │    │
│   │   3. 获取最新工具列表                                               │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   方式二:手动刷新                                                            │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   // 手动调用 Tools() 会重新获取工具列表                            │    │
│   │   tools := mcpToolSet.Tools(ctx)                                   │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   方式三:重新初始化                                                          │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   // 关闭旧连接,重新初始化                                         │    │
│   │   mcpToolSet.Close()                                               │    │
│   │   mcpToolSet = mcp.NewMCPToolSet(config)                           │    │
│   │   mcpToolSet.Init(ctx)                                             │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
核心代码
代码语言:javascript
复制
// agent/llmagent/option.go:377-386

// WithRefreshToolSetsOnRun controls whether tools from ToolSets are
// refreshed from the underlying ToolSet on each run.
// When enabled, the agent will call ToolSet.Tools again when building
// the tools list for each invocation instead of using a fixed snapshot.
// This is useful when ToolSets provide a dynamic tool list (for example,
// MCP ToolSets that support ListTools at runtime).
func WithRefreshToolSetsOnRun(refresh bool) Option {
    returnfunc(opts *Options) {
        opts.RefreshToolSetsOnRun = refresh
    }
}

// agent/llmagent/llm_agent.go

func (a *Agent) Run(ctx context.Context, prompt string) (string, error) {
    // 如果配置了每次运行刷新工具
    if a.option.RefreshToolSetsOnRun && len(a.option.ToolSets) > 0 {
        a.refreshTools(ctx)  // 重新获取所有 ToolSet 的工具
    }
    // ... 继续执行
}

// tool/mcp/toolset.go

// Tools 每次调用都会尝试刷新(从 MCP Server 重新获取)
func (ts *ToolSet) Tools(ctx context.Context) []tool.Tool {
    if err := ts.listTools(ctx); err != nil {
        // 刷新失败返回缓存的工具
        log.ErrorContext(ctx, "Failed to refresh tools", err)
    }
    return ts.tools
}
关键点
代码语言:javascript
复制
配置 llmagent.WithRefreshToolSetsOnRun(true),每次 Run 自动获取最新工具

4. 自动重连机制

MCP 连接可能因网络问题或服务端重启而断开,框架提供了自动重连机制:

代码语言:javascript
复制
┌──────────────────────────────────────────────────────────────────────────────┐
│                           自动重连机制                                        │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│   配置:                                                                      │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   mcpToolSet := mcp.NewMCPToolSet(                                 │    │
│   │       config,                                                      │    │
│   │       mcp.WithSessionReconnect(3),  // 最多重试 3 次               │    │
│   │   )                                                                │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│   重连流程:                                                                  │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                                                                    │    │
│   │   tool.Call() 或 toolSet.Tools()                                   │    │
│   │         │                                                          │    │
│   │         ▼                                                          │    │
│   │   执行操作 ──► 成功 ──► 返回结果                                    │    │
│   │         │                                                          │    │
│   │         │ 失败                                                      │    │
│   │         ▼                                                          │    │
│   │   是连接/会话错误?                                                  │    │
│   │         │                                                          │    │
│   │    否   │   是                                                      │    │
│   │    ↓    └──► 断开连接 → 重新连接 → 重新初始化 → 重试操作             │    │
│   │  返回错误                    │                                      │    │
│   │                             ▼                                      │    │
│   │                       超过重试次数?                                 │    │
│   │                          是 → 返回错误                              │    │
│   │                                                                    │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

核心代码

代码语言:javascript
复制
// tool/mcp/toolset.go

func (m *mcpSessionManager) executeWithSessionReconnect(ctx context.Context, fn func() error) error {
    var lastErr error
    for attempt := 0; attempt <= m.maxReconnectAttempts; attempt++ {
        lastErr = fn()
        if lastErr == nil {
            returnnil
        }

        // 检查是否是可重连的错误
        if !m.isReconnectableError(lastErr) {
            return lastErr
        }

        // 重建连接
        if err := m.reconnect(ctx); err != nil {
            return err
        }
    }
    return lastErr
}

func (m *mcpSessionManager) isReconnectableError(err error) bool {
    // 检测连接断开、会话过期等错误
    return errors.Is(err, ErrConnectionClosed) ||
           errors.Is(err, ErrSessionExpired) ||
           isNetworkError(err)
}

5. 完整使用示例

代码语言:javascript
复制
package main

import (
    "context"
    "log"
    "time"

    "trpc.group/trpc-go/trpc-agent-go/agent/llmagent"
    "trpc.group/trpc-go/trpc-agent-go/model/openai"
    "trpc.group/trpc-go/trpc-agent-go/tool"
    "trpc.group/trpc-go/trpc-agent-go/tool/mcp"
)

func main() {
    ctx := context.Background()

    // 1. 创建 MCP 工具集(此时不连接)
    mcpToolSet := mcp.NewMCPToolSet(
        mcp.ConnectionConfig{
            Transport: "streamable_http",
            ServerURL: "http://localhost:3000/mcp",
            Timeout:   10 * time.Second,
        },
        mcp.WithSessionReconnect(3),  // 断连自动重试 3 次
    )

    // 2. 显式初始化(此时建立连接,推荐做法)
    if err := mcpToolSet.Init(ctx); err != nil {
        log.Fatalf("MCP 初始化失败: %v", err)
    }
    defer mcpToolSet.Close()  // 程序退出时关闭连接

    // 3. 创建 Agent
    agent := llmagent.New(
        "assistant",
        llmagent.WithModel(openai.New("gpt-4o-mini")),
        llmagent.WithToolSets([]tool.ToolSet{mcpToolSet}),
        llmagent.WithRefreshToolSetsOnRun(true),  // 每次运行刷新工具列表
    )

    // 4. 运行(内部会获取工具列表、调用 LLM、执行工具)
    result, err := agent.Run(ctx, "查询北京今天的天气")
    if err != nil {
        log.Fatalf("运行失败: %v", err)
    }
    log.Printf("结果: %s", result)
}

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 有文化的技术人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. MCP 简介
    • 1.1 什么是 MCP?
    • 1.2 MCP 核心概念
    • 1.3 MCP 三大核心能力
      • Resource vs Tool 对比
      • Resource 典型场景
      • Prompt 的作用
    • 1.5 MCP 协议核心方法
    • 1.6 MCP 支持的传输方式
      • 协议来源说明
      • 关于"Streamable"的澄清
  • 2. trpc-agent-go 的 MCP 实现架构
    • 2.1 整体架构
    • 2.2 核心组件
  • 3. 四个核心问题详解
    • 3.1 LLM 怎么知道有哪些 MCP 工具?
      • 流程图
      • 核心代码
      • 关键点
    • 3.2 工具是怎么执行的?
      • 流程图
      • 核心代码
      • 关键点
    • 3.3 连接什么时候建立、什么时候关闭?
      • 连接生命周期
      • 核心代码
      • 关键点
    • 3.4 MCP Server 有新工具了,Agent 怎么感知?
      • 工具刷新机制
      • 核心代码
      • 关键点
  • 4. 自动重连机制
    • 核心代码
  • 5. 完整使用示例
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档