golang mcp 服务端指南

工具签名

本文是知识卡。想知道 In / Out 两个泛型参数到底换来了什么,看这张表。

签名长什么样

func(_ context.Context, request *CallToolRequest, input In) (result *CallToolResult, output Out, _ error)

In 和 Out 是泛型参数。写工具时可以只关心 input → output / error 这条线,request 和 result 直接传 nil。

In / Out 不是摆设

框架在背后做了这些事:

行为 触发条件 说明
生成默认 input schema 总是 用 In 的类型推断;想自定义,在 mcp.Tool.InputSchema 里显式传一个覆盖
自动反序列化入参 总是 把客户端传来的 arguments 填进 input,不用自己 json.Unmarshal
调用前校验参数 总是 不合法直接在协议层拒掉(InvalidParams),不用在业务代码里写校验
生成默认 output schema Out 不是 any 时 成功路径下,结构化输出写进结果的 StructuredOutput
自动补内容 没设置 result.Content 时 用输出 JSON 填上,方便「只关心返回一个 JSON 对象」的用法
把 error 当业务错误 返回非 nil error 时 SDK 把描述塞进 content 并把 IsError 置为 true,符合 MCP 对工具调用失败的建模

什么时候才需要碰 request 和 result

只有这三种情况:

  • 要读原始请求元数据(比如客户端的 _meta 字段)
  • 要自定义返回的 content(比如返回图片、多段内容)
  • 要精细控制结果的各个字段

其余时候让 SDK 补全就行。错误类型的选择见错误返回与重试。

参数是怎么从 In 推出来的

结构体里写的 变成 schema 的
字段名 + json 标签 属性名
Go 字段类型 属性类型(string / array / integer …)
jsonschema 标签 属性的 description,模型能读到
没有 omitempty 进 required 列表
有 omitempty 可选

枚举、默认值、最小值这些推断不出来的约束,靠 mcp.Tool.InputSchema 覆盖。完整做法见工具的参数。

mcp.Tool 的字段

字段 用途
Name 工具名称,客户端靠它发起调用
Description 给人看,也给模型看——模型靠它决定什么时候调用
InputSchema JSON Schema;不填时由 In 类型推断
OutputSchema 输出结构;Out 不是 any 时自动推断
Title / Icons / Annotations 展示与补充信息,进阶场景

完整定义见 pkg.go.dev。