Skip to content

Commit 8ab19ea

Browse files
committed
internal/mcp: describe standard rpc signature
Mention that all methods from the spec have the same signature, and then don't repeat those method declarations. Modify all method calls in the doc to take a Params struct, even if the current MCP spec says it is empty. Change `string` to `[]byte` in some of the listed struct fields. The current code generator incorrectly generates these as strings. (I have a forthcoming CL to fix that.) Also, elaborate the logging design. Change-Id: I5f323d4d98a4b6045d3cdef770d13b4bfdcb1044 Reviewed-on: https://go-review.googlesource.com/c/tools/+/671358 Reviewed-by: Sam Thanawalla <[email protected]> Reviewed-by: Robert Findley <[email protected]> TryBot-Bypass: Jonathan Amsterdam <[email protected]>
1 parent 4d1336a commit 8ab19ea

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

internal/mcp/design/design.md

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ type Content struct {
347347
Type string `json:"type"`
348348
Text string `json:"text,omitempty"`
349349
MIMEType string `json:"mimeType,omitempty"`
350-
Data string `json:"data,omitempty"`
350+
Data []byte `json:"data,omitempty"`
351351
Resource *Resource `json:"resource,omitempty"`
352352
}
353353

@@ -359,7 +359,7 @@ type Resource struct {
359359
URI string `json:"uri,"`
360360
MIMEType string `json:"mimeType,omitempty"`
361361
Text string `json:"text"`
362-
Blob *string `json:"blob"`
362+
Blob []byte `json:"blob"`
363363
}
364364
```
365365
@@ -438,12 +438,14 @@ transport := mcp.NewCommandTransport(exec.Command("myserver"))
438438
session, err := client.Connect(ctx, transport)
439439
if err != nil { ... }
440440
// Call a tool on the server.
441-
content, err := session.CallTool(ctx, "greet", map[string]any{"name": "you"})
441+
content, err := session.CallTool(ctx, &CallToolParams{
442+
Name: "greet",
443+
Arguments: map[string]any{"name": "you"} ,
444+
})
442445
...
443446
return session.Close()
444447
```
445-
446-
And here's an example from the server side:
448+
A server that can handle that client call would look like this:
447449
448450
```go
449451
// Create a server with a single tool.
@@ -463,6 +465,8 @@ session until the client disconnects:
463465
func (*Server) Run(context.Context, Transport)
464466
```
465467
468+
469+
466470
**Differences from mcp-go**: the Server APIs are very similar to mcp-go,
467471
though the association between servers and transports is different. In
468472
mcp-go, a single server is bound to what we would call an `SSEHTTPHandler`,
@@ -484,6 +488,24 @@ behavior, whereas an options struct is used here. We felt that in this case, an
484488
options struct would be more readable, and result in cleaner package
485489
documentation.
486490
491+
### Spec Methods
492+
493+
As we saw above, the `ClientSession` method for the specification's
494+
`CallTool` RPC takes a context and a params pointer as arguments, and returns a
495+
result pointer and error:
496+
```go
497+
func (*ClientSession) CallTool(context.Context, *CallToolParams) (*CallToolResult, error)
498+
```
499+
Our SDK has a method for every RPC in the spec, and their signatures all share
500+
this form. To avoid boilerplate, we don't repeat this signature for RPCs
501+
defined in the spec; readers may assume it when we mention a "spec method."
502+
503+
Why do we use params instead of the full request? JSON-RPC requests consist of a method
504+
name and a set of parameters, and the method is already encoded in the Go method name.
505+
Technically, the MCP spec could add a field to a request while preserving backward
506+
compatibility, which would break the Go SDK's compatibility. But in the unlikely event
507+
that were to happen, we would add that field to the Params struct.
508+
487509
### Middleware
488510
489511
We provide a mechanism to add MCP-level middleware, which runs after the
@@ -589,8 +611,8 @@ Both `ClientSession` and `ServerSession` expose a `Ping` method to call "ping"
589611
on their peer.
590612
591613
```go
592-
func (c *ClientSession) Ping(ctx context.Context) error
593-
func (c *ServerSession) Ping(ctx context.Context) error
614+
func (c *ClientSession) Ping(ctx context.Context, *PingParams) error
615+
func (c *ServerSession) Ping(ctx context.Context, *PingParams) error
594616
```
595617
596618
Additionally, client and server sessions can be configured with automatic
@@ -634,14 +656,12 @@ func (*Client) AddRoots(roots ...Root)
634656
func (*Client) RemoveRoots(uris ...string)
635657
```
636658
637-
Servers can call `ListRoots` to get the roots. If a server installs a
659+
Servers can call the spec method `ListRoots` to get the roots. If a server installs a
638660
`RootsChangedHandler`, it will be called when the client sends a roots-changed
639661
notification, which happens whenever the list of roots changes after a
640662
connection has been established.
641663
642664
```go
643-
func (*Server) ListRoots(context.Context, *ListRootsParams) (*ListRootsResult, error)
644-
645665
type ServerOptions {
646666
...
647667
// If non-nil, called when a client sends a roots-changed notification.
@@ -652,15 +672,13 @@ type ServerOptions {
652672
### Sampling
653673
654674
Clients that support sampling are created with a `CreateMessageHandler` option
655-
for handling server calls. To perform sampling, a server calls `CreateMessage`.
675+
for handling server calls. To perform sampling, a server calls the spec method `CreateMessage`.
656676
657677
```go
658678
type ClientOptions struct {
659679
...
660680
CreateMessageHandler func(context.Context, *ClientSession, *CreateMessageParams) (*CreateMessageResult, error)
661681
}
662-
663-
func (*ServerSession) CreateMessage(context.Context, *CreateMessageParams) (*CreateMessageResult, error)
664682
```
665683
666684
## Server Features
@@ -839,12 +857,7 @@ server.AddPrompts(
839857
server.RemovePrompts("code_review")
840858
```
841859
842-
Clients can call `ListPrompts` to list the available prompts and `GetPrompt` to get one.
843-
844-
```go
845-
func (*ClientSession) ListPrompts(context.Context, *ListPromptParams) (*ListPromptsResult, error)
846-
func (*ClientSession) GetPrompt(context.Context, *GetPromptParams) (*GetPromptResult, error)
847-
```
860+
Clients can call the spec method `ListPrompts` to list the available prompts and the spec method `GetPrompt` to get one.
848861
849862
**Differences from mcp-go**: We provide a `NewPrompt` helper to bind a prompt
850863
handler to a Go function using reflection to derive its arguments. We provide
@@ -942,9 +955,9 @@ A client will receive these notifications if it was created with the correspondi
942955
```go
943956
type ClientOptions struct {
944957
...
945-
ToolListChangedHandler func(context.Context, *ClientConnection, *ToolListChangedParams)
946-
PromptListChangedHandler func(context.Context, *ClientConnection, *PromptListChangedParams)
947-
ResourceListChangedHandler func(context.Context, *ClientConnection, *ResourceListChangedParams)
958+
ToolListChangedHandler func(context.Context, *ClientSession, *ToolListChangedParams)
959+
PromptListChangedHandler func(context.Context, *ClientSession, *PromptListChangedParams)
960+
ResourceListChangedHandler func(context.Context, *ClientSession, *ResourceListChangedParams)
948961
}
949962
```
950963
@@ -954,12 +967,7 @@ feature-specific handlers here.
954967
955968
### Completion
956969
957-
Clients call `Complete` to request completions.
958-
959-
```go
960-
func (*ClientSession) Complete(context.Context, *CompleteParams) (*CompleteResult, error)
961-
```
962-
970+
Clients call the spec method `Complete` to request completions.
963971
Servers automatically handle these requests based on their collections of
964972
prompts and resources.
965973
@@ -968,23 +976,44 @@ defined its server-side behavior.
968976
969977
### Logging
970978
979+
Server-to-client logging is configured with `ServerOptions`:
980+
981+
```go
982+
type ServerOptions {
983+
...
984+
// The value for the "logger" field of the notification.
985+
LoggerName string
986+
// Log notifications to a single ClientSession will not be
987+
// send more frequently than this duration.
988+
LogInterval time.Duration
989+
}
990+
```
991+
971992
ServerSessions have access to a `slog.Logger` that writes to the client. A call to
972993
a log method like `Info`is translated to a `LoggingMessageNotification` as
973994
follows:
974995
975-
- An attribute with key "logger" is used to populate the "logger" field of the notification.
976-
977-
- The remaining attributes and the message populate the "data" field with the
996+
- The attributes and the message populate the "data" property with the
978997
output of a `slog.JSONHandler`: The result is always a JSON object, with the
979998
key "msg" for the message.
980999
1000+
- If the `LoggerName` server option is set, it populates the "logger" property.
1001+
9811002
- The standard slog levels `Info`, `Debug`, `Warn` and `Error` map to the
9821003
corresponding levels in the MCP spec. The other spec levels will be mapped
9831004
to integers between the slog levels. For example, "notice" is level 2 because
9841005
it is between "warning" (slog value 4) and "info" (slog value 0).
9851006
The `mcp` package defines consts for these levels. To log at the "notice"
9861007
level, a handler would call `session.Log(ctx, mcp.LevelNotice, "message")`.
9871008
1009+
A client that wishes to receive log messages must provide a handler:
1010+
```go
1011+
type ClientOptions struct {
1012+
...
1013+
LogMessageHandler func(context.Context, *ClientSession, *LoggingMessageParams)
1014+
}
1015+
```
1016+
9881017
### Pagination
9891018
9901019
<!-- TODO: needs design -->

0 commit comments

Comments
 (0)