一、先说结论(避免混淆)

很多人学 MCP 第一坑就是:

❌ 把 MCP 和 Tool 当成一回事

正确关系应该是:

MCP = 协议(通信规则)
Tool = 能力(具体接口)

👉 一句话记住:

MCP 负责"怎么调",Tool 负责"调什么"


二、用后端架构彻底拆开

从你熟悉的系统来看:

LLM(Agent)
   ↓
MCP Client(协议实现)
   ↓
MCP Server(协议网关)
   ↓
Tool(具体能力)
   ↓
后端服务(DB / IBE / Redis)

👉 分层解释

本质

对标后端

MCP

协议

HTTP / Dubbo

MCP Server

网关

API Gateway

Tool

能力接口

Service 方法

后端系统

数据源

DB / 微服务


三、MCP 到底是什么?

MCP = 一套标准化的调用协议(基于 JSON-RPC 2.0)

它解决的问题是:

让 LLM 可以用统一方式调用外部能力

类比你熟的东西:

HTTP:浏览器调用接口
Dubbo:服务间调用
MCP:LLM 调用能力

四、从 chao-go 项目看 MCP 协议层

4.1 协议类型定义(types.go)

// JSON-RPC 请求 - 协议层不关心业务
type Request struct {
    JSONRPC string      `json:"jsonrpc"`           // 协议版本,固定 "2.0"
    ID      interface{} `json:"id,omitempty"`      // 请求ID,用于匹配响应
    Method  string      `json:"method"`            // 方法名,如 "tools/call"
    Params  interface{} `json:"params,omitempty"`  // 参数,由具体方法解析
}

// JSON-RPC 响应
type Response struct {
    JSONRPC string      `json:"jsonrpc"`
    ID      interface{} `json:"id,omitempty"`
    Result  interface{} `json:"result,omitempty"`
    Error   *Error      `json:"error,omitempty"`
}

// 标准错误码 - 协议层错误,不是业务错误
var (
    ErrParseError     = &Error{Code: -32700, Message: "Parse error"}
    ErrInvalidRequest = &Error{Code: -32600, Message: "Invalid request"}
    ErrMethodNotFound = &Error{Code: -32601, Message: "Method not found"}
    ErrInvalidParams  = &Error{Code: -32602, Message: "Invalid params"}
    ErrInternal       = &Error{Code: -32603, Message: "Internal error"}
)

👉 关键点:这些类型定义的是"怎么传",完全不关心"传什么"。

4.2 协议方法路由(server.go)

// HandleMessage 处理 MCP 请求 - 协议层只做路由
func (s *Server) HandleMessage(body []byte) *Response {
    var req Request
    if err := json.Unmarshal(body, &req); err != nil {
        return &Response{JSONRPC: "2.0", Error: ErrParseError}
    }

    // 验证协议版本
    if req.JSONRPC != "2.0" {
        return &Response{JSONRPC: "2.0", ID: req.ID, Error: ErrInvalidRequest}
    }

    // 协议层路由 - 不执行业务逻辑
    switch req.Method {
    case "initialize":
        return s.handleInitialize(req)
    case "tools/list":
        return s.handleToolsList(req)
    case "tools/call":
        return s.handleToolsCall(req)
    case "ping":
        return s.handlePing(req)
    default:
        return &Response{JSONRPC: "2.0", ID: req.ID, Error: ErrMethodNotFound}
    }
}

👉 关键点:MCP Server 只是一个"协议网关",它:

  • 解析协议格式
  • 路由到对应方法
  • 不执行任何业务逻辑

五、Tool 到底是什么?

Tool = MCP 暴露出来的"可调用能力"

本质就是:

一个带描述的 RPC 方法

5.1 Tool 的组成(非常关键)

// Tool 工具定义 - 能力层
type Tool struct {
    Name        string      `json:"name"`        // 接口名
    Description string      `json:"description"` // 给 LLM 的说明书(核心!)
    InputSchema InputSchema `json:"inputSchema"` // 参数定义
}

// InputSchema 输入参数 Schema - 告诉 LLM 怎么调用
type InputSchema struct {
    Type       string              `json:"type"`
    Properties map[string]Property `json:"properties,omitempty"`
    Required   []string            `json:"required,omitempty"`
}

// Property 参数属性
type Property struct {
    Type        string      `json:"type"`
    Description string      `json:"description,omitempty"`
    Enum        []string    `json:"enum,omitempty"`
    Default     interface{} `json:"default,omitempty"`
}

👉 对应关系

字段

作用

name

接口名

description

给 LLM 的说明书(核心)

schema

参数定义


六、从 chao-go 看分层实现

6.1 项目目录结构

