---
title: SDK Options
description: Configuration options for the Kit Go SDK.
---

# SDK Options

Pass an `Options` struct to `kit.New()` to configure the Kit instance.

## Full options reference

```go
host, err := kit.New(ctx, &kit.Options{
    // Model
    Model:        "ollama/llama3",
    SystemPrompt: "You are a helpful bot",
    ConfigFile:   "/path/to/config.yml",

    // Behavior
    MaxSteps:     10,
    Streaming:    true,
    Quiet:        true,
    Debug:        true,

    // Generation parameters (override env/config/per-model defaults)
    MaxTokens:        16384,              // 0 = auto-resolve; non-zero suppresses right-sizing
    ThinkingLevel:    "medium",           // "off", "low", "medium", "high"
    Temperature:      ptrFloat32(0.2),    // pointer so explicit 0.0 != unset
    TopP:             nil,                 // nil = provider/per-model default
    TopK:             nil,
    FrequencyPenalty: nil,
    PresencePenalty:  nil,

    // Provider configuration
    ProviderAPIKey: "sk-...",                      // "" = use config / provider env var
    ProviderURL:    "https://proxy.internal/v1",  // "" = provider default endpoint
    TLSSkipVerify:  false,                         // only effective when true

    // Session
    SessionPath:  "./session.jsonl",
    SessionDir:   "/custom/sessions/",
    Continue:     true,
    NoSession:    true,

    // Tools
    Tools:            []kit.Tool{...},     // Replace default tool set entirely
    ExtraTools:       []kit.Tool{...},     // Add tools alongside defaults
    DisableCoreTools: true,                // Use no core tools (0 tools, for chat-only)

    // Configuration
    SkipConfig:   true,                   // Skip .kit.yml files (viper defaults + env vars still apply)

    // Compaction
    AutoCompact:  true,

    // Skills
    Skills:       []string{"/path/to/skill.md"},
    SkillsDir:    "/path/to/skills/",
    NoSkills:     true,

    // Feature toggles
    NoExtensions:   true,               // disable Yaegi extension loading
    NoContextFiles: true,               // disable automatic AGENTS.md loading

    // Session (advanced)
    SessionManager: myCustomSession,    // custom SessionManager implementation

    // MCP OAuth — both opt-in. Leave MCPAuthHandler nil to disable
    // OAuth entirely (remote MCP 401s bubble up as errors). CLI apps
    // pass kit.NewCLIMCPAuthHandler(); custom UX embedders implement
    // MCPAuthHandler or configure DefaultMCPAuthHandler + OnAuthURL.
    MCPAuthHandler: authHandler,                  // nil = OAuth disabled
    MCPTokenStoreFactory: func(serverURL string) (kit.MCPTokenStore, error) {
        return myStore(serverURL), nil
    },

    // In-Process MCP Servers
    InProcessMCPServers: map[string]*kit.MCPServer{
        "docs": mcpSrv,  // *server.MCPServer from mcp-go
    },
})
```

## Options fields

### Core

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `Model` | `string` | config default | Model string (provider/model format) |
| `SystemPrompt` | `string` | — | System prompt text or file path |
| `ConfigFile` | `string` | `~/.kit.yml` | Path to config file |
| `MaxSteps` | `int` | `0` | Max agent steps (0 = unlimited) |
| `Streaming` | `bool` | `true` | Enable streaming output |
| `Quiet` | `bool` | `false` | Suppress output |
| `Debug` | `bool` | `false` | Enable debug logging |

### Generation parameters

