Skip to main content
Bifrost uses BifrostContext — a custom context.Context — to pass configuration and metadata through the request lifecycle. Context keys allow you to customize request behavior, pass request-specific settings, and read metadata set by Bifrost. The idiomatic pattern is to create a BifrostContext and call SetValue (or the chainable WithValue) directly on it:
bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeyRequestID, "req-001")

response, err := client.ChatCompletionRequest(bfCtx, &schemas.BifrostChatRequest{...})

Request Configuration Keys

These keys can be set before making a request to customize behavior.

Virtual Key

Pass a virtual key identifier to the governance plugin for budget and rate-limit enforcement.
bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeyVirtualKey, "vk-my-team")

Extra Headers

Pass custom headers with individual requests. Headers are automatically propagated to the provider.
bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeyExtraHeaders, map[string][]string{
    "user-id":    {"user-123"},
    "session-id": {"session-abc"},
})

response, err := client.ChatCompletionRequest(bfCtx, &schemas.BifrostChatRequest{
    Provider: schemas.OpenAI,
    Model:    "gpt-4o-mini",
    Input:    messages,
})
See Custom Headers Per Request for detailed information on header handling and security restrictions.

API Key Selection

Bifrost supports selecting a specific key by ID or name. When both are present, ID takes priority.

By ID

Explicitly select a key by its unique ID.
bfCtx.SetValue(schemas.BifrostContextKeyAPIKeyID, "key-uuid-1234")

By Name

Explicitly select a named API key from your configured keys.
bfCtx.SetValue(schemas.BifrostContextKeyAPIKeyName, "premium-key")

Direct Key

Provide credentials directly, bypassing Bifrost’s key selection entirely. Useful for dynamic or per-request key scenarios.
bfCtx.SetValue(schemas.BifrostContextKeyDirectKey, schemas.Key{
    Value:  "sk-direct-api-key",
    Models: []string{"gpt-4o"},
    Weight: 1.0,
})

Skip Key Selection

Skip key selection entirely and pass an empty key to the provider. Useful for providers that don’t require authentication or when using ambient credentials (e.g., IAM roles).
bfCtx.SetValue(schemas.BifrostContextKeySkipKeySelection, true)

Session Stickiness (Session ID)

Bind a session to a specific API key so that requests with the same session ID consistently use the same key. Useful for predictable rate-limit buckets, cost attribution per user, and consistent model routing per session. On the first request for a session ID, Bifrost selects a key (via weighted random) and caches the binding in the KV store. Subsequent requests with the same session ID reuse the cached key as long as it remains valid. If the cached key is no longer in the supported set (disabled, removed, or model support changed), Bifrost re-selects and overwrites the cache.
Session stickiness requires a KVStore to be configured in BifrostConfig.
bfCtx.SetValue(schemas.BifrostContextKeySessionID, "user-123-session-abc")

Session TTL

Controls how long the session-to-key binding is cached. If not set, Bifrost uses a default TTL of 1 hour. The TTL is refreshed on each request so active sessions do not expire.
bfCtx.SetValue(schemas.BifrostContextKeySessionTTL, 30*time.Minute)

Request ID

Set a custom request ID for tracking and correlation.
bfCtx.SetValue(schemas.BifrostContextKeyRequestID, "req-12345-abc")

Custom URL Path

Append a custom path to the provider’s base URL. Useful for accessing provider-specific endpoints.
bfCtx.SetValue(schemas.BifrostContextKeyURLPath, "/custom/endpoint")

Stream Idle Timeout

Set a per-chunk idle timeout for streaming responses. If no chunk arrives within this duration, the stream is considered stalled and cancelled.
bfCtx.SetValue(schemas.BifrostContextKeyStreamIdleTimeout, 10*time.Second)

Raw Request Body

Send a raw request body instead of Bifrost’s standardized format. The provider receives your payload as-is. You must both set the context key AND populate RawRequestBody on the request.
rawPayload := []byte(`{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Hello!"}],
    "custom_field": "provider-specific-value"
}`)

bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeyUseRawRequestBody, true)

response, err := client.ChatCompletionRequest(bfCtx, &schemas.BifrostChatRequest{
    Provider:       schemas.OpenAI,
    Model:          "gpt-4o",
    RawRequestBody: rawPayload,
})
When using raw request body, Bifrost bypasses its request conversion and sends your payload directly to the provider. You are responsible for ensuring the payload matches the provider’s expected format.

