Issuer-gated remote MCP, OAuth for assistant tools, and full Slack write access
This release wires /x/mcp into per-server OAuth via user_session_issuer_id, lets assistants complete MCP OAuth mid-task, closes the Slack write-tools gap, and adds an early Remote MCP server management UI behind a feature flag.
Features
- Issuer-gated
/x/mcpand full OAuth surface per server #2926 - Adds an optionaluser_session_issuer_idonmcpServers.createandmcpServers.update. When set,/x/mcprequests without a valid Authorization receive 401 and aWWW-Authenticatepointing at/.well-known/oauth-protected-resource/x/mcp/{slug}, and the full dynamic client registration, authorize, IDP callback, consent, token, and revoke surface is mounted under/x/mcp/{slug}/.... Both well-known metadata routes return the issuer-gated shape for any addressed server with an issuer set, including remote-backed servers. The/oauth/proxy-registerhelper now also registers<server>/x/mcp/remote_login_callbackso remote-OAuth servers reached via/x/mcp/{slug}/connectcan complete the upstream callback. (Author: @bflad ) - Assistants relay MCP OAuth links mid-task #2935 - When a configured MCP server requires user authentication, the assistant relays the authorization link through an available output tool, then reconnects and continues its task once the user completes authentication. (Author: @danielkov )
- Slack assistants gain full message and channel lifecycle tools #2887 - Slack assistants can now edit, delete, and send ephemeral messages; pull permalinks; open DMs; create, join, leave, invite, archive, and rename channels; and manage pins, bookmarks, usergroup membership, reminders, file uploads, canvases, and presence/DND. Closes the previous gap where assistants could read Slack but barely write to it. (Author: @danielkov )
- Remote MCP-backed server management UI #2717 - Adds the initial dashboard UI for managing Remote MCP-backed MCP servers, gated behind the
gram-remote-mcpfeature flag. (Author: @bflad ) - Deny rules in the RBAC role editor #2946 - Admins can now grant broad access in a role and then carve out specific resources or tools that the role should not access. (Author: @adaam2 )
Bug fixes
- Disable OpenRouter reasoning across completion paths #2950 - Chat completions no longer generate hidden reasoning tokens. OpenRouter could route requests through models that produced reasoning output Gram discarded before storage while still billing for it. The proxy and every internal completion caller — chat title generation, the Slack agent loop, risk policy naming, and structured object completion — now explicitly disable reasoning. (Author: @danielkov )
- Preserve Anthropic
cache_controlthrough the chat proxy #2953 - The/chat/completionsproxy previously strippedcache_controlmarkers off the request body before forwarding to OpenRouter, so every Anthropic call billed at the full input rate. Markers are now preserved at the top level, on tool definitions, and on message content blocks, so Claude requests with stable prefixes can serve from cache. (Author: @danielkov ) - Assistants can update their own triggers #2885 - Calling
configure_triggeron an existing trigger previously returned a generic internal error because the assistant’s scoped tool was being swapped for a stricter variant. As a side effect, an assistant’s trigger list no longer leaks sibling assistants’ triggers in the same project. (Author: @danielkov ) - Attribute outbound OpenRouter completions #2952 - Outbound OpenRouter chat completions now carry a session ID, user, source metadata, and distributed-trace identifiers so OpenRouter’s dashboard can group requests per conversation and roll up cost per customer, and so Datadog traces correlate with OpenRouter’s request records. (Author: @danielkov )
- Version outbox event names #2944 - Deprecates obsolete outbox event types and adds explicit versioning in the name scheme. In particular,
risk_finding.createdis replaced byrisk_finding.created_v1. (Author: @disintegrator ) - Preserve token graph data while filtering by agent type #2936 - Fixes the token graph blanking when filtering by agent type on /insights/costs. Claude Code usage metrics were missing the
hook_sourceattribute, so the filter returned no data for non-Cursor agents. (Author: @simplesagar ) - Update Moonshine to 1.36.1 #2933 - Bumps the
@speakeasy-api/moonshinedashboard dependency to 1.36.1. (Author: @alx-xo )