使用 Go SDK 轻松构建类型安全的 MCP 服务
该文章介绍了一个名为 **go-mcp** 的 Go SDK,用于构建类型安全的 MCP 服务。 **go-mcp** 提供了类型安全、直观的 API,简化了 MCP 服务的开发流程。文章展示了如何通过代码生成和服务器逻辑实现一个温度转换的 MCP 服务,并提供了快速开始的示例。该 SDK 支持多种功能,如工具、提示、资源管理等,并计划未来增加批处理和流式 HTTP 传输等特性。文章还强调了该 SDK 不支持动态添加工具的原因,并欢迎社区贡献。
⚡ 一款类型安全、直观的 Go SDK,让你轻松自信地构建 MCP 服务。
License
ktr0731/go-mcp
⚡ go-mcp
一款类型安全、直观的 Go SDK,用于 MCP 服务开发
🤔 什么是 go-mcp? • ✨ 功能特性 • 🏁 快速开始 • 🔍 示例 • ✅ 支持的功能 • 🤝 贡献
🤔 什么是 go-mcp?
go-mcp 是一个 Go SDK,旨在让你能够轻松自信地构建 MCP (Model Context Protocol) 服务。 它提供了一个类型安全、直观的接口,让服务器开发变得轻而易举。
✨ 功能特性
- 🔒 类型安全 – 代码生成确保你的工具和 prompt 参数是静态类型,以便在编译时而不是运行时捕获错误。
- 🧩 简单直观的 API – 一种自然的、符合 Go 语言习惯的接口,让你能够快速构建服务器,而无需陡峭的学习曲线。
- 🔌 对开发者友好 – 在设计时考虑了 API 的人体工程学,使其平易近人。
🏁 快速开始
使用 go-mcp 创建 MCP 服务器非常简单!
目录结构
以下是一个温度转换 MCP 服务器的示例目录结构:
.
├── cmd
│ ├── mcpgen
│ │ └── main.go
│ └── temperature
│ └── main.go
├── mcp.gen.go
└── temperature.go
1. 定义 MCP 服务器
首先,创建 cmd/mcpgen/main.go
用于代码生成。 运行此文件将自动生成必要的代码。
package main
import (
"log"
"os"
"path/filepath"
"github.com/ktr0731/go-mcp/codegen"
)
func main() {
// Create output directory
outDir := "."
if err := os.MkdirAll(outDir, 0o755); err != nil {
log.Fatalf("failed to create output directory: %v", err)
}
// Create output file
f, err := os.Create(filepath.Join(outDir, "mcp.gen.go"))
if err != nil {
log.Fatalf("failed to create file: %v", err)
}
defer f.Close()
// Server definition
def := &codegen.ServerDefinition{
Capabilities: codegen.ServerCapabilities{
Tools: &codegen.ToolCapability{},
Logging: &codegen.LoggingCapability{},
},
Implementation: codegen.Implementation{
Name: "Temperature MCP Server",
Version: "1.0.0",
},
// Tool definitions (declared with Go structs)
Tools: []codegen.Tool{
{
Name: "convert_temperature",
Description: "Convert temperature between Celsius and Fahrenheit",
InputSchema: struct {
Temperature float64 `json:"temperature" jsonschema:"description=Temperature value to convert"`
FromUnit string `json:"from_unit" jsonschema:"description=Source temperature unit,enum=celsius,enum=fahrenheit"`
ToUnit string `json:"to_unit" jsonschema:"description=Target temperature unit,enum=celsius,enum=fahrenheit"`
}{},
},
},
}
// Generate code
if err := codegen.Generate(f, def, "temperature"); err != nil {
log.Fatalf("failed to generate code: %v", err)
}
}
生成代码:
go run ./cmd/mcpgen
2. 实现 MCP 服务器
接下来,在 cmd/temperature/main.go
中实现服务器逻辑:
package main
import (
"context"
"fmt"
"log"
"math"
mcp "github.com/ktr0731/go-mcp"
"golang.org/x/exp/jsonrpc2"
)
type toolHandler struct{}
func (h *toolHandler) HandleToolConvertTemperature(ctx context.Context, req *ToolConvertTemperatureRequest) (*mcp.CallToolResult, error) {
temperature := req.Temperature
fromUnit := req.FromUnit
toUnit := req.ToUnit
var result float64
switch {
case fromUnit == ConvertTemperatureFromUnitTypeCelsius && toUnit == ConvertTemperatureToUnitTypeFahrenheit:
// °C → °F: (C × 9/5) + 32
result = (temperature*9/5 + 32)
case fromUnit == ConvertTemperatureFromUnitTypeFahrenheit && toUnit == ConvertTemperatureToUnitTypeCelsius:
// °F → °C: (F − 32) × 5/9
result = (temperature - 32) * 5 / 9
case fromUnit == toUnit:
result = temperature
default:
return nil, fmt.Errorf("unsupported conversion: %s to %s", fromUnit, toUnit)
}
// Round to two decimal places
result = math.Round(result*100) / 100
resultText := fmt.Sprintf("%.2f %s = %.2f %s", temperature, fromUnit, result, toUnit)
return &mcp.CallToolResult{
Content: []mcp.CallToolContent{
mcp.TextContent{Text: resultText},
},
}, nil
}
func main() {
handler := NewHandler(&toolHandler{})
ctx, listener, binder := mcp.NewStdioTransport(context.Background(), handler, nil)
srv, err := jsonrpc2.Serve(ctx, listener, binder)
if err != nil {
log.Fatalf("failed to serve: %v", err)
}
srv.Wait()
}
运行服务器:
go run ./cmd/temperature
🔍 示例
请参阅 examples 目录 和 API 文档 中的完整示例。
✅ 支持的功能
- Ping
- Tools
- Prompts
- Prompts, Tools, Resources, Resource Templates
- Resource subscription
- Resource update notification
- Logging
- Completion
- Cancellation
🚧 开发中
- Batching (JSON-RPC 2.0)
- Streamable HTTP transport
- Progress notification
🚫 未计划
- 动态 prompt 和 tool 更改
Go 不太适合动态添加工具。 动态添加工具需要在运行时构造工具定义、JSON Schema 和 handlers。 虽然生成的代码保持类型安全,但动态添加的组件并非如此,从而强制大量使用 any
和类型断言,并损害接口一致性。 我们将这些用例委派给更适合动态更改的语言的 SDK,例如 TypeScript。
目前大多数已实现的 MCP 服务器仅使用静态定义,并且动态更改似乎还不是主要用例。
🤝 贡献
欢迎贡献! 随时提交 pull request。
📄 License
本项目根据 MIT License 授权 – 有关详细信息,请参阅 LICENSE 文件。