|
11 | 11 |
|
12 | 12 | ## Prompts |
13 | 13 |
|
14 | | -**Server-side**: |
15 | | -MCP servers can provide LLM prompt templates (called simply _prompts_) to clients. |
16 | | -Every prompt has a required name which identifies it, and a set of named arguments, which are strings. |
17 | | -Construct a prompt with a name and descriptions of its arguments. |
18 | | -Associated with each prompt is a handler that expands the template given values for its arguments. |
19 | | -Use [`Server.AddPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddPrompt) |
20 | | -to add a prompt along with its handler. |
21 | | -If `AddPrompt` is called before a server is connected, the server will have the `prompts` capability. |
22 | | -If all prompts are to be added after connection, set [`ServerOptions.HasPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts) |
23 | | -to advertise the capability. |
24 | | - |
25 | | -**Client-side**: |
26 | | -To list the server's prompts, call |
27 | | -Call [`ClientSession.Prompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Prompts) to get an iterator. |
28 | | -If needed, you can use the lower-level |
29 | | -[`ClientSession.ListPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListPrompts) to list the server's prompts. |
30 | | -Call [`ClientSession.GetPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.GetPrompt) to retrieve a prompt by name, providing |
31 | | -arguments for expansion. |
32 | | -Set [`ClientOptions.PromptListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.PromptListChangedHandler) to be notified of changes in the list of prompts. |
| 14 | +MCP servers can provide LLM prompt templates (called simply |
| 15 | +[_prompts_](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts)) |
| 16 | +to clients. Every prompt has a required name which identifies it, and a set of |
| 17 | +named arguments, which are strings. |
| 18 | + |
| 19 | +**Client-side**: To list the server's prompts, use the |
| 20 | +[`ClientSession.Prompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Prompts) |
| 21 | +iterator, or the lower-level |
| 22 | +[`ClientSession.ListPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListPrompts) |
| 23 | +(see [pagination](#pagination) below). Set |
| 24 | +[`ClientOptions.PromptListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.PromptListChangedHandler) |
| 25 | +to be notified of changes in the list of prompts. |
| 26 | + |
| 27 | +Call |
| 28 | +[`ClientSession.GetPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.GetPrompt) |
| 29 | +to retrieve a prompt by name, providing arguments for expansion. |
| 30 | + |
| 31 | +**Server-side**: Use |
| 32 | +[`Server.AddPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddPrompt) |
| 33 | +to add a prompt to the server along with its handler. |
| 34 | +The server will have the `prompts` capability if any prompt is added before the |
| 35 | +server is connected to a client, or if |
| 36 | +[`ServerOptions.HasPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts) |
| 37 | +is explicitly set. When a prompt is added, any clients already connected to the |
| 38 | +server will be notified via a `notifications/prompts/list_changed` |
| 39 | +notification. |
33 | 40 |
|
34 | 41 | ```go |
35 | 42 | func Example_prompts() { |
@@ -73,6 +80,7 @@ func Example_prompts() { |
73 | 80 | if err != nil { |
74 | 81 | log.Fatal(err) |
75 | 82 | } |
| 83 | + defer cs.Close() |
76 | 84 |
|
77 | 85 | // List the prompts. |
78 | 86 | for p, err := range cs.Prompts(ctx, nil) { |
@@ -105,7 +113,170 @@ func Example_prompts() { |
105 | 113 |
|
106 | 114 | ## Tools |
107 | 115 |
|
108 | | -<!-- TODO --> |
| 116 | +MCP servers can provide |
| 117 | +[tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) |
| 118 | +to allow clients to interact with external systems or functionality. Tools are |
| 119 | +effectively remote function calls, and the Go SDK provides mechanisms to bind |
| 120 | +them to ordinary Go functions. |
| 121 | + |
| 122 | +**Client-side**: To list the server's tools, use the |
| 123 | +[`ClientSession.Tools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Tools) |
| 124 | +iterator, or the lower-level |
| 125 | +[`ClientSession.ListTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListTools) |
| 126 | +(see [pagination](#pagination)). Set |
| 127 | +[`ClientOptions.ToolListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ToolListChangedHandler) |
| 128 | +to be notified of changes in the list of tools. |
| 129 | + |
| 130 | +To call a tool, use |
| 131 | +[`ClientSession.CallTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.CallTool) |
| 132 | +with `CallToolParams` holding the name and arguments of the tool to call. |
| 133 | + |
| 134 | +```go |
| 135 | +res, err := session.CallTool(ctx, &mcp.CallToolParams{ |
| 136 | + Name: "my_tool", |
| 137 | + Arguments: map[string]any{"name": "user"}, |
| 138 | +}) |
| 139 | +``` |
| 140 | + |
| 141 | +Arguments may be any value that can be marshaled to JSON. |
| 142 | + |
| 143 | +**Server-side**: the basic API for adding a tool is symmetrical with the API |
| 144 | +for prompts or resources: |
| 145 | +[`Server.AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddTool) |
| 146 | +adds a |
| 147 | +[`Tool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Tool) to |
| 148 | +the server along with its |
| 149 | +[`ToolHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ToolHandler) |
| 150 | +to handle it. The server will have the `tools` capability if any tool is added |
| 151 | +before the server is connected to a client, or if |
| 152 | +[`ServerOptions.HasTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts) |
| 153 | +is explicitly set. When a tool is added, any clients already connected to the |
| 154 | +server will be notified via a `notifications/tools/list_changed` notification. |
| 155 | + |
| 156 | +However, the `Server.AddTool` API leaves it to the user to implement the tool |
| 157 | +handler correctly according to the spec, providing very little out of the box. |
| 158 | +In order to implement a tool, the user must do all of the following: |
| 159 | + |
| 160 | +- Provide a tool input and output schema. |
| 161 | +- Validate the tool arguments against its input schema. |
| 162 | +- Unmarshal the input schema into a Go value |
| 163 | +- Execute the tool logic. |
| 164 | +- Marshal the tool's structured output (if any) to JSON, and store it in the |
| 165 | + result's `StructuredOutput` field as well as the unstructured `Content` field. |
| 166 | +- Validate that output JSON against the tool's output schema. |
| 167 | +- If any tool errors occurred, pack them into the unstructured content and set |
| 168 | + `IsError` to `true.` |
| 169 | + |
| 170 | +For this reason, the SDK provides a generic |
| 171 | +[`AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#AddTool) |
| 172 | +function that handles this for you. It can bind a tool to any function with the |
| 173 | +following shape: |
| 174 | + |
| 175 | +```go |
| 176 | +func(_ context.Context, request *CallToolRequest, input In) (result *CallToolResult, output Out, _ error) |
| 177 | +``` |
| 178 | + |
| 179 | +This is like a `ToolHandler`, but with an extra arbitrary `In` input parameter, |
| 180 | +and `Out` output parameter. |
| 181 | + |
| 182 | +Such a function can then be bound to the server using `AddTool`: |
| 183 | + |
| 184 | +```go |
| 185 | +mcp.AddTool(server, &mcp.Tool{Name: "my_tool"}, handler) |
| 186 | +``` |
| 187 | + |
| 188 | +This does the following automatically: |
| 189 | + |
| 190 | +- If `Tool.InputSchema` or `Tool.OutputSchema` are unset, the input and output |
| 191 | + schemas are inferred from the `In` type, which must be a struct or map. |
| 192 | + Optional `jsonschema` struct tags provide argument descriptions. |
| 193 | +- Tool arguments are validated against the input schema. |
| 194 | +- Tool arguments are marshaled into the `In` value. |
| 195 | +- Tool output (the `Out` value) is marshaled into the result's |
| 196 | + `StructuredOutput`, as well as the unstructured `Content`. |
| 197 | +- Output is validated against the tool's output schema. |
| 198 | +- If an ordinary error is returned, it is stored int the `CallToolResult` and |
| 199 | + `IsError` is set to `true`. |
| 200 | + |
| 201 | +In fact, under ordinary circumstances, the user can ignore `CallToolRequest` |
| 202 | +and `CallToolResult`. |
| 203 | + |
| 204 | +For a more realistic example, consider a tool that retrieves the weather: |
| 205 | + |
| 206 | +```go |
| 207 | +type WeatherInput struct { |
| 208 | + Location Location `json:"location" jsonschema:"user location"` |
| 209 | + Days int `json:"days" jsonschema:"number of days to forecast"` |
| 210 | +} |
| 211 | + |
| 212 | +type WeatherOutput struct { |
| 213 | + Summary string `json:"summary" jsonschema:"a summary of the weather forecast"` |
| 214 | + Confidence Probability `json:"confidence" jsonschema:"confidence, between 0 and 1"` |
| 215 | + AsOf time.Time `json:"asOf" jsonschema:"the time the weather was computed"` |
| 216 | + DailyForecast []Forecast `json:"dailyForecast" jsonschema:"the daily forecast"` |
| 217 | + Source string `json:"source,omitempty" jsonschema:"the organization providing the weather forecast"` |
| 218 | +} |
| 219 | + |
| 220 | +func WeatherTool(ctx context.Context, req *mcp.CallToolRequest, in WeatherInput) (*mcp.CallToolResult, WeatherOutput, error) { |
| 221 | + perfectWeather := WeatherOutput{ |
| 222 | + Summary: "perfect", |
| 223 | + Confidence: 1.0, |
| 224 | + AsOf: time.Now(), |
| 225 | + } |
| 226 | + for range in.Days { |
| 227 | + perfectWeather.DailyForecast = append(perfectWeather.DailyForecast, Forecast{ |
| 228 | + Forecast: "another perfect day", |
| 229 | + Type: Sunny, |
| 230 | + Rain: 0.0, |
| 231 | + High: 72.0, |
| 232 | + Low: 72.0, |
| 233 | + }) |
| 234 | + } |
| 235 | + return nil, perfectWeather, nil |
| 236 | +} |
| 237 | +``` |
| 238 | + |
| 239 | +In this case, we want to customize part of the inferred schema, though we can |
| 240 | +still infer the rest. Since we want to control the inference ourselves, we set |
| 241 | +the `Tool.InputSchema` explicitly: |
| 242 | + |
| 243 | +```go |
| 244 | +// Distinguished Go types allow custom schemas to be reused during inference. |
| 245 | +customSchemas := map[any]*jsonschema.Schema{ |
| 246 | + Probability(0): {Type: "number", Minimum: jsonschema.Ptr(0.0), Maximum: jsonschema.Ptr(1.0)}, |
| 247 | + WeatherType(""): {Type: "string", Enum: []any{Sunny, PartlyCloudy, Cloudy, Rainy, Snowy}}, |
| 248 | +} |
| 249 | +opts := &jsonschema.ForOptions{TypeSchemas: customSchemas} |
| 250 | +in, err := jsonschema.For[WeatherInput](opts) |
| 251 | +if err != nil { |
| 252 | + log.Fatal(err) |
| 253 | +} |
| 254 | + |
| 255 | +// Furthermore, we can tweak the inferred schema, in this case limiting |
| 256 | +// forecasts to 0-10 days. |
| 257 | +daysSchema := in.Properties["days"] |
| 258 | +daysSchema.Minimum = jsonschema.Ptr(0.0) |
| 259 | +daysSchema.Maximum = jsonschema.Ptr(10.0) |
| 260 | + |
| 261 | +// Output schema inference can reuse our custom schemas from input inference. |
| 262 | +out, err := jsonschema.For[WeatherOutput](opts) |
| 263 | +if err != nil { |
| 264 | + log.Fatal(err) |
| 265 | +} |
| 266 | + |
| 267 | +// Now add our tool to a server. Since we've customized the schemas, we need |
| 268 | +// to override the default schema inference. |
| 269 | +server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil) |
| 270 | +mcp.AddTool(server, &mcp.Tool{ |
| 271 | + Name: "weather", |
| 272 | + InputSchema: in, |
| 273 | + OutputSchema: out, |
| 274 | +}, WeatherTool) |
| 275 | +``` |
| 276 | + |
| 277 | +_See [mcp/tool_example_test.go](../mcp/tool_example_test.go) for the full |
| 278 | +example, or [examples/server/toolschemas](examples/server/toolschemas/main.go) |
| 279 | +for more examples of customizing tool schemas._ |
109 | 280 |
|
110 | 281 | ## Utilities |
111 | 282 |
|
|
0 commit comments