---
title: "Begin an OAuth connect for an MCP server"
method: POST
path: "/v1/mcp-servers/oauth/start"
tags: ["mcp-servers"]
---

# Begin an OAuth connect for an MCP server

`POST /v1/mcp-servers/oauth/start`

## Request

- Base URL: `https://api.patricia.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.patricia.app/v1/mcp-servers/oauth/start`
- Auth: HTTP bearer

Discovers the server's authorization service, registers a client if one is needed, and returns the URL to send the connecting person to. Nothing is connected until the ceremony completes.

## Headers

- `X-Tenant-Id` string, nullable

## Request body

- OAuthStartBody: The address, and — only on a second attempt — the client credential the server needs. No auth-mode chips. The client credential is a LATER step by design, offered only after every automatic path has been tried and refused: asking for it up front would make the common case (96.2% of hosts register automatically) look like the hard case. The dashboard does not show the fields until a start has come back with ``MCP_CLIENT_CREDENTIALS_REQUIRED`` or ``MCP_PUBLIC_CLIENT_ID_REQUIRED``, and then it resubmits this same body with them filled in. The second code is what makes the secret optional on that form, for a service that issues none. **A secret never arrives without an id.** A lone secret is a 422, not a partial credential; a lone id is a public client, and only the discovered server can say whether that is one this service issues. **An empty secret is read as none supplied; a whitespace-only one is refused.** Those are different answers on purpose: an empty field is somebody who has no secret, and spaces are a mistyped one. An empty client id is refused either way. The generated types cannot express any of this on their own — they describe two independent optional strings, which is what a second consumer would build against. The pair, its bounds and both of those rules are INHERITED from :class:`services.mcp_oauth.PastedClientCredentialFields`, which is the only implementation. This body adds the three fields the console has and the chat setup lane must not: the address, the account to re-consent, and the audience.
  - `client_id` string, nullable
  - `client_secret` string, nullable
  - `base_url` string, required
  - `account_id` string, uuid, nullable
  - `visibility` 'team' | 'personal', nullable

## Response `200`

Successful Response

- OAuthStartResponse: Where to send the browser, and what it will come back as.
  - `authorize_url` string, required
  - `attempt_id` string, uuid, required
  - `expires_at` string, date-time, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/patricia/apis/patricia-api.md) · [All operations](https://skmtc.dev/patricia/apis/patricia-api/llms.txt) · [OpenAPI document](https://skmtc.dev/patricia/apis/patricia-api/revisions/0dfb44495ea1?raw)
