MCP Client Usage Guide
The MCP client provides a simple and intuitive way to interact with MCP servers. This guide will walk you through initializing the client, connecting to a server, and using various MCP features.
Installation
Add the MCP Golang package to your project:
go get github.com/metoro-io/mcp-golang
Basic Usage
Here’s a simple example of creating and initializing an MCP client:
import (
mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/stdio"
)
// Create a transport (stdio in this example)
transport := stdio.NewStdioServerTransportWithIO(stdout, stdin)
// Create a new client
client := mcp.NewClient(transport)
// Initialize the client
response, err := client.Initialize(context.Background())
if err != nil {
log.Fatalf("Failed to initialize client: %v", err)
}
tools, err := client.ListTools(context.Background(), nil)
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
for _, tool := range tools.Tools {
log.Printf("Tool: %s. Description: %s", tool.Name, *tool.Description)
}
// Define a type-safe struct for your tool arguments
type CalculateArgs struct {
Operation string `json:"operation"`
A int `json:"a"`
B int `json:"b"`
}
// Create typed arguments
args := CalculateArgs{
Operation: "add",
A: 10,
B: 5,
}
response, err := client.CallTool(context.Background(), "calculate", args)
if err != nil {
log.Printf("Failed to call tool: %v", err)
}
// Handle the response
if response != nil && len(response.Content) > 0 {
if response.Content[0].TextContent != nil {
log.Printf("Response: %s", response.Content[0].TextContent.Text)
}
}
Working with Prompts
Listing Available Prompts
prompts, err := client.ListPrompts(context.Background(), nil)
if err != nil {
log.Printf("Failed to list prompts: %v", err)
}
for _, prompt := range prompts.Prompts {
log.Printf("Prompt: %s. Description: %s", prompt.Name, *prompt.Description)
}
Using a Prompt
// Define a type-safe struct for your prompt arguments
type PromptArgs struct {
Input string `json:"input"`
}
// Create typed arguments
args := PromptArgs{
Input: "Hello, MCP!",
}
response, err := client.GetPrompt(context.Background(), "prompt_name", args)
if err != nil {
log.Printf("Failed to get prompt: %v", err)
}
if response != nil && len(response.Messages) > 0 {
log.Printf("Response: %s", response.Messages[0].Content.TextContent.Text)
}
Working with Resources
Listing Resources
resources, err := client.ListResources(context.Background(), nil)
if err != nil {
log.Printf("Failed to list resources: %v", err)
}
for _, resource := range resources.Resources {
log.Printf("Resource: %s", resource.Uri)
}
Reading a Resource
resource, err := client.ReadResource(context.Background(), "resource_uri")
if err != nil {
log.Printf("Failed to read resource: %v", err)
}
if resource != nil {
log.Printf("Resource content: %s", resource.Content)
}
Both ListTools
and ListPrompts
support pagination. You can pass a cursor to get the next page of results:
var cursor *string
for {
tools, err := client.ListTools(context.Background(), cursor)
if err != nil {
log.Fatalf("Failed to list tools: %v", err)
}
// Process tools...
if tools.NextCursor == nil {
break // No more pages
}
cursor = tools.NextCursor
}
Error Handling
The client includes comprehensive error handling. All methods return an error as their second return value:
response, err := client.CallTool(context.Background(), "calculate", args)
if err != nil {
switch {
case errors.Is(err, mcp.ErrClientNotInitialized):
// Handle initialization error
default:
// Handle other errors
}
}
Best Practices
- Always initialize the client before making any calls
- Use appropriate context management for timeouts and cancellation
- Handle errors appropriately for your use case
- Close or clean up resources when done
- Define type-safe structs for tool and prompt arguments
- Use struct tags to ensure correct JSON field names
Complete Example
For a complete working example, check out our example client implementation.
Transport Options
The MCP client supports multiple transport options:
Standard I/O Transport
For command-line tools that communicate through stdin/stdout:
transport := stdio.NewStdioClientTransport()
client := mcp.NewClient(transport)
This transport supports all MCP features including bidirectional communication and notifications.
HTTP Transport
For web-based tools that communicate over HTTP/HTTPS:
transport := http.NewHTTPClientTransport("/mcp")
transport.WithBaseURL("http://localhost:8080")
client := mcp.NewClient(transport)
Note that the HTTP transport is stateless and does not support bidirectional features like notifications. Each request-response cycle is independent, making it suitable for simple tool invocations but not for scenarios requiring real-time updates or persistent connections.
Context Support
All client operations now support context propagation:
ctx := context.Background()
// With timeout
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
// Call tool with context
response, err := client.CallTool(ctx, "tool-name", args)
if err != nil {
// Handle error
}
// List tools with context
tools, err := client.ListTools(ctx)
if err != nil {
// Handle error
}
The context allows you to:
- Set timeouts for operations
- Cancel long-running operations
- Pass request-scoped values
- Implement tracing and monitoring