直接用 mark3labs/mcp-go@v0.23.1 即可跑通 mcp 协议服务;需严格匹配参数 schema 与 handler 签名,按客户端 transport(stdio/http/sse)正确配置启动方式。

直接用 mcp-go 就能跑通 MCP 协议服务,不用自己解析 JSON-RPC 或手写 gRPC 接口。关键不是“能不能做”,而是选对 SDK、注册好工具、传参别错类型——这三点卡住 90% 的初学者。
选哪个 Go MCP SDK:mark3labs/mcp-go 是当前唯一生产就绪的选择
社区里有 mcp-golang(metoro-io)和 mcp-go(mark3labs)两个主流实现,但后者在 2025 年底已明确成为事实标准:它支持完整 MCP v0.3 规范、内置 stdio/sse/http 三种 transport、有 Kubernetes 生产案例(mcp-k8s)、且维护活跃。而 mcp-golang 的 RegisterTool 接口仍基于旧版参数结构体 + jsonschema 标签,反序列化容错弱,遇到空字段或类型不匹配容易 panic。
执行这行命令拉取正确版本:
go get github.com/mark3labs/mcp-go@v0.23.1
- 别用
go get github.com/metoro-io/mcp-golang—— 它的ToolResponse返回值类型和上下文处理与当前 LLM 运行时(如 Claude MCP Client、Ollama MCP 插件)不兼容 - 检查
go.mod中是否出现github.com/mark3labs/mcp-go v0.23.1,不是latest或无版本号 - 如果项目已有
github.com/metoro-io/mcp-golang,必须先go mod edit -dropreplace=github.com/metoro-io/mcp-golang再清理 vendor
注册工具时最常踩的坑:参数定义和 handler 签名必须严格匹配
MCP 客户端发来的调用请求是 JSON 对象,mcp-go 会按你定义的参数 schema 做强校验。一旦字段名、必填标记、枚举值或嵌套结构对不上,整个调用就静默失败(不是报错,而是返回空响应)。
比如这个常见错误写法:
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("执行基本的算术运算"),
mcp.WithString("op", mcp.Required(), mcp.Description("操作类型")), // ❌ 字段名写成 "op"
mcp.WithNumber("a", mcp.Required()), // ❌ 字段名太简略,LLM 容易混淆
)
正确写法要和实际调用 payload 对齐:
calculatorTool := mcp.NewTool("calculate",
mcp.WithDescription("执行基本的算术运算"),
mcp.WithString("operation", mcp.Required(), mcp.Enum("add", "subtract", "multiply", "divide")),
mcp.WithNumber("x", mcp.Required(), mcp.Description("第一个数字")),
mcp.WithNumber("y", mcp.Required(), mcp.Description("第二个数字")),
)
- handler 函数签名必须是
func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error),少一个context.Context或返回类型不对,编译过不了 -
req.Params.Arguments是map[string]interface{},取值后务必做类型断言:req.Params.Arguments["x"].(float64),不能直接当int用 - 空参数(
"parameters": null)会被当成nil map,访问Arguments["x"]会 panic,得先判空
启动服务时 transport 选错会导致客户端连不上
MCP 客户端连接方式决定了 transport 类型:stdio 用于本地调试(比如 Ollama 的 --tool 模式),http 用于部署到容器或云函数,sse 仅在需要流式响应时用。混用会直接卡死。
例如你在本地用 Ollama 测试,却写了:
s := server.NewMCPServer("demo", "1.0.0", server.WithHTTPPort(8080))
Ollama 根本不会发 HTTP 请求,它只往进程 stdin 写 JSON-RPC;反过来,如果你把服务部署到 K8s,却只启了 stdio,那外部根本没入口。
- 本地验证:用
server.WithStdIO()启动,然后手动 echo 一条 JSON-RPC 调用到进程 stdin,看 stdout 是否返回结果 - HTTP 部署:必须加
server.WithHTTPPort(8080)和server.WithHTTPPath("/mcp"),路径必须是/mcp(多数客户端硬编码) - 不要同时启用
WithStdIO()和WithHTTPPort()——mcp-go不支持多 transport 共存,会 panic
真正难的不是写完第一个工具,而是让每个参数的 jsonschema 描述足够精确、让 handler 能处理 nil / "" / 0 这些边界值、以及确认客户端到底走的是哪条 transport 路径——这些细节不会报错,但会让整个调用链静默失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











