Skip to content

Commit 1b65d0b

Browse files
committed
merge
2 parents fd9d5b9 + 8b6391b commit 1b65d0b

File tree

8 files changed

+608
-54
lines changed

8 files changed

+608
-54
lines changed

docs/protocol.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ If [`RequireBearerTokenOptions.ResourceMetadataURL`](https://pkg.go.dev/github.c
254254
the middleware function sets the WWW-Authenticate header as required by the [Protected Resource
255255
Metadata spec](https://datatracker.ietf.org/doc/html/rfc9728).
256256

257+
Server handlers, such as tool handlers, can obtain the `TokenInfo` returned by the `TokenVerifier`
258+
from `req.Extra.TokenInfo`, where `req` is the handler's request. (For example, a
259+
[`CallToolRequest`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CallToolRequest).)
260+
HTTP handlers wrapped by the `RequireBearerToken` middleware can obtain the `TokenInfo` from the context
261+
with [`auth.TokenInfoFromContext`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenInfoFromContext).
262+
263+
257264
The [_auth middleware example_](https://github.com/modelcontextprotocol/go-sdk/tree/main/examples/server/auth-middleware) shows how to implement authorization for both JWT tokens and API keys.
258265

259266
### Client

docs/server.md

Lines changed: 313 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,32 @@
1111

1212
## Prompts
1313

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.
3340

3441
```go
3542
func Example_prompts() {
@@ -102,11 +109,296 @@ func Example_prompts() {
102109

103110
## Resources
104111

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+
```
106235

107236
## Tools
108237

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._
110402

111403
## Utilities
112404

internal/docs/protocol.src.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,13 @@ If [`RequireBearerTokenOptions.ResourceMetadataURL`](https://pkg.go.dev/github.c
181181
the middleware function sets the WWW-Authenticate header as required by the [Protected Resource
182182
Metadata spec](https://datatracker.ietf.org/doc/html/rfc9728).
183183

184+
Server handlers, such as tool handlers, can obtain the `TokenInfo` returned by the `TokenVerifier`
185+
from `req.Extra.TokenInfo`, where `req` is the handler's request. (For example, a
186+
[`CallToolRequest`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CallToolRequest).)
187+
HTTP handlers wrapped by the `RequireBearerToken` middleware can obtain the `TokenInfo` from the context
188+
with [`auth.TokenInfoFromContext`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/auth#TokenInfoFromContext).
189+
190+
184191
The [_auth middleware example_](https://github.com/modelcontextprotocol/go-sdk/tree/main/examples/server/auth-middleware) shows how to implement authorization for both JWT tokens and API keys.
185192

186193
### Client

0 commit comments

Comments
 (0)