These fields override the corresponding values from `.kit.yml` / `KIT_*`
environment variables. Leaving a field at its zero/nil value lets the
precedence chain resolve a value (`KIT_*` env → config file → per-model
defaults from `modelSettings`/`customModels` → an 8192 SDK floor for
`MaxTokens` (matching the CLI `--max-tokens` default) and provider-level
defaults for samplers).

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `MaxTokens` | `int` | auto-resolved | Max output tokens per response. `0` = auto-resolve; non-zero suppresses automatic right-sizing (same semantics as `--max-tokens`). |
| `ThinkingLevel` | `string` | auto-resolved | Reasoning effort: `"off"`, `"low"`, `"medium"`, `"high"` (some providers also accept `"minimal"`). `""` falls through to config/env/per-model/`"off"`. |
| `Temperature` | `*float32` | — | Sampling randomness. Pointer type so explicit `0.0` is distinguishable from "unset". |
| `TopP` | `*float32` | — | Nucleus sampling cutoff. `nil` leaves provider/per-model default. |
| `TopK` | `*int32` | — | Top-K sampling limit. `nil` leaves provider/per-model default. |
| `FrequencyPenalty` | `*float32` | — | OpenAI-family frequency penalty. `nil` leaves provider default. |
| `PresencePenalty` | `*float32` | — | OpenAI-family presence penalty. `nil` leaves provider default. |

Pointer-typed samplers are populated via a tiny helper:

```go
func ptrFloat32(v float32) *float32 { return &v }
```

These fields eliminate the need for `viper.Set()` calls before `kit.New()`
when embedding Kit as a library.

### Provider configuration

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `ProviderAPIKey` | `string` | — | API key used to authenticate with the provider. `""` falls back to config / provider-specific env var (e.g. `ANTHROPIC_API_KEY`). When set, overrides any pre-existing viper state. |
| `ProviderURL` | `string` | — | Override the provider endpoint (e.g. LiteLLM, vLLM, Azure OpenAI, internal proxy). `""` = provider default. |
| `TLSSkipVerify` | `bool` | `false` | Disable TLS certificate verification on the provider HTTP client. Only effective when `true`; to force-disable, use config file or env var instead. For self-signed dev certs only. |

### Session

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `SessionPath` | `string` | — | Open a specific session file |
| `SessionDir` | `string` | — | Base directory for session discovery |
| `Continue` | `bool` | `false` | Resume most recent session |
| `NoSession` | `bool` | `false` | Ephemeral mode (no persistence) |
| `SessionManager` | `SessionManager` | — | Custom session backend (advanced) |

### Tools & extensions

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `Tools` | `[]Tool` | — | Replace the entire default tool set |
| `ExtraTools` | `[]Tool` | — | Additional tools alongside core/MCP/extension tools |
| `DisableCoreTools` | `bool` | `false` | Use no core tools (0 tools, for chat-only) |
| `NoExtensions` | `bool` | `false` | Disable Yaegi extension loading |
| `NoContextFiles` | `bool` | `false` | Disable automatic AGENTS.md loading |

### Skills & configuration

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `SkipConfig` | `bool` | `false` | Skip `.kit.yml` file loading (viper defaults + env vars still apply) |
| `Skills` | `[]string` | — | Explicit skill files/dirs to load |
| `SkillsDir` | `string` | — | Override default skills directory |
| `NoSkills` | `bool` | `false` | Disable skill loading entirely |

