The Client API provides functionality for connecting to and interacting with MCP servers. Clients can discover and invoke tools, retrieve prompts, and read resources from servers.
import mcp "github.com/metoro-io/mcp-golang"The Client type represents an MCP client that manages communication with an MCP server.
type Client struct {
// Contains unexported fields
}func NewClient(transport transport.Transport) *ClientCreates a new MCP client with the specified transport.
Parameters:
transport: A transport implementation (stdio, HTTP, etc.) for communicationReturns: A new Client instance
Example:
import (
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
)
transport := stdio.NewStdioServerTransport()
client := mcp.NewClient(transport)func NewClientWithInfo(transport transport.Transport, info ClientInfo) *ClientCreates a new MCP client with custom client information. This is required by Anthropic MCP tools to identify the client.
Parameters:
transport: A transport implementation for communicationinfo: Client identification informationReturns: A new Client instance with the specified info
Example:
transport := stdio.NewStdioServerTransport()
info := mcp.ClientInfo{
Name: "my-mcp-client",
Version: "1.0.0",
}
client := mcp.NewClientWithInfo(transport, info)type ClientInfo struct {
Name string `json:"name"`
Version string `json:"version"`
}Information identifying the MCP client.
Fields:
Name: The name of the client applicationVersion: The version of the client applicationfunc (c *Client) Initialize(ctx context.Context) (*InitializeResponse, error)Connects to the MCP server and retrieves its capabilities. This must be called before any other client operations.
Parameters:
ctx: Context for the operation (for cancellation and timeouts)Returns:
*InitializeResponse: Server information and capabilitieserror: Error if initialization failsExample:
ctx := context.Background()
initResp, err := client.Initialize(ctx)
if err != nil {
log.Fatalf("Failed to initialize: %v", err)
}
log.Printf("Connected to server: %s %s",
initResp.ServerInfo.Name,
initResp.ServerInfo.Version)
log.Printf("Protocol version: %s", initResp.ProtocolVersion)func (c *Client) GetCapabilities() *ServerCapabilitiesReturns the server capabilities obtained during initialization.
Returns: Server capabilities describing what features the server supports
Example:
caps := client.GetCapabilities()
if caps.Tools != nil && caps.Tools.ListChanged != nil && *caps.Tools.ListChanged {
log.Println("Server supports tool list change notifications")
}func (c *Client) Ping(ctx context.Context) errorSends a ping request to the server to check connectivity.
Parameters:
ctx: Context for the operationReturns: Error if ping fails
Example:
err := client.Ping(context.Background())
if err != nil {
log.Printf("Server is not responding: %v", err)
}func (c *Client) ListTools(ctx context.Context, cursor *string) (*ToolsResponse, error)Retrieves the list of available tools from the server. Supports pagination for large tool lists.
Parameters:
ctx: Context for the operationcursor: Pagination cursor (nil for first page, or value from previous response's NextCursor)Returns:
*ToolsResponse: List of tools and optional pagination cursorerror: Error if the request failsExample:
// Get first page of tools
toolsResp, err := client.ListTools(context.Background(), nil)
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
for _, tool := range toolsResp.Tools {
log.Printf("Tool: %s - %s", tool.Name, *tool.Description)
}
// Get next page if available
if toolsResp.NextCursor != nil {
nextResp, err := client.ListTools(context.Background(), toolsResp.NextCursor)
// Process next page...
}func (c *Client) CallTool(ctx context.Context, name string, arguments any) (*ToolResponse, error)Calls a specific tool on the server with the provided arguments.
Parameters:
ctx: Context for the operationname: The name of the tool to callarguments: Tool arguments (typically a struct that matches the tool's input schema)Returns:
*ToolResponse: The tool's outputerror: Error if the tool call failsExample:
type CalculateArgs struct {
Operation string `json:"operation"`
A int `json:"a"`
B int `json:"b"`
}
args := CalculateArgs{
Operation: "add",
A: 10,
B: 5,
}
response, err := client.CallTool(context.Background(), "calculate", args)
if err != nil {
log.Fatalf("Tool call failed: %v", err)
}
// Process tool response
for _, content := range response.Content {
if content.Type == mcp.ContentTypeText {
log.Printf("Result: %s", content.TextContent.Text)
}
}func (c *Client) ListPrompts(ctx context.Context, cursor *string) (*ListPromptsResponse, error)Retrieves the list of available prompts from the server. Supports pagination.
Parameters:
ctx: Context for the operationcursor: Pagination cursor (nil for first page)Returns:
*ListPromptsResponse: List of prompts and optional pagination cursorerror: Error if the request failsExample:
promptsResp, err := client.ListPrompts(context.Background(), nil)
if err != nil {
log.Fatalf("Failed to list prompts: %v", err)
}
for _, prompt := range promptsResp.Prompts {
log.Printf("Prompt: %s", prompt.Name)
if prompt.Description != nil {
log.Printf(" Description: %s", *prompt.Description)
}
for _, arg := range prompt.Arguments {
log.Printf(" Argument: %s", arg.Name)
}
}func (c *Client) GetPrompt(ctx context.Context, name string, arguments any) (*PromptResponse, error)Retrieves a specific prompt from the server, optionally with arguments for template rendering.
Parameters:
ctx: Context for the operationname: The name of the prompt to retrievearguments: Prompt arguments for template rendering (can be nil if prompt has no arguments)Returns:
*PromptResponse: The rendered prompt messageserror: Error if the request failsExample:
type PromptArgs struct {
Topic string `json:"topic"`
Style string `json:"style"`
}
args := PromptArgs{
Topic: "quantum computing",
Style: "educational",
}
response, err := client.GetPrompt(context.Background(), "explain-topic", args)
if err != nil {
log.Fatalf("Failed to get prompt: %v", err)
}
for _, msg := range response.Messages {
log.Printf("[%s]: %s", msg.Role, msg.Content.TextContent.Text)
}func (c *Client) ListResources(ctx context.Context, cursor *string) (*ListResourcesResponse, error)Retrieves the list of available resources from the server. Supports pagination.
Parameters:
ctx: Context for the operationcursor: Pagination cursor (nil for first page)Returns:
*ListResourcesResponse: List of resources and optional pagination cursorerror: Error if the request failsExample:
resourcesResp, err := client.ListResources(context.Background(), nil)
if err != nil {
log.Fatalf("Failed to list resources: %v", err)
}
for _, resource := range resourcesResp.Resources {
log.Printf("Resource: %s", resource.Name)
log.Printf(" URI: %s", resource.Uri)
if resource.MimeType != nil {
log.Printf(" MIME Type: %s", *resource.MimeType)
}
}func (c *Client) ReadResource(ctx context.Context, uri string) (*ResourceResponse, error)Reads a specific resource from the server.
Parameters:
ctx: Context for the operationuri: The URI of the resource to readReturns:
*ResourceResponse: The resource contentserror: Error if the request failsExample:
response, err := client.ReadResource(context.Background(), "file://config.json")
if err != nil {
log.Fatalf("Failed to read resource: %v", err)
}
for _, content := range response.Contents {
if content.EmbeddedResourceType == /* text */ {
log.Printf("Resource content: %s", content.TextResourceContents.Text)
}
}type InitializeResponse struct {
Capabilities ServerCapabilities `json:"capabilities"`
ProtocolVersion string `json:"protocolVersion"`
ServerInfo implementation `json:"serverInfo"`
Instructions *string `json:"instructions,omitempty"`
Meta initializeResultMeta `json:"_meta,omitempty"`
}Server's response to initialization request.
Fields:
Capabilities: Server capabilities (tools, prompts, resources, etc.)ProtocolVersion: MCP protocol version the server usesServerInfo: Server name and version informationInstructions: Optional usage instructions from the serverMeta: Additional metadataMethods:
func (j *InitializeResponse) UnmarshalJSON(b []byte) errorCustom JSON unmarshaling for InitializeResponse. This method is typically called automatically by Go's encoding/json package.
Parameters:
b: JSON-encoded dataReturns: Error if unmarshaling fails
type ServerCapabilities struct {
Tools *ServerCapabilitiesTools `json:"tools,omitempty"`
Prompts *ServerCapabilitiesPrompts `json:"prompts,omitempty"`
Resources *ServerCapabilitiesResources `json:"resources,omitempty"`
Logging ServerCapabilitiesLogging `json:"logging,omitempty"`
Experimental ServerCapabilitiesExperimental `json:"experimental,omitempty"`
}Capabilities that the server supports.
Fields:
Tools: Tool capabilities (present if server offers tools)Prompts: Prompt capabilities (present if server offers prompts)Resources: Resource capabilities (present if server offers resources)Logging: Logging capabilitiesExperimental: Experimental/non-standard capabilitiestype ServerCapabilitiesTools struct {
ListChanged *bool `json:"listChanged,omitempty"`
}Tool-specific capabilities.
Fields:
ListChanged: Whether server supports notifications for changes to the tool listtype ServerCapabilitiesPrompts struct {
ListChanged *bool `json:"listChanged,omitempty"`
}Prompt-specific capabilities.
Fields:
ListChanged: Whether server supports notifications for changes to the prompt listtype ServerCapabilitiesResources struct {
ListChanged *bool `json:"listChanged,omitempty"`
Subscribe *bool `json:"subscribe,omitempty"`
}Resource-specific capabilities.
Fields:
ListChanged: Whether server supports notifications for changes to the resource listSubscribe: Whether server supports subscribing to resource updatestype ServerCapabilitiesLogging map[string]interface{}Logging capabilities map.
type ServerCapabilitiesExperimental map[string]map[string]interface{}Experimental/non-standard capabilities map.
package main
import (
"context"
"log"
"os/exec"
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
)
func main() {
// Start server subprocess
cmd := exec.Command("./mcp-server")
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatal(err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
defer cmd.Process.Kill()
// Create client
transport := stdio.NewStdioServerTransportWithIO(stdout, stdin)
client := mcp.NewClientWithInfo(transport, mcp.ClientInfo{
Name: "my-client",
Version: "1.0.0",
})
// Initialize
ctx := context.Background()
initResp, err := client.Initialize(ctx)
if err != nil {
log.Fatalf("Initialize failed: %v", err)
}
log.Printf("Connected to %s", initResp.ServerInfo)
// List and call tools
toolsResp, err := client.ListTools(ctx, nil)
if err != nil {
log.Fatalf("ListTools failed: %v", err)
}
for _, tool := range toolsResp.Tools {
log.Printf("Available tool: %s", tool.Name)
}
// Call a tool
type Args struct {
Input string `json:"input"`
}
result, err := client.CallTool(ctx, "process", Args{Input: "test"})
if err != nil {
log.Fatalf("CallTool failed: %v", err)
}
for _, content := range result.Content {
if content.Type == mcp.ContentTypeText {
log.Printf("Tool result: %s", content.TextContent.Text)
}
}
}// Always check initialization
initResp, err := client.Initialize(ctx)
if err != nil {
// Handle connection failure
log.Fatalf("Failed to connect to server: %v", err)
}
// Check for tool existence before calling
toolsResp, err := client.ListTools(ctx, nil)
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
toolExists := false
for _, tool := range toolsResp.Tools {
if tool.Name == "my-tool" {
toolExists = true
break
}
}
if !toolExists {
log.Fatal("Required tool 'my-tool' not available")
}
// Call tool with timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := client.CallTool(ctx, "my-tool", args)
if err != nil {
// Handle tool call failure
log.Printf("Tool call failed: %v", err)
}