Skip to content

Commit eea1130

Browse files
📝 Add docstrings to main
Docstrings generation was requested by @yuehaii. * #620 (comment) The following files were modified: * `client/client.go` * `client/transport/inprocess.go` * `examples/roots_client/main.go` * `examples/roots_http_client/main.go` * `examples/roots_http_server/main.go` * `examples/roots_server/main.go` * `server/inprocess_session.go` * `server/server.go` * `server/streamable_http.go`
1 parent 8b7d60c commit eea1130

File tree

9 files changed

+652
-26
lines changed

9 files changed

+652
-26
lines changed

client/client.go

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7-
"net/http"
87
"slices"
98
"sync"
109
"sync/atomic"
@@ -25,6 +24,7 @@ type Client struct {
2524
serverCapabilities mcp.ServerCapabilities
2625
protocolVersion string
2726
samplingHandler SamplingHandler
27+
rootsHandler RootsHandler
2828
elicitationHandler ElicitationHandler
2929
}
3030

@@ -38,15 +38,26 @@ func WithClientCapabilities(capabilities mcp.ClientCapabilities) ClientOption {
3838
}
3939

4040
// WithSamplingHandler sets the sampling handler for the client.
41-
// When set, the client will declare sampling capability during initialization.
41+
// WithSamplingHandler sets the SamplingHandler on the client and causes the client to declare sampling
42+
// capability during Initialize. The provided `handler` will be invoked for incoming sampling requests.
43+
// The returned ClientOption applies this handler to a Client.
4244
func WithSamplingHandler(handler SamplingHandler) ClientOption {
4345
return func(c *Client) {
4446
c.samplingHandler = handler
4547
}
4648
}
4749

