Skip to content

Commit bddd810

Browse files
author
Marek Safarik
committed
added ollama provider (compatible with anthropic)
Signed-off-by: Marek Safarik <msafarik@redhat.com>
1 parent 5f5a632 commit bddd810

File tree

2 files changed

+55
-23
lines changed

2 files changed

+55
-23
lines changed

cmd/client/main.go

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
const (
1818
defaultServerPath = "./server"
1919
defaultPort = "3000"
20+
defaultOllamaURL = "http://localhost:11434"
2021
envFileLocation = "./../.env"
2122
)
2223

@@ -46,22 +47,20 @@ func main() {
4647
port = defaultPort
4748
}
4849

49-
apiKey := strings.TrimSpace(os.Getenv("ANTHROPIC_API_KEY"))
50-
if apiKey == "" {
51-
log.Println("ANTHROPIC_API_KEY environment variable not set")
52-
return
53-
}
54-
5550
if _, err := os.Stat(serverPath); os.IsNotExist(err) { // #nosec G703 -- serverPath from env/default, not user input
5651
log.Printf("Warning: MCP server not found at %s", serverPath)
5752
log.Printf("Build the server first: go build -o bin/server cmd/server/main.go")
5853
return
5954
}
6055

61-
provider := agent.NewClaudeProvider(apiKey)
62-
agentInstance := agent.NewAgent(agent.Config{
63-
ServerPath: serverPath,
64-
}, provider)
56+
provider, model := createProvider()
57+
58+
cfg := agent.Config{ServerPath: serverPath}
59+
if model != "" {
60+
cfg.Model = model
61+
}
62+
63+
agentInstance := agent.NewAgent(cfg, provider)
6564

6665
if err := agentInstance.Connect(ctx); err != nil {
6766
log.Printf("Failed to connect to MCP server: %v", err)
@@ -89,3 +88,27 @@ func main() {
8988
return
9089
}
9190
}
91+
92+
// createProvider selects the LLM provider based on environment variables.
93+
// OLLAMA_URL or OLLAMA_MODEL → local Ollama (Anthropic-compatible API)
94+
// ANTHROPIC_API_KEY → Claude cloud API
95+
func createProvider() (agent.LLMProvider, string) {
96+
ollamaURL := os.Getenv("OLLAMA_URL")
97+
ollamaModel := os.Getenv("OLLAMA_MODEL")
98+
99+
if ollamaURL != "" || ollamaModel != "" {
100+
if ollamaURL == "" {
101+
ollamaURL = defaultOllamaURL
102+
}
103+
log.Printf("Using Ollama provider at %s", ollamaURL)
104+
return agent.NewOllamaProvider(ollamaURL), ollamaModel
105+
}
106+
107+
apiKey := strings.TrimSpace(os.Getenv("ANTHROPIC_API_KEY"))
108+
if apiKey == "" {
109+
log.Fatal("Set ANTHROPIC_API_KEY for Claude or OLLAMA_URL/OLLAMA_MODEL for local Ollama")
110+
}
111+
112+
log.Printf("Using Claude provider")
113+
return agent.NewClaudeProvider(apiKey), ""
114+
}
Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,28 @@ import (
99
"github.com/modelcontextprotocol/go-sdk/mcp"
1010
)
1111

12-
type ClaudeProvider struct {
12+
type AnthropicProvider struct {
1313
client anthropic.Client
1414
}
1515

16-
func NewClaudeProvider(apiKey string) *ClaudeProvider {
17-
return &ClaudeProvider{
16+
func NewClaudeProvider(apiKey string) *AnthropicProvider {
17+
return &AnthropicProvider{
1818
client: anthropic.NewClient(option.WithAPIKey(apiKey)),
1919
}
2020
}
2121

22-
func (p *ClaudeProvider) Chat(ctx context.Context, opts ChatOptions) (*LLMResponse, error) {
23-
messages := convertMessagesToClaude(opts.Messages)
24-
tools := convertToolsToClaude(opts.Tools)
22+
func NewOllamaProvider(baseURL string) *AnthropicProvider {
23+
return &AnthropicProvider{
24+
client: anthropic.NewClient(
25+
option.WithBaseURL(baseURL),
26+
option.WithAPIKey("ollama"),
27+
),
28+
}
29+
}
30+
31+
func (p *AnthropicProvider) Chat(ctx context.Context, opts ChatOptions) (*LLMResponse, error) {
32+
messages := convertMessagesToAnthropic(opts.Messages)
33+
tools := convertToolsToAnthropic(opts.Tools)
2534

2635
response, err := p.client.Messages.New(ctx, anthropic.MessageNewParams{
2736
Model: anthropic.Model(opts.Model),
@@ -31,13 +40,13 @@ func (p *ClaudeProvider) Chat(ctx context.Context, opts ChatOptions) (*LLMRespon
3140
Tools: tools,
3241
})
3342
if err != nil {
34-
return nil, fmt.Errorf("claude API error: %w", err)
43+
return nil, fmt.Errorf("LLM API error: %w", err)
3544
}
3645

37-
return parseClaudeResponse(response), nil
46+
return parseAnthropicResponse(response), nil
3847
}
3948

40-
func convertMessagesToClaude(messages []Message) []anthropic.MessageParam {
49+
func convertMessagesToAnthropic(messages []Message) []anthropic.MessageParam {
4150
result := make([]anthropic.MessageParam, 0, len(messages))
4251

4352
i := 0
@@ -77,15 +86,15 @@ func convertMessagesToClaude(messages []Message) []anthropic.MessageParam {
7786
return result
7887
}
7988

80-
func convertToolsToClaude(tools []*mcp.Tool) []anthropic.ToolUnionParam {
89+
func convertToolsToAnthropic(tools []*mcp.Tool) []anthropic.ToolUnionParam {
8190
result := make([]anthropic.ToolUnionParam, 0, len(tools))
8291
for _, tool := range tools {
83-
result = append(result, convertMCPToolToClaude(tool))
92+
result = append(result, convertMCPToolToAnthropic(tool))
8493
}
8594
return result
8695
}
8796

88-
func convertMCPToolToClaude(tool *mcp.Tool) anthropic.ToolUnionParam {
97+
func convertMCPToolToAnthropic(tool *mcp.Tool) anthropic.ToolUnionParam {
8998
inputSchemaMap, ok := tool.InputSchema.(map[string]any)
9099
if !ok || inputSchemaMap == nil {
91100
inputSchemaMap = map[string]any{}
@@ -120,7 +129,7 @@ func convertMCPToolToClaude(tool *mcp.Tool) anthropic.ToolUnionParam {
120129
return toolParam
121130
}
122131

123-
func parseClaudeResponse(response *anthropic.Message) *LLMResponse {
132+
func parseAnthropicResponse(response *anthropic.Message) *LLMResponse {
124133
result := &LLMResponse{}
125134

126135
for _, block := range response.Content {

0 commit comments

Comments
 (0)