# Claude SDK for Go The Claude SDK for Go is the official Go library for accessing Anthropic's Claude API. It provides a comprehensive, type-safe interface for building AI-powered applications with Claude models, enabling developers to integrate conversational AI, vision capabilities, tool use, and advanced features like streaming responses and batch processing into their Go applications. The SDK supports multiple deployment targets including the direct Anthropic API, AWS Bedrock, and Google Cloud Vertex AI. It offers both synchronous and streaming request patterns, structured outputs with JSON schemas, multi-turn conversations, and advanced features like thinking mode, file uploads, and MCP (Model Context Protocol) server integration. The library requires Go 1.22+ and follows idiomatic Go patterns with functional options for configuration. ## Installation Import the SDK and install it using Go modules. ```go import ( "github.com/anthropics/anthropic-sdk-go" ) // Or explicitly add the dependency: // go get -u 'github.com/anthropics/anthropic-sdk-go@v1.29.0' ``` ## Creating a Client The `NewClient` function creates a new API client that reads configuration from environment variables by default, with options for customization. ```go package main import ( "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/option" ) func main() { // Default client reads ANTHROPIC_API_KEY from environment client := anthropic.NewClient() // Or with explicit configuration client = anthropic.NewClient( option.WithAPIKey("my-anthropic-api-key"), option.WithBaseURL("https://custom-api-endpoint.com"), option.WithMaxRetries(3), ) } ``` ## Messages API - Basic Request The `Messages.New` method sends a message to Claude and returns a complete response. This is the core API for interacting with Claude models. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")), }, Model: anthropic.ModelClaudeOpus4_6, }) if err != nil { panic(err) } // Access the response content fmt.Printf("Response: %s\n", message.Content[0].Text) fmt.Printf("Stop Reason: %s\n", message.StopReason) fmt.Printf("Input Tokens: %d, Output Tokens: %d\n", message.Usage.InputTokens, message.Usage.OutputTokens) } ``` ## Messages API - Streaming Responses The `Messages.NewStreaming` method returns a stream for processing responses incrementally as they're generated, ideal for real-time user interfaces. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Write a short poem about Go programming.")), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, StopSequences: []string{"```\n"}, }) for stream.Next() { event := stream.Current() switch eventVariant := event.AsAny().(type) { case anthropic.MessageDeltaEvent: fmt.Print(eventVariant.Delta.StopSequence) case anthropic.ContentBlockDeltaEvent: switch deltaVariant := eventVariant.Delta.AsAny().(type) { case anthropic.TextDelta: fmt.Print(deltaVariant.Text) } } } if stream.Err() != nil { panic(stream.Err()) } } ``` ## Multi-Turn Conversations Build conversational applications by maintaining message history across multiple exchanges with the model. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() messages := []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("My name is Alice.")), } // First turn response, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: messages, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) if err != nil { panic(err) } fmt.Printf("Claude: %s\n", response.Content[0].Text) // Add assistant response and user follow-up to conversation history messages = append(messages, response.ToParam()) messages = append(messages, anthropic.NewUserMessage( anthropic.NewTextBlock("What was my name again?"), )) // Second turn response, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: messages, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) if err != nil { panic(err) } fmt.Printf("Claude: %s\n", response.Content[0].Text) } ``` ## Tool Use (Function Calling) Enable Claude to use custom tools by defining tool schemas and handling tool use blocks in responses. ```go package main import ( "context" "encoding/json" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() messages := []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather in San Francisco?")), } toolParams := []anthropic.ToolParam{ { Name: "get_weather", Description: anthropic.String("Get the current weather for a location"), InputSchema: anthropic.ToolInputSchemaParam{ Properties: map[string]any{ "location": map[string]any{ "type": "string", "description": "City and state, e.g. San Francisco, CA", }, "unit": map[string]any{ "type": "string", "enum": []string{"celsius", "fahrenheit"}, }, }, }, }, } tools := make([]anthropic.ToolUnionParam, len(toolParams)) for i, toolParam := range toolParams { tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam} } for { message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ Model: anthropic.ModelClaudeSonnet4_5_20250929, MaxTokens: 1024, Messages: messages, Tools: tools, }) if err != nil { panic(err) } messages = append(messages, message.ToParam()) toolResults := []anthropic.ContentBlockParamUnion{} for _, block := range message.Content { switch variant := block.AsAny().(type) { case anthropic.TextBlock: fmt.Printf("Claude: %s\n", variant.Text) case anthropic.ToolUseBlock: fmt.Printf("Tool call: %s(%s)\n", block.Name, variant.JSON.Input.Raw()) // Execute the tool and create result result := `{"temperature": 72, "unit": "fahrenheit", "condition": "sunny"}` toolResults = append(toolResults, anthropic.NewToolResultBlock(block.ID, result, false)) } } if len(toolResults) == 0 { break } messages = append(messages, anthropic.NewUserMessage(toolResults...)) } } ``` ## Tool Runner (Automatic Tool Execution) The Tool Runner framework automatically handles the tool use loop, calling your tool functions and managing the conversation flow. ```go package main import ( "context" "fmt" "strconv" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/toolrunner" ) type CalculatorInput struct { Operation string `json:"operation" jsonschema:"required,enum=add,subtract,multiply,divide"` A float64 `json:"a" jsonschema:"required"` B float64 `json:"b" jsonschema:"required"` } func calculate(ctx context.Context, calc CalculatorInput) (anthropic.BetaToolResultBlockParamContentUnion, error) { var result float64 switch calc.Operation { case "add": result = calc.A + calc.B case "subtract": result = calc.A - calc.B case "multiply": result = calc.A * calc.B case "divide": if calc.B == 0 { return anthropic.BetaToolResultBlockParamContentUnion{}, fmt.Errorf("division by zero") } result = calc.A / calc.B } return anthropic.BetaToolResultBlockParamContentUnion{ OfText: &anthropic.BetaTextBlockParam{Text: strconv.FormatFloat(result, 'g', -1, 64)}, }, nil } func main() { client := anthropic.NewClient() ctx := context.Background() calculatorTool, err := toolrunner.NewBetaToolFromJSONSchema( "calculator", "Perform basic arithmetic operations", calculate, ) if err != nil { panic(err) } runner := client.Beta.Messages.NewToolRunner( []anthropic.BetaTool{calculatorTool}, anthropic.BetaToolRunnerParams{ BetaMessageNewParams: anthropic.BetaMessageNewParams{ Model: anthropic.ModelClaudeSonnet4_20250514, MaxTokens: 1000, Messages: []anthropic.BetaMessageParam{ anthropic.NewBetaUserMessage( anthropic.NewBetaTextBlock("Calculate 15 * 23, then add 10 to the result"), ), }, }, MaxIterations: 5, }, ) finalMessage, err := runner.RunToCompletion(ctx) if err != nil { panic(err) } fmt.Printf("Final: %+v\n", finalMessage) } ``` ## Vision - Image Analysis Send images to Claude for analysis using base64 encoding or URL references. ```go package main import ( "context" "encoding/base64" "fmt" "io" "os" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() // Read and encode image file, err := os.Open("image.png") if err != nil { panic(err) } fileBytes, err := io.ReadAll(file) if err != nil { panic(err) } fileEncoded := base64.StdEncoding.EncodeToString(fileBytes) message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage( anthropic.NewTextBlock("What do you see in this image?"), anthropic.NewImageBlockBase64("image/png", fileEncoded), ), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) if err != nil { panic(err) } fmt.Printf("Analysis: %s\n", message.Content[0].Text) } ``` ## Structured Outputs with JSON Schema Request responses in a specific JSON schema format using the Beta Messages API with structured outputs. ```go package main import ( "context" "encoding/json" "fmt" "github.com/anthropics/anthropic-sdk-go" "github.com/invopop/jsonschema" ) type WeatherQuery struct { Location string `json:"location" jsonschema:"description=The city and state"` Units string `json:"units,omitempty" jsonschema:"enum=celsius,enum=fahrenheit"` Days int `json:"days" jsonschema:"minimum=1,maximum=7"` IncludeWind bool `json:"include_wind,omitempty"` } func main() { client := anthropic.NewClient() // Generate JSON schema from struct reflector := jsonschema.Reflector{ AllowAdditionalProperties: false, DoNotReference: true, } schema := reflector.Reflect(&WeatherQuery{}) schemaBytes, _ := json.Marshal(schema) var schemaMap map[string]any json.Unmarshal(schemaBytes, &schemaMap) msg, err := client.Beta.Messages.New(context.TODO(), anthropic.BetaMessageNewParams{ Model: anthropic.Model("claude-sonnet-4-5"), MaxTokens: 1024, Messages: []anthropic.BetaMessageParam{ anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock( "What's the weather in San Francisco for 3 days? Include wind.", )), }, OutputFormat: anthropic.BetaJSONSchemaOutputFormat(schemaMap), Betas: []anthropic.AnthropicBeta{"structured-outputs-2025-11-13"}, }) if err != nil { panic(err) } for _, block := range msg.Content { if v, ok := block.AsAny().(anthropic.BetaTextBlock); ok { fmt.Printf("Structured output: %s\n", v.Text) } } } ``` ## File Upload (Beta) Upload files to use in messages with the Beta Files API. ```go package main import ( "context" "fmt" "os" "github.com/anthropics/anthropic-sdk-go" ) func main() { ctx := context.Background() client := anthropic.NewClient() file, err := os.Open("document.txt") if err != nil { panic(err) } // Upload file uploadResult, err := client.Beta.Files.Upload(ctx, anthropic.BetaFileUploadParams{ File: anthropic.File(file, "document.txt", "text/plain"), Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14}, }) if err != nil { panic(err) } // Use file in message message, err := client.Beta.Messages.New(ctx, anthropic.BetaMessageNewParams{ MaxTokens: 1024, Messages: []anthropic.BetaMessageParam{ anthropic.NewBetaUserMessage( anthropic.NewBetaTextBlock("Summarize this document."), anthropic.NewBetaDocumentBlock(anthropic.BetaFileDocumentSourceParam{ FileID: uploadResult.ID, }), ), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, Betas: []anthropic.AnthropicBeta{anthropic.AnthropicBetaFilesAPI2025_04_14}, }) if err != nil { panic(err) } fmt.Printf("Summary: %s\n", message.Content[0].Text) } ``` ## Token Counting Count tokens in messages before sending them to estimate costs and ensure they fit within context limits. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() count, err := client.Messages.CountTokens(context.TODO(), anthropic.MessageCountTokensParams{ Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello, how are you today?")), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) if err != nil { panic(err) } fmt.Printf("Input tokens: %d\n", count.InputTokens) } ``` ## Message Batches Process large volumes of messages asynchronously with the Batches API for cost-effective bulk operations. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() ctx := context.Background() // Create a batch of requests batch, err := client.Messages.Batches.New(ctx, anthropic.MessageBatchNewParams{ Requests: []anthropic.BatchMessageRequest{ { CustomID: "request-1", Params: anthropic.MessageNewParams{ Model: anthropic.ModelClaudeSonnet4_5_20250929, MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What is 2+2?")), }, }, }, { CustomID: "request-2", Params: anthropic.MessageNewParams{ Model: anthropic.ModelClaudeSonnet4_5_20250929, MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("What is the capital of France?")), }, }, }, }, }) if err != nil { panic(err) } fmt.Printf("Batch created: %s, Status: %s\n", batch.ID, batch.ProcessingStatus) // Get batch status status, err := client.Messages.Batches.Get(ctx, batch.ID) if err != nil { panic(err) } fmt.Printf("Processing: %d/%d\n", status.RequestCounts.Processing, status.RequestCounts.Processing + status.RequestCounts.Succeeded) } ``` ## AWS Bedrock Integration Use Claude through AWS Bedrock by configuring the client with Bedrock options. ```go package main import ( "context" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/bedrock" ) func main() { client := anthropic.NewClient( bedrock.WithLoadDefaultConfig(context.Background()), ) message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from Bedrock!")), }, Model: "us.anthropic.claude-sonnet-4-5-20250929-v1:0", }) if err != nil { panic(err) } println(message.Content[0].Text) } ``` ## Google Cloud Vertex AI Integration Use Claude through Google Cloud Vertex AI with OAuth authentication. ```go package main import ( "context" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/vertex" ) func main() { client := anthropic.NewClient( vertex.WithGoogleAuth(context.Background(), "us-central1", "your-project-id"), ) message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello from Vertex AI!")), }, Model: "claude-sonnet-4-v1@20250514", }) if err != nil { panic(err) } println(message.Content[0].Text) } ``` ## MCP Server Integration Connect to Model Context Protocol servers for external tool access in streaming mode. ```go package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/option" "github.com/anthropics/anthropic-sdk-go/packages/param" ) func main() { client := anthropic.NewClient( option.WithHeader("anthropic-beta", anthropic.AnthropicBetaMCPClient2025_04_04), ) mcpServers := []anthropic.BetaRequestMCPServerURLDefinitionParam{ { URL: "http://example-server.modelcontextprotocol.io/sse", Name: "example", AuthorizationToken: param.NewOpt("YOUR_TOKEN"), ToolConfiguration: anthropic.BetaRequestMCPServerToolConfigurationParam{ Enabled: anthropic.Bool(true), AllowedTools: []string{"echo", "add"}, }, }, } stream := client.Beta.Messages.NewStreaming(context.TODO(), anthropic.BetaMessageNewParams{ MaxTokens: 1024, Messages: []anthropic.BetaMessageParam{ anthropic.NewBetaUserMessage(anthropic.NewBetaTextBlock("what is 1+1?")), }, MCPServers: mcpServers, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) message := anthropic.BetaMessage{} for stream.Next() { event := stream.Current() message.Accumulate(event) switch eventVariant := event.AsAny().(type) { case anthropic.BetaRawContentBlockDeltaEvent: if delta, ok := eventVariant.Delta.AsAny().(anthropic.BetaTextDelta); ok { fmt.Print(delta.Text) } } } if stream.Err() != nil { panic(stream.Err()) } } ``` ## Error Handling Handle API errors with detailed information about the failure including status codes and request IDs. ```go package main import ( "context" "errors" "fmt" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/internal/apierror" ) func main() { client := anthropic.NewClient() message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, }) if err != nil { var apiErr *apierror.Error if errors.As(err, &apiErr) { fmt.Printf("API Error: Status %d\n", apiErr.StatusCode) fmt.Printf("Request ID: %s\n", apiErr.RequestID) fmt.Printf("Raw response: %s\n", apiErr.RawJSON()) // Debug helpers fmt.Printf("Request dump:\n%s\n", apiErr.DumpRequest(true)) fmt.Printf("Response dump:\n%s\n", apiErr.DumpResponse(true)) } else { fmt.Printf("Other error: %v\n", err) } return } fmt.Printf("Success: %s\n", message.Content[0].Text) } ``` ## Available Models The SDK provides constants for available Claude models to ensure type safety and discoverability. ```go package main import ( "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { // Current models fmt.Println(anthropic.ModelClaudeOpus4_6) // claude-opus-4-6 fmt.Println(anthropic.ModelClaudeSonnet4_5_20250929) // claude-sonnet-4-5-20250929 fmt.Println(anthropic.ModelClaudeSonnet4_20250514) // claude-sonnet-4-20250514 fmt.Println(anthropic.ModelClaude3_5Haiku20241022) // claude-3-5-haiku-20241022 // Model aliases (latest versions) fmt.Println(anthropic.ModelClaudeOpus4Latest) // claude-opus-4-latest fmt.Println(anthropic.ModelClaudeSonnet4Latest) // claude-sonnet-4-latest } ``` ## Request Options Configure individual requests with options for headers, timeouts, retries, and middleware. ```go package main import ( "context" "fmt" "net/http" "time" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/option" ) func main() { client := anthropic.NewClient() // Custom logging middleware loggingMiddleware := func(req *http.Request, next option.MiddlewareNext) (*http.Response, error) { fmt.Printf("Request: %s %s\n", req.Method, req.URL) resp, err := next(req) if resp != nil { fmt.Printf("Response: %d\n", resp.StatusCode) } return resp, err } message, err := client.Messages.New( context.TODO(), anthropic.MessageNewParams{ MaxTokens: 1024, Messages: []anthropic.MessageParam{ anthropic.NewUserMessage(anthropic.NewTextBlock("Hello!")), }, Model: anthropic.ModelClaudeSonnet4_5_20250929, }, option.WithRequestTimeout(30*time.Second), option.WithMaxRetries(5), option.WithHeader("X-Custom-Header", "custom-value"), option.WithMiddleware(loggingMiddleware), ) if err != nil { panic(err) } fmt.Printf("Response: %s\n", message.Content[0].Text) } ``` ## Summary The Claude SDK for Go provides a complete solution for integrating Claude's AI capabilities into Go applications. The primary use cases include building chatbots and conversational interfaces, implementing AI-powered document analysis with vision capabilities, creating agent systems with tool use and function calling, processing large volumes of requests efficiently with batch operations, and integrating Claude into existing Go microservices architectures. For integration patterns, the SDK follows idiomatic Go conventions with functional options for configuration, context-based cancellation support, and comprehensive error handling. Applications can seamlessly switch between direct Anthropic API access, AWS Bedrock, or Google Cloud Vertex AI by simply changing client configuration options. The streaming API enables real-time response processing for interactive applications, while the batch API provides cost-effective processing for high-volume workloads. The Tool Runner framework simplifies agent development by automatically managing the tool use conversation loop.