Remote MCP servers

Register your organization's own MCP servers and serve their tools through the same authenticated surface.

An organization admin can register any HTTPS MCP server as a remote connector. Its tools appear as org__<slug>__<tool> on the org's /mcp surface (the org__ marker is what lets your slug coexist with a same-named built-in connector) — same authentication, same holds, same activity trail as every built-in capability. Registration is org-scoped: nothing you register is visible to any other organization.

Register from Dashboard → Connectors, with the manage__remote_add MCP tool, or via POST /connectors/org. Three auth modes:

  • oauth — each member authorizes their own account against the server's authorization server; CoreSpeed stores and refreshes the grant. A member can share their account with another member, an agent, or the whole organization (see Sharing an account).
  • static_bearer — one org-wide Authorization: Bearer <token> sent upstream; the token is encrypted at rest.
  • none — no credential; anyone who knows the URL can call the server.

OAuth mode and the callback URL

On an oauth registration CoreSpeed discovers the server's authorization server (RFC 9728) and — when that AS advertises a registration_endpoint — registers an OAuth client automatically (RFC 7591 dynamic client registration). The client is always registered with this exact redirect URI:

OAuth redirect URI (production)
https://app.corespeed.io/connectors/callback

The path is always /connectors/callback under the environment's dashboard origin.

Servers that implement registration without the optional RFC 7592 management extension — Cloudflare Access, Neon, and everything built on Cloudflare's workers-oauth-provider — work normally: the client registers and activates. The one consequence is on removal: CoreSpeed deletes everything on its side, but the inert client record stays on the authorization server, because that server offers no way to delete it.

Many authorization servers restrict registration: some offer no dynamic registration at all, and some accept it only for redirect URIs already allowlisted in their configuration (Cloudflare Access behaves this way — its registration endpoint answers invalid_client_metadata for any redirect URI the Access application has not been told about). Either setup works:

  1. Allow the redirect URI, keep automatic registration. Add the redirect URI above to the authorization server's allowed redirect URIs, then register the connector in oauth mode — dynamic registration proceeds on its own.
  2. Pre-register a client yourself. Create a client in the authorization server's console with the redirect URI above, grant types authorization_code + refresh_token, and response type code; then pass its client_id (and client_secret, unless it is a public PKCE-only client) with the registration.

When an OAuth registration fails

  • The authorization server rejects the registration (an HTTP 4xx error response): the error carries the HTTP status, plus the server's machine-readable error code whenever the answer uses a registered one (the RFC 7591 registration errors or the generic OAuth vocabulary — free-text detail stays confined to the server). Nothing is left behind and the slug stays free — fix the configuration using one of the two setups above and register again. In the rare case the cleanup itself fails mid-flight, the slug falls back to a dcr_pending reservation; clear it as below.
  • The outcome is unknown (network failure, timeout, or a 5xx answer): the slug is held by a dcr_pending reservation so that a blind retry cannot create a duplicate client on the upstream server. An organization admin clears it with manage__remote_remove, passing expected_status=dcr_pending and the reservation's registration_id from manage__remote_list as expected_registration_id, then registers again.

After a successful registration each member authorizes their own account from the dashboard. The server's tools appear in tools/list once a member's authorization has fetched them.

Sharing an account

On an oauth server, a member who authorized can share that account like any other connected account: choose Share on it on the server's page, or call manage__accounts_share with connector: "org__<slug>" and the slug as alias. A share allows every tool or a list you pick (org__<slug>__<tool>), and can require your approval on every call.

A call acts under the caller's own account. A caller with no account of their own acts under the account shared with them. When two or more members shared theirs and the caller has none, the call fails with ambiguous_account: connect your own, or call from an environment that holds one of them. A static_bearer or none server needs no sharing: every member already uses it.