Skip to content
Conduit

mcp server

bucephalus

a Go LLM client library that provides a unified API across multiple providers

i2y/bucephaluscommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 23, 2026

Bucephalus

A Go LLM client library that provides a unified API across multiple providers (OpenAI, Anthropic, Gemini).

Installation

go get github.com/i2y/bucephalus

Quick Start

package main

import (
    "context"
    "fmt"

    _ "github.com/i2y/bucephalus/anthropic"
    "github.com/i2y/bucephalus/llm"
)

func main() {
    ctx := context.Background()

    resp, err := llm.Call(ctx, "Hello, world!",
        llm.WithProvider("anthropic"),
        llm.WithModel("claude-sonnet-4-5-20250929"),
    )
    if err != nil {
        panic(err)
    }

    fmt.Println(resp.Text())
}

Features

Basic Calls

// Simple call
resp, _ := llm.Call(ctx, "What is Go?",
    llm.WithProvider("openai"),
    llm.WithModel("o4-mini"),
)
fmt.Println(resp.Text())

// Call with message array
messages := []llm.Message{
    llm.SystemMessage("You are a helpful assistant."),
    llm.UserMessage("Hello!"),
}
resp, _ := llm.CallMessages(ctx, messages, opts...)

Structured Output

type Recipe struct {
    Name        string   `json:"name"`
    Ingredients []string `json:"ingredients"`
}

resp, _ := llm.CallParse[Recipe](ctx, "Give me a pasta recipe", opts...)
recipe, _ := resp.Parsed()
fmt.Println(recipe.Name)

Note (Anthropic): Structured output requires Claude Sonnet 4.5, Claude Opus 4.1/4.5, or Claude Haiku 4.5. Older models like Claude Sonnet 4 do not support the output_format feature.

Streaming

stream, _ := llm.CallStream(ctx, "Tell me a story", opts...)
for chunk, err := range stream {
    if err != nil {
        break
    }
    fmt.Print(chunk.Text())
}

Multi-turn Conversations (Resume)

resp1, _ := llm.Call(ctx, "Recommend a book", opts...)
fmt.Println(resp1.Text())

// Continue the conversation
resp2, _ := resp1.Resume(ctx, "Why did you recommend that?")
fmt.Println(resp2.Text())

Tool Calling

weatherTool := llm.NewTool(
    "get_weather",
    "Get weather for a city",
    func(ctx context.Context, args struct{ City string }) (string, error) {
        return fmt.Sprintf("Weather in %s: Sunny, 22°C", args.City), nil
    },
)

resp, _ := llm.Call(ctx, "What's the weather in Tokyo?",
    llm.WithTools(weatherTool),
    opts...,
)

if resp.HasToolCalls() {
    results, _ := llm.ExecuteToolCalls(ctx, resp.ToolCalls(), registry)
    resp2, _ := resp.ResumeWithToolOutputs(ctx, results)
    fmt.Println(resp2.Text())
}

Built-in Tools

The tools package provides ready-to-use tools for common operations.

import "github.com/i2y/bucephalus/tools"

// Use all built-in tools
resp, _ := llm.Call(ctx, "Find all Go files with 'TODO' comments",
    llm.WithProvider("anthropic"),
    llm.WithModel("claude-sonnet-4-5-20250929"),
    llm.WithTools(tools.AllTools()...),
)

// Use specific tool groups
resp, _ := llm.Call(ctx, "Read the README.md file",
    llm.WithTools(tools.FileTools()...),
)

// Search Wikipedia
resp, _ := llm.Call(ctx, "What is Go programming language?",
    llm.WithTools(tools.KnowledgeTools()...),
)

Available Tools:

ToolDescription
ReadRead file contents with offset/limit support
WriteWrite content to a file (creates directories)
GlobFind files matching a glob pattern (**/*.go)
GrepSearch files with regular expressions
BashExecute shell commands with timeout
WebFetchFetch and extract content from URLs
WebSearchSearch the web (DuckDuckGo)
WikipediaSearch and retrieve Wikipedia articles

Tool Groups:

FunctionTools
AllTools()All 8 tools
FileTools()Read, Write, Glob, Grep
WebTools()WebFetch, WebSearch, Wikipedia
KnowledgeTools()WebSearch, Wikipedia
ReadOnlyTools()Read, Glob, Grep, WebFetch, WebSearch, Wikipedia
SystemTools()Write, Bash

MCP Integration

Integrate with Model Context Protocol servers using the official Go SDK.

import "github.com/i2y/bucephalus/mcp"

// Get tools from an MCP server
tools, cleanup, err := mcp.ToolsFromMCP(ctx, "./my-mcp-server", nil)
if err != nil {
    return err
}
defer cleanup()

// Use MCP tools with LLM
resp, _ := llm.Call(ctx, "List files in current directory",
    llm.WithProvider("openai"),
    llm.WithModel("o4-mini"),
    llm.WithTools(tools...),
)

Plugin Support (Claude Code-style)

Load plugins using a directory structure similar to Claude Code.

import "github.com/i2y/bucephalus/plugin"

p, _ := plugin.Load("./my-plugin")

// Command expansion with $ARGUMENTS substitution
expanded, _ := p.ExpandCommand("/translate Hello World")
resp, _ := llm.Call(ctx, expanded.Arguments, expanded.ToOption())

// Auto-detect slash commands
opt, userMsg, _ := p.ProcessInput("/greet John")
resp, _ := llm.Call(ctx, userMsg, opt, otherOpts...)

// Use skill context
skill := p.GetSkill("code-review")
resp, _ := llm.Call(ctx, "Review this code", skill.ToOption())

// Run agent with conversation context
agent := p.GetAgent("helper")
runner := agent.NewRunner(
    plugin.WithAgentProvider("anthropic"),
    plugin.WithAgentModel("claude-sonnet-4-5-20250929"),
    plugin.WithAgentTools(tools...),  // Filtered by agent.Tools
    // Pass additional llm.Options for all Run() calls
    plugin.WithAgentLLMOptions(
        llm.WithTopP(0.9),
        llm.WithSystemMessage(p.SkillsIndexSystemMessage()),
    ),
)

// Multi-turn conversation - context is maintained across calls
resp1, _ := runner.Run(ctx, "My name is Alice")
resp2, _ := runner.Run(ctx, "What is my name?")  // Remembers "Alice"

// Pass options for a specific Run() call only
resp3, _ := runner.Run(ctx, "Help me with this task",
    plugin.WithRunSystemMessage("Extra context for this call"),
    plugin.WithRunLLMOptions(llm.WithTemperature(0.5)),
)

// Access conversation history and state
history := runner.Context().History()
runner.Context().SetState("user_id", 123)
runner.ClearHistory()  // Clear conversation, keep state

// Progressive Disclosure (Claude Code style)
// Include only metadata in system prompt, load full content when needed
indexMsg := p.PluginIndexSystemMessage()  // ~60% smaller than full content
resp, _ := llm.Call(ctx, "Help me with code quality",
    llm.WithSystemMessage(indexMsg),  // Compact skills/commands list
)

Supported structure:

  • .claude-plugin/plugin.json - Manifest
  • commands/*.md - Slash commands (with $ARGUMENTS substitution)
  • agents/*.md - Sub-agents (with conversation context)
  • skills/*/SKILL.md - Skills

Options

LLM Call Options

OptionDescription
WithProvider(name)Select provider ("openai", "anthropic", "gemini")
WithModel(name)Select model
WithTemperature(t)Sampling temperature (0.0-2.0)
WithMaxTokens(n)Maximum tokens
WithTopP(p)Nucleus sampling
WithTopK(k)Top-K (Anthropic, Gemini)
WithSeed(s)Seed value (OpenAI only)
WithStopSequences(...)Stop sequences
WithSystemMessage(msg)System message
WithTools(...)Tool definitions

AgentRunner Options

OptionDescription
WithAgentProvider(name)Set provider for the agent
WithAgentModel(name)Set model for the agent
WithAgentTools(...)Provide tools (filtered by agent.Tools)
WithAgentTemperature(t)Set temperature
WithAgentMaxTokens(n)Set max tokens
WithAgentContext(ctx)Share context between agents
WithAgentLLMOptions(...)Pass additional llm.Options for all Run() calls

Run Options (per-call)

OptionDescription
WithRunSystemMessage(msg)Add extra system message for this call only
WithRunLLMOptions(...)Add extra llm.Options for this call only

Package Structure

llm/          # Public API
provider/     # Provider interface
openai/       # OpenAI implementation
anthropic/    # Anthropic implementation
gemini/       # Google Gemini implementation
schema/       # JSON schema generation
mcp/          # Model Context Protocol integration (official Go SDK)
plugin/       # Claude Code Plugin loader
tools/        # Built-in tools (Read, Write, Glob, Grep, Bash, Web)

License

MIT

↑↓ navigate openesc close