50+
// WithRootsHandler sets the roots handler for the client.
51+
// WithRootsHandler returns a ClientOption that sets the client's RootsHandler.
52+
// When provided, the client will declare the roots capability (ListChanged) during initialization.
53+
func WithRootsHandler(handler RootsHandler) ClientOption {
54+
return func(c *Client) {
55+
c.rootsHandler = handler
56+
}
57+
}
58+
4859
// WithElicitationHandler sets the elicitation handler for the client.
49-
// When set, the client will declare elicitation capability during initialization.
60+
// to declare elicitation capability during initialization.
5061
func WithElicitationHandler(handler ElicitationHandler) ClientOption {
5162
return func(c *Client) {
5263
c.elicitationHandler = handler
@@ -141,7 +152,6 @@ func (c *Client) sendRequest(
141152
ctx context.Context,
142153
method string,
143154
params any,
144-
header http.Header,
145155
) (*json.RawMessage, error) {
146156
if !c.initialized && method != "initialize" {
147157
return nil, fmt.Errorf("client not initialized")
@@ -154,7 +164,6 @@ func (c *Client) sendRequest(
154164
ID: mcp.NewRequestId(id),
155165
Method: method,
156166
Params: params,
157-
Header: header,
158167
}
159168

160169
response, err := c.transport.SendRequest(ctx, request)
@@ -180,6 +189,13 @@ func (c *Client) Initialize(
180189
if c.samplingHandler != nil {
181190
capabilities.Sampling = &struct{}{}
182191
}
192+
if c.rootsHandler != nil {
193+
capabilities.Roots = &struct {
194+
ListChanged bool `json:"listChanged,omitempty"`
195+
}{
196+
ListChanged: true,
197+
}
198+
}
183199
// Add elicitation capability if handler is configured
184200
if c.elicitationHandler != nil {
185201
capabilities.Elicitation = &struct{}{}
@@ -196,7 +212,7 @@ func (c *Client) Initialize(
196212
Capabilities: capabilities,
197213
}
198214

199-
response, err := c.sendRequest(ctx, "initialize", params, request.Header)
215+
response, err := c.sendRequest(ctx, "initialize", params)
200216
if err != nil {
201217
return nil, err
202218
}
@@ -241,7 +257,7 @@ func (c *Client) Initialize(
241257
}
242258

243259
func (c *Client) Ping(ctx context.Context) error {
244-
_, err := c.sendRequest(ctx, "ping", nil, nil)
260+
_, err := c.sendRequest(ctx, "ping", nil)
245261
return err
246262
}
247263

@@ -322,7 +338,7 @@ func (c *Client) ReadResource(
322338
ctx context.Context,
323339
request mcp.ReadResourceRequest,
324340
) (*mcp.ReadResourceResult, error) {
325-
response, err := c.sendRequest(ctx, "resources/read", request.Params, request.Header)
341+
response, err := c.sendRequest(ctx, "resources/read", request.Params)
326342
if err != nil {
327343
return nil, err
328344
}
@@ -334,15 +350,15 @@ func (c *Client) Subscribe(
334350
ctx context.Context,
335351
request mcp.SubscribeRequest,
336352
) error {
337-
_, err := c.sendRequest(ctx, "resources/subscribe", request.Params, request.Header)
353+
_, err := c.sendRequest(ctx, "resources/subscribe", request.Params)
338354
return err
339355
}
340356

341357
func (c *Client) Unsubscribe(
342358
ctx context.Context,
343359
request mcp.UnsubscribeRequest,
344360
) error {
345-
_, err := c.sendRequest(ctx, "resources/unsubscribe", request.Params, request.Header)
361+
_, err := c.sendRequest(ctx, "resources/unsubscribe", request.Params)
346362
return err
347363
}
348364

@@ -386,7 +402,7 @@ func (c *Client) GetPrompt(
386402
ctx context.Context,
387403
request mcp.GetPromptRequest,
388404
) (*mcp.GetPromptResult, error) {
389-
response, err := c.sendRequest(ctx, "prompts/get", request.Params, request.Header)
405+
response, err := c.sendRequest(ctx, "prompts/get", request.Params)
390406
if err != nil {
391407
return nil, err
392408
}
@@ -434,7 +450,7 @@ func (c *Client) CallTool(
434450
ctx context.Context,
435451
request mcp.CallToolRequest,
436452
) (*mcp.CallToolResult, error) {
437-
response, err := c.sendRequest(ctx, "tools/call", request.Params, request.Header)
453+
response, err := c.sendRequest(ctx, "tools/call", request.Params)
438454
if err != nil {
439455
return nil, err
440456
}
@@ -446,15 +462,15 @@ func (c *Client) SetLevel(
446462
ctx context.Context,
447463
request mcp.SetLevelRequest,
448464
) error {
449-
_, err := c.sendRequest(ctx, "logging/setLevel", request.Params, request.Header)
465+
_, err := c.sendRequest(ctx, "logging/setLevel", request.Params)
450466
return err
451467
}
452468

453469
func (c *Client) Complete(
454470
ctx context.Context,
455471
request mcp.CompleteRequest,
456472
) (*mcp.CompleteResult, error) {
457-
response, err := c.sendRequest(ctx, "completion/complete", request.Params, request.Header)
473+
response, err := c.sendRequest(ctx, "completion/complete", request.Params)
458474
if err != nil {
459475
return nil, err
460476
}
@@ -467,6 +483,27 @@ func (c *Client) Complete(
467483
return &result, nil
468484
}
469485

486+
func (c *Client) RootListChanges(
487+
ctx context.Context,
488+
) error {
489+
// Send root list changes notification
490+
notification := mcp.JSONRPCNotification{
491+
JSONRPC: mcp.JSONRPC_VERSION,
492+
Notification: mcp.Notification{
493+
Method: mcp.MethodNotificationToolsListChanged,
494+
},
495+
}
496+
497+
err := c.transport.SendNotification(ctx, notification)
498+
if err != nil {
499+
return fmt.Errorf(
500+
"failed to send root list change notification: %w",
501+
err,
502+
)
503+
}
504+
return nil
505+
}
506+
470507
// handleIncomingRequest processes incoming requests from the server.
471508
// This is the main entry point for server-to-client requests like sampling and elicitation.
472509
func (c *Client) handleIncomingRequest(ctx context.Context, request transport.JSONRPCRequest) (*transport.JSONRPCResponse, error) {
@@ -477,6 +514,8 @@ func (c *Client) handleIncomingRequest(ctx context.Context, request transport.JS
477514
return c.handleElicitationRequestTransport(ctx, request)
478515
case string(mcp.MethodPing):
479516
return c.handlePingRequestTransport(ctx, request)
517+
case string(mcp.MethodListRoots):
518+
return c.handleListRootsRequestTransport(ctx, request)
480519
default:
481520
return nil, fmt.Errorf("unsupported request method: %s", request.Method)
482521
}
@@ -539,6 +578,37 @@ func (c *Client) handleSamplingRequestTransport(ctx context.Context, request tra
539578
return response, nil
540579
}
541580

581+
// handleListRootsRequestTransport handles list roots requests at the transport level.
582+
func (c *Client) handleListRootsRequestTransport(ctx context.Context, request transport.JSONRPCRequest) (*transport.JSONRPCResponse, error) {
583+
if c.rootsHandler == nil {
584+
return nil, fmt.Errorf("no roots handler configured")
585+
}
586+
587+
// Create the MCP request
588+
mcpRequest := mcp.ListRootsRequest{
589+
Request: mcp.Request{
590+
Method: string(mcp.MethodListRoots),
591+
},
592+
}
593+
594+
// Call the list roots handler
595+
result, err := c.rootsHandler.ListRoots(ctx, mcpRequest)
596+
if err != nil {
597+
return nil, err
598+
}
599+
600+
// Marshal the result
601+
resultBytes, err := json.Marshal(result)
602+
if err != nil {
603+
return nil, fmt.Errorf("failed to marshal result: %w", err)
604+
}
605+
606+
// Create the transport response
607+
response := transport.NewJSONRPCResultResponse(request.ID, resultBytes)
608+
609+
return response, nil
610+
}
611+
542612
// handleElicitationRequestTransport handles elicitation requests at the transport level.
543613
func (c *Client) handleElicitationRequestTransport(ctx context.Context, request transport.JSONRPCRequest) (*transport.JSONRPCResponse, error) {
544614
if c.elicitationHandler == nil {
@@ -594,7 +664,7 @@ func listByPage[T any](
594664
request mcp.PaginatedRequest,
595665
method string,
596666
) (*T, error) {
597-
response, err := client.sendRequest(ctx, method, request.Params, nil)
667+
response, err := client.sendRequest(ctx, method, request.Params)
598668
if err != nil {
599669
return nil, err
600670
}
@@ -635,4 +705,4 @@ func (c *Client) GetSessionId() string {
635705
// IsInitialized returns true if the client has been initialized.
636706
func (c *Client) IsInitialized() bool {
637707
return c.initialized
638-
}
708+
}

client/transport/inprocess.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type InProcessTransport struct {
1414
server *server.MCPServer
1515
samplingHandler server.SamplingHandler
1616
elicitationHandler server.ElicitationHandler
17+
rootsHandler server.RootsHandler
1718
session *server.InProcessSession
1819
sessionID string
1920

@@ -31,12 +32,23 @@ func WithSamplingHandler(handler server.SamplingHandler) InProcessOption {
3132
}
3233
}
3334

35+
// WithElicitationHandler returns an InProcessOption that sets the elicitation handler on an InProcessTransport.
36+
// The provided handler will be used to handle elicitation requests for the in-process session when the transport is started.
3437
func WithElicitationHandler(handler server.ElicitationHandler) InProcessOption {
3538
return func(t *InProcessTransport) {
3639
t.elicitationHandler = handler
3740
}
3841
}
3942

43+
// WithRootsHandler returns an InProcessOption that sets the transport's roots handler.
44+
// The provided handler is assigned to the transport's rootsHandler field when the option is applied.
45+
func WithRootsHandler(handler server.RootsHandler) InProcessOption {
46+
return func(t *InProcessTransport) {
47+
t.rootsHandler = handler
48+
}
49+
}
50+
51+
// NewInProcessTransport creates an InProcessTransport that wraps the provided MCPServer with default (zero-value) configuration.
4052
func NewInProcessTransport(server *server.MCPServer) *InProcessTransport {
4153
return &InProcessTransport{
4254
server: server,
@@ -66,8 +78,8 @@ func (c *InProcessTransport) Start(ctx context.Context) error {
6678
c.startedMu.Unlock()
6779

6880
// Create and register session if we have handlers
69-
if c.samplingHandler != nil || c.elicitationHandler != nil {
70-
c.session = server.NewInProcessSessionWithHandlers(c.sessionID, c.samplingHandler, c.elicitationHandler)
81+
if c.samplingHandler != nil || c.elicitationHandler != nil || c.rootsHandler != nil {
82+
c.session = server.NewInProcessSessionWithHandlers(c.sessionID, c.samplingHandler, c.elicitationHandler, c.rootsHandler)
7183
if err := c.server.RegisterSession(ctx, c.session); err != nil {
7284
c.startedMu.Lock()
7385
c.started = false
@@ -130,4 +142,4 @@ func (c *InProcessTransport) Close() error {
130142

131143
func (c *InProcessTransport) GetSessionId() string {
132144
return ""
133-
}
145+
}

0 commit comments

Comments
 (0)