一个类型安全、直观的 Go SDK,用于轻松自信地构建 MCP 服务器
A type-safe, intuitive Go SDK for building MCP servers with ease and confidence

原始链接: https://github.com/ktr0731/go-mcp

`go-mcp` 是一个 Go 语言 SDK,用于构建类型安全且易于使用的 MCP(模型上下文协议)服务器。它利用代码生成来确保工具和提示参数具有静态类型,从而在编译时捕获错误。该 SDK 提供了一个简单直观的 Go API,使服务器开发变得简单直接。 提供的示例演示了如何使用 Go 结构体定义工具(例如温度转换),生成必要的代码,以及使用处理程序实现服务器逻辑。主要功能包括对工具、提示、资源和日志的支持。正在开发的功能包括批量处理和可流式传输的 HTTP 传输。由于 Go 语言在处理动态类型方面的限制,故意不计划动态工具更改,对于此类用例,更倾向于使用 TypeScript 等语言。欢迎在 MIT 许可下贡献代码。

Hacker News 最新 | 往期 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 一个类型安全、直观的 Go SDK,用于轻松自信地构建 MCP 服务器 (github.com/ktr0731) 4 分,来自 ktr0731,1 小时前 | 隐藏 | 往期 | 收藏 | 讨论 加入我们,参加 6 月 16-17 日在旧金山举办的 AI 初创公司学校! 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系我们 搜索:

原文

A type‑safe, intuitive Go SDK for MCP server development

🤔 What is go‑mcp?✨ Features🏁 Quick Start🔍 Examples✅ Supported Features🤝 Contributing


go‑mcp is a Go SDK for building MCP (Model Context Protocol) servers with ease and confidence. It provides a type‑safe, intuitive interface that makes server development a breeze.


  • 🔒 Type‑Safe – Code generation ensures your tools and prompt parameters are statically typed, so errors are caught at compile time instead of at runtime.
  • 🧩 Simple & Intuitive API – A natural, idiomatic Go interface that lets you build servers quickly without a steep learning curve.
  • 🔌 Developer‑Friendly – Designed with API ergonomics in mind, making it approachable.

Creating an MCP server with go‑mcp is straightforward!

Below is an example directory structure for a temperature‑conversion MCP server:

.
├── cmd
│   ├── mcpgen
│   │   └── main.go
│   └── temperature
│       └── main.go
├── mcp.gen.go
└── temperature.go

First, create cmd/mcpgen/main.go for code generation. Running this file will automatically generate the necessary code.

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)
    }
}

Generate the code:

2. Implement the MCP server

Next, implement the server logic in 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()
}

Run the server:


See complete examples in the examples directory and the API documentation.


  • Ping
  • Tools
  • Prompts
  • Prompts, Tools, Resources, Resource Templates
  • Resource subscription
  • Resource update notification
  • Logging
  • Completion
  • Cancellation

🚧 Under Development

  • Batching (JSON‑RPC 2.0)
  • Streamable HTTP transport
  • Progress notification

🚫 Not Planned

  • Dynamic prompt and tool changes

    Go is not well‑suited for dynamic tool additions. Adding tools dynamically requires constructing tool definitions, JSON Schema, and handlers at runtime. While generated code remains type‑safe, dynamically added components do not, forcing heavy use of any and type assertions and harming interface consistency. We delegate these use cases to SDKs in languages better suited for dynamic changes, such as TypeScript.

    Most currently implemented MCP servers use static definitions only, and dynamic changes do not seem to be a primary use case yet.


Contributions are welcome! Feel free to submit a pull request.


This project is licensed under the MIT License – see the LICENSE file for details.

联系我们 contact @ memedata.com