### Compaction & MCP

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `AutoCompact` | `bool` | `false` | Auto-compact when near context limit |
| `CompactionOptions` | `*CompactionOptions` | — | Configuration for auto-compaction |
| `MCPAuthHandler` | `MCPAuthHandler` | — | OAuth handler for remote MCP servers. `nil` disables OAuth (servers returning 401 fail with the authorization-required error). See [MCP OAuth](#mcp-oauth-authorization) below. |
| `MCPTokenStoreFactory` | `func` | — | Custom OAuth token storage for MCP servers (default: JSON file in `$XDG_CONFIG_HOME/.kit/mcp_tokens.json`). |
| `InProcessMCPServers` | `map[string]*MCPServer` | — | In-process mcp-go servers (no subprocess) |

## MCP OAuth Authorization

When a remote MCP server (SSE or Streamable HTTP) requires OAuth, Kit runs
the full authorization flow (dynamic client registration → PKCE → user
consent → token exchange → token persistence) but delegates the **user-facing
step** — displaying the authorization URL and receiving the callback — to
an `MCPAuthHandler`.

The SDK is deliberately inert when `MCPAuthHandler` is `nil`: it does **not**
auto-construct a default handler, bind a local TCP port, or open a browser.
This keeps library, daemon, and web-app embedders free of surprise I/O.
Consumers opt in by passing a handler explicitly.

| Building block | When to use |
|---|---|
| `MCPAuthHandler = nil` (default) | OAuth disabled. Remote MCP servers requiring auth fail with a clear error. Correct for libraries, daemons, and web apps. |
| `kit.NewCLIMCPAuthHandler()` | CLI/TUI apps. Opens the system browser, prints status to stderr (or via `NotifyFunc`), runs a localhost callback server. Used by the `kit` binary. |
| `kit.NewDefaultMCPAuthHandler()` + `OnAuthURL` | Custom UX. Use the SDK's port reservation and callback server; plug in your own presentation via the `OnAuthURL(serverName, authURL)` closure. |
| Implement `kit.MCPAuthHandler` directly | Full control. No localhost binding — e.g. return the URL from an HTTP endpoint and have the consumer POST the callback URL back. |

**CLI-style embedder:**

```go
authHandler, err := kit.NewCLIMCPAuthHandler()
if err != nil {
    log.Fatal(err)
}
defer authHandler.Close() // release the reserved port

host, _ := kit.New(ctx, &kit.Options{
    MCPAuthHandler: authHandler,
})
```

**Custom UX embedder (TUI modal, QR code, web redirect, etc.):**

```go
authHandler, _ := kit.NewDefaultMCPAuthHandler()
authHandler.OnAuthURL = func(serverName, authURL string) {
    // No browser or terminal assumptions — render however you like.
    myUI.ShowAuthPrompt(serverName, authURL)
}
defer authHandler.Close()

host, _ := kit.New(ctx, &kit.Options{
    MCPAuthHandler: authHandler,
})
```

**Fully custom handler (no local port binding at all):**

```go
type WebAuthHandler struct {
    redirectURI string
    callbacks   chan string
}

func (h *WebAuthHandler) RedirectURI() string { return h.redirectURI }

func (h *WebAuthHandler) HandleAuth(ctx context.Context, serverName, authURL string) (string, error) {
    // Push the URL to the user's existing browser session via your web app,
    // then block on the callback that your HTTP handler pushes onto the channel.
    h.pushToUserSession(serverName, authURL)
    select {
    case callbackURL := <-h.callbacks:
        return callbackURL, nil
    case <-ctx.Done():
        return "", ctx.Err()
    }
}
```

::: warning
`DefaultMCPAuthHandler` with no `OnAuthURL` set will silently drop the
authorization URL and hang until the 2-minute callback timeout fires. Always
set `OnAuthURL`, or use a higher-level wrapper like `CLIMCPAuthHandler`.
:::

## Precedence

For any given generation or provider field, the effective value is resolved
in this order (highest priority first):

1. `Options.X` (SDK caller)
2. `KIT_X` environment variable
3. `.kit.yml` (project-local then `~/.kit.yml`)
4. Per-model defaults (`modelSettings[provider/model]` or `customModels[...].params`)
5. Provider-level defaults (e.g. Anthropic's own temperature default)
6. SDK last-resort floor (currently: `MaxTokens = 8192`, matching the CLI `--max-tokens` default)

Sampling params that remain `nil` after the SDK resolution step are left out
of the provider call entirely, so the LLM library applies its own default.

## Tool configuration

**`Tools`** replaces ALL default tools (core + MCP + extension). **`ExtraTools`** adds tools alongside the defaults. Use `Tools` to restrict capabilities; use `ExtraTools` to extend them.

Create custom tools with `kit.NewTool` — no external dependencies needed:

```go
type LookupInput struct {
    ID string `json:"id" description:"Record ID to look up"`
}

lookupTool := kit.NewTool("lookup", "Look up a record by ID",
    func(ctx context.Context, input LookupInput) (kit.ToolOutput, error) {
        record := db.Find(input.ID)
        return kit.TextResult(record.String()), nil
    },
)

host, _ := kit.New(ctx, &kit.Options{
    ExtraTools: []kit.Tool{lookupTool},
})
```

See [Overview](/sdk/overview#custom-tools) for full custom tool documentation.
