> ## Documentation Index
> Fetch the complete documentation index at: https://docs.caret.so/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Authentication

> How to authenticate with the Caret MCP server using OAuth 2.0 or API keys

The Caret MCP server supports two authentication methods: **OAuth 2.0 with PKCE** (recommended) and **API Key** (legacy).

## OAuth 2.0 with PKCE

Most MCP clients (Claude Desktop, Cursor, etc.) handle the OAuth flow automatically. This section is for developers building custom MCP clients.

### 1. Dynamic Client Registration

Register your client to get a `client_id` and `client_secret`.

<CodeGroup>
  ```bash curl theme={null}

  curl -X POST "https://api.caret.so/mcp/oauth/register" \
   -H "Content-Type: application/json" \
   -d '{
  "client_name": "My MCP Client",
  "redirect_uris": ["http://localhost:3000/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "client_secret_post",
  "scope": "read offline_access"
  }'

  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "client_id": "caret_abc123...",
  "client_secret": "secret_xyz...",
  "client_name": "My MCP Client",
  "redirect_uris": ["http://localhost:3000/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "client_secret_post",
  "scope": "read write offline_access openid profile email"
}
```

### 2. Authorization Request

Redirect the user to the authorization endpoint.

```
GET https://api.caret.so/mcp/oauth/authorize
  ?response_type=code
  &client_id={client_id}
  &redirect_uri={redirect_uri}
  &code_challenge={code_challenge}
  &code_challenge_method=S256
  &state={state}
  &scope=read+offline_access
```

| Parameter               | Required       | Description                                 |
| :---------------------- | :------------- | :------------------------------------------ |
| `response_type`         | Yes            | Must be `code`                              |
| `client_id`             | Yes            | From client registration                    |
| `redirect_uri`          | Yes            | Must match a registered redirect URI        |
| `code_challenge`        | Recommended    | PKCE code challenge (S256)                  |
| `code_challenge_method` | With challenge | Must be `S256`                              |
| `state`                 | Recommended    | Opaque value for CSRF protection            |
| `scope`                 | Optional       | Space-separated scopes (defaults to `read`) |

The user will be redirected to Google sign-in, then prompted to select a Caret workspace. After authorization, the user is redirected back to your `redirect_uri` with a `code` parameter.

### 3. Token Exchange

Exchange the authorization code for tokens.

<CodeGroup>
  ```bash curl theme={null}

  curl -X POST "https://api.caret.so/mcp/oauth/token" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=authorization_code" \
   -d "code={authorization_code}" \
   -d "redirect_uri={redirect_uri}" \
   -d "client_id={client_id}" \
   -d "client_secret={client_secret}" \
   -d "code_verifier={code_verifier}"

  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_abc123...",
  "scope": "read offline_access"
}
```

### 4. Token Refresh

When the access token expires, use the refresh token to get a new one.

<CodeGroup>
  ```bash curl theme={null}

  curl -X POST "https://api.caret.so/mcp/oauth/token" \
   -H "Content-Type: application/x-www-form-urlencoded" \
   -d "grant_type=refresh_token" \
   -d "refresh_token={refresh_token}" \
   -d "client_id={client_id}" \
   -d "client_secret={client_secret}"

  ```
</CodeGroup>

The old refresh token is revoked and a new one is issued with each refresh.

### Scopes

| Scope            | Description                                             |
| :--------------- | :------------------------------------------------------ |
| `read`           | Read access to notes, knowledge, workspace, and members |
| `write`          | Write access (reserved for future use)                  |
| `offline_access` | Request a refresh token                                 |
| `openid`         | OpenID Connect identity                                 |
| `profile`        | User profile info                                       |
| `email`          | User email address                                      |

### Token Lifetime

| Token              | Lifetime   |
| :----------------- | :--------- |
| Access token (JWT) | 1 hour     |
| Refresh token      | 30 days    |
| Authorization code | 10 minutes |

## API Key Authentication

As an alternative to OAuth, you can use an existing Caret API key.

<CodeGroup>
  ```bash curl theme={null}

  curl -X POST "https://api.caret.so/mcp" \
    -H "Authorization: Bearer your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{"method": "tools/call", ...}'
  ```
</CodeGroup>

Create API keys in **Settings > Developer** in the Caret app. See [API Authentication](/api-reference/authentication) for details.

## Permission Mapping

| Permission        | MCP Tools                                                                            |
| :---------------- | :----------------------------------------------------------------------------------- |
| `notes` / `read`  | `caret_list_notes`, `caret_get_note`, `caret_search_notes`, `caret_search_knowledge` |
| `users` / `read`  | `caret_list_members`                                                                 |
| *(none required)* | `caret_get_workspace`                                                                |

## Errors

| Error             | Status  | Description                                                           |
| :---------------- | :------ | :-------------------------------------------------------------------- |
| `invalid_client`  | 400/401 | Unknown client or authentication failed                               |
| `invalid_grant`   | 400     | Authorization code expired, already used, or PKCE verification failed |
| `invalid_scope`   | 400     | Requested scope not supported or not allowed                          |
| `invalid_request` | 400     | Missing or malformed parameters                                       |
| `server_error`    | 500     | Internal server error                                                 |
