# Remote MCP servers (/docs/connectors/remote-mcp)

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](https://app.corespeed.io/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.
* **`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 \[#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:

```text title="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 \[#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 `remote_remove`, passing `expected_status=dcr_pending` and
  the reservation's `registration_id` from `remote_list`, then registers
  again.

After a successful registration each member authorizes their own account from
the dashboard; the connector's tools appear in `tools/list` once the caller
has a usable grant.