☰

本文整理自一次关于 Model Context Protocol(MCP)的完整讨论,覆盖 MCP 的核心概念、Go 实现、对外发布、自然语言注册、远程服务化,以及 MCP 与 Agent Skill 的关系与选型。

1. MCP 是什么:AI 应用的"USB-C 端口"

Model Context Protocol(MCP) 是由 Anthropic 于 2024 年 11 月推出的开放协议,用于标准化大语言模型与外部数据源、工具之间的集成方式。它常被类比为"AI 应用的 USB-C 端口":就像 USB-C 统一了设备与配件的连接方式,MCP 统一了 AI 模型与外部服务的对接标准。

MCP 基于 JSON-RPC 2.0,定义了三层架构:

  • Hosts:发起连接的 LLM 应用,如 AI IDE、聊天界面。
  • Clients:Host 内部的连接器,每个 Client 维护一个独立会话。
  • Servers:提供上下文和能力的服务,可以是本地进程,也可以是远程服务。

MCP Server 向客户端暴露三类核心能力:

能力说明
Resources可供 AI 读取的上下文数据,如文件内容、数据库记录
Prompts预定义的模板化消息和工作流
ToolsAI 模型可调用的函数,如查询数据库、调用 API、读写文件

传输层方面,MCP 支持:

  • stdio:标准输入输出,适合本地工具,零网络配置。
  • Streamable HTTP:推荐的远程传输方式,单一 HTTP 端点,接受 POST,返回 JSON 或 SSE 流。
  • HTTP + SSE:已弃用的双端点模式。

MCP 的设计灵感来自 Language Server Protocol(LSP):LSP 统一了编辑器对编程语言的支持,MCP 则以类似方式统一了 AI 应用对外部工具和数据的集成。

2. 用 Go 实现一个最简单的 MCP Server

最简洁的方式是使用 MCP 官方 Go SDK:github.com/modelcontextprotocol/go-sdk 。

2.1 初始化项目

1mkdir mcp-demo && cd mcp-demo
2go mod init mcp-demo
3go get github.com/modelcontextprotocol/go-sdk@latest

2.2 编写服务器代码

实现一个提供"获取当前时间"工具的 MCP Server:

 1package main
 2
 3import (
 4    "context"
 5    "fmt"
 6    "time"
 7
 8    "github.com/modelcontextprotocol/go-sdk/mcp"
 9)
10
11func main() {
12    // 1. 创建 MCP 服务器实例
13    server := mcp.NewServer("mcp-demo", "1.0.0")
14
15    // 2. 注册 "getCurrentTime" 工具
16    server.AddTool(mcp.Tool{
17        Name:        "getCurrentTime",
18        Description: "获取当前时间(支持时区参数)",
19        InputSchema: map[string]interface{}{
20            "type": "object",
21            "properties": map[string]interface{}{
22                "timezone": map[string]interface{}{
23                    "type":        "string",
24                    "description": "时区名称,如 'Asia/Shanghai',默认为本地时区",
25                    "default":     "Local",
26                },
27            },
28            "required": []string{},
29        },
30        Handler: func(ctx context.Context, args map[string]interface{}) (interface{}, error) {
31            tzName, _ := args["timezone"].(string)
32            loc := time.Local
33
34            if tzName != "" && tzName != "Local" {
35                var err error
36                loc, err = time.LoadLocation(tzName)
37                if err != nil {
38                    return nil, fmt.Errorf("无效时区: %v", err)
39                }
40            }
41
42            now := time.Now().In(loc).Format("2006-01-02 15:04:05 MST")
43            return map[string]string{"time": now}, nil
44        },
45    })
46
47    // 3. 通过 stdio 启动服务器
48    if err := server.ServeStdio(); err != nil {
49        fmt.Println("服务器错误:", err)
50    }
51}

