github maximhq/bifrost transports/v2.3.1
Bifrost HTTP v2.3.1

2 hours ago

Bifrost HTTP Transport Release v2.3.1

✨ Features

  • OpenAPI MCP Servers - New openapi MCP connection type. Bifrost turns an OpenAPI or Swagger document (inline spec, config.json-only spec_file, or spec_url, capped at 5 MiB) into an in-process MCP server where each operation is a tool that calls the upstream API, with security_credentials per security scheme, an optional base_url, include_deprecated and max_response_bytes. Configure it in config.json, the MCP management API, or the new OpenAPI option in the New MCP Server sheet, which can also replace the document later. Go SDK users opt in with MCPConfig.InProcessServerFactory (#8307, #8308, #8309, #8310, #8311, #8312, #8313, #8314, #8315, #8558)
  • Gateway Tool Search - Requests that defer tools with defer_loading on a model with no tool search of its own (Gemini, older GPT, Bedrock non-Claude) no longer get every tool loaded up front or a rejection. The deferred tools sit behind a bifrost_tool_search function that Bifrost resolves in the gateway (select: or BM25, at most 3 model calls per request), on both non-streaming and streaming Responses requests (#8504, #8505)
  • Passthrough Logs as Conversations - With content logging on, passthrough calls (/openai_passthrough, /anthropic_passthrough, /genai_passthrough, ...) are parsed into the same fields as typed requests: chat, Responses, Anthropic messages, Gemini, embeddings, speech, transcription and images. Streamed responses are rebuilt from the recorded SSE, and multipart uploads are logged as a form summary. Rows are stored under their inferred request type with an is_passthrough flag, count in per-type filters, render as a conversation in the log sheet, and keep the raw bodies alongside (#8516, #8517, #8518, #8519, #8520, #8521, #8522, #8523, #8524, #8525)
  • Extra Fields as Response Headers - New client.extra_fields_placement setting: body (default, unchanged behaviour) or headers. With headers, inference responses drop the extra_fields object from the body and send it as x-bifrost-* response headers on native and integration routes, unary and streaming. Set it in Client Settings, the config API or config.json (#8476, #8477, #8478)
  • Virtual Key Metadata - Virtual keys carry string key/value metadata (for example cost_center, owner; keys use letters, digits, ., _ and -, values up to 512 characters, up to 50 entries) set from config.json, Helm (bifrost.governance.virtualKeys[].metadata), the API (omit to keep, {} to clear) or the virtual key sheet. The list API filters by metadata_<key>=<value> and search matches metadata. Each log carries a snapshot of its key's metadata, so logs and spend filter by it, and the key's values override x-bf-lh-*, logging headers and x-bf-dim-* dimensions so callers cannot spoof attribution (#7934, #7935, #7936, #7937, #8680) (thanks @jimseiwert!)
  • News Feeds - The notification tray has a News tab with product and provider announcements from RSS and Atom feeds (Bifrost, OpenAI, Anthropic, Gemini and Cursor built in). Admins toggle built-in feeds and add custom ones with their own logo; the gateway fetches, caches and merges them server-side through /api/rss/feeds and /api/rss/items (#8537, #8538, #8539, #8540)
  • Code Mode Scripting - The Starlark sandbox adds the json and math modules. A failed nested tool call reaches the script as an error value (hasattr(r, "error"), r.error) instead of a plain string, the executeToolCode reply carries only what the script prints and returns, runtime errors include a Python-style traceback, and error hints match the messages the interpreter actually emits (#8605, #8606, #8607, #8692, #8693)
  • Native Decisions on Azure and Databricks - /v1/decisions reaches Microsoft's Microsoft-Decision-1 on Azure (Foundry /providers/microsoft/v1/systemone, with API key, Entra ID or managed identity auth) and Databricks ai_decide. Typesafe accepts images by reference and answers box questions (#8485, #8498, #8571)
  • Vertex Session Routing - Vertex keys accept use_session_routing: true, which sends the request's prompt cache key as sessionId on Gemini generateContent calls so requests sharing a prefix reach the same replica's implicit cache. Off by default, since Google enables it per project (#8650)
  • Secret References in Extra Headers - network_config.extra_headers values accept env. and vault. references. Values are masked in API responses and restored on save, and the network form and the Databricks and Cloudflare migration planners treat masked values as unreadable (#8618, #8619, #8620)
  • Prompt Caching on Tool Calls - cache_control on an assistant message's tool_calls entry on /v1/chat/completions now reaches the Anthropic and Bedrock tool_use block instead of being dropped (#8494, #8495)
  • Mistral Thinking Blocks - Mistral streams that carry thinking blocks in delta.content arrays map them to reasoning instead of failing, and assistant reasoning is dropped before a request is sent, so replayed multi-turn conversations no longer hit Mistral's 422 extra_forbidden (#8567, #8612)
  • Observability Attributes - Spans and Prometheus metrics carry the stored prompt a request ran (bifrost.prompt.id, name, version), MCP spans carry the client name and bifrost.mcp.tool.is_error when a tool reports failure, and the inbound W3C tracestate is captured for connectors. A2A operations export bodies, stream updates and the a2a.client.operation.duration metric to OTel, Maxim and telemetry, and gRPC ingress keeps caller request and trace IDs (#8575, #8681, #8682, #8683)
  • Calendar Date Presets - The date filter adds Today, This week and This month. The server resolves them in the caller's time zone (#8592)
  • MCP OAuth Redirect URI Wildcard - oauth2_server_config.allowed_redirect_uris syncs from config.json and accepts a bare "*" to approve any remote callback (shape checks still apply; partial patterns return 400). A startup warning and a dashboard alert flag the wildcard, and the MCP settings page has an Allowed redirect URIs input (#8480)
  • Antigravity Client Detection - Requests from Antigravity CLI and Antigravity Desktop are logged as their own apps instead of Other or Gemini CLI, including behind the edge proxy (#8543, #8658)

🐞 Fixed

  • Go Module Path - The transports module is now published as github.com/maximhq/bifrost/transports/v2, so go get resolves the v2.x tags (#8450)

    Go code that imports github.com/maximhq/bifrost/transports/bifrost-http/... must switch to github.com/maximhq/bifrost/transports/v2/bifrost-http/....
  • Explicit Public URLs for Agent Gateway and Skills - Bifrost no longer builds agent-card endpoints or skills marketplace clone URLs from the incoming Host header, which a caller controls. These URLs come only from the configured public URL; an existing mcp_external_client_url is copied to the new skills_external_client_url on upgrade when it is a public URL. The MCP settings page also requires an Issuer URL in OAuth and Both modes (#8484, #8526)

    If your Agent Gateway or skills marketplace relied on the request host, set the public URL explicitly before upgrading, or clients receive no usable agent-card endpoint.
  • Agent Gateway Destination Permissions - Card discovery, OAuth and JSON-RPC, REST and gRPC runtime connections (including through a proxy) only reach approved destinations and only forward credentials to permitted origins, per agent credential_origins and require_public_target. The unused tenant and extension_uris registration options are removed (#8552)
  • A2A Idle Goroutine Leak - The A2A push relay no longer leaks one goroutine every 3 seconds (about 1,200 per hour on v2.3.0, until OOM), and ClickHouse no longer issues a heavyweight agent_logs mutation every minute when no rows match (#8596)
  • Calendar-Aligned Reset Windows - Calendar-aligned budgets and rate limits honour the duration multiplier, so a 7d budget no longer resets daily and a 2w limit no longer resets weekly (#8596)
  • Agent OAuth Cache and ClickHouse Contention - The Agent Gateway OAuth token and fingerprint caches are bounded at 5,000 entries (about 12 MB) with expired entries evicted first, and a failed token fetch drops its stale entry. ClickHouse agent-log correlation no longer loads large payload columns or rewrites complete rows, so large A2A responses no longer back up the logging queue (#8608, #8617, #8657)
  • Request Body Memory Retention - Pooled keep-alive connections no longer keep their largest-ever request-body buffer, which made per-pod memory ratchet up with large LLM payloads. Buffers above server.body_buffer_pool_limit_bytes (default 4 MiB) are released after each request; larger bodies are still accepted up to max_request_body_size_mb. Set a negative value to restore the previous behaviour. Async jobs (x-bf-async) that forward the raw body now copy it instead of reading a buffer the next request can overwrite (#8602)
  • Oversized Request Bodies - A body above client_config.max_request_body_size_mb returns 413 with request_too_large and the configured limit, and logs a warning, instead of a generic 400 Error when parsing request (#8700)
  • Rolling Upgrade Migrations - Postgres migrations wait for a live CREATE INDEX CONCURRENTLY from a killed pod instead of dropping it, logstore upgrade migrations no longer stall behind long queries on old replicas, and the Helm chart adds a configurable startupProbe (#8479, #8572)
  • OpenAI-Compatible xhigh Reasoning Effort - reasoning_effort: "xhigh" is forwarded to vLLM, Ollama, SGL and custom OpenAI-compatible providers instead of being rewritten to high (#6244) (thanks @pranavthakur0-0!)
  • Tool Search Round-Trips - Deferred tools on OpenAI gpt-5.4+ (and Azure and Bedrock gpt) get the tool_search OpenAI requires instead of a 400. OpenAI tool_search_call and tool_search_output items render for /anthropic clients. Claude's server tool search server_tool_use and tool_search_tool_result blocks replay unchanged, and tool_reference blocks in a client tool_result survive on the Anthropic and Vertex routes (#7813, #8502, #8503, #8555) (thanks @CMWR421!)
  • Client web_search and web_fetch Tools - On the Anthropic endpoint, a client tool_use named web_search or web_fetch stays a function call instead of becoming a server tool call, so its tool_result is no longer orphaned and Bedrock stops rejecting the replay (#8370) (thanks @17jmumford!)
  • Bedrock Prompt Caching - Anthropic automatic caching (top-level cache_control) now creates a Bedrock cache point after the last cacheable block instead of being dropped, and cache_control on a tool message emits one standalone cachePoint after the toolResult (#8573, #8595)
  • OpenRouter Claude Cache Markers - cache_control markers to Claude models on OpenRouter are clamped to four, so Claude no longer rejects the request (#8512)
  • Parallel Tool Calls on Claude - parallel_tool_calls: false and tool_choice.disable_parallel_tool_use reach Claude on every path (Anthropic Responses, Bedrock, Vertex), not only /v1/chat/completions to Anthropic direct (#8471)
  • Responses Instructions with System Messages - Top-level instructions are no longer dropped when the input also has a system or developer message; they lead the system prompt as OpenAI does (#8515)
  • Chat Tool Results on Responses Models - Tool messages with array content use Responses input block types, and an empty tool result keeps output: "", so OpenAI and Azure no longer reject the converted request (#8514, #8621)
  • Responses Streaming Wire Format - Lifecycle events no longer send output: null and no longer carry an invalid item object, which crashed or aborted strict clients (#8563)
  • Responses Input Items - configuration_update items reach OpenAI with their reasoning effort (and are dropped on routes that cannot accept them), and replayed assistant messages with an id keep their status (#8599, #8634)
  • Converted Chat Stream Identity - Chat streams served through the Responses conversion carry the upstream id, model and created on every chunk, so clients no longer see empty text (#8699)
  • Gemini Prompt Blocks - A prompt Gemini or Vertex refuses outright (promptFeedback.blockReason) returns an error instead of a completed response with empty output (#8564)
  • Reasoning Token Usage - Gemini and Vertex batch results include thinking tokens in completion_tokens and report reasoning_tokens, and SGLang's top-level usage.reasoning_tokens maps to completion_tokens_details (#8600, #8687) (thanks @Shashank2985!)
  • Bedrock Converse Round-Trip - Converse responses keep stopReason and additionalModelResponseFields verbatim (#8704)
  • Prompt Cache Mode on Bedrock Converse - prompt_cache_options in additionalModelRequestFields on /bedrock Converse and ConverseStream now reaches OpenAI, Azure and Bedrock Mantle gpt-5.6 models. Send {"mode": "explicit"} with a cachePoint after the system prompt to cache only the system prompt, or without a cachePoint to turn caching off (#8554)
  • Azure Deployments Route - Unknown chat fields are forwarded on the /openai/deployments/... route instead of being dropped (#8703)
  • Decisions - Custom OpenAI-base providers are gated on /v1/decisions by their allowed requests alone, so models outside OpenAI's own list are no longer rejected with unsupported_operation, and answer objects a model JSON-encodes as strings are recovered (#8617, #8626, #8705)
  • Zero-Key Custom Providers in Routing - A custom provider with no keys no longer claims every model during provider inference, and no_key_supports_model no longer stops the fallback chain (#8706)
  • Keyless Provider Discovery - A custom provider switched from keyed to keyless runs model discovery despite leftover disabled keys, and those keys can be deleted (#8530)
  • Provider Key enabled in config.json - enabled on a provider key in config.json or Helm now persists across restarts, without re-syncing keys that UI edits had turned back on (#8610, #8647)
  • MCP Endpoint Slugs - A config.json MCP client without an endpoint_slug keeps its derived slug across re-syncs, so /mcp/<slug> no longer returns 403 after a reboot (#8535)
  • MCP Library Installed Badge - "Installed" is computed server-side over every MCP client, not only the first 100 matched by URL or name (#8581)
  • Code Mode Tool Results - Tools restored from the config store keep their parameters in Starlark stubs, and nested results arrive as structured values: multiple JSON blocks, structuredContent and JSON-in-a-string are decoded (#8603, #8604)
  • OAuth Refresh Failures - Token endpoint rejections are classified by OAuth error code, so Slack and Atlassian refresh failures prompt re-auth (#8559)
  • Throughput Metric - Dashboard tokens/sec counts only inference requests, so list_models and similar calls no longer skew it (#8579)
  • Passthrough Logs - Passthrough log keys no longer show "(deleted)", and passthrough streams with no upstream Content-Type are no longer labelled text/plain (#8601, #8638, #8689)
  • SQLite Log Writes - SQLite SQLITE_BUSY and SQLITE_LOCKED are treated as transient, and a failed batch is retried whole instead of row by row (#8707)
  • Model Catalog Prices - Per-1M token prices show up to 4 decimals, so $0.075 no longer displays as $0.08 (#8326) (thanks @Shashank2985!)

🗄️ Database Migrations

  • add_mcp_client_openapi_spec_column - Adds openapi_spec to config_mcp_clients. Non-reversible: dropping it would delete the only stored copy of every OpenAPI client's document. Additive; older binaries ignore it.
  • add_mcp_client_openapi_config_json_column - Adds openapi_config_json to config_mcp_clients. Non-reversible: dropping it would delete every OpenAPI client's base URL and stored credentials. Additive.
  • add_client_config_extra_fields_placement_column - Adds extra_fields_placement (NOT NULL DEFAULT 'body') to config_client. Reversible: rollback drops the column.
  • add_skills_external_client_url_column - Adds skills_external_client_url to config_client. Non-reversible: dropping it would discard marketplace configuration. Additive.
  • backfill_skills_external_client_url - Copies mcp_external_client_url into skills_external_client_url where it is empty and the value is a public URL. Non-reversible: migrated marketplace configuration is preserved.
  • add_virtual_key_metadata_column - Adds the nullable metadata column to governance_virtual_keys. Non-reversible: dropping it would delete every key's metadata. Additive.
  • add_a2a_private_allowlist_column - Adds a2a_private_allowlist_json to config_client. Reversible: rollback drops the column.
  • add_agent_destination_policy_columns - Adds credential_origins and require_public_target to config_agent_registrations. Non-reversible: removing them would discard security policy. Additive.
  • drop_agent_registration_options - Drops tenant and extension_uris from config_agent_registrations. Non-reversible: the removed values cannot be recovered.

    This migration drops columns. An older binary running alongside it during a rolling upgrade loses access to those values, and rolling back does not restore them.
  • add_vertex_use_session_routing_column - Adds vertex_use_session_routing to the provider keys table. Reversible: rollback drops the column.
  • add_rss_feeds_table - Creates rss_feeds and seeds the built-in feeds. Non-reversible: dropping it would delete custom feeds, their logos and every built-in enabled choice. Additive.
  • add_rss_feeds_icon_url_column - Adds icon_url to rss_feeds tables created before it existed. Non-reversible: dropping it would delete every custom feed logo. Additive.
  • logs_add_matview_refresh_state_table - Creates matview_refresh_state to record when each materialized view last refreshed across the cluster. Reversible: rollback drops the table.
  • logs_add_is_passthrough_column - Adds is_passthrough to logs. Rollback is a no-op and leaves the column in place. Additive.

🐙 Closed GitHub Issues

  • #3440 - [Feature]: Add nodeSelector support for all workloads managed by Helm Chart
  • #6193 - [Bug]: Cannot pass xhigh reasoning effort to vLLM provider
  • #6499 - [Feature]: Add "today" "this week" "this month" to date filter
  • #7763 - All /mcp/ endpoints return 403 access_denied on v2.1.1-enterprise (silent optional-interface assertion failure)
  • #7933 - [Feature]: Custom metadata on virtual keys (API, UI, and spend filtering)
  • #8078 - [Bug]: Anthropic endpoint converts a client tool_use named web_search/web_fetch into a server tool call, orphaning its tool_result (Bedrock 400)
  • #8324 - [bug]: Model catalog rounds per-1M token prices to 2 decimals, so $0.075 shows as $0.08 and $0.0004 as $0.00
  • #8359 - [Bug]: ClickHouse store still issues a heavyweight mutation on agent_logs every minute
  • #8361 - [Bug]: /anthropic/v1/messages to OpenAI gpt-5.4+ fails with 400 when tools have defer_loading but no tool_search tool
  • #8383 - [Bug]: calendar_aligned budgets and rate limits silently ignore the numeric part of reset_duration (7d resets daily)
  • #8500 - [Bug]: Keyless provider with residual disabled keys never discovers models - key CRUD blocked, deadlock
  • #8541 - [Bug]: Bedrock: top-level cache_control is silently dropped, automatic caching never creates a cache point
  • #8548 - [Bug]: MCP Library "Installed" badge only checks the first 100 clients and only matches by URL or name
  • #8554 - [Bug]: Bedrock Converse cache points no longer limit gpt-5.6 caching to the system prompt in v2.3.0, and prompt_cache_options cannot be sent on this route
  • #8568 - [Bug]: Empty tool message breaks requests to Responses API models
  • #8590 - [Bug]: goroutine count climbs ~1,200/hour on v2.3.0 until OOM, even at low traffic
  • #8616 - [Bug]: Responses API configuration_update input items drop the reasoning field
  • #8684 - [Bug]: Gemini and Vertex batch results ignore thinking tokens (thoughtsTokenCount), so batch cost, budgets and totals are understated
  • #8709 - A2A push relay leaks one goroutine every 3s: gateContext result is never cancelled (v2.3.0)

Installation

Docker

docker run -p 8080:8080 maximhq/bifrost:v2.3.1

Binary Download

npx @maximhq/bifrost --transport-version v2.3.1

Docker Images

  • maximhq/bifrost:v2.3.1 - This specific version
  • maximhq/bifrost:latest - Latest version (updated with this release)

This release was automatically created with dependencies: core v1.13.0, framework v1.10.0. All plugins have been validated and updated.

Don't miss a new bifrost release

NewReleases is sending notifications on new releases.