# Support for MCP client features 1. [Roots](#roots) 1. [Sampling](#sampling) 1. [Elicitation](#elicitation) ## Roots MCP allows clients to specify a set of filesystem ["roots"](https://modelcontextprotocol.io/specification/2025-06-18/client/roots). The SDK supports this as follows: **Client-side**: The SDK client always has the `roots.listChanged` capability. To add roots to a client, use the [`Client.AddRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client.AddRoots) and [`Client.RemoveRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client.RemoveRoots) methods. If any servers are already [connected](protocol.md#lifecycle) to the client, a call to `AddRoot` or `RemoveRoots` will result in a `notifications/roots/list_changed` notification to each connected server. **Server-side**: To query roots from the server, use the [`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots) method. To receive notifications about root changes, set [`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler). ```go func Example_roots() { ctx := context.Background() // Create a client with a single root. c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil) c.AddRoots(&mcp.Root{URI: "file://a"}) // Now create a server with a handler to receive notifications about roots. rootsChanged := make(chan struct{}) handleRootsChanged := func(ctx context.Context, req *mcp.RootsListChangedRequest) { rootList, err := req.Session.ListRoots(ctx, nil) if err != nil { log.Fatal(err) } var roots []string for _, root := range rootList.Roots { roots = append(roots, root.URI) } fmt.Println(roots) close(rootsChanged) } s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, &mcp.ServerOptions{ RootsListChangedHandler: handleRootsChanged, }) // Connect the server and client... t1, t2 := mcp.NewInMemoryTransports() if _, err := s.Connect(ctx, t1, nil); err != nil { log.Fatal(err) } clientSession, err := c.Connect(ctx, t2, nil) if err != nil { log.Fatal(err) } defer clientSession.Close() // ...and add a root. The server is notified about the change. c.AddRoots(&mcp.Root{URI: "file://b"}) <-rootsChanged // Output: [file://a file://b] } ``` ## Sampling [Sampling](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling) is a way for servers to leverage the client's AI capabilities. It is implemented in the SDK as follows: **Client-side**: To add the `sampling` capability to a client, set [`ClientOptions.CreateMessageHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.CreateMessageHandler). This function is invoked whenever the server requests sampling. **Server-side**: To use sampling from the server, call [`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage). ```go func Example_sampling() { ctx := context.Background() // Create a client with a sampling handler. c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, &mcp.ClientOptions{ CreateMessageHandler: func(_ context.Context, req *mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) { return &mcp.CreateMessageResult{ Content: &mcp.TextContent{ Text: "would have created a message", }, }, nil }, }) // Connect the server and client... ct, st := mcp.NewInMemoryTransports() s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil) session, err := s.Connect(ctx, st, nil) if err != nil { log.Fatal(err) } defer session.Close() if _, err := c.Connect(ctx, ct, nil); err != nil { log.Fatal(err) } msg, err := session.CreateMessage(ctx, &mcp.CreateMessageParams{}) if err != nil { log.Fatal(err) } fmt.Println(msg.Content.(*mcp.TextContent).Text) // Output: would have created a message } ``` ## Elicitation [Elicitation](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation) allows servers to request user inputs. It is implemented in the SDK as follows: **Client-side**: To add the `elicitation` capability to a client, set [`ClientOptions.ElicitationHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ElicitationHandler). The elicitation handler must return a result that matches the requested schema; otherwise, elicitation returns an error. **Server-side**: To use elicitation from the server, call [`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit). ```go func Example_elicitation() { ctx := context.Background() ct, st := mcp.NewInMemoryTransports() s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil) ss, err := s.Connect(ctx, st, nil) if err != nil { log.Fatal(err) } defer ss.Close() c := mcp.NewClient(testImpl, &mcp.ClientOptions{ ElicitationHandler: func(context.Context, *mcp.ElicitRequest) (*mcp.ElicitResult, error) { return &mcp.ElicitResult{Action: "accept", Content: map[string]any{"test": "value"}}, nil }, }) if _, err := c.Connect(ctx, ct, nil); err != nil { log.Fatal(err) } res, err := ss.Elicit(ctx, &mcp.ElicitParams{ Message: "This should fail", RequestedSchema: &jsonschema.Schema{ Type: "object", Properties: map[string]*jsonschema.Schema{ "test": {Type: "string"}, }, }, }) if err != nil { log.Fatal(err) } fmt.Println(res.Content["test"]) // Output: value } ```