Send Back Raw Request/Response

Include the original request or response bytes in ExtraFields for debugging.
bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeySendBackRawRequest, true)
bfCtx.SetValue(schemas.BifrostContextKeySendBackRawResponse, true)

response, _ := client.ChatCompletionRequest(bfCtx, request)
if response.ChatResponse != nil {
    rawReq := response.ChatResponse.ExtraFields.RawRequest
    rawResp := response.ChatResponse.ExtraFields.RawResponse
}

Passthrough Extra Parameters

When enabled, any parameters in ExtraParams are merged directly into the JSON body sent to the provider, bypassing Bifrost’s parameter filtering. Useful for provider-specific parameters that Bifrost doesn’t natively support.
bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)
bfCtx.SetValue(schemas.BifrostContextKeyPassthroughExtraParams, true)

response, err := client.ChatCompletionRequest(bfCtx, &schemas.BifrostChatRequest{
    Provider: schemas.OpenAI,
    Model:    "gpt-4o-mini",
    Input:    messages,
    Params: &schemas.ChatParameters{
        ExtraParams: map[string]interface{}{
            "custom_param": "value",
            "another_param": 123,
            "nested_param": map[string]interface{}{
                "nested_key": "nested_value",
            },
        },
    },
})
  • This feature only works for JSON requests, not multipart/form-data requests
  • Parameters already handled by Bifrost are not duplicated — they appear in their proper location
  • Nested parameters are merged recursively with existing nested structures

MCP Context Keys

These keys control MCP tool execution behavior on a per-request basis. Request-level filtering takes priority over client-level configuration.

Include Clients

Restrict which MCP clients can provide tools for this request. Pass []string{"*"} to include all clients, or an empty slice to exclude all.
bfCtx.SetValue(schemas.MCPContextKeyIncludeClients, []string{"github", "filesystem"})

Include Tools

Restrict which tools are available for this request. Use "clientName-toolName" format for individual tools or "clientName-*" as a wildcard for all tools from a client.
// Allow only the search tool from the github client
bfCtx.SetValue(schemas.MCPContextKeyIncludeTools, []string{"github-search_repositories"})

// Allow all tools from filesystem client
bfCtx.SetValue(schemas.MCPContextKeyIncludeTools, []string{"filesystem-*"})

MCP Extra Headers

Forward additional headers to MCP servers during tool execution. Only headers present in the MCP client’s configured allowlist are forwarded.
bfCtx.SetValue(schemas.BifrostContextKeyMCPExtraHeaders, map[string][]string{
    "x-user-id":    {"user-123"},
    "x-session-id": {"session-abc"},
})

Response Metadata Keys

These keys are set by Bifrost and can be read from the context after a request completes. They are particularly useful in plugins and post-hooks.

Selected Key Information

After Bifrost selects an API key, it stores the selection details in the context.
keyID := ctx.Value(schemas.BifrostContextKeySelectedKeyID).(string)
keyName := ctx.Value(schemas.BifrostContextKeySelectedKeyName).(string)

Retry and Fallback Information

Track retry attempts and fallback progression.
// Number of retries attempted (0 = first attempt)
retries := ctx.Value(schemas.BifrostContextKeyNumberOfRetries).(int)

// Fallback index (0 = primary, 1 = first fallback, etc.)
fallbackIdx := ctx.Value(schemas.BifrostContextKeyFallbackIndex).(int)

// Request ID used for the fallback attempt
fallbackReqID := ctx.Value(schemas.BifrostContextKeyFallbackRequestID).(string)

Stream End Indicator

For streaming responses, indicates when the stream has completed. Set by Bifrost automatically.
isStreamEnd := ctx.Value(schemas.BifrostContextKeyStreamEndIndicator).(bool)
Plugin developers: When implementing a short-circuit streaming response in PreLLMHook or PostLLMHook, set BifrostContextKeyStreamEndIndicator to true on the last chunk to trigger proper cleanup.

Integration Type

Identifies which SDK integration format is in use (useful in gateway plugins).
integrationType := ctx.Value(schemas.BifrostContextKeyIntegrationType).(string)
// e.g., "openai", "anthropic", "bedrock"

