<!-- Autogenerated by weave; DO NOT EDIT -->
# Support for MCP server features

1. [Prompts](#prompts)
1. [Resources](#resources)
1. [Tools](#tools)
1. [Utilities](#utilities)
	1. [Completion](#completion)
	1. [Logging](#logging)
1. [Capabilities](#capabilities)
	1. [Capability inference](#capability-inference)
	1. [Explicit capabilities](#explicit-capabilities)
	1. [Pagination](#pagination)

## Prompts

MCP servers can provide LLM prompt templates (called simply
[_prompts_](https://modelcontextprotocol.io/specification/2025-06-18/server/prompts))
to clients. Every prompt has a required name which identifies it, and a set of
named arguments, which are strings.

**Client-side**: To list the server's prompts, use the 
[`ClientSession.Prompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Prompts)
iterator, or the lower-level
[`ClientSession.ListPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListPrompts)
(see [pagination](#pagination) below). 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.

Call
[`ClientSession.GetPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.GetPrompt)
to retrieve a prompt by name, providing arguments for expansion. 

**Server-side**: Use
[`Server.AddPrompt`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddPrompt)
to add a prompt to the server along with its handler.
The server will have the `prompts` capability if any prompt is added before the
server is connected to a client, or if
[`ServerOptions.HasPrompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts)
is explicitly set. When a prompt is added, any clients already connected to the
server will be notified via a `notifications/prompts/list_changed`
notification.

```go
func Example_prompts() {
	ctx := context.Background()

	promptHandler := func(ctx context.Context, req *mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
		return &mcp.GetPromptResult{
			Description: "Hi prompt",
			Messages: []*mcp.PromptMessage{
				{
					Role:    "user",
					Content: &mcp.TextContent{Text: "Say hi to " + req.Params.Arguments["name"]},
				},
			},
		}, nil
	}

	// Create a server with a single prompt.
	s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
	prompt := &mcp.Prompt{
		Name: "greet",
		Arguments: []*mcp.PromptArgument{
			{
				Name:        "name",
				Description: "the name of the person to greet",
				Required:    true,
			},
		},
	}
	s.AddPrompt(prompt, promptHandler)

	// Create a client.
	c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)

	// Connect the server and client.
	t1, t2 := mcp.NewInMemoryTransports()
	if _, err := s.Connect(ctx, t1, nil); err != nil {
		log.Fatal(err)
	}
	cs, err := c.Connect(ctx, t2, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer cs.Close()

	// List the prompts.
	for p, err := range cs.Prompts(ctx, nil) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(p.Name)
	}

	// Get the prompt.
	res, err := cs.GetPrompt(ctx, &mcp.GetPromptParams{
		Name:      "greet",
		Arguments: map[string]string{"name": "Pat"},
	})
	if err != nil {
		log.Fatal(err)
	}
	for _, msg := range res.Messages {
		fmt.Println(msg.Role, msg.Content.(*mcp.TextContent).Text)
	}
	// Output:
	// greet
	// user Say hi to Pat
}
```

## Resources

In MCP terms, a _resource_ is some data referenced by a URI.
MCP servers can serve resources to clients.
They can register resources individually, or register a _resource template_
that uses a URI pattern to describe a collection of resources.


**Client-side**:
Call [`ClientSession.ReadResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ReadResource)
to read a resource.
The SDK ensures that a read succeeds only if the URI matches a registered resource exactly,
or matches the URI pattern of a resource template.

To list a server's resources and resource templates, use the 
[`ClientSession.Resources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Resources)
and
[`ClientSession.ResourceTemplates`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ResourceTemplates)
iterators, or the lower-level `ListXXX` calls (see [pagination](#pagination)).
Set
[`ClientOptions.ResourceListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceListChangedHandler)
to be notified of changes in the lists of resources or resource templates.

Clients can be notified when the contents of a resource changes by subscribing to the resource's URI.
Call
[`ClientSession.Subscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Subscribe)
to subscribe to a resource
and
[`ClientSession.Unsubscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Unsubscribe)
to unsubscribe.
Set
[`ClientOptions.ResourceUpdatedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceUpdatedHandler)
to be notified of changes to subscribed resources.

**Server-side**:
Use
[`Server.AddResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResource)
or
[`Server.AddResourceTemplate`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResourceTemplate)
to add a resource or resource template to the server along with its handler.
A
[`ResourceHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ResourceHandler)
maps a URI to the contents of a resource, which can include text, binary data,
or both. 
If `AddResource` or `AddResourceTemplate` is called before a server is connected, the server will have the
`resources` capability.
The server will have the `resources` capability if any resource or resource template is added before the
server is connected to a client, or if
[`ServerOptions.HasResources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasResources)
is explicitly set. When a prompt is added, any clients already connected to the
server will be notified via a `notifications/resources/list_changed`
notification.


```go
func Example_resources() {
	ctx := context.Background()

	resources := map[string]string{
		"file:///a":     "a",
		"file:///dir/x": "x",
		"file:///dir/y": "y",
	}

	handler := func(_ context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
		uri := req.Params.URI
		c, ok := resources[uri]
		if !ok {
			return nil, mcp.ResourceNotFoundError(uri)
		}
		return &mcp.ReadResourceResult{
			Contents: []*mcp.ResourceContents{{URI: uri, Text: c}},
		}, nil
	}

	// Create a server with a single resource.
	s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
	s.AddResource(&mcp.Resource{URI: "file:///a"}, handler)
	s.AddResourceTemplate(&mcp.ResourceTemplate{URITemplate: "file:///dir/{f}"}, handler)

	// Create a client.
	c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)

	// Connect the server and client.
	t1, t2 := mcp.NewInMemoryTransports()
	if _, err := s.Connect(ctx, t1, nil); err != nil {
		log.Fatal(err)
	}
	cs, err := c.Connect(ctx, t2, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer cs.Close()

	// List resources and resource templates.
	for r, err := range cs.Resources(ctx, nil) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(r.URI)
	}
	for r, err := range cs.ResourceTemplates(ctx, nil) {
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(r.URITemplate)
	}

	// Read resources.
	for _, path := range []string{"a", "dir/x", "b"} {
		res, err := cs.ReadResource(ctx, &mcp.ReadResourceParams{URI: "file:///" + path})
		if err != nil {
			fmt.Println(err)
		} else {
			fmt.Println(res.Contents[0].Text)
		}
	}
	// Output:
	// file:///a
	// file:///dir/{f}
	// a
	// x
	// calling "resources/read": Resource not found
}
```

## Tools

MCP servers can provide
[tools](https://modelcontextprotocol.io/specification/2025-06-18/server/tools)
to allow clients to interact with external systems or functionality. Tools are
effectively remote function calls, and the Go SDK provides mechanisms to bind
them to ordinary Go functions.

**Client-side**: To list the server's tools, use the
[`ClientSession.Tools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Tools)
iterator, or the lower-level
[`ClientSession.ListTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ListTools)
(see [pagination](#pagination)). Set
[`ClientOptions.ToolListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ToolListChangedHandler)
to be notified of changes in the list of tools.

To call a tool, use
[`ClientSession.CallTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.CallTool)
with `CallToolParams` holding the name and arguments of the tool to call.

```go
res, err := session.CallTool(ctx, &mcp.CallToolParams{
	Name:      "my_tool",
	Arguments: map[string]any{"name": "user"},
})
```

Arguments may be any value that can be marshaled to JSON.

**Server-side**: the basic API for adding a tool is symmetrical with the API
for prompts or resources:
[`Server.AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddTool)
adds a
[`Tool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Tool) to
the server along with its
[`ToolHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ToolHandler)
to handle it. The server will have the `tools` capability if any tool is added
before the server is connected to a client, or if
[`ServerOptions.HasTools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasPrompts)
is explicitly set. When a tool is added, any clients already connected to the
server will be notified via a `notifications/tools/list_changed` notification.

However, the `Server.AddTool` API leaves it to the user to implement the tool
handler correctly according to the spec, providing very little out of the box.
In order to implement a tool, the user must do all of the following:

- Provide a tool input and output schema.
- Validate the tool arguments against its input schema.
- Unmarshal the input schema into a Go value
- Execute the tool logic.
- Marshal the tool's structured output (if any) to JSON, and store it in the
  result's `StructuredOutput` field as well as the unstructured `Content` field.
- Validate that output JSON against the tool's output schema.
- If any tool errors occurred, pack them into the unstructured content and set
  `IsError` to `true.`

For this reason, the SDK provides a generic
[`AddTool`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#AddTool)
function that handles this for you. It can bind a tool to any function with the
following shape:

```go
func(_ context.Context, request *CallToolRequest, input In) (result *CallToolResult, output Out, _ error)
```

This is like a `ToolHandler`, but with an extra arbitrary `In` input parameter,
and `Out` output parameter.

Such a function can then be bound to the server using `AddTool`:

```go
mcp.AddTool(server, &mcp.Tool{Name: "my_tool"}, handler)
```

This does the following automatically:

- If `Tool.InputSchema` or `Tool.OutputSchema` are unset, the input and output
  schemas are inferred from the `In` type, which must be a struct or map.
  Optional `jsonschema` struct tags provide argument descriptions.
- Tool arguments are validated against the input schema.
- Tool arguments are marshaled into the `In` value.
- Tool output (the `Out` value) is marshaled into the result's
  `StructuredOutput`, as well as the unstructured `Content`.
- Output is validated against the tool's output schema.
- If an ordinary error is returned, it is stored int the `CallToolResult` and
  `IsError` is set to `true`.

In fact, under ordinary circumstances, the user can ignore `CallToolRequest`
and `CallToolResult`.

For a more realistic example, consider a tool that retrieves the weather:

```go
type WeatherInput struct {
	Location Location `json:"location" jsonschema:"user location"`
	Days     int      `json:"days" jsonschema:"number of days to forecast"`
}

type WeatherOutput struct {
	Summary       string      `json:"summary" jsonschema:"a summary of the weather forecast"`
	Confidence    Probability `json:"confidence" jsonschema:"confidence, between 0 and 1"`
	AsOf          time.Time   `json:"asOf" jsonschema:"the time the weather was computed"`
	DailyForecast []Forecast  `json:"dailyForecast" jsonschema:"the daily forecast"`
	Source        string      `json:"source,omitempty" jsonschema:"the organization providing the weather forecast"`
}

func WeatherTool(ctx context.Context, req *mcp.CallToolRequest, in WeatherInput) (*mcp.CallToolResult, WeatherOutput, error) {
	perfectWeather := WeatherOutput{
		Summary:    "perfect",
		Confidence: 1.0,
		AsOf:       time.Now(),
	}
	for range in.Days {
		perfectWeather.DailyForecast = append(perfectWeather.DailyForecast, Forecast{
			Forecast: "another perfect day",
			Type:     Sunny,
			Rain:     0.0,
			High:     72.0,
			Low:      72.0,
		})
	}
	return nil, perfectWeather, nil
}
```

In this case, we want to customize part of the inferred schema, though we can
still infer the rest. Since we want to control the inference ourselves, we set
the `Tool.InputSchema` explicitly:

```go
// Distinguished Go types allow custom schemas to be reused during inference.
customSchemas := map[reflect.Type]*jsonschema.Schema{
	reflect.TypeFor[Probability](): {Type: "number", Minimum: jsonschema.Ptr(0.0), Maximum: jsonschema.Ptr(1.0)},
	reflect.TypeFor[WeatherType](): {Type: "string", Enum: []any{Sunny, PartlyCloudy, Cloudy, Rainy, Snowy}},
}
opts := &jsonschema.ForOptions{TypeSchemas: customSchemas}
in, err := jsonschema.For[WeatherInput](opts)
if err != nil {
	log.Fatal(err)
}

// Furthermore, we can tweak the inferred schema, in this case limiting
// forecasts to 0-10 days.
daysSchema := in.Properties["days"]
daysSchema.Minimum = jsonschema.Ptr(0.0)
daysSchema.Maximum = jsonschema.Ptr(10.0)

// Output schema inference can reuse our custom schemas from input inference.
out, err := jsonschema.For[WeatherOutput](opts)
if err != nil {
	log.Fatal(err)
}

// Now add our tool to a server. Since we've customized the schemas, we need
// to override the default schema inference.
server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
mcp.AddTool(server, &mcp.Tool{
	Name:         "weather",
	InputSchema:  in,
	OutputSchema: out,
}, WeatherTool)
```

_See [mcp/tool_example_test.go](https://github.com/modelcontextprotocol/go-sdk/blob/main/mcp/tool_example_test.go) for the full
example, or [examples/server/toolschemas](https://github.com/modelcontextprotocol/go-sdk/blob/main/examples/server/toolschemas/main.go)
for more examples of customizing tool schemas._

**Stateless server deployments:** Some deployments create a new
[`Server`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server)
for each incoming request, re-registering tools every time. To avoid repeated
schema generation, create a
[`SchemaCache`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#SchemaCache)
and share it across server instances:

```go
var schemaCache = mcp.NewSchemaCache() // create once at startup

func handleRequest(w http.ResponseWriter, r *http.Request) {
    s := mcp.NewServer(impl, &mcp.ServerOptions{SchemaCache: schemaCache})
    mcp.AddTool(s, myTool, myHandler)
    // ...
}
```

## Utilities

### Completion

To support the
[completion](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/completion)
capability, the server needs a completion handler.

**Client-side**: completion is called using the
[`ClientSession.Complete`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Complete)
method.

**Server-side**: completion is enabled by setting
[`ServerOptions.CompletionHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.CompletionHandler).
If this field is set to a non-nil value, the server will advertise the
`completions` server capability, and use this handler to respond to completion
requests.

```go
myCompletionHandler := func(_ context.Context, req *mcp.CompleteRequest) (*mcp.CompleteResult, error) {
	// In a real application, you'd implement actual completion logic here.
	// For this example, we return a fixed set of suggestions.
	var suggestions []string
	switch req.Params.Ref.Type {
	case "ref/prompt":
		suggestions = []string{"suggestion1", "suggestion2", "suggestion3"}
	case "ref/resource":
		suggestions = []string{"suggestion4", "suggestion5", "suggestion6"}
	default:
		return nil, fmt.Errorf("unrecognized content type %s", req.Params.Ref.Type)
	}

	return &mcp.CompleteResult{
		Completion: mcp.CompletionResultDetails{
			HasMore: false,
			Total:   len(suggestions),
			Values:  suggestions,
		},
	}, nil
}

// Create the MCP Server instance and assign the handler.
// No server running, just showing the configuration.
_ = mcp.NewServer(&mcp.Implementation{Name: "server"}, &mcp.ServerOptions{
	CompletionHandler: myCompletionHandler,
})
```

### Logging

MCP servers can send logging messages to MCP clients.
(This form of logging is distinct from server-side logging, where the
server produces logs that remain server-side, for use by server maintainers.)

**Server-side**:
The minimum log level is part of the server state.
For stateful sessions, there is no default log level: no log messages will be sent
until the client calls `SetLevel` (see below).
For stateful sessions, the level defaults to "info".

[`ServerSession.Log`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Log) is the low-level way for servers to log to clients.
It sends a logging notification to the client if the level of the message
is at least the minimum log level.

For a simpler API, use [`NewLoggingHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#NewLoggingHandler) to obtain a [`slog.Handler`](https://pkg.go.dev/log/slog#Handler).
By setting [`LoggingHandlerOptions.MinInterval`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#LoggingHandlerOptions.MinInterval), the handler can be rate-limited
to avoid spamming clients with too many messages.

Servers always report the logging capability.


**Client-side**:
Set [`ClientOptions.LoggingMessageHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.LoggingMessageHandler) to receive log messages.

Call [`ClientSession.SetLevel`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.SetLevel) to change the log level for a session.

```go
func Example_logging() {
	ctx := context.Background()

	// Create a server.
	s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)

	// Create a client that displays log messages.
	done := make(chan struct{}) // solely for the example
	var nmsgs atomic.Int32
	c := mcp.NewClient(
		&mcp.Implementation{Name: "client", Version: "v0.0.1"},
		&mcp.ClientOptions{
			LoggingMessageHandler: func(_ context.Context, r *mcp.LoggingMessageRequest) {
				m := r.Params.Data.(map[string]any)
				fmt.Println(m["msg"], m["value"])
				if nmsgs.Add(1) == 2 { // number depends on logger calls below
					close(done)
				}
			},
		})

	// Connect the server and client.
	t1, t2 := mcp.NewInMemoryTransports()
	ss, err := s.Connect(ctx, t1, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer ss.Close()
	cs, err := c.Connect(ctx, t2, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer cs.Close()

	// Set the minimum log level to "info".
	if err := cs.SetLoggingLevel(ctx, &mcp.SetLoggingLevelParams{Level: "info"}); err != nil {
		log.Fatal(err)
	}

	// Get a slog.Logger for the server session.
	logger := slog.New(mcp.NewLoggingHandler(ss, nil))

	// Log some things.
	logger.Info("info shows up", "value", 1)
	logger.Debug("debug doesn't show up", "value", 2)
	logger.Warn("warn shows up", "value", 3)

	// Wait for them to arrive on the client.
	// In a real application, the log messages would appear asynchronously
	// while other work was happening.
	<-done

	// Output:
	// info shows up 1
	// warn shows up 3
}
```

## Capabilities

Server capabilities are advertised to clients during the initialization
handshake. By default, the SDK advertises only the `logging` capability.
Additional capabilities are automatically added when features are registered
(e.g., adding a tool adds the `tools` capability).

### Capability inference

When features such as tools, prompts, or resources are added to the server
(e.g., via `Server.AddTool`), their capability is automatically inferred, with
default value `{listChanged:true}`. Similarly, if the
`ServerOptions.SubscribeHandler` or `ServerOptions.CompletionHandler` are set,
the corresponding capability is added.

### Explicit capabilities

To explicitly declare capabilities, or to override the [default inferred
capability](#capability-inference), set
[`ServerOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.Capabilities).
This sets the default server capabilities, before any capabilities are added
based on configured handlers. If a capability is already present as a field in
`Capabilities`, adding a feature or handler will not change its configuration.

This allows you to:

- **Disable default capabilities**: Pass an empty `&ServerCapabilities{}` to
  disable all defaults, including logging.
- **Disable listChanged notifications**: Set `ListChanged: false` on a
  capability to prevent the server from sending list-changed notifications
  when features are added or removed.
- **Pre-declare capabilities**: Declare capabilities before features are
  registered, useful for servers that load features dynamically.

```go
// Disable listChanged notifications for tools
server := mcp.NewServer(impl, &mcp.ServerOptions{
    Capabilities: &mcp.ServerCapabilities{
        Logging: &mcp.LoggingCapabilities{},
        Tools:   &mcp.ToolCapabilities{ListChanged: false},
    },
})
```

**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
`ServerOptions` are deprecated. Use `Capabilities` instead.

### Pagination

Server-side feature lists may be
[paginated](https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/pagination),
using cursors. The SDK supports this by default.

**Client-side**: The `ClientSession` provides methods returning
[iterators](https://go.dev/blog/range-functions) for each feature type.
These iterators are an `iter.Seq2[Feature, error]`, where the error value
indicates whether page retrieval failed.

- [`ClientSession.Prompts`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Prompts)
  iterates prompts.
- [`ClientSession.Resource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Resource)
  iterates resources.
- [`ClientSession.ResourceTemplates`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ResourceTemplates)
  iterates resource templates.
- [`ClientSession.Tools`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Tools)
  iterates tools.

The `ClientSession` also exposes `ListXXX` methods for fine-grained control
over pagination.

**Server-side**: pagination is on by default, so in general nothing is required
server-side. However, you may use
[`ServerOptions.PageSize`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.PageSize)
to customize the page size.
