如何使用Golang开发MCP服务器:从mcp-go到mcp-k8s实践
如何使用Golang开发MCP服务器:从mcp-go到mcp-k8s实践
April 19, 2025
随着大语言模型(LLM)与开发工具的深度融合,Model Control Protocol (MCP)协议正在成为AI与软件工具交互的重要桥梁。MCP允许LLM以结构化的方式调用工具,使AI能够执行具体的操作而不仅仅是生成文本。
本文将详细介绍如何使用Golang和 mcp-go 这个SDK来开发MCP服务器,并以我的开源项目 mcp-k8s 为具体案例,讲解如何构建一个与Kubernetes集群交互的MCP服务器。
MCP协议简介 Permalink for this section
MCP (Model Control Protocol)是一种协议,允许LLM与外部工具进行结构化交互。通过MCP,LLM可以:
- 获取可用工具及其参数列表
- 调用这些工具执行操作
- 获取操作结果并基于结果继续交互
这使得LLM能够"控制"外部系统,执行从查询数据库到操作Kubernetes资源等各种任务。
mcp-go SDK概述 Permalink for this section
mcp-go 是一个用Golang实现的MCP协议SDK,它提供了构建MCP服务器所需的核心组件:
- 工具注册和管理
- 协议消息处理
- 多种传输方式支持(stdio、HTTP SSE等)
使用mcp-go,我们可以快速构建自己的MCP服务器,而无需关心底层协议细节。
开发MCP服务器的基本步骤 Permalink for this section
使用mcp-go开发MCP服务器通常包括以下步骤:
- 设计并定义工具(Tools)
- 实现工具的具体功能
- 创建服务器并注册工具
- 配置并启动服务器
下面我们将详细介绍每一步。
1. 设计并定义工具 Permalink for this section
在MCP中,工具(Tool)是LLM可以调用的功能单元。每个工具需要定义:
- 名称(Name):工具的标识符
- 描述(Description):工具的功能描述
- 参数(Parameters):工具接受的参数及其类型
- 处理函数(Handler):实现工具功能的函数
以mcp-k8s中的 get_api_resources
工具为例:
// 定义工具
var getAPIResourcesTool = server.Tool{
Name: "get_api_resources",
Description: "获取集群中所有支持的API资源类型",
Parameters: nil, // 此工具不需要参数
Handler: handleGetAPIResources,
}
// 实现处理函数
func handleGetAPIResources(ctx context.Context, rawParams json.RawMessage) (interface{}, error) {
// 具体实现...
}
2. 实现工具的具体功能 Permalink for this section
工具的Handler函数实现具体的业务逻辑。在mcp-k8s中,这些函数主要与Kubernetes API交互。
例如,获取API资源列表的实现:
func handleGetAPIResources(ctx context.Context, rawParams json.RawMessage) (interface{}, error) {
// 创建k8s discovery客户端
discoveryClient, err := discovery.NewDiscoveryClientForConfig(kubeConfig)
if err != nil {
return nil, fmt.Errorf("创建discovery客户端失败: %w", err)
}
// 获取服务器上所有API组
apiGroups, err := discoveryClient.ServerGroups()
if err != nil {
return nil, fmt.Errorf("获取API组失败: %w", err)
}
// 处理结果并返回
result := processAPIGroups(apiGroups)
return result, nil
}
3. 创建服务器并注册工具 Permalink for this section
使用mcp-go创建MCP服务器并注册工具:
func main() {
// 创建MCP服务器
s, err := server.NewServer(
server.WithLogger(log.Default()),
)
if err != nil {
log.Fatalf("创建服务器失败: %v", err)
}
// 注册工具
s.RegisterTool(getAPIResourcesTool)
s.RegisterTool(getResourceTool)
s.RegisterTool(listResourcesTool)
// ... 注册更多工具
// 启动服务器
if err := s.Start(); err != nil {
log.Fatalf("启动服务器失败: %v", err)
}
}
4. 配置并启动服务器 Permalink for this section
mcp-go支持多种传输方式,最常用的是stdio(标准输入/输出)和SSE(Server-Sent Events)。
// stdio模式(默认)
s, err := server.NewServer(
server.WithLogger(log.Default()),
server.WithTransport(server.TransportStdio),
)
// SSE模式
s, err := server.NewServer(
server.WithLogger(log.Default()),
server.WithTransport(server.TransportSSE),
server.WithHost("localhost"),
server.WithPort(8080),
)
mcp-k8s: 一个完整的实践案例 Permalink for this section
mcp-k8s 是一个使用mcp-go开发的、用于与Kubernetes集群交互的MCP服务器。它提供了以下工具:
-
资源类型查询工具
get_api_resources
: 获取集群中所有支持的API资源类型
-
资源操作工具
get_resource
: 获取特定资源的详细信息list_resources
: 列出某种资源类型的所有实例create_resource
: 创建新资源(可配置禁用)update_resource
: 更新现有资源(可配置禁用)delete_resource
: 删除资源(可配置禁用)
以下是mcp-k8s的核心实现:
目录结构 Permalink for this section
mcp-k8s/
├── cmd/
│ └── server/
│ └── main.go # 主程序入口
├── internal/
│ ├── config/ # 配置处理
│ ├── k8s/ # Kubernetes客户端
│ └── tools/ # MCP工具实现
├── go.mod
└── go.sum
主程序入口 Permalink for this section
// cmd/server/main.go
func main() {
// 解析命令行参数
kubeconfig := flag.String("kubeconfig", "", "Kubernetes配置文件路径")
enableCreate := flag.Bool("enable-create", false, "启用资源创建操作")
enableUpdate := flag.Bool("enable-update", false, "启用资源更新操作")
enableDelete := flag.Bool("enable-delete", false, "启用资源删除操作")
transport := flag.String("transport", "stdio", "传输方式: stdio或sse")
host := flag.String("host", "localhost", "SSE模式的主机名")
port := flag.Int("port", 8080, "SSE模式的端口")
flag.Parse()
// 初始化Kubernetes客户端
if err := k8s.InitClient(*kubeconfig); err != nil {
log.Fatalf("初始化K8s客户端失败: %v", err)
}
// 创建MCP服务器
serverOpts := []server.Option{
server.WithLogger(log.Default()),
}
// 配置传输方式
if *transport == "sse" {
serverOpts = append(serverOpts,
server.WithTransport(server.TransportSSE),
server.WithHost(*host),
server.WithPort(*port),
)
} else {
serverOpts = append(serverOpts, server.WithTransport(server.TransportStdio))
}
s, err := server.NewServer(serverOpts...)
if err != nil {
log.Fatalf("创建服务器失败: %v", err)
}
// 注册工具
tools.RegisterTools(s, &tools.Options{
EnableCreate: *enableCreate,
EnableUpdate: *enableUpdate,
EnableDelete: *enableDelete,
})
// 启动服务器
if err := s.Start(); err != nil {
log.Fatalf("启动服务器失败: %v", err)
}
}
工具实现示例 Permalink for this section
以 get_resource
工具为例:
// internal/tools/get_resource.go
var GetResourceTool = server.Tool{
Name: "get_resource",
Description: "获取特定资源的详细信息",
Parameters: []server.Parameter{
{
Name: "apiVersion",
Description: "资源的API版本",
Type: "string",
Required: true,
},
{
Name: "kind",
Description: "资源类型",
Type: "string",
Required: true,
},
{
Name: "name",
Description: "资源名称",
Type: "string",
Required: true,
},
{
Name: "namespace",
Description: "资源所在的命名空间(如适用)",
Type: "string",
Required: false,
},
},
Handler: handleGetResource,
}
type GetResourceParams struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace"`
}
func handleGetResource(ctx context.Context, rawParams json.RawMessage) (interface{}, error) {
var params GetResourceParams
if err := json.Unmarshal(rawParams, ¶ms); err != nil {
return nil, fmt.Errorf("解析参数失败: %w", err)
}
// 获取动态客户端
dynamicClient, err := k8s.GetDynamicClient()
if err != nil {
return nil, err
}
// 获取资源GVR (Group Version Resource)
gvr, namespaced, err := k8s.GetGVR(params.APIVersion, params.Kind)
if err != nil {
return nil, err
}
// 确定是命名空间级别还是集群级别的资源
var object *unstructured.Unstructured
if namespaced {
// 如果是命名空间级别资源但未提供命名空间,使用默认命名空间
namespace := params.Namespace
if namespace == "" {
namespace = "default"
}
object, err = dynamicClient.Resource(gvr).Namespace(namespace).Get(ctx, params.Name, metav1.GetOptions{})
} else {
object, err = dynamicClient.Resource(gvr).Get(ctx, params.Name, metav1.GetOptions{})
}
if err != nil {
return nil, fmt.Errorf("获取资源失败: %w", err)
}
return object.Object, nil
}
注册所有工具 Permalink for this section
// internal/tools/tools.go
type Options struct {
EnableCreate bool
EnableUpdate bool
EnableDelete bool
}
func RegisterTools(s *server.Server, opts *Options) {
// 注册查询工具(始终启用)
s.RegisterTool(GetAPIResourcesTool)
s.RegisterTool(GetResourceTool)
s.RegisterTool(ListResourcesTool)
// 根据配置注册写操作工具
if opts.EnableCreate {
s.RegisterTool(CreateResourceTool)
}
if opts.EnableUpdate {
s.RegisterTool(UpdateResourceTool)
}
if opts.EnableDelete {
s.RegisterTool(DeleteResourceTool)
}
}
使用方法 Permalink for this section
mcp-k8s支持两种通信模式:
1. Stdio模式(默认) Permalink for this section
在stdio模式下,mcp-k8s通过标准输入/输出流与客户端通信。
// MCP客户端配置
{
"mcpServers": {
"mcp-k8s": {
"command": "/path/to/mcp-k8s",
"args": [\
"-kubeconfig", "/path/to/kubeconfig",\
"-enable-create",\
"-enable-delete",\
"-enable-update"\
]
}
}
}
2. SSE模式 Permalink for this section
在SSE模式下,mcp-k8s暴露HTTP端点供MCP客户端连接。
# 运行SSE模式服务
./bin/mcp-k8s -kubeconfig=/path/to/kubeconfig -transport=sse -port=8080 -host=localhost -enable-create -enable-delete -enable-update
// MCP客户端配置
{
"mcpServers": {
"mcp-k8s": {
"url": "http://localhost:8080/sse",
"args": []
}
}
}