# MCP OAuth and Access

> How CurrencyCore MCP sign-in works, how organization selection is bound to a connection, what the client can access, and how to revoke it.

Canonical: https://currency-core.com/docs/mcp-oauth/
Updated: 2026-11-12

---
The CurrencyCore MCP server is a remote service, so it uses OAuth instead of an
API key pasted into a config file. You sign in through your browser once, choose
an organization, and the client keeps the resulting credential.

This page explains the user-facing flow. It does not document OAuth internals
such as token formats or lifetimes, because those are managed by the client and
the authorization server.

> **Status note.** The 2026-11-11 release fixed MCP OAuth discovery: an
> unauthenticated request to `/mcp` now returns `401` with a
> `WWW-Authenticate` challenge, and the protected-resource metadata names the
> exact `/mcp` URL. If a client connected to an older deployment never opens a
> browser, see the
> [troubleshooting note](/docs/mcp-troubleshooting/#only-two-tools-and-no-sign-in-prompt).

## Why OAuth instead of an API key

An API key is a long-lived secret. Copying one into every client config makes it
easy to leak, hard to scope to a person, and awkward to revoke when someone
leaves a team.

OAuth changes the unit of access from "a key someone pasted" to "a signed-in
user, a client application, and an organization". That gives you:

- No secret in the client config file. The URL is the only thing you add.
- A browser consent step that names the organization being connected.
- Access that follows the user's membership. Removing a member removes their MCP
  access.
- An organization-level switch that stops MCP traffic without touching REST
  keys.

## The consent flow

1. **You add the server URL** `https://mcp.currency-core.com/mcp` to the client.
   You do not create an OAuth client or copy a client ID. The MCP client
   registers itself with the authorization server as part of the connection.
2. **The server challenges the connection, and the client opens a browser** the
   first time you connect or call any tool. The current server requires an
   authorized connection for every `/mcp` request, including the two reference
   tools.
3. **You sign in to CurrencyCore** with your normal account. If you are already
   signed in, the consent screen appears directly.
4. **You choose one organization.** Only organizations you belong to are
   available. The choice is recorded for this user and this client application.
5. **You approve the connection** and return to the client. The client stores the
   credential and sends it as a bearer token on MCP requests.

The connection is bound to the organization you chose. To switch organizations,
reconnect the server in the client and choose a different one. A second client
application is a separate grant, so it asks you to choose an organization again.

## Metadata a client reads

The client discovers the authorization server from the `WWW-Authenticate`
challenge on `/mcp`, then reads the protected-resource metadata at one of these
paths:

| Request | Purpose |
|---|---|
| `GET https://mcp.currency-core.com/.well-known/oauth-protected-resource/mcp` | Names the resource and the authorization server for the `/mcp` endpoint |
| `GET https://mcp.currency-core.com/.well-known/oauth-protected-resource` | The same metadata at the host root |

The response names the resource, the authorization server, and the supported
scope. The resource is the exact `/mcp` URL, not the bare host, and the scope is
`mcp:tools`. The client then fetches the authorization server metadata from the
URL named in that response and starts the browser flow.

You do not hard-code these paths in your client. A compliant MCP client follows
the challenge and the metadata links. They are listed here so you can diagnose a
connection that never opens a browser.

## What the connection can access

An authorized connection exposes the full tool set that the organization's plan
allows:

| Access | Included |
|---|---|
| Tools | All 14 tools are listed after sign-in. The two reference tools are unmetered. The seven `analyze_` tools require Growth or higher. |
| Resources | The bundled API docs and the OpenAPI 3.1 specification. |
| Prompts | `convert_with_ppp`, `compare_cost_of_living`, `build_rate_table`, `explain_error`. |
| Account changes | None. Every tool is read-only. |
| API keys | None. MCP does not mint or reveal an API key. |
| Billing changes | None. The connection cannot change a plan or payment method. |

The client cannot create, rotate, or revoke REST API keys, invite members, change
SSO settings, or read billing details. It can only fetch currency, PPP, and
analytics data.

### About scopes

The authorization server advertises standard OpenID Connect scopes (`openid`,
`profile`, `email`, and `offline_access`) plus the baseline `mcp:tools` scope
used by the connection challenge. There are no separate per-tool or
per-endpoint scopes. In practice:

- Any authorized connection can see every tool the plan allows.
- Analytics gating is enforced by the API at call time, not by an OAuth scope.
- There is no read-only versus read-write scope split, because every tool is
  already read-only.

Do not expect a consent screen that asks you to tick individual tools. It asks
you to sign in and pick an organization.

### Token handling

- The access token stays inside the client. It is not returned in tool results.
- You do not paste it into another client or into a config file.
- If the token expires or the client loses it, the next keyed call asks you to
  sign in again.
- Disconnecting in the client removes the local credential. Disabling MCP in the
  dashboard stops the organization's keyed MCP traffic for every client.

## Organization selection and membership

- The organization you pick at consent is the one that pays for the calls and
  owns the usage. The monthly quota is shared by the organization.
- Membership is revalidated on every request. If you are removed from the
  organization after connecting, the next keyed call fails even if the client
  still holds a token.
- If you belong to no organization, you cannot complete an authorized
  connection. Create an organization first, or ask an owner to invite you.
- A teammate using the same client signs in separately. They get their own grant
  and choose their own organization; they do not inherit yours.

## Usage, limits, and the MCP switch

- Each successful keyed tool call counts as one API request against the
  organization's monthly quota. Public tool calls are free.
- MCP uses no AI credits. The AI endpoint is HTTP-only and is not an MCP tool.
- MCP traffic shares the organization's per-minute limit and monthly quota with
  REST traffic.
- The dashboard shows MCP usage in the Developer area, in the MCP server panel.
  The same panel has an enable/disable switch for the organization.

Disabling MCP does not revoke REST API keys, delete the organization, or change
the plan. It stops keyed MCP calls for that organization. The switch is enforced by
the API on the next tool call, so an existing client credential can keep the
connection open but cannot complete a keyed call.

## Disconnecting and revoking

| Goal | What to do | Effect |
|---|---|---|
| Stop using the server in one client | Remove or disconnect the server in the client's MCP settings | The client deletes its local credential. Other clients are unaffected. |
| Stop all MCP traffic for the organization | Turn off the MCP switch in Dashboard, Developer, MCP server | Keyed MCP calls return `403`. REST keys keep working. |
| Stop one person's access | Remove them from the organization, or ask them to disconnect | Membership is revalidated per request, so their grant stops resolving. |
| Reconnect to a different organization | Disconnect in the client, add the server again, and choose the other organization | A new grant replaces the old one for that user and client. |

There is no separate MCP API key to rotate. If you suspect a client credential
was exposed, disconnect that client and disable the organization's MCP switch
while you investigate.

## 401 and 403 behavior

| Status | Typical cause | What to do |
|---|---|---|
| `401 unauthorized` | No token, an expired token, a revoked client, or a grant that no longer resolves to an organization (for example, after membership removal) | Reconnect the server and sign in again. If it repeats, confirm you are still a member of the organization. |
| `403 forbidden` | MCP is disabled for the organization, the tool needs Growth or higher, or the requested history window is outside the plan | Read the message. Re-enable MCP, upgrade the organization, or narrow the date range. |
| `402 billing_past_due` | The organization's billing is past due | API access is paused until payment clears. Test keys are exempt from the pause and stay capped at the Free rate limit; MCP connections are treated as live and return `402`. |
| `429 rate_limited` | The organization hit its per-minute limit or monthly quota | Wait for the window to reset, or upgrade. Read `currencycore/retry_after_s` in the tool result. |

A `403` is not automatically an authentication problem. Re-signing in will not
fix a plan gate or a disabled MCP switch. The
[troubleshooting guide](/docs/mcp-troubleshooting/) separates these cases.

## Related

- [MCP tools](/docs/mcp-tools/)
- [MCP troubleshooting](/docs/mcp-troubleshooting/)
- [Authentication and keys](/docs/authentication/)
- [Billing and limits](/docs/billing/)