internal/
├── mcp/              # MCP 协议层
│   ├── types.go      # 协议类型定义
│   ├── server.go     # 协议服务器(网关)
│   ├── handler.go    # HTTP 传输层
│   └── tools.go      # 工具注册(能力层入口)
│
├── handler/          # HTTP Handler(传统接口)
│   └── ai.go
│
└── service/          # 业务服务层
    ├── json.go
    ├── encode.go
    ├── crypto.go
    └── ...

6.2 分层调用链

┌─────────────────────────────────────────────────────────────┐
│                     调用链路图                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  LLM 发起请求                                               │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  HTTP Handler (handler.go)                          │   │
│  │  - 接收 HTTP 请求                                    │   │
│  │  - 支持 SSE 长连接                                   │   │
│  └─────────────────────────────────────────────────────┘   │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  MCP Server (server.go)                             │   │
│  │  - 解析 JSON-RPC 协议                                │   │
│  │  - 路由到对应方法                                    │   │
│  │  - initialize / tools/list / tools/call             │   │
│  └─────────────────────────────────────────────────────┘   │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Tool Registry (tools.go)                           │   │
│  │  - 查找工具定义                                      │   │
│  │  - 获取工具处理器                                    │   │
│  └─────────────────────────────────────────────────────┘   │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Tool Handler (闭包函数)                            │   │
│  │  - 解析业务参数                                      │   │
│  │  - 调用 Service 层                                   │   │
│  └─────────────────────────────────────────────────────┘   │
│       ↓                                                     │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Service 层 (service/*.go)                          │   │
│  │  - 执行具体业务逻辑                                   │   │
│  │  - JSON格式化、编解码、加密等                         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

SSE 长连接 是指 Server-Sent Events(服务器推送事件),是一种让服务器主动向客户端(LLM/Agent)推送数据的通信方式。


七、Tool 注册实战(tools.go)

7.1 工具注册表设计

// ToolHandler 工具处理函数类型 - 能力层接口
type ToolHandler func(args map[string]interface{}) (*ToolResult, error)

// ToolRegistry 工具注册表
type ToolRegistry struct {
    tools    map[string]Tool        // 工具定义(给 LLM 看)
    handlers map[string]ToolHandler // 工具处理器(执行逻辑)
}

// Register 注册工具 - 同时注册定义和处理器
func (r *ToolRegistry) Register(tool Tool, handler ToolHandler) {
    r.tools[tool.Name] = tool
    r.handlers[tool.Name] = handler
}

7.2 具体工具注册示例

// JSON 格式化工具
r.Register(Tool{
    Name:        "json_format",
    Description: "格式化 JSON 字符串,使其更易读",  // ← LLM 靠这个理解工具用途
    InputSchema: InputSchema{
        Type: "object",
        Properties: map[string]Property{
            "input":  {Type: "string", Description: "要格式化的 JSON 字符串"},
            "indent": {Type: "string", Description: "缩进字符,默认为两个空格", Default: "  "},
        },
        Required: []string{"input"},
    },
}, func(args map[string]interface{}) (*ToolResult, error) {
    // 这是 Tool Handler - 调用 Service 层
    input, _ := args["input"].(string)
    indent, _ := args["indent"].(string)
    if indent == "" {
        indent = "  "
    }
    result, err := services.JSON.Format(input, indent, false, false)
    if err != nil {
        return &ToolResult{Content: []Content{{Type: "text", Text: err.Error()}}, IsError: true}, nil
    }
    return &ToolResult{Content: []Content{{Type: "text", Text: result.Output}}}, nil
})

7.3 更多工具示例

// Base64 编解码工具
r.Register(Tool{
    Name:        "encode_base64",
    Description: "Base64 编码或解码字符串",
    InputSchema: InputSchema{
        Type: "object",
        Properties: map[string]Property{
            "input": {Type: "string", Description: "要处理的字符串"},
            "mode":  {Type: "string", Description: "模式:encode 或 decode", 
                      Enum: []string{"encode", "decode"}},  // ← 枚举限制
        },
        Required: []string{"input", "mode"},
    },
}, func(args map[string]interface{}) (*ToolResult, error) {
    input, _ := args["input"].(string)
    mode, _ := args["mode"].(string)
    decode := mode == "decode"
    result, err := services.Encode.Base64(input, decode, false)
    // ...
})

// AI 智能日志分析工具
r.Register(Tool{
    Name:        "ai_analyze_log",
    Description: "使用 AI 分析日志内容,识别错误类型并给出排查建议",
    InputSchema: InputSchema{
        Type: "object",
        Properties: map[string]Property{
            "log_content": {Type: "string", Description: "要分析的日志内容"},
        },
        Required: []string{"log_content"},
    },
}, func(args map[string]interface{}) (*ToolResult, error) {
    logContent, _ := args["log_content"].(string)
    result, err := services.AI.AnalyzeLog(logContent)
    // ...
})

八、为什么会混淆?

因为在传统后端里:

协议 + 接口 = 一起出现

比如:

HTTP + /api/query
Dubbo + method()

👉 所以你会下意识觉得:

MCP = 接口

但在 MCP 里是拆开的:

MCP(协议)
+ Tool(能力)

九、一个完整调用流程(彻底打通理解)

用户:帮我格式化这段 JSON

↓ LLM 推理

决定调用 Tool:json_format

↓ MCP Client 发送请求

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "json_format",
    "arguments": {
      "input": "{\"name\":\"test\"}",
      "indent": "  "
    }
  }
}

↓ MCP Server 接收 (server.go)

HandleMessage() 解析 JSON-RPC
    ↓
路由到 handleToolsCall()
    ↓
从 ToolRegistry 获取 handler

↓ Tool Handler 执行 (tools.go)

解析 arguments
    ↓
调用 services.JSON.Format()

↓ Service 层执行业务 (service/json.go)

格式化 JSON
    ↓
返回结果

↓ MCP Server 返回响应

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\n  \"name\": \"test\"\n}"
      }
    ]
  }
}

↓ LLM 组织语言回复用户

"已为您格式化完成:..."

👉 关键点

  • MCP 不关心业务 ❗
  • Tool 才承载业务 ❗

十、用一句话彻底区分

MCP 是"高速公路",Tool 是"车"

再换一个后端类比:

MCP = HTTP协议
Tool = Controller接口

十一、从后端角度的正确建模

你以后设计系统时应该这样拆:

❌ 错误建模

MCP = 接口

✅ 正确建模

MCP(协议层)      → internal/mcp/server.go
   ↓
Tool(能力层)     → internal/mcp/tools.go
   ↓
Service(业务层)  → internal/service/*.go

十二、chao-go 项目中的工具清单

工具名

功能

对应 Service

json_format

JSON 格式化

JSONService

json_compress

JSON 压缩

JSONService

encode_base64

Base64 编解码

EncodeService

encode_url

URL 编解码

EncodeService

encode_unicode

Unicode 编解码

EncodeService

crypto_hash

哈希计算

CryptoService

time_convert

时间转换

TimeService

text_stats

文本统计

TextService

text_transform

文本转换

TextService

qrcode_generate

二维码生成

QRCodeService

regex_test

正则测试

RegexService

diff_compare

文本对比

DiffService

markdown_render

Markdown 渲染

MarkdownService

cron_parse

Cron 解析

CronService

color_convert

颜色转换

ColorService

ai_analyze_log

AI 日志分析

AIService

ai_generate_regex

AI 正则生成

AIService

ai_explain_code

AI 代码解释

AIService


十三、后端工程师最容易犯的错误

❌ 错误 1:把 Tool 写成底层接口

queryDB
getList

👉 LLM 不会用,因为 description 不够清晰

❌ 错误 2:把 MCP 当业务层

// 错误:在 MCP Server 里写业务逻辑
func (s *Server) handleToolsCall(req Request) *Response {
    // 不要在这里写业务逻辑!
    if params.Name == "query_user" {
        // 直接查数据库...
    }
}

👉 MCP 只做协议路由,业务逻辑在 Service 层

❌ 错误 3:忽略 description

// 错误:description 太简单
Tool{
    Name:        "format",
    Description: "格式化",  // ← LLM 无法理解
}
// 正确:description 要详细
Tool{
    Name:        "json_format",
    Description: "格式化 JSON 字符串,使其更易读。支持自定义缩进,默认为两个空格。",
}

十四、你应该建立的新认知

你不是在"写接口",而是在"暴露能力给 AI"

传统接口:

设计给 人 调用的
文档在 Wiki/Swagger
调用者看文档决定怎么调

MCP Tool:

设计给 LLM 调用的
文档在 description 字段
LLM 根据 description 自动决定怎么调

十五、最终总结

✔ MCP 是什么?

一套让 LLM 调用外部能力的协议(基于 JSON-RPC 2.0)

✔ Tool 是什么?

MCP 协议下暴露的具体能力,包含 name、description、inputSchema

✔ 两者关系?

MCP(怎么调) + Tool(调什么)

✔ 分层架构

协议层 (MCP Server) → 能力层 (Tool) → 业务层 (Service)

最后一刀(重点)

如果你还在问"Tool 是不是接口",说明你还在用传统后端思维

真正的转变是:

从"设计接口" → "设计 AI 能理解的能力"

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