We're excited to announce the v0.26.0 release of the Obot Platform. This release replaces composite MCP servers with virtual MCPs, adds an in-app MCP tester, and adds opt-in product analytics.
Important
Existing installations should not upgrade to this release. vMCPs do not fully support upgrades in v0.26.0, and upgrade support will follow in a patch release. Only net new installations should install v0.26.0. See #7802 for details.
Big Updates
Virtual MCP Servers
Virtual MCPs (vMCPs) are now the resource used to expose newly created MCP endpoints. A vMCP holds one or many catalog components, so a single server and an aggregation of several now use the same resource and the same connection model. Standalone and composite servers remain available for migration compatibility.
Each component stores a snapshot of its catalog entry instead of resolving against the live entry at runtime. A catalog edit, a failed sync, or a deletion no longer changes or stops a running server on its own. Drift and missing sources are reported, and a snapshot changes only through an explicit, validated upgrade. Each component also carries a configuration policy that classifies every input as preconfigured, provided at connection time, or ignored.
Access and tool grants come from additive user and group profiles on the vMCP. A profile can grant every tool or map specific tools per component, and a user connecting to the vMCP can narrow their grant but never widen it. Administrators can create vMCPs that other users consume, and a user can create a personal vMCP from catalog entries they already have access to, but cannot share it.
MCP Tester
Users can now connect to any vMCP server they have access to and exercise it directly inside Obot. With the tester, users can chat with the configured default model and make real tool calls against the server. An inspector lists the server's tools, prompts, and resources so they can be viewed and invoked individually.
Conversations are ephemeral and are not stored. Chat traffic both show up in the audit logs like any other activity.
Detached Catalog Entries
Removing an entry from a Git-backed MCP catalog no longer deletes the servers that people have already deployed from it. When a sync removes an entry that still has connections, Obot marks that entry detached and keeps it in a read-only state, so the deployments that depend on it keep working. An administrator can then accept ownership of a detached entry, which converts it into an Obot-managed entry they can edit. If the entry later reappears in the catalog source, the sync reports the conflict instead of silently overwriting the version Obot is holding.
Note
The AntV Charts, Brave Search, Browserbase, Chroma Cloud, MarkItDown, and Playwright MCP servers have been deprecated and will be removed from a future release. Update instructions will be provided one minor-version release prior to their removal. See #7626 for details.
Product Analytics
Obot will now report anonymous product usage data; this is disabled until an administrator explicitly opts in. Consent is stored installation-wide as an explicit three-state value, undecided, granted, or declined, and only an Owner or Admin can read or change it.
Administrators are asked once and can change the answer later. In deployments where product analytics is force-enabled through configuration, the consent API is not exposed at all.
Improvements
- Token spend graphs have been added to the usage and dashboard pages, and spend is now reported for Bedrock and Azure Entra models.
- Agent Auth Scopes are now revoked rather than deleted. LLM and MCP audit logs record the API key ID and name behind each request, can be filtered by key, and identify revoked keys.
- A new CLI command validates catalog YAML before you commit it, and a
system mcp validatecommand checks a configured MCP server. - Administrators can cap CPU and memory requests and limits for MCP server scheduling from the UI.
- The MCP servers page loads faster, and the app navigation has been reworked.
- Obot now emits structured JSON logs through slog.
- Group listings are paginated, and catalog entry forms support option lists for environment variables and headers.
- Device scan submissions are compressed on the wire and cleaned up on a retention schedule, and auditors have read-only access to MDM configuration routes.
- The audit logger no longer pre-allocates 2GB for its buffer.
- The app-facing Basic user role is now called Standard.
- Controller leader election is held in a SQL table instead of a Kubernetes Lease.
Security
One security advisory is published alongside this release.
GHSA-6fwv-3h4c-37j9: Authorization bypass through the composite MCP connect route (High). The fix for GHSA-vw82-7fv8-r6gp guarded the /mcp-connect/ route but not the sibling composite route, which reaches the same gateway handler. Any authenticated user, including one with the Standard role, could therefore connect to and use MCP servers through that route without the access control rules that were meant to gate them. This affects v0.21.1 through v0.24.1 and was fixed in v0.25.0. Note that upgrading in response to GHSA-vw82-7fv8-r6gp does not by itself cover this issue, because the fix that advisory describes is the incomplete one. If you are still running v0.24.1 or earlier, upgrade. Reported by @arpitjain099.
Upgrade Notes
Okta users on versions earlier than v0.19.0 must upgrade to v0.25.x first. This release removes an Okta group migration that has been present since v0.19.0 and that pre-v0.19.0 installations still need. Upgrade to v0.25.x so that migration runs, then move to v0.26.0. See #7779 for details.
Replicas in an HA deployment can briefly fall behind during the rolling upgrade. kinm watches now use Postgres LISTEN/NOTIFY instead of polling every two seconds, which cuts idle database load from watches by roughly 15x and propagates a change from one replica to another in tens of milliseconds rather than up to two seconds. During the first rolling deploy of this version, a replica that has already upgraded does not hear from a replica still running the previous version, so it can take some additional time to upgrade. This happens once, closes on its own, and needs no action. Each replica also opens one additional Postgres connection, and connection poolers running in transaction mode do not carry LISTEN, in which case kinm detects it on connect and keeps the previous polling behavior. See #7737 for details.
What's Changed
- fix: let websocket handlers under /api hijack the connection by @ibuildthecloud in #7442
- fix(ci): authenticate Depot on same-repo PRs and run CI on feat/* branches by @ibuildthecloud in #7470
- feat: add the hosted agent resource model (1/11) by @ibuildthecloud in #7459
- feat: add an interface for running agent sandboxes (2/11) by @ibuildthecloud in #7460
- feat: run agent sandboxes on Kubernetes (3/11) by @ibuildthecloud in #7461
- feat: let a sandbox reach the models and MCP servers it was granted (4/11) by @ibuildthecloud in #7462
- feat: attach a terminal to a sandbox and publish agents that serve HTTP (5/11) by @ibuildthecloud in #7463
- feat: wire the agent backend into the server (6/11) by @ibuildthecloud in #7464
- feat: reconcile hosted agents, pools and config sources (7/11) by @ibuildthecloud in #7465
- feat: add the hosted agents admin UI (9/11) by @ibuildthecloud in #7467
- feat: add the hosted agents user UI (10/11) by @ibuildthecloud in #7468
- feat: seed a default config source for hosted agents (11/11) by @ibuildthecloud in #7469
- chore: docs & user ui dependencies by @ivyjeong13 in #7479
- fix: eliminate 2GB pre-allocation in audit logger buffer by @kyu1204 in #5779
- fix: reject duplicate skill sources by @calvinmclean in #7295
- fix: track usage in formatted LLM responses by @calvinmclean in #7474
- fix: preserve file credential bytes by @calvinmclean in #7371
- feat: detach removed catalog entries with active servers by @calvinmclean in #7445
- chore: add modernize linter by @thedadams in #7473
- fix: docs navbar on mobile not showing by @ivyjeong13 in #7490
- feat(auth): add device authorization lifecycle by @thedadams in #7431
- fix: compress device scan submissions on the wire by @njhale in #7480
- fix: migrate ReverseProxy.Director to Rewrite by @ibuildthecloud in #7436
- Require configured static OAuth before MCP use by @thedadams in #7444
- chore: update nanobot to v0.0.92 by @calvinmclean in #7493
- fix: return invalid_grant for invalid refresh tokens by @calvinmclean in #7502
- fix: prompt for access policy on multi-tenant catalog entry deployment by @ivyjeong13 in #7446
- enhance: add token spend graphs in usage & dashboard by @ivyjeong13 in #7478
- fix: multi-tenant deployment check fix for Server Activity in dashboard by @ivyjeong13 in #7487
- refactor: consolidate LLM request rewriting by @calvinmclean in #7495
- feat: add CLI command to validate catalog YAML by @calvinmclean in #7492
- feat: explicit detach state and "accept ownership" action by @calvinmclean in #7505
- chore: bump obot-sentry to v0.1.5 by @njhale in #7509
- fix: invalidate refresh grants for deleted MCP servers by @calvinmclean in #7508
- fix: resolve remote URL templates for tool previews by @calvinmclean in #7503
- chore(deps): bump mermaid from 11.16.0 to 11.16.1 in /docs in the npm_and_yarn group across 1 directory by @dependabot[bot] in #7513
- chore(deps): bump the npm_and_yarn group across 1 directory with 2 updates by @dependabot[bot] in #7514
- feat: obot app scheduling info & page by @ivyjeong13 in #7070
- enhance: use go-sdk client by @thedadams in #7510
- fix: honor static catalog env in connect flow by @calvinmclean in #7512
- fix: report spend for Bedrock and Azure Entra models by @calvinmclean in #7516
- fix(mcp): apply backend URL validation to clients by @thedadams in #7520
- chore(deps): bump github.com/go-git/go-git/v5 from 5.19.1 to 5.19.2 in the go_modules group across 1 directory by @dependabot[bot] in #7521
- chore(deps-dev): bump dompurify from 3.4.12 to 3.4.13 in /ui/user in the npm_and_yarn group across 1 directory by @dependabot[bot] in #7522
- enhance: add setting max caps for request/limits cpu/memory in server-scheduling in ui by @ivyjeong13 in #7486
- chore: ui dompurify/nanoid dependabot bumps by @ivyjeong13 in #7524
- Fix editing configuration for remote MCP deployments by @calvinmclean in #7519
- chore: bump default obot-sentry assets to v0.1.6 by @njhale in #7535
- enhance: add system mcp validate command by @thedadams in #7533
- entra docs by @cjellick in #7539
- feat: add runtime class name for hosted agents by @thedadams in #7536
- chore: switch to upstream version of remotedialer by @thedadams in #7544
- enhance: add retention-based cleanup for submitted device scans by @njhale in #7530
- enhance: add APIKeyID and APIKeyName to LLM and MCP audit logs by @calvinmclean in #7542
- chore: setup ui tests by @ivyjeong13 in #7437
- Add architecture decision record process by @cjellick in #7556
- chore: support scheduling settings for hosted agents by @drpebcak in #7552
- feat: revoke API keys instead of delete by @calvinmclean in #7541
- fix(docs): add missing export and update models by @calvinmclean in #7560
- fix: best-effort token spend estimation for Azure API-key by @calvinmclean in #7559
- fix: allow editing OAuth credentials for git entries by @calvinmclean in #7532
- enhance: filter token usage/spend on API keys by @calvinmclean in #7546
- fix: deployment k8s details & devices sorted fixes by @ivyjeong13 in #7517
- fix: use static OAuth credentials when generating tool previews by @njhale in #7564
- enhance: structured JSON logging via slog by @njhale in #7575
- feat: add catalog configuration options by @calvinmclean in #7566
- enhance: use MCP Go SDK for gateway instead of nanobot by @thedadams in #7569
- chore: fix small lint-type issues by @thedadams in #7599
- enhance: add API key filtering to audit logs by @calvinmclean in #7551
- fix(oauth): preserve MCP resource during token exchange by @calvinmclean in #7568
- fix(mcp): canonicalize remote header names by @calvinmclean in #7600
- fix: ignore description whitespace when detecting composite tool overrides by @njhale in #7585
- chore: bump go version to 1.27 by @thedadams in #7609
- fix(mcp): strip gateway authorization upstream by @calvinmclean in #7610
- docs: drop OPENAI_API_KEY from Docker install examples by @cjellick in #7574
- Chore: Update release-notes skill and add security skill by @cjellick in #7271
- enhance: use virtual session to track clients by @thedadams in #7616
- docs: improve styling by @g-linville in #7618
- enhance: support options in catalog enty form envs/headers by @ivyjeong13 in #7604
- enhance: paginate groups by @g-linville in #7603
- fix: avoid exposing encrypted user data in API key filters by @calvinmclean in #7606
- Linting updates by @thedadams in #7624
- fix: return group ids in the order they were given when splitting by @njhale in #7630
- chore: bump remaining modules to go 1.27 by @njhale in #7631
- fix: allow admins to delete device scans by @njhale in #7628
- feat: auth scope api key details/logs page by @ivyjeong13 in #7605
- enhance: replace nanobot with mmmcp completely by @thedadams in #7629
- chore: bump trivy version by @drpebcak in #7636
- enhance: add upgradeNote for catalog entries by @calvinmclean in #7623
- enhance: filters: add ability to target devices (API/UI only) by @g-linville in #7586
- fix(ui): identify revoked keys in audit logs by @calvinmclean in #7627
- chore: bump mmmcp to pick up sqlite file parsing changes by @njhale in #7640
- fix: decode gzip bodies for audit logs by @thedadams in #7639
- chore: removed unused packages by @drpebcak in #7643
- chore: remove unused functions and parameters by @thedadams in #7638
- fix(ui): preserve MCP server descriptions with badges by @calvinmclean in #7646
- Revert "enhance: filters: add ability to target devices (API/UI only) (#7586)" by @g-linville in #7652
- fix(ui): prevent MCP search input resets while typing by @calvinmclean in #7641
- fix: delete group references when auth provider is deconfigured by @g-linville in #7635
- fix: stop audit logging nanobot agent requests by @thedadams in #7660
- fix: properly align responses for server requests by @thedadams in #7661
- enhance: provide config for client native overrides by @thedadams in #7664
- fix: authenticate device credentials when authentication is disabled by @njhale in #7662
- enhance: stop deploying obot-mcp-server if agents aren't enabled by @thedadams in #7668
- chore: add feature flag around hosted agents by @g-linville in #7654
- enhance: add preconfigure option for entry in MCP Servers by @ivyjeong13 in #7679
- fix: route composite requests to a single replica by @thedadams in #7673
- feat: improved E2E testing with simple integration test by @calvinmclean in #7248
- fix: use downstream oauth client name when proxying by @g-linville in #7672
- chore: allow setting full deployment strategy by @drpebcak in #7682
- feat: mcp gateway experience by @ivyjeong13 in #7676
- fix: add reauthenticate option in preconfigure for MCP Servers by @ivyjeong13 in #7687
- fix: revert premature removal of MCP Servers from Layout by @ivyjeong13 in #7688
- fix: obot community/auth provider ui/ux updates by @ivyjeong13 in #7491
- fix: show reauthenticate only if oauthmetadata and no configurations by @ivyjeong13 in #7692
- fix(mcp): prevent forwarding gateway credentials by @cjellick in #7697
- fix: synchronize auth provider configuration by @g-linville in #7685
- fix: ensure composite manifest populated on update by @thedadams in #7698
- fix(license): ensure all replicas have current entitlements by @thedadams in #7702
- chore: add adr for provider daemon sync by @g-linville in #7703
- ui asset 404 user agent gate by @cjellick in #7701
- chore: bump mmmcp to pick server name fix by @thedadams in #7704
- fix: honor forced dynamic OAuth clients by @thedadams in #7705
- fix: allow public static OAuth clients by @thedadams in #7706
- fix(oauth): auto detect token endpoint client auth by @thedadams in #7720
- feat: add telemetry API client by @calvinmclean in #7717
- enhance: optimize MCP servers page load performance by @calvinmclean in #7674
- Hold the controller leader lock in a SQL table instead of a Lease by @cjellick in #7727
- chore(deps): bump fast-uri from 3.1.5 to 3.1.7 in /docs in the npm_and_yarn group across 1 directory by @dependabot[bot] in #7734
- fix: flaky drag handler test case in vmcps page route by @ivyjeong13 in #7735
- chore(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.1 in the go_modules group across 1 directory by @dependabot[bot] in #7728
- feat: add product telemetry consent API by @calvinmclean in #7731
- Refresh every watch when this replica is promoted to leader by @cjellick in #7736
- refactor: move version checker to new package by @calvinmclean in #7700
- chore: add directions regarding table tests by @thedadams in #7742
- chore: add Obot Cloud entitlement by @thedadams in #7743
- enhance: navigation ux/ui updates by @ivyjeong13 in #7707
- fix: skip the npx audit when launching NPX MCP servers by @cjellick in #7757
- Add an ADR for the SQL-backed controller leader lock, and bump nah for its startup logging by @cjellick in #7738
- fix: wait for the default catalog before running integration tests by @cjellick in #7756
- fix: stop re-sweeping the legacy audit log credential on every reconcile by @cjellick in #7755
- fix: reconcile OAuth credentials for catalog entries in one pass by @cjellick in #7726
- feat: local auth bootstrapping by @njhale in #7671
- chore(deps): resolve dependabot alerts by @calvinmclean in #7749
- fix: revert/remove app scheduling endpoint by @ivyjeong13 in #7748
- chore: remove okta group migration by @g-linville in #7778
- chore(deps): bump google.golang.org/grpc from 1.83.1 to 1.83.2 in the go_modules group across 1 directory by @dependabot[bot] in #7787
- fix: rename MCP tool call telemetry field by @calvinmclean in #7746
- feat: add MCP tester by @g-linville in #7744
- fix: allow auditors read-only access to MDM configuration routes by @njhale in #7761
- chore: modernize using 'cmp' standard library by @calvinmclean in #7791
- chore: bump obot-sentry to v0.1.7 by @njhale in #7760
- docs(installation): fix Helm secrets and ingress examples by @cloudnautique in #7776
- Add vMCP support by @thedadams in #7785
- chore: strip symbols, remove kustomize plugin support by @drpebcak in #7783
- fix: skip invalid components on composite migration by @thedadams in #7801
- fix: skip invalid components instead of erroring by @thedadams in #7803
- fix: post navigation update bugfixes by @ivyjeong13 in #7789
- fix: initial owner activation flow by @njhale in #7790
- fix: prevent local auth password reuse after reset by @njhale in #7781
- fix: reopen a staged auth provider switch and unstage it with a button by @njhale in #7800
- enhance: provide tool list change notifications by @thedadams in #7808
- feat: add product analytics consent UI by @calvinmclean in #7747
- fix: prompt for configuration for vMCPs by @thedadams in #7807
- fix: use existing fixed config on vMCP update by @thedadams in #7814
- enhance: vmcps ui/ux update by @ivyjeong13 in #7804
- enhance: add more APIs for vMCPs by @thedadams in #7815
- docs: correct provider availability, encryption, and MCP architecture by @cloudnautique in #7812
- fix: remove finish later option from password change page by @njhale in #7823
- fix: retry on setting configuration hash on vMCP create by @thedadams in #7832
- docs: simplify product analytics consent documentation by @calvinmclean in #7822
- fix: hide device unique user counts from dashboards by @njhale in #7834
- fix: disallow basic users for setting profiles on vMCP by @thedadams in #7830
- fix: add information to vMCP MCP servers for tracking by @thedadams in #7821
- fix: use user API endpiont for catalog entry by @thedadams in #7833
- enhance: determine multi-user status by component by @thedadams in #7817
- fix(vmcp): set "fixed" for required config on create by @thedadams in #7852
- chore: bump mmmcp to pickup header fix by @thedadams in #7853
- feat: publish product telemetry by @calvinmclean in #7767
- fix: allow connections to multi-user MCP servers by @thedadams in #7843
- fix(audit): preserve commas in MCP server filters by @thedadams in #7854
- fix: expand URL templates for vMCP by @thedadams in #7845
- chore: change app-facing basic user to standard user by @ivyjeong13 in #7872
- enhance: vmcps ux adjustments by @ivyjeong13 in #7855
- fix: add various fixes for MCP Tester by @g-linville in #7824
- test: cover catalog entry preservation after parse failures by @calvinmclean in #7826
- fix: skip hidden catalog directories and support include paths by @calvinmclean in #7828
- fix(vmcp): remove static configuration from vMCP setup by @thedadams in #7858
- fix: keep vMCPs working after their source catalog entry is deleted by @thedadams in #7874
- fix: give access to all referenced tools to vMCP owner by @thedadams in #7873
- fix: keep the email filled in after a failed local login by @njhale in #7881
- fix: allow selecting vMCPs for filtering by @thedadams in #7882
- fix(vmcp): retry instance configuration writes on conflict by @thedadams in #7875
- fix: fix reauthenticate link in MCP Tester for vMCPs by @g-linville in #7841
- fix: tolerate concurrent identity creation on first sign-in by @njhale in #7883
- docs: clarify unsupported MCP tools behavior by @calvinmclean in #7888
- fix: update get started guides with ux changes by @ivyjeong13 in #7876
- fix: refresh MCP tester after OAuth is complete by @g-linville in #7897
- fix(vmcp): allow tool setup with user-supplied credentials by @thedadams in #7896
- fix(ui): hide license actions from auditors by @thedadams in #7900
- fix(ui): keep product analytics save near settings by @thedadams in #7899
- fix: support filtering audit logs by vMCP by @thedadams in #7898
- fix: match the built-in MCP catalog source URL by prefix by @njhale in #7903
- fix: show secret bindings for synced catalog entries by @calvinmclean in #7906
- fix: batch vmcps related bugfixes by @ivyjeong13 in #7892
- docs: describe the staged auth provider switch by @njhale in #7905
- feat: integrate MCP Tester with model proxy by @g-linville in #7806
- fix: use creator for show my vmcps and owner label by @ivyjeong13 in #7909
- fix: use correct user agent in MCP Tester when using model proxy by @g-linville in #7917
- fix: streamline first local user setup process by @g-linville in #7910
- fix(ui): remove audit logs links from servers view by @thedadams in #7915
- fix: incorporate search weight for search vmcps/mcp servers in sidebar by @ivyjeong13 in #7927
- fix: don't show errors during vmcp oauth in MCP Tester by @g-linville in #7916
- fix: detect changed server configuration to break tool cache by @thedadams in #7931
- fix: ignore vMCP servers and instances in catalog cleanup by @thedadams in #7930
- enhance: onboarding ux tweaks and sign up in vmcp tester by @ivyjeong13 in #7891
- fix: resolve vMCP in MCP server table by @thedadams in #7933
- fix: make profiles more flexible by @thedadams in #7935
- fix: create vmcp button missing by @ivyjeong13 in #7938
- fix: properly determine whether a model provider is configured by @g-linville in #7939
- fix: vmcps inspector and mcps searchbar fixes by @ivyjeong13 in #7932
- chore: add logging around model provider determination errors by @g-linville in #7937
- enhance: vmcp designer create and guide updates by @ivyjeong13 in #7941
- fix: copy redirect for local auth logins by @thedadams in #7946
- fix: ensure new pod when command or args change by @thedadams in #7945
- chore: make default profile all admins by @thedadams in #7948
- enhance: move local auth owner creation to dedicated route /admin/setup by @ivyjeong13 in #7943
- fix: populate Obot groups for token auth by @thedadams in #7949
New Contributors
Full Changelog: v0.25.1...v0.26.0