We're excited to announce the v0.28.0 release of the Obot Platform. This release introduces a unified LLM gateway with profiles, budgets, and guardrails, publishes vMCPs through the MCP Registry API, adds Keycloak and OneLogin auth providers with SCIM provisioning for Entra and OneLogin, and lets remote MCP servers receive trusted caller attribution headers.
Big Updates
Unified LLM Gateway with Profiles, Budgets, and Guardrails
Obot now reaches every model through one LLM gateway. A single endpoint, /api/llm-proxy/v1, serves every configured model in the OpenAI Chat Completions, OpenAI Responses, and Anthropic Messages formats, so Claude Code can use GPT models and the OpenAI SDK can use Claude. Administrators manage providers, keys, routing rules, weighted splits, and fallbacks from the LLM Gateway page, and the Connect tab gives ready-to-copy setup for Claude Code, Codex, OpenCode, Goose, Cline, Open WebUI, and the common SDKs. Bedrock and Azure providers support each of their authentication methods, and all providers' configuration is stored in Obot's own database.
Model access policies are now profiles. Each profile names users and groups, the models they can use, budgets that cap spend, tokens, or requests over rolling or calendar windows, and applied guardrails. Guardrails include built-in secrets, regex/PII, and LLM judge checks, along with integrations for Presidio, Azure AI Language and Content Safety, AWS Bedrock Guardrails, Google Model Armor, Lakera Guard (Check Point), Patronus, and CrowdStrike AIDR. They block, redact, or log model traffic, including streamed responses, and guardrail filters apply the same checks to MCP tool calls. Administrators can also let Claude Code users bill requests to their own Claude subscription while Obot still enforces access and guardrails and records each request in the audit log. See the docs for details.
Important
Existing LLM gateway and model provider users should wait to upgrade. Provider credentials, models, default model aliases, and model access policies are not migrated to the new gateway in v0.28.0. Migration support is planned for v0.28.1. See #8475 for details.
vMCPs in the MCP Registry API
The MCP Registry API now publishes vMCPs with their connection URLs. What each user discovers follows vMCP ownership and profile access, and authenticated discovery returns a personalized view.
Administrators can enable anonymous discovery under Platform → Settings → MCP Registry API for clients that don't authenticate registry requests, such as VS Code. Anonymous requests see only shared vMCPs whose profiles grant access to All Obot Users, and connecting still requires authentication and current vMCP permissions. See the docs for details.
New Enterprise Auth Providers and SCIM Provisioning
Keycloak and OneLogin are now available as authentication providers. See the docs for setup.
Microsoft Entra and OneLogin can now provision users and groups into Obot through SCIM, as Okta could in v0.27.0. Administrators decide in their identity provider which users and groups Obot can see, and users removed there are deactivated in Obot. See the docs for Entra SCIM and OneLogin SCIM.
Caller Attribution Headers for Remote MCP Servers
Remote MCP servers and catalog entries can now receive trusted X-Obot-* headers that identify the caller: the Obot user ID, name, and email, the identity provider user ID and groups, and the API key ID and name. Each header is selected individually under Advanced Configuration → Inject Obot headers.
Obot strips any incoming copies of these headers before forwarding a request, so a backend can attribute actions to a user or enforce per-caller policy without trusting client input. See the docs for details.
Improvements
- The Devices tab lists enrolled devices with their latest scan, and administrators can remove devices to free seats.
- Local auth users are managed from the Users page.
- The Users page stays usable with thousands of users.
- Claude Environments model requests go through the LLM gateway, and audit logs can be opened from environment sessions.
- MCP client sessions recover after server restarts.
- The vMCP card or table view choice is remembered.
Upgrade Notes
Existing LLM gateway and model provider users should wait to upgrade. v0.28.0 does not migrate existing provider credentials, models, default model aliases, or model access policies to the new LLM gateway. Migration support is planned for v0.28.1 and tracked in #8474. Earlier gateway data is not changed, and LLM audit history stays readable. The per-provider proxy routes for Amazon Bedrock, Azure OpenAI, and Generic Responses (/api/llm-proxy/aws-bedrock, aws-bedrock-api-key, azure, azure-entra, and generic-responses) are temporarily unavailable and return HTTP 410. They will be restored, see #8495. /api/llm-proxy/openai and /api/llm-proxy/anthropic still work. See #8475 for details.
Message policies are now disabled LLM judge guardrails. Message policies are converted into LLM judge guardrails on upgrade, and every converted rule starts disabled. OBOT_SERVER_ENABLE_MESSAGE_POLICIES is removed. If you enforced message policies, review and enable the converted rules under LLM Gateway → Profiles. Enabled rules fail closed when the judge's model is unavailable. See #8302 for details.
Anonymous MCP Registry API discovery is now opt-in. Anonymous discovery is disabled by default. OBOT_SERVER_ENABLE_REGISTRY_AUTH no longer has any effect, and its value is not imported. If clients such as VS Code discover servers without authenticating, enable Allow anonymous registry discovery under Platform → Settings → MCP Registry API after upgrading. See #8310 for details.
Obot attribution headers are reserved. The seven X-Obot-* attribution headers can no longer be configured manually on MCP servers, and configurations that set them may fail validation. Before upgrading, remove them and use Advanced Configuration → Inject Obot headers instead. See #8402 for details.
Owner and admin email environment variables are removed. OBOT_SERVER_AUTH_OWNER_EMAILS and OBOT_SERVER_AUTH_ADMIN_EMAILS are removed. Users who were granted roles by them keep those roles, but those roles can now be changed on the Users page. See #8440 for details.
The users.verified_email database column is dropped. During a rolling upgrade, v0.27 pods can return errors to users until the rollout finishes. See #8482 for details.
Embedded PostgreSQL moves from 17 to 18. This is a breaking change for installations using the embedded database: Docker without OBOT_SERVER_DSN, and Helm with dev.useEmbeddedDb: true. Obot stops at startup on a PostgreSQL 17 data directory. Follow the dump and restore guide before upgrading. Installations using external PostgreSQL are not affected. See #8439 for details.
What's Changed
- chore: fix winget release and allow publishing manually by @njhale in #8337
- docs: describe bounded license fallback and address #8292 review follow-ups by @cjellick in #8314
- chore: switch to custom keygen domain by @thedadams in #8328
- fix: exclude missing durations from audit log duration filters by @calvinmclean in #8326
- enhance: adjust graphs w/ sparse data & change horizontal graphs by @ivyjeong13 in #8340
- chore: find release blog reference posts dynamically by @cjellick in #8341
- fix(claude): delete expired environment API keys by @thedadams in #8339
- feat: unified LLM gateway with budgets and guardrails by @cjellick in #8244
- docs: update README for v0.24 through v0.27 by @cjellick in #8347
- chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates by @dependabot[bot] in #8349
- chore(deps): bump github.com/klauspost/compress from 1.18.6 to 1.18.7 in /apiclient in the go_modules group across 1 directory by @dependabot[bot] in #8348
- fix(claude): disable upstream TLS session resumption in the egress proxy by @cjellick in #8358
- fix(claude): let WebSocket upgrades through the egress audit filter by @cjellick in #8359
- fix: general ui fixes by @ivyjeong13 in #8345
- enhance: add view audit logs option in environment sessions by @ivyjeong13 in #8360
- Integrate LLM proxy with Claude Environments by @thedadams in #8362
- test(ui): stop forced click from skipping audit log export submit by @thedadams in #8364
- fix(mcp): reuse configured base image for Docker setup containers by @calvinmclean in #8350
- fix: fix tests with unaccounted for mock handlers & errors by @ivyjeong13 in #8365
- Docs/versioned agent exports by @cloudnautique in #8369
- fix(mcp-tester): expose raw responses in error details by @calvinmclean in #8368
- fix(mcp): reconnect filter sessions after server restarts by @thedadams in #8378
- enhance: delay first upgrade check and product telemetry report until 30 minutes after startup by @cjellick in #8373
- fix: resolve a number of trivy-reported issues by @drpebcak in #8382
- fix(claude): remove crashed executions so their sessions can continue by @thedadams in #8383
- enhance: move local auth user management to users pages by @ivyjeong13 in #8372
- feat: add OneLogin auth provider by @g-linville in #8330
- fix: fall back to the registered Community license on delete by @njhale in #8375
- chore: bump ui & docs packages by @ivyjeong13 in #8379
- feat(registry): expose vMCPs with opt-in anonymous access by @calvinmclean in #8296
- chore: dependabot ui/docs packages bump qs/dompurify by @ivyjeong13 in #8386
- fix(oauth): check MCP access when exchanging an authorization code by @cjellick in #8380
- fix: update test for new parameter type by @thedadams in #8390
- fix: capture oauth request id for authz by @thedadams in #8388
- fix: Okta scim: ensure base URL has trailing slash by @g-linville in #8394
- fix(mcp): recover shared client sessions after server restarts by @thedadams in #8389
- chore(ci): add i18n linting by @calvinmclean in #8381
- fix: support 401/403 for any MCP request by @thedadams in #8385
- test(vmcps): split the configuration policy test to stop timeouts by @njhale in #8404
- chore(ci): cache golangci-lint results and drop redundant gofmt by @thedadams in #8403
- feat: list and remove enrolled devices on the Devices tab by @njhale in #8399
- chore: add doc describing mcp-images maintenance process by @drpebcak in #8401
- fix: allow scheduling updates without a vMCP connection by @thedadams in #8407
- fix: refuse sessions of deleted users instead of recreating them by @g-linville in #8408
- chore: mock/drop animations during ui test runs by @ivyjeong13 in #8406
- fix(ui): resume MCP client login when upstream OAuth completes by @cloudnautique in #8410
- fix: sanitize fallback sign-out redirects by @thedadams in #8411
- chore: dependabot/audit ui/docs bumps by @ivyjeong13 in #8412
- fix: update complete.svelte.spec.ts by @ivyjeong13 in #8416
- fix(docs): serve root llms-full.txt and label .md 404s as HTML by @cloudnautique in #8414
- fix: stop unused Bifrost A2A gateway to prevent idle goroutine leaks by @thedadams in #8421
- chore: remove leftover published artifacts references by @g-linville in #8426
- fix: discard MCP audit entries when encryption fails by @thedadams in #8424
- Stop draining failed requests by @thedadams in #8425
- fix: remember vmcp card/table state via localstorage by @ivyjeong13 in #8413
- fix: retain egress audit records and batch recovery by @thedadams in #8431
- feat: add Keycloak authentication provider by @cloudnautique in #8395
- Properly cleanup vMCPs after user access changes by @thedadams in #8428
- chore: remove email-based identity linking and env-configured roles by @g-linville in #8415
- chore(deps): bump github.com/go-jose/go-jose/v4 from 4.1.4 to 4.1.6 in the go_modules group across 1 directory by @dependabot[bot] in #8437
- chore: fix broken test by @g-linville in #8438
- fix: compare token usage times in UTC by @thedadams in #8436
- Upgrade embedded PostgreSQL to 18 with manual migration guidance by @drpebcak in #8441
- feat(ui): add icons for all model providers by @calvinmclean in #8442
- feat(mcp): add selectable caller attribution headers by @calvinmclean in #8392
- docs: tell admins to clear cookies when recovering from a provider lockout by @g-linville in #8447
- fix: coordinate audit shutdown with a shared deadline by @thedadams in #8433
- fix: allow oauth2 static access through proxy by @ivyjeong13 in #8446
- fix: enforce MCP session ownership by user and connection by @calvinmclean in #8409
- feat: add resource-backed LLM gateway configuration storage by @calvinmclean in #8434
- feat: add support for SCIM for Entra by @g-linville in #8432
- docs: move caller attribution to shared MCP server configuration by @calvinmclean in #8455
- fix: read camelCase provider manifest fields from YAML registry files by @g-linville in #8456
- fix: vmcps long page load fix by @ivyjeong13 in #8422
- fix: flaky test case scimview.spec & vmcps page.svelte.spec by @ivyjeong13 in #8458
- docs: restore MCP server tutorials to the sidebar and add Vercel by @cloudnautique in #8459
- chore: bump mmmcp to v0.2.1 by @thedadams in #8465
- feat: add standalone core LLM engine without subscription passthrough by @calvinmclean in #8454
- fix: keep the Users page usable with thousands of users by @g-linville in #8464
- fix(enforcement): allow Codex's built-in tools by @g-linville in #8463
- ci: raise the golangci-lint timeout to 10m by @g-linville in #8473
- chore: bump default obot-sentry to v0.1.9 by @g-linville in #8472
- docs: document Sentry tool call enforcement limits by @cjellick in #8478
- refactor: run the LLM gateway on llmcore by @calvinmclean in #8469
- docs: remove LLM gateway metrics from user documentation by @calvinmclean in #8479
- feat: clarify model provider authentication setup by @calvinmclean in #8443
- fix: discover Azure deployments with Entra credentials by @calvinmclean in #8483
- chore: release v0.28 docs by @cjellick in #8496
Full Changelog: v0.27.0...v0.28.0