Skip to content

v0.30.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 02:44
· 176 commits to main since this release

v0.30.0 — browser tabs, custom apps, ranked tool search

The browser toolset moves from one page per user to one Chromium per user with as many tabs as the work needs. Two agents, or one agent with subagents, each open their own tab and stop stepping on each other. search_tools now understands how agents phrase a task. Workbench also stops being limited to its built-in plugins. A user can point it at any MCP server as a custom app, and its tools appear beside the native ones. Ships as a release candidate first: it touches the routing path behind CLUSTER_ENABLED, adds a table, and changes the /mcp request path.

Features

  • Browser: tabs. browser_start now opens a new tab and returns its session_id; every other tool acts on that tab. browser_tabs lists open tabs, browser_close closes one and leaves the browser up. Tabs share the profile and cookie jar, so a login in one is visible in the others. Cap per user: BROWSER_TAB_LIMIT (default 8).
  • Browser: routing key derived from the bearer. The replica-affinity header is set by the server from the authenticated user; the agent no longer carries a routing key in session_id. See the finding.
  • Custom apps: register any MCP server. On the Apps page, New custom app takes a name and an MCP server URL. Workbench discovers the server's OAuth metadata, registers itself as a client (dynamic client registration), and runs the OAuth 2.1 flow per user. The server's tools are exposed as appName__tool next to the native plugins, through search_tools and execute_tools. Custom apps are per user: nobody else sees or can connect to an app you add. Streamable HTTP is used with an SSE fallback for older servers; sessions are cached, and tool calls get a 120s timeout (10 min ceiling with progress). See the finding.
  • Custom apps: connect on create. The dialog's button reads Connect. It registers the app and goes straight into its OAuth, showing Registering… then Connecting… while the dialog stays up, so the human no longer has to find the new app and press Connect. The trigger is now a square + button in the Apps toolbar, with a tooltip.
  • MCP: search_tools ranks by word, forgives typos. Search was a literal substring match on the whole query. On the built-in catalog, 10 of 12 common agent phrasings (create jira issue, send email, list github pull requests, …) returned [], and hits came back unranked and unlimited. Now the query and every tool's name, integration and description are split into words and stemmed. A word matches exactly, by prefix, or through a small synonym list (ticket → issue, email → gmail, pull request ↔ pr). A word no tool uses is first corrected to the nearest one that does (emial → email). Name matches outrank integration matches, which outrank description matches, and rare words count more. All 12 phrasings, and five misspelt ones, now put the right tool first. Built-in and custom-app tools are ranked together. Each row gains a score, the top 10 come back by default, and a new optional limit goes up to 50. It costs about 0.5 MB of cached word lists and 1–3 ms per query. See the finding.
  • MCP: curl_session token lifetime. Callers can pass expiresInSeconds, an integer from 60 to 3600 (default 900). The cap bounds how long a leaked token stays live, since there is no revoke. The response's expiresIn echoes the lifetime minted.
  • Portal: one-time link page in one column. The create form is down to one field; the expiry moved into a compact popover beside Create link. Once minted, the link takes the value's place with Copy beside it. Home gets a vault quick-access card.
  • Portal: copy the MCP endpoint from Home. The Connect your agent card has an icon-only copy button beside the URL.

