公告

任何建议或需求可联系我!


Skip to content

服务端基础

学习如何使用不同的传输选项创建、配置和启动 MCP 服务端。

创建服务端

任何 MCP 服务端的基础是 NewMCPServer() 函数。这会创建一个带有基本元数据和可选配置的服务端实例。

基本服务端创建

go
package main

import (
    "github.com/mark3labs/mcp-go/server"
)

func main() {
    // 创建基本服务端
    s := server.NewMCPServer(
        "My MCP Server",  // 服务端名称
        "1.0.0",          // 服务端版本
    )
    
    // 启动服务端(stdio 传输)
    server.ServeStdio(s)
}

带选项的服务端

使用服务端选项配置能力和行为:

go
s := server.NewMCPServer(
    "Advanced Server",
    "2.0.0",
    server.WithToolCapabilities(true),      // 启用工具
    server.WithResourceCapabilities(true, true),  // 启用资源
    server.WithPromptCapabilities(true),    // 启用提示词
    server.WithRecovery(),                  // 添加 panic 恢复
    server.WithHooks(myHooks),              // 添加生命周期钩子
    server.WithIcons(                       // 添加服务端图标
        mcp.Icon{
            Src:      "https://example.com/server-icon.png",
            MIMEType: "image/png",
            Sizes:    []string{"48x48"},
        },
    ),
)

服务端配置

能力

能力告诉客户端你的服务端支持哪些功能:

go
// 启用特定能力
s := server.NewMCPServer(
    "Specialized Server",
    "1.0.0",
    server.WithToolCapabilities(true),      // 可以执行工具
    server.WithResourceCapabilities(true, true),  // 可以提供资源
    server.WithPromptCapabilities(true),    // 可以提供提示词
)

// 或启用所有能力
s := server.NewMCPServer(
    "Full-Featured Server", 
    "1.0.0",
    server.WithToolCapabilities(true),
    server.WithResourceCapabilities(true, true),
    server.WithPromptCapabilities(true),
)

