|
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() { |
@@ -102,11 +109,296 @@ func Example_prompts() { |
102 | 109 |
|
103 | 110 | ## Resources |
104 | 111 |
|
105 | | -<!-- TODO --> |
| 112 | +In MCP terms, a _resource_ is some data referenced by a URI. |
| 113 | +MCP servers can serve resources to clients. |
| 114 | +They can register resources individually, or register a _resource template_ |
| 115 | +that uses a URI pattern to describe a collection of resources. |
| 116 | + |
| 117 | + |
| 118 | +**Client-side**: |
| 119 | +Call [`ClientSession.ReadResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ReadResource) |
| 120 | +to read a resource. |
| 121 | +The SDK ensures that a read succeeds only if the URI matches a registered resource exactly, |
| 122 | +or matches the URI pattern of a resource template. |
| 123 | + |
| 124 | +To list a server's resources and resource templates, use the |
| 125 | +[`ClientSession.Resources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Resources) |
| 126 | +and |
| 127 | +[`ClientSession.ResourceTemplates`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ResourceTemplates) |
| 128 | +iterators, or the lower-level `ListXXX` calls (see [pagination](#pagination)). |
| 129 | +Set |
| 130 | +[`ClientOptions.ResourceListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceListChangedHandler) |
| 131 | +to be notified of changes in the lists of resources or resource templates. |
| 132 | + |
| 133 | +Clients can be notified when the contents of a resource changes by subscribing to the resource's URI. |
| 134 | +Call |
| 135 | +[`ClientSession.Subscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Subscribe) |
| 136 | +to subscribe to a resource |
| 137 | +and |
| 138 | +[`ClientSession.Unsubscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Unsubscribe) |
| 139 | +to unsubscribe. |
| 140 | +Set |
| 141 | +[`ClientOptions.ResourceUpdatedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceUpdatedHandler) |
| 142 | +to be notified of changes to subscribed resources. |
| 143 | + |
| 144 | +**Server-side**: |
| 145 | +Use |
| 146 | +[`Server.AddResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResource) |
| 147 | +or |
| 148 | +[`Server.AddResourceTemplate`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResourceTemplate) |
| 149 | +to add a resource or resource template to the server along with its handler. |
| 150 | +A |
| 151 | +[`ResourceHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ResourceHandler) |
| 152 | +maps a URI to the contents of a resource, which can include text, binary data, |
| 153 | +or both. |
| 154 | +If `AddResource` or `AddResourceTemplate` is called before a server is connected, the server will have the |
| 155 | +`resources` capability. |
| 156 | +The server will have the `resources` capability if any resource or resource template is added before the |
| 157 | +server is connected to a client, or if |
| 158 | +[`ServerOptions.HasResources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasResources) |
| 159 | +is explicitly set. When a prompt is added, any clients already connected to the |
| 160 | +server will be notified via a `notifications/resources/list_changed` |
| 161 | +notification. |
| 162 | + |
| 163 | + |
| 164 | +```go |
| 165 | +func Example_resources() { |
| 166 | + ctx := context.Background() |
| 167 | + |
| 168 | + resources := map[string]string{ |
| 169 | + "file:///a": "a", |
| 170 | + "file:///dir/x": "x", |
| 171 | + "file:///dir/y": "y", |
| 172 | + } |
| 173 | + |
| 174 | + handler := func(_ context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) { |
| 175 | + uri := req.Params.URI |
| 176 | + c, ok := resources[uri] |
| 177 | + if !ok { |
| 178 | + return nil, mcp.ResourceNotFoundError(uri) |
| 179 | + } |
| 180 | + return &mcp.ReadResourceResult{ |
| 181 | + Contents: []*mcp.ResourceContents{{URI: uri, Text: c}}, |
| 182 | + }, nil |
| 183 | + } |
| 184 | + |
| 185 | + // Create a server with a single resource. |
| 186 | + s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil) |
| 187 | + s.AddResource(&mcp.Resource{URI: "file:///a"}, handler) |
| 188 | + s.AddResourceTemplate(&mcp.ResourceTemplate{URITemplate: "file:///dir/{f}"}, handler) |
| 189 | + |
| 190 | + // Create a client. |
| 191 | + c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil) |
| 192 | + |
| 193 | + // Connect the server and client. |
| 194 | + t1, t2 := mcp.NewInMemoryTransports() |
| 195 | + if _, err := s.Connect(ctx, t1, nil); err != nil { |
| 196 | + log.Fatal(err) |
| 197 | + } |
| 198 | + cs, err := c.Connect(ctx, t2, nil) |
| 199 | + if err != nil { |
| 200 | + log.Fatal(err) |
| 201 | + } |
| 202 | + defer cs.Close() |
| 203 | + |
| 204 | + // List resources and resource templates. |
| 205 | + for r, err := range cs.Resources(ctx, nil) { |
| 206 | + if err != nil { |
| 207 | + log.Fatal(err) |
| 208 | + } |
| 209 | + fmt.Println(r.URI) |
| 210 | + } |
| 211 | + for r, err := range cs.ResourceTemplates(ctx, nil) { |
| 212 | + if err != nil { |
| 213 | + log.Fatal(err) |
| 214 | + } |
| 215 | + fmt.Println(r.URITemplate) |
| 216 | + } |
| 217 | + |
| 218 | + // Read resources. |
| 219 | + for _, path := range []string{"a", "dir/x", "b"} { |
| 220 | + res, err := cs.ReadResource(ctx, &mcp.ReadResourceParams{URI: "file:///" + path}) |
| 221 | + if err != nil { |
| 222 | + fmt.Println(err) |
| 223 | + } else { |
| 224 | + fmt.Println(res.Contents[0].Text) |
| 225 | + } |
| 226 | + } |
| 227 | + // Output: |
| 228 | + // file:///a |
| 229 | + // file:///dir/{f} |
| 230 | + // a |
| 231 | + // x |
| 232 | + // calling "resources/read": Resource not found |
| 233 | +} |
| 234 | +``` |
106 | 235 |
|
107 | 236 | ## Tools |
108 | 237 |
|
109 | | -<!-- TODO --> |
| 238 | +MCP servers can provide |
| 239 | +[tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools) |
| 240 | +to allow clients to interact with external systems or functionality. Tools are |
| 241 | +effectively remote function calls, and the Go SDK provides mechanisms to bind |
| 242 | +them to ordinary Go functions. |
| 243 | + |
| 244 | +**Client-side**: To list the server's tools, use the |
| 245 | +[`ClientSession.Tools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Tools) |
| 246 | +iterator, or the lower-level |
| 247 | +[`ClientSession.ListTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListTools) |
| 248 | +(see [pagination](#pagination)). Set |
| 249 | +[`ClientOptions.ToolListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ToolListChangedHandler) |
| 250 | +to be notified of changes in the list of tools. |
| 251 | + |
| 252 | +To call a tool, use |
| 253 | +[`ClientSession.CallTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.CallTool) |
| 254 | +with `CallToolParams` holding the name and arguments of the tool to call. |
| 255 | + |
| 256 | +```go |
| 257 | +res, err := session.CallTool(ctx, &mcp.CallToolParams{ |
| 258 | + Name: "my_tool", |
| 259 | + Arguments: map[string]any{"name": "user"}, |
| 260 | +}) |
| 261 | +``` |
| 262 | + |
| 263 | +Arguments may be any value that can be marshaled to JSON. |
| 264 | + |
| 265 | +**Server-side**: the basic API for adding a tool is symmetrical with the API |
| 266 | +for prompts or resources: |
| 267 | +[`Server.AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddTool) |
| 268 | +adds a |
| 269 | +[`Tool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Tool) to |
| 270 | +the server along with its |
| 271 | +[`ToolHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ToolHandler) |
| 272 | +to handle it. The server will have the `tools` capability if any tool is added |
| 273 | +before the server is connected to a client, or if |
| 274 | +[`ServerOptions.HasTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts) |
| 275 | +is explicitly set. When a tool is added, any clients already connected to the |
| 276 | +server will be notified via a `notifications/tools/list_changed` notification. |
| 277 | + |
| 278 | +However, the `Server.AddTool` API leaves it to the user to implement the tool |
| 279 | +handler correctly according to the spec, providing very little out of the box. |
| 280 | +In order to implement a tool, the user must do all of the following: |
| 281 | + |
| 282 | +- Provide a tool input and output schema. |
| 283 | +- Validate the tool arguments against its input schema. |
| 284 | +- Unmarshal the input schema into a Go value |
| 285 | +- Execute the tool logic. |
| 286 | +- Marshal the tool's structured output (if any) to JSON, and store it in the |
| 287 | + result's `StructuredOutput` field as well as the unstructured `Content` field. |
| 288 | +- Validate that output JSON against the tool's output schema. |
| 289 | +- If any tool errors occurred, pack them into the unstructured content and set |
| 290 | + `IsError` to `true.` |
| 291 | + |
| 292 | +For this reason, the SDK provides a generic |
| 293 | +[`AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#AddTool) |
| 294 | +function that handles this for you. It can bind a tool to any function with the |
| 295 | +following shape: |
| 296 | + |
| 297 | +```go |
| 298 | +func(_ context.Context, request *CallToolRequest, input In) (result *CallToolResult, output Out, _ error) |
| 299 | +``` |
| 300 | + |
| 301 | +This is like a `ToolHandler`, but with an extra arbitrary `In` input parameter, |
| 302 | +and `Out` output parameter. |
| 303 | + |
| 304 | +Such a function can then be bound to the server using `AddTool`: |
| 305 | + |
| 306 | +```go |
| 307 | +mcp.AddTool(server, &mcp.Tool{Name: "my_tool"}, handler) |
| 308 | +``` |
| 309 | + |
| 310 | +This does the following automatically: |
| 311 | + |
| 312 | +- If `Tool.InputSchema` or `Tool.OutputSchema` are unset, the input and output |
| 313 | + schemas are inferred from the `In` type, which must be a struct or map. |
| 314 | + Optional `jsonschema` struct tags provide argument descriptions. |
| 315 | +- Tool arguments are validated against the input schema. |
| 316 | +- Tool arguments are marshaled into the `In` value. |
| 317 | +- Tool output (the `Out` value) is marshaled into the result's |
| 318 | + `StructuredOutput`, as well as the unstructured `Content`. |
| 319 | +- Output is validated against the tool's output schema. |
| 320 | +- If an ordinary error is returned, it is stored int the `CallToolResult` and |
| 321 | + `IsError` is set to `true`. |
| 322 | + |
| 323 | +In fact, under ordinary circumstances, the user can ignore `CallToolRequest` |
| 324 | +and `CallToolResult`. |
| 325 | + |
| 326 | +For a more realistic example, consider a tool that retrieves the weather: |
| 327 | + |
| 328 | +```go |
| 329 | +type WeatherInput struct { |
| 330 | + Location Location `json:"location" jsonschema:"user location"` |
| 331 | + Days int `json:"days" jsonschema:"number of days to forecast"` |
| 332 | +} |
| 333 | + |
| 334 | +type WeatherOutput struct { |
| 335 | + Summary string `json:"summary" jsonschema:"a summary of the weather forecast"` |
| 336 | + Confidence Probability `json:"confidence" jsonschema:"confidence, between 0 and 1"` |
| 337 | + AsOf time.Time `json:"asOf" jsonschema:"the time the weather was computed"` |
| 338 | + DailyForecast []Forecast `json:"dailyForecast" jsonschema:"the daily forecast"` |
| 339 | + Source string `json:"source,omitempty" jsonschema:"the organization providing the weather forecast"` |
| 340 | +} |
| 341 | + |
| 342 | +func WeatherTool(ctx context.Context, req *mcp.CallToolRequest, in WeatherInput) (*mcp.CallToolResult, WeatherOutput, error) { |
| 343 | + perfectWeather := WeatherOutput{ |
| 344 | + Summary: "perfect", |
| 345 | + Confidence: 1.0, |
| 346 | + AsOf: time.Now(), |
| 347 | + } |
| 348 | + for range in.Days { |
| 349 | + perfectWeather.DailyForecast = append(perfectWeather.DailyForecast, Forecast{ |
| 350 | + Forecast: "another perfect day", |
| 351 | + Type: Sunny, |
| 352 | + Rain: 0.0, |
| 353 | + High: 72.0, |
| 354 | + Low: 72.0, |
| 355 | + }) |
| 356 | + } |
| 357 | + return nil, perfectWeather, nil |
| 358 | +} |
| 359 | +``` |
| 360 | + |
| 361 | +In this case, we want to customize part of the inferred schema, though we can |
| 362 | +still infer the rest. Since we want to control the inference ourselves, we set |
| 363 | +the `Tool.InputSchema` explicitly: |
| 364 | + |
| 365 | +```go |
| 366 | +// Distinguished Go types allow custom schemas to be reused during inference. |
| 367 | +customSchemas := map[any]*jsonschema.Schema{ |
| 368 | + Probability(0): {Type: "number", Minimum: jsonschema.Ptr(0.0), Maximum: jsonschema.Ptr(1.0)}, |
| 369 | + WeatherType(""): {Type: "string", Enum: []any{Sunny, PartlyCloudy, Cloudy, Rainy, Snowy}}, |
| 370 | +} |
| 371 | +opts := &jsonschema.ForOptions{TypeSchemas: customSchemas} |
| 372 | +in, err := jsonschema.For[WeatherInput](opts) |
| 373 | +if err != nil { |
| 374 | + log.Fatal(err) |
| 375 | +} |
| 376 | + |
| 377 | +// Furthermore, we can tweak the inferred schema, in this case limiting |
| 378 | +// forecasts to 0-10 days. |
| 379 | +daysSchema := in.Properties["days"] |
| 380 | +daysSchema.Minimum = jsonschema.Ptr(0.0) |
| 381 | +daysSchema.Maximum = jsonschema.Ptr(10.0) |
| 382 | + |
| 383 | +// Output schema inference can reuse our custom schemas from input inference. |
| 384 | +out, err := jsonschema.For[WeatherOutput](opts) |
| 385 | +if err != nil { |
| 386 | + log.Fatal(err) |
| 387 | +} |
| 388 | + |
| 389 | +// Now add our tool to a server. Since we've customized the schemas, we need |
| 390 | +// to override the default schema inference. |
| 391 | +server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil) |
| 392 | +mcp.AddTool(server, &mcp.Tool{ |
| 393 | + Name: "weather", |
| 394 | + InputSchema: in, |
| 395 | + OutputSchema: out, |
| 396 | +}, WeatherTool) |
| 397 | +``` |
| 398 | + |
| 399 | +_See [mcp/tool_example_test.go](../mcp/tool_example_test.go) for the full |
| 400 | +example, or [examples/server/toolschemas](examples/server/toolschemas/main.go) |
| 401 | +for more examples of customizing tool schemas._ |
110 | 402 |
|
111 | 403 | ## Utilities |
112 | 404 |
|
|
0 commit comments