Complete Example

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/maximhq/bifrost"
    "github.com/maximhq/bifrost/core/schemas"
)

func makeRequest(client *bifrost.Bifrost) {
    bfCtx := schemas.NewBifrostContext(context.Background(), schemas.NoDeadline)

    // Request tracking
    bfCtx.SetValue(schemas.BifrostContextKeyRequestID, "req-001")

    // Custom headers forwarded to the provider
    bfCtx.SetValue(schemas.BifrostContextKeyExtraHeaders, map[string][]string{
        "x-correlation-id": {"corr-12345"},
        "x-tenant-id":      {"tenant-abc"},
    })

    // Include raw provider response for debugging
    bfCtx.SetValue(schemas.BifrostContextKeySendBackRawResponse, true)

    // Restrict MCP tools to a specific client
    bfCtx.SetValue(schemas.MCPContextKeyIncludeClients, []string{"filesystem"})

    messages := []schemas.BifrostMessage{
        {Role: "user", Content: &schemas.BifrostMessageContent{Text: bifrost.Ptr("Hello!")}},
    }

    response, err := client.ChatCompletionRequest(bfCtx, &schemas.BifrostChatRequest{
        Provider: schemas.OpenAI,
        Model:    "gpt-4o-mini",
        Input:    messages,
    })
    if err != nil {
        log.Printf("Request failed: %v", err)
        return
    }

    if response.ChatResponse != nil {
        extra := response.ChatResponse.ExtraFields
        fmt.Printf("Provider: %s\n", extra.Provider)
        fmt.Printf("Latency: %dms\n", extra.Latency)
        if extra.RawResponse != nil {
            fmt.Println("Raw response captured for debugging")
        }
    }
}

Context Keys Reference

KeyTypeDirectionDescription
BifrostContextKeyVirtualKeystringSetVirtual key identifier for governance
BifrostContextKeyAPIKeyNamestringSetExplicit API key name selection
BifrostContextKeyAPIKeyIDstringSetExplicit API key ID selection (priority over name)
BifrostContextKeyRequestIDstringSetCustom request ID for tracking
BifrostContextKeyFallbackRequestIDstringReadRequest ID used for fallback attempt
BifrostContextKeyDirectKeyschemas.KeySetProvide credentials directly, bypassing key selection
BifrostContextKeySkipKeySelectionboolSetSkip key selection entirely
BifrostContextKeySessionIDstringSetSession ID for key stickiness (requires KV store)
BifrostContextKeySessionTTLtime.DurationSetTTL for session-to-key cache (default: 1 hour)
BifrostContextKeyExtraHeadersmap[string][]stringSetCustom headers forwarded to the provider
BifrostContextKeyURLPathstringSetCustom URL path appended to provider base URL
BifrostContextKeyStreamIdleTimeouttime.DurationSetPer-chunk idle timeout for streaming responses
BifrostContextKeyUseRawRequestBodyboolSetSend raw request body directly to provider
BifrostContextKeySendBackRawRequestboolSetInclude raw request in ExtraFields
BifrostContextKeySendBackRawResponseboolSetInclude raw provider response in ExtraFields
BifrostContextKeyPassthroughExtraParamsboolSetMerge ExtraParams directly into provider request
MCPContextKeyIncludeClients[]stringSetAllowlist of MCP client names for this request
MCPContextKeyIncludeTools[]stringSetAllowlist of MCP tools ("client-tool" or "client-*")
BifrostContextKeyMCPExtraHeadersmap[string][]stringSetExtra headers forwarded to MCP servers during tool execution
BifrostContextKeySelectedKeyIDstringReadID of the key selected by Bifrost
BifrostContextKeySelectedKeyNamestringReadName of the key selected by Bifrost
BifrostContextKeyNumberOfRetriesintReadNumber of retry attempts made
BifrostContextKeyFallbackIndexintReadCurrent fallback index (0 = primary)
BifrostContextKeyStreamEndIndicatorboolReadWhether the stream has completed
BifrostContextKeyIntegrationTypestringReadSDK integration format in use (e.g. "openai")
BifrostContextKeyUserAgentstringReadUser agent of the incoming request

Next Steps