核心逻辑非常直接:

  • mcp.NewServer 创建服务器实例。
  • AddTool 注册工具,包含名称、描述、输入 JSON Schema 和处理函数。
  • ServeStdio 通过标准输入输出通信。

2.3 运行与测试

1go run main.go

服务器启动后,会通过 stdin 等待 JSON-RPC 请求。可以手动发送:

1{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"getCurrentTime","arguments":{"timezone":"Asia/Shanghai"}}}

在 VS Code 中配置 MCP Server 时,可在 .vscode/mcp.json 中添加:

1{
2  "servers": {
3    "mcp-demo": {
4      "type": "stdio",
5      "command": "go",
6      "args": ["run", "main.go"]
7    }
8  }
9}

3. 对外发布:让用户"下载即用"

如果希望用户下载对应平台的二进制文件后直接使用,核心思路是:交叉编译多平台二进制,通过 GitHub Releases 托管,再辅以包管理器或 Bundle 格式降低安装门槛。

3.1 交叉编译多平台二进制

Go 的交叉编译只需设置 GOOS 和 GOARCH。建议关闭 CGO,生成纯静态文件:

1# Linux amd64
2CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o mcp-demo-linux-amd64
3
4# macOS Apple Silicon
5CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -o mcp-demo-darwin-arm64
6
7# Windows amd64
8CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o mcp-demo-windows-amd64.exe

建议至少覆盖:

平台GOOSGOARCH
Linux x64linuxamd64
Linux ARM64linuxarm64
macOS Inteldarwinamd64
macOS Apple Silicondarwinarm64
Windows x64windowsamd64

3.2 用 GoReleaser 自动化发布

手动逐个编译和上传容易出错。推荐使用 GoReleaser ,一条命令完成多平台构建、打包归档、生成校验和并上传 GitHub Releases。

初始化:

1goreleaser init

配置 GitHub Actions:.github/workflows/release.yml

 1name: Release
 2on:
 3  push:
 4    tags: ['v*']
 5jobs:
 6  release:
 7    runs-on: ubuntu-latest
 8    permissions:
 9      contents: write
10    steps:
11      - uses: actions/checkout@v4
12        with:
13          fetch-depth: 0
14      - uses: actions/setup-go@v5
15        with:
16          go-version: 'stable'
17      - uses: goreleaser/goreleaser-action@v6
18        with:
19          args: release --clean
20        env:
21          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

打 tag 推送即可自动发布:

1git tag v0.1.0 && git push origin v0.1.0

3.3 降低安装门槛:包管理器与 Bundle 格式

有了 GitHub Releases 产物,可以进一步接入分发渠道:

  • Homebrew Tap:自建 tap 仓库,用户 brew install 一条命令安装。
  • Scoop / Winget(Windows)、APT/YUM 仓库(Linux):按目标用户群选择。
  • npm 包装:即使工具是 Go 编写,也可以发一个 npm 包,安装时按平台下载对应二进制——这是很多 CLI 工具(如 esbuild)采用的模式。
  • MCP Bundle(.mcpb):Anthropic 推出的打包格式,把 MCP Server 及其依赖打成一个文件,用户在 Claude Desktop 里一键安装,适合面向非开发者用户分发。

4. 自然语言注册:让 AI 自己装 MCP

随着 MCP 生态成熟,出现了"用自然语言描述需求 → AI 自动寻找并配置 MCP Server"的玩法。典型流程:

  1. 用户在支持 MCP 的客户端(如 Claude Code、Cursor)中用自然语言说:“帮我接入一个能查 GitHub Issue 的 MCP 工具”。
  2. 客户端/AI 通过 MCP Registry (官方注册表)或社区目录检索匹配的 Server。
  3. AI 生成配置(stdio 命令或远程 URL),写入 mcp.json,必要时引导完成 OAuth 授权。
  4. 重启会话后,新工具即可被模型调用。