能力类型:

  • 工具:服务端可以执行来自 LLM 的函数调用
  • 资源:服务端可以向 LLM 提供数据/内容
  • 提示词:服务端可以提供提示词模板
  • 任务:服务端支持异步任务增强的工具执行(参见任务增强工具
  • 自动补全:服务端提供参数自动补全(参见自动补全
  • 征求意见:服务端可以请求额外的用户输入(参见征求意见
  • 根目录:服务端可以向客户端请求根目录信息

恢复中间件

添加自动 panic 恢复以防止服务端崩溃:

go
s := server.NewMCPServer(
    "Robust Server",
    "1.0.0", 
    server.WithRecovery(), // 从 panic 自动恢复
)

这会捕获处理器中的 panic 并返回正确的错误响应而不是崩溃。

自定义元数据

添加额外服务端信息:

go
s := server.NewMCPServer(
    "My Server",
    "1.0.0",
    server.WithInstructions("A server that does amazing things"),
)

实现元数据

服务端的 Implementation 结构支持额外的可选字段,用于在初始化期间发送更丰富的元数据:

go
// 这些字段从 NewMCPServer 参数自动设置:
//   Name    string — 服务端名称
//   Version string — 服务端版本
//
// mcp.Implementation 上的其他可选字段:
//   Title       string — 人类可读的显示标题
//   Description string — 服务端简要描述
//   WebsiteURL  string — 服务端网站或文档的 URL
//   Icons       []Icon — 实现的视觉标识符

你可以通过服务端选项设置这些:

go
s := server.NewMCPServer(
    "My Server",
    "1.0.0",
    server.WithTitle("My Server"),                                    // 人类可读的显示标题
    server.WithDescription("A server that does amazing things"),     // 简要描述
    server.WithWebsiteURL("https://example.com"),                    // 网站或文档 URL
    server.WithIcons(                                                // 视觉标识符
        mcp.Icon{
            Src:      "https://example.com/icon.png",
            MIMEType: "image/png",
            Sizes:    []string{"48x48"},
        },
    ),
)

扩展 vs 实验性能力

服务端可以通告两种非标准能力:

  • 扩展ServerCapabilities.Extensions)—— 用于通告已知扩展支持的标准化扩展点
  • 实验性ServerCapabilities.Experimental)—— 非标准、实验性能力
go
s := server.NewMCPServer("My Server", "1.0.0",
    // 设置实验性能力
    server.WithExperimental(map[string]any{
        "claude/channel": map[string]any{
            "supported": true,
        },
    }),
)

两个字段都是 map[string]any,并在初始化期间包含在服务端的能力中。相同的 Extensions 字段在 ClientCapabilities 上可用,客户端可以用它通告扩展支持。

启动服务端

MCP-Go 支持多种传输方式以适应不同的部署场景。

Stdio 传输

标准输入/输出 - 最常用于本地工具:

go
func main() {
    s := server.NewMCPServer("My Server", "1.0.0")
    
    // 启动 stdio 服务端(阻塞直到终止)
    if err := server.ServeStdio(s); err != nil {
        log.Fatal(err)
    }
}

适用于:

  • 本地开发工具
  • CLI 集成
  • 桌面应用程序
  • 单客户端场景

HTTP 传输

传统 HTTP 请求/响应:

go
func main() {
    s := server.NewMCPServer("HTTP Server", "1.0.0")
    
    // 创建 HTTP 服务端
    httpServer := server.NewStreamableHTTPServer(s)
    
    // 在端口 8080 启动 HTTP 服务端
    if err := httpServer.Start(":8080"); err != nil {
        log.Fatal(err)
    }
}

适用于:

  • Web 服务
  • 负载均衡部署
  • REST 风格 API
  • 缓存场景

Server-Sent Events (SSE)

基于 HTTP 的流式传输,用于实时更新:

go
func main() {
    s := server.NewMCPServer("SSE Server", "1.0.0")
    
    // 创建 SSE 服务端
    sseServer := server.NewSSEServer(s)
    
    // 在端口 8080 启动 SSE 服务端
    if err := sseServer.Start(":8080"); err != nil {
        log.Fatal(err)
    }
}

适用于:

  • Web 应用程序
  • 实时通知
  • 多个并发客户端
  • 基于浏览器的工具

自定义传输选项

配置传输特定选项:

go
// 带自定义选项的 HTTP
httpServer := server.NewStreamableHTTPServer(s,
    server.WithEndpointPath("/mcp"),
    server.WithStateLess(true),
    server.WithTLSCert("/path/to/cert.pem", "/path/to/key.pem"),
)

if err := httpServer.Start(":8080"); err != nil {
    log.Fatal(err)
}

// 带自定义选项的 SSE
sseServer := server.NewSSEServer(s,
    server.WithSSEEndpoint("/events"),
    server.WithMessageEndpoint("/message"),
    server.WithKeepAlive(true),
)

if err := sseServer.Start(":8080"); err != nil {
    log.Fatal(err)
}

基于环境的配置

根据环境变量配置服务端:

go
func main() {
    s := server.NewMCPServer("Configurable Server", "1.0.0")
    
    // 根据环境选择传输
    transport := os.Getenv("MCP_TRANSPORT")
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    
    switch transport {
    case "http":
        httpServer := server.NewStreamableHTTPServer(s)
        httpServer.Start(":"+port)
    case "sse":
        sseServer := server.NewSSEServer(s)
        sseServer.Start(":"+port)
    default:
        server.ServeStdio(s)
    }
}
}

服务端生命周期

理解服务端生命周期有助于正确的资源管理:

go
func main() {
    hooks := &server.Hooks{}
    
    // 添加会话生命周期钩子
    hooks.AddOnRegisterSession(func(ctx context.Context, session server.ClientSession) {
        log.Printf("Client %s connected", session.ID())
    })
    
    hooks.AddOnUnregisterSession(func(ctx context.Context, session server.ClientSession) {
        log.Printf("Client %s disconnected", session.ID())
    })
    
    // 添加请求钩子
    hooks.AddBeforeAny(func(ctx context.Context, id any, method mcp.MCPMethod, message any) {
        log.Printf("Processing %s request", method)
    })
    
    hooks.AddOnError(func(ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
        log.Printf("Error in %s: %v", method, err)
    })
    
    s := server.NewMCPServer("Lifecycle Server", "1.0.0",
        server.WithHooks(hooks),
    )
    
    // 优雅关闭
    c := make(chan os.Signal, 1)
    signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    
    go func() {
        <-c
        log.Println("Shutting down server...")
        s.Shutdown()
    }()
    
    server.ServeStdio(s)
}

错误处理

正确的错误处理确保服务端健壮运行:

go
func main() {
    s := server.NewMCPServer("Error-Safe Server", "1.0.0",
        server.WithRecovery(), // Panic 恢复
    )
    
    // 添加服务端启动的错误处理
    if err := server.ServeStdio(s); err != nil {
        if errors.Is(err, server.ErrServerClosed) {
            log.Println("Server closed gracefully")
        } else {
            log.Fatalf("Server error: %v", err)
        }
    }
}

下一步

现在你了解了服务端基础,学习如何添加功能: