[Feat] Deployment-scoped custom MCP servers (remote, OAuth, and stdio) - #1147
Conversation
…un-token stdio query
…and pinned metadata
|
Fixed in 97537bb. The cap was enforced after Capped upstreams now read through Covered by three tests: an oversized parsed body, an oversized |
isDefinitiveOAuthRejection matched 'invalid_grant|invalid_client' against the wrapped error message, so any upstream failure whose body happened to contain those words (a proxy error page, a 5xx with prose) would kill a healthy connection into the reconnect state, and message rewording would silently break the classification. Token-endpoint failures now throw OAuthTokenRequestError carrying the parsed RFC 6749 error code from the response body, and the classifier decides on that code alone. Non-JSON bodies yield no code and are always treated as transient.
MCP servers are distributed as JSON snippets, so the add dialog now has an Import from JSON button that accepts an mcpServers wrapper (or VS Code's servers wrapper, a single-entry map, or a bare config) and prefills the form for review. Import is create-time only: the edit dialog keeps field-by-field editing because blank secret values there mean 'keep the stored value'. Snippets that launch mcp-remote are converted to remote servers on the upstream URL, carrying --header pairs and reporting any dropped flags, since the proxy path keeps credentials server-side and supports per-tool management.
The header deny list reserved 'authorization' for the proxy, which made it impossible to configure remote servers that expect a plain 'Authorization: Bearer <api-key>', the most common auth scheme for hosted MCP endpoints. The reservation only exists to protect proxy-injected credentials, and header auth can never coincide with those: the schema rejects custom headers on OAuth servers, and the proxy rebuilds upstream headers from scratch so the caller's run token is never forwarded either way. Authorization is now allowed for header-auth servers, with a proxy test pinning that the operator value reaches the upstream while the run token still does not.
…st edits on disabled servers Two follow-ups from review: - The Settings tool lister's session fallback jumped from initialize straight to tools/list, which spec-strict servers refuse until the client sends notifications/initialized. The notification is now sent between the two, best-effort: lenient servers that reject it still get the tools/list, and if a strict server required it the tools/list failure surfaces as before. - setDisabledTools required the server to be enabled, so a disabled server's deny list could not be adjusted while preparing it for re-enablement. The enabled filter is dropped.
[Feat] Deployment-scoped custom MCP servers (remote + OAuth + stdio)
Closes #1142.
Adds a Custom MCP Servers section to Settings → Integrations where deployment admins can connect MCP servers that are not in the built-in catalog. Custom servers become available to agents in every task.
What's supported
/api/mcp/custom/<id>); the proxy injects credentials per request, so header values and OAuth tokens never enter sandbox-readable config or the browser.mcpServers(inheriting the reserved-env-reference defenses and the mise shim fix). Env values are encrypted at rest and write-only in the UI.Security
safeFetchegress guard for all control-plane traffic to operator-supplied URLs (the proxy data path and every OAuth discovery hop, including URLs the remote server itself supplies): private/special-use ranges blocked, DNS answers vetted and pinned (anti-rebinding), redirects refused. Self-hosters can allow specific internal ranges withR_CUSTOM_MCP_ALLOWED_PRIVATE_CIDRS(a CIDR list, deliberately not a boolean).roomote, catalog ids,github,slack) and reserved runtime env references are rejected at save time.authorization,host,mcp-session-id, ...) cannot be overridden; header values are validated against CR/LF injection.R_CUSTOM_MCP_DISABLEDkill switch, independent ofR_CURATED_INTEGRATIONS_DISABLED(operators who disable the catalog are the primary custom-server audience).Notes
mcpServers; the more specific scope wins name collisions.integrations/custom-mcp-serverspage plus updates to the integrations index and the add-integration skill.mcpConnectionsunder acustom:<serverId>id namespace, which previous-release code ignores.Testing
Screenshots
Custom servers render as ordinary integration cards in the same Connected/Configured grids as the built-in catalog, marked with a small Custom badge. A prompt bar at the top is the entry point for adding one.
Adding a server starts from one dialog that chooses between a remote (HTTP) and a local (stdio) server: