go-sdk/docs/server.md
2025-09-18 14:27:35 -04:00

6.4 KiB

Support for MCP server features

  1. Prompts
  2. Resources
  3. Tools
  4. Utilities
    1. Completion
    2. Logging
    3. Pagination

Prompts

Server-side: MCP servers can provide LLM prompt templates (called simply prompts) to clients. Every prompt has a required name which identifies it, and a set of named arguments, which are strings. Construct a prompt with a name and descriptions of its arguments. Associated with each prompt is a handler that expands the template given values for its arguments. Use Server.AddPrompt to add a prompt along with its handler. If AddPrompt is called before a server is connected, the server will have the prompts capability. If all prompts are to be added after connection, set ServerOptions.HasPrompts to advertise the capability.

Client-side: To list the server's prompts, call Call ClientSession.Prompts to get an iterator. If needed, you can use the lower-level ClientSession.ListPrompts to list the server's prompts. Call ClientSession.GetPrompt to retrieve a prompt by name, providing arguments for expansion. Set ClientOptions.PromptListChangedHandler to be notified of changes in the list of prompts.

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)
	}

	// 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

Tools

Utilities

Completion

To support the completion capability, the server needs a completion handler.

Client-side: completion is called using the ClientSession.Complete method.

Server-side: completion is enabled by setting 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.

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

Pagination

Server-side feature lists may be paginated, using cursors. The SDK supports this by default.

Client-side: The ClientSession provides methods returning iterators for each feature type. These iterators are an iter.Seq2[Feature, error], where the error value indicates whether page retrieval failed.

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 to customize the page size.