要让你的 Server 被自然语言"搜到",关键是:

  • 在 MCP Registry 提交 Server 元数据(名称、描述、传输方式、安装方式)。
  • Description 写清楚工具做什么、参数含义——模型正是靠这些描述决定何时调用。
  • 保持命名语义化,避免无意义的缩写。

5. 远程服务化:Streamable HTTP

stdio 模式要求 Server 与客户端同机运行。当工具需要共享状态、访问内网数据或被多人使用时,需要把 MCP Server 部署为远程 HTTP 服务。

5.1 Go 实现 Streamable HTTP 端点

官方 Go SDK 提供 Streamable HTTP 传输,只需把 ServeStdio 换成 HTTP handler:

 1func main() {
 2    server := mcp.NewServer("mcp-demo", "1.0.0")
 3    // ... 同前注册 Tool ...
 4
 5    handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server {
 6        return server
 7    }, nil)
 8
 9    http.Handle("/mcp", handler)
10    log.Println("MCP server listening on :8080/mcp")
11    log.Fatal(http.ListenAndServe(":8080", nil))
12}

客户端配置:

1{
2  "servers": {
3    "mcp-demo": {
4      "type": "http",
5      "url": "https://mcp.example.com/mcp"
6    }
7  }
8}

5.2 部署要点

  • 认证:MCP 授权基于 OAuth 2.1;公网部署必须在网关层做鉴权,不能裸奔。
  • 会话管理:Streamable HTTP 通过 Mcp-Session-Id 头维持会话,水平扩容时需保证同一会话路由到同一实例或共享会话状态。
  • SSE 流式响应:工具执行耗时长时可返回 SSE 流,注意反向代理(Nginx 等)要关闭缓冲。
  • 部署形态:单二进制 + systemd/容器皆可;Kubernetes 部署时配合 HPA 按连接数或 CPU 扩缩容。

6. MCP 与 Agent Skill:关系与选型

MCP 之外,Anthropic 还推出了 Agent Skills(SKILL.md 格式)。两者常被拿来比较,实际定位不同:

维度MCPAgent Skill
本质工具/数据接入协议(JSON-RPC)指令 + 脚本的知识包(Markdown)
运行形态独立进程或远程服务客户端内按需加载的文件
适合提供动态能力:查数据库、调 API、实时数据静态知识:工作流程、领域规范、操作手册
集成成本需实现协议、部署服务复制一个目录即可
生态跨厂商开放标准,客户端支持广目前主要在 Claude 系客户端

协同模式:二者不是竞争关系。典型组合是——Skill 教会 Agent “怎么做”(流程、规范),MCP 提供"用什么做"(工具、数据)。例如一个运维排障 Skill 定义排查步骤,其中"查日志"这一步调用 MCP 的日志查询工具。

选型建议:

  • 要暴露动态能力/私有数据给任何支持 MCP 的客户端 → 写 MCP Server。
  • 要沉淀团队流程和领域知识,且主要在 Claude 生态使用 → 写 Skill。
  • 复杂 Agent 产品 → 两者并用,Skill 编排流程,MCP 供给能力。

7. 总结

MCP 把"AI 应用 ↔ 外部工具"的集成从 N×M 的私有对接变成了 N+M 的标准对接。对个人和团队而言,现实的路径是:

  1. 用官方 Go SDK 几十行代码写出最小 Server,stdio 跑通本地工具。
  2. GoReleaser + GitHub Releases 完成多平台分发,按需接入包管理器或 .mcpb。
  3. 提交 MCP Registry 元数据,让 Server 可被自然语言检索和安装。
  4. 有共享/内网需求时,切换 Streamable HTTP 远程化,做好 OAuth 与会话管理。
  5. 与 Agent Skill 按需组合:Skill 管知识,MCP 管能力。

从本地 stdio 到远程服务,从手动安装到自然语言注册,MCP 生态正在快速补齐"发布—发现—使用"的完整链路,现在投入的集成成本,未来会随客户端支持的普及而持续摊薄。