Fixes

  • REST: POST /rest/browser is now routed to the owning replica. It ran wherever it landed, which under CLUSTER_ENABLED could start a second Chromium on the shared profile.
  • Custom apps: a custom app can no longer loop back to workbench. This workbench's own /mcp passed the SSRF guard (its public URL is not private), so it could be added as a custom app. Its tools are then the meta-tools, and execute_tools could call itself through it. Adding one is now refused when the server's protected-resource metadata names this instance, which also catches another hostname, a CNAME or an IP. At call time every outbound custom-app request carries X-Workbench-Via, the chain of instances it has passed through. /mcp answers 508 Loop Detected when the chain already names this instance, which also catches A → B → A across two deployments, or when the chain reaches 4 hops. Apps registered before this release are covered by the call-time check. See the finding.
  • Vault: one-time links survive chat link previews. Pasting a one-time link into Slack spent it, because the redeem was a GET and Slack's unfurl was that first GET. Teams, Discord, iMessage and mail scanners do the same. Only POST /api/vault/otl/:token spends the token now. A browser GET gets a no-script page with a Download secret button, and any other GET gets 405 Allow: POST. The link's preview card reads "Open once, then it burns." See the finding.
  • Vault: the one-time link card now renders in Slack. The page served its og: tags only when Accept contained text/html. Slack's unfurler sends Accept: */*, so it got the 405 and chat showed no card. Known link-preview bots (Slack, Twitter/X, Facebook, Discord, Telegram, WhatsApp, LinkedIn, Teams, …) are now served the page by User-Agent. This only picks page vs 405, and no GET spends the token. Verified against real Slack through a tunnelled build.
  • Google Drive: Shared Drive files and folders are reachable. Drive v3 hides Shared Drive items unless each call opts in. A Shared Drive id 404'd as "File not found" and listing a Shared Drive folder returned []. Every google-drive tool now sends supportsAllDrives=true, and list and search also send includeItemsFromAllDrives=true. No scope change, no reconnect. See the finding.

Compatibility

  • Callers of one-time links must POST. curl "$URL" now fails with a 405; use curl -X POST "$URL".
  • A session_id minted by a pre-v0.30 browser_start keeps working for this release and drives the default tab. The fallback is removed in v0.31.
  • BAD_SESSION_KEY is gone; the new errors are BROWSER_TAB_NOT_FOUND and BROWSER_TAB_LIMIT.
  • browser_live_url no longer takes session_id.
  • The portal live view shows the default tab.
  • Schema: a custom_apps table is created on boot (SQLite and PostgreSQL). It is additive; rolling back leaves it unused.
  • bcryptjs 2 → 3. New API-key hashes are written as $2b$ instead of $2a$. Existing $2a$ hashes still verify, and bcryptjs 2.4.3 reads $2b$, so existing keys keep working and a rollback does not lock anyone out.
  • search_tools returns at most 10 tools by default. Before, it returned every match. An agent that enumerated a whole plugin with one keyword ("gitlab") should pass limit: 50. Rows gain a score field; clients that ignore unknown fields are unaffected.
  • Toolchain: TypeScript 7, @types/node 26. The MCP SDK, Fastify and the portal's React Query/Router get patch updates.

Commits since v0.30.0-rc.1

  • feat(mcp): correct misspelt search words before matching them (0594ce0) — rc.4
  • feat(mcp): rank search_tools results by word, with typos and synonyms (80651cf) — rc.4
  • fix(vault): show the one-time link card to Slack and other unfurlers (b10f424) — rc.3
  • fix(custom-apps): refuse a custom app that loops back to workbench (47f6e81)
  • feat(portal): copy button beside the MCP endpoint on Home (7f245d9)
  • feat(portal): keep the custom app modal up while it connects (c48afa2)
  • feat(portal): connect a custom app as soon as it is created (54010fa)
  • feat(portal): icon-only New custom app button with a tooltip (234c6c7)
  • fix(vault): shorten one-time link card copy (43e4950)
  • feat(mcp): let curl_session callers choose the token lifetime (4736e4b)
  • fix(google-drive): reach Shared Drive files and folders (44db919)
  • feat(portal): one-time link page in one column; vault quick access on Home (9c3c038)
  • fix(vault): one-time links survive chat link previews; redeem is POST (8cc58dd)
  • feat: register external MCP servers as custom apps (#107) (00a52d2)
  • chore(deps): bump bcryptjs and @types/bcryptjs (9ef563d), plus TypeScript 7, @types/node 26 and grouped dependency/actions updates

Full diff: v0.27.0...v0.30.0