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

# Connect Your AI Assistant to Cal ID

> Set up the Cal ID MCP server in Claude Desktop, Cursor, ChatGPT, or any MCP-compatible client, verify the connection works, and fix the most common setup errors.

Connecting takes three things: the server URL, your API key, and a client that speaks MCP. This page covers the setup for the most common clients, how to confirm it worked, and what to do when it doesn't.

## Before you start

<Steps>
  <Step title="Get your API key">
    Go to **Settings → Developer → API Keys** and create a key, or follow [How to get your API key](/docs/developers/api-key). It looks like `calid_` followed by a long string.
  </Step>

  <Step title="Copy the server URL">
    Every client uses the same endpoint:

    ```
    https://mcp.cal.id/mcp
    ```
  </Step>

  <Step title="Have your client ready">
    Install or open the app you want to connect, and find where it manages MCP servers or connectors.
  </Step>
</Steps>

<Warning>
  In every example below, replace `calid_xxx` with your real key. Treat it like a password — don't commit it to a repository or paste it into a shared document.
</Warning>

## Set up your client

<Tabs>
  <Tab title="Claude Desktop">
    Open **Settings → Developer** (or **Connectors**), add a custom MCP server, and use this configuration:

    ```json theme={null}
    {
      "mcpServers": {
        "calid": {
          "type": "http",
          "url": "https://mcp.cal.id/mcp",
          "headers": {
            "Authorization": "Bearer calid_xxx"
          }
        }
      }
    }
    ```

    Save, then restart Claude Desktop if the server doesn't appear right away.

    <Note>
      **If the direct setup isn't accepted**, use the `mcp-remote` bridge instead. It runs a small local process that forwards to the hosted server:

      ```json theme={null}
      {
        "mcpServers": {
          "calid": {
            "command": "npx",
            "args": ["-y", "mcp-remote", "https://mcp.cal.id/mcp",
                     "--header", "Authorization:${AUTH_HEADER}"],
            "env": { "AUTH_HEADER": "Bearer calid_xxx" }
          }
        }
      }
      ```

      The bridge needs Node.js installed.
    </Note>

    <Warning>
      **Copy `Authorization:${AUTH_HEADER}` exactly — there is no space after the colon.** It looks like a typo, and it isn't. `mcp-remote` splits the `--header` value on the first colon, and on Windows and inside Cursor a space there breaks the argument, so the header never reaches the server.

      Two more things that go wrong here:

      * **`--header` is the only way to send a header.** There is no `MCP_REMOTE_HEADER_AUTHORIZATION` environment variable. If you set one, `mcp-remote` ignores it and connects **unauthenticated** — and the connection still looks healthy, because tools still list. See [Verify the connection](#verify-the-connection).
      * **The `env` block is what keeps your key out of the process list.** `mcp-remote` substitutes `${AUTH_HEADER}` from `env` at launch. You can inline the key in `args` instead, but then it shows up in your shell history and process table.
    </Warning>
  </Tab>

  <Tab title="Cursor">
    Open **Settings → MCP** and add a server named `calid`, or create a `.cursor/mcp.json` file in your project:

    ```json theme={null}
    {
      "mcpServers": {
        "calid": {
          "url": "https://mcp.cal.id/mcp",
          "headers": {
            "Authorization": "Bearer calid_xxx"
          }
        }
      }
    }
    ```

    Reload Cursor or reconnect the server, then confirm it shows as connected.

    <Tip>
      A project-level `.cursor/mcp.json` is convenient, but it puts your key in the repository. Add it to `.gitignore`, or configure the server in Cursor's global settings instead.
    </Tip>
  </Tab>

  <Tab title="ChatGPT">
    Open **Settings → Connectors** (or **Apps & Connectors**) and add a custom connector.

    <Steps>
      <Step title="Add the connector">
        Paste `https://mcp.cal.id/mcp` as the MCP server URL.
      </Step>

      <Step title="Authenticate">
        When asked for authentication, choose **Bearer token** and paste your Cal ID API key.
      </Step>

      <Step title="Enable it">
        Save the connector, then enable it in a chat.
      </Step>
    </Steps>

    ```json theme={null}
    {
      "name": "Cal ID",
      "mcp_url": "https://mcp.cal.id/mcp",
      "authentication": {
        "type": "bearer",
        "token": "calid_xxx"
      }
    }
    ```

    <Note>
      Custom connectors depend on your ChatGPT plan and workspace settings, and may need developer mode or admin approval. If you can't add one, use Claude or Cursor.
    </Note>
  </Tab>

  <Tab title="Other clients">
    Any client that supports remote MCP servers over HTTP works. Provide the URL and an authorization header:

    ```json theme={null}
    {
      "mcpServers": {
        "calid": {
          "type": "http",
          "url": "https://mcp.cal.id/mcp",
          "headers": {
            "Authorization": "Bearer calid_xxx",
            "Accept": "application/json, text/event-stream"
          }
        }
      }
    }
    ```

    If your client asks for a transport, choose **HTTP** or **Streamable HTTP**. If it only supports stdio, use the `mcp-remote` bridge shown in the Claude Desktop tab.

    <Warning>
      **`Accept: application/json, text/event-stream` is mandatory.** The server needs both values. Send only `application/json` and every request fails with `406` and `Client must accept both`. Most MCP clients set this for you; hand-rolled HTTP clients usually don't.
    </Warning>
  </Tab>
</Tabs>

## Verify the connection

<Warning>
  **A connected server does not mean an accepted key.** Cal ID does not check your credentials during `initialize` or `tools/list`. A completely made-up key gets a 200, gets a session ID, and gets all 58 tools listed back. Your client will show `calid` as connected, with a full tool list, whether or not your key is real.

  The key is only checked when a tool actually runs. So seeing the tools appear tells you the URL and transport are right — and nothing at all about your authentication.
</Warning>

The only real check is to **call a tool**. Use `get_users_me`: it reads your own profile, changes nothing, and needs no arguments.

The quickest version is conversational: open a new chat and ask **"Who am I in Cal ID?"** If your own name and email come back, your key works. If the assistant reports an error from the tool, the key is the first thing to suspect.

### Check it manually

Useful when a client fails silently, or when support asks what the server returned.

<Steps>
  <Step title="Open a session">
    ```bash theme={null}
    curl -i https://mcp.cal.id/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer calid_xxx" \
      -d '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0.0"}}}'
    ```

    The response identifies the server and returns a session ID in the `mcp-session-id` response header:

    ```
    event: message
    data: {"result":{"protocolVersion":"2025-03-26","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"calid-connector-mcp","version":"1.0.0"}},"jsonrpc":"2.0","id":"init-1"}
    ```

    Copy the `mcp-session-id` value out of the response headers. **This step succeeds with any key, including a fake one** — it proves the endpoint is reachable, nothing more.
  </Step>

  <Step title="List the tools (optional)">
    Pass the session ID back to see what the server offers:

    ```bash theme={null}
    curl -i https://mcp.cal.id/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer calid_xxx" \
      -H "mcp-session-id: <SESSION_ID>" \
      -d '{"jsonrpc":"2.0","id":"2","method":"tools/list","params":{}}'
    ```

    All 58 tools come back. **This also succeeds with a fake key** — skip it if all you want to know is whether you're authenticated.
  </Step>

  <Step title="Call get_users_me — this is the real test">
    ```bash theme={null}
    curl -i https://mcp.cal.id/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json, text/event-stream" \
      -H "Authorization: Bearer calid_xxx" \
      -H "mcp-session-id: <SESSION_ID>" \
      -d '{"jsonrpc":"2.0","id":"3","method":"tools/call","params":{"name":"get_users_me","arguments":{}}}'
    ```

    **Your key works** when the `result` object's first content block reports a 200 and your profile follows in the second:

    ```json theme={null}
    {
      "content": [
        { "type": "text", "text": "HTTP 200 GET /users/me" },
        { "type": "text", "text": "{\"success\":true,\"data\":{\"id\":123,\"email\":\"you@example.com\"}}" }
      ]
    }
    ```

    **Your key is rejected** when `isError` is `true` and the first content block reports a 401:

    ```json theme={null}
    {
      "content": [
        { "type": "text", "text": "HTTP 401 GET /users/me" }
      ],
      "isError": true
    }
    ```
  </Step>
</Steps>

<Warning>
  **An auth failure arrives as a tool result, not as an HTTP error.** The `tools/call` request itself returns `200 OK`. The 401 is text *inside* the JSON-RPC result, flagged by `isError: true`. Anything that only inspects HTTP status codes — a health check, a retry wrapper, a client's connection indicator — will read a rejected key as a success. Check `isError` and read `content[0]`.
</Warning>

<Note>
  Responses stream as server-sent events, so each payload arrives on a line beginning with `data: `. That's expected — it isn't an error.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Tools are listed, but every tool call fails">
    This is what a bad or missing key looks like — the server connects and lists all 58 tools, then rejects the first real call with `HTTP 401 GET /users/me` and `isError: true`.

    * Confirm the header is `Authorization: Bearer calid_xxx` — the word `Bearer`, one space, then the key.
    * Check for a trailing space or line break from copy-paste.
    * Confirm the key still exists under **Settings → Developer → API Keys**.
    * **If you use `mcp-remote`**, check that the key is passed with `--header`, not through an environment variable like `MCP_REMOTE_HEADER_AUTHORIZATION`. That variable does nothing, and the bridge will connect without any credentials at all. See the [Claude Desktop tab](#set-up-your-client).
    * Also with `mcp-remote`, check there is no space after the colon in `Authorization:${AUTH_HEADER}`.

    Cal ID accepts the key **only** as a Bearer token. Appending `?apiKey=` to the URL will not authenticate.
  </Accordion>

  <Accordion title="The server connects but no tools appear">
    Usually the client hasn't finished the MCP handshake, or it isn't sending the `Accept` header the server requires.

    * **Send `Accept: application/json, text/event-stream`.** Both values are mandatory. Sending only `application/json` returns `406` with the message `Client must accept both`, and most clients surface that as an empty tool list rather than an error.
    * Restart the client fully, then reopen it.
    * Make sure the URL ends in `/mcp`, not `/` or `/docs`.
    * If your client needs stdio, switch to the `mcp-remote` bridge.

    An empty tool list is never an authentication problem — auth is not checked until a tool runs.
  </Accordion>

  <Accordion title="The configuration is rejected as invalid">
    Almost always JSON syntax — a missing comma, a stray trailing comma, or unbalanced braces. Paste the config into a JSON validator before saving.
  </Accordion>

  <Accordion title="A tool returns 'Expected string, received number' — or the reverse">
    `eventTypeId` is a **string** for `get_slots` and a **number** for `create_booking`, so the slots-then-book flow needs it converted in between: `"106371"` for slots, `106371` for the booking.

    If you're prompting conversationally you'll rarely hit this. If you're calling tools directly, see the [type gotchas](/docs/mcp/tools#input-gotchas).
  </Accordion>

  <Accordion title="A tool returns 'Required' with path ['body']">
    Every write tool nests its arguments under a `body` object. Sending the fields at the top level fails validation before the request reaches the API. See [the `body` wrapper](/docs/mcp/tools#input-gotchas).
  </Accordion>

  <Accordion title="Creating a booking fails with no_available_users_found_error">
    You're trying to book a time that isn't actually on offer. You cannot calculate bookable times yourself — a slot that looks valid can still be rejected.

    Always call `get_slots` first and book one of the times it returns. See [Booking through MCP](/docs/mcp/tools#booking-through-mcp).
  </Accordion>

  <Accordion title="I'm not sure which client to use">
    Claude Desktop and Cursor have the broadest MCP support and are the easiest to get working. ChatGPT connectors depend on your plan and workspace permissions.
  </Accordion>
</AccordionGroup>

<Info>
  Still stuck? Ask the assistant on this site, or start a live chat from the widget in the corner. Include the `get_users_me` result from the manual check above — with your key redacted — since that's the step that shows whether you're authenticated.
</Info>

## MCP tools and API access

<CardGroup cols={2}>
  <Card title="Tool reference" icon="wrench" href="/docs/mcp/tools">
    Every tool, what it maps to, and the gotchas worth knowing.
  </Card>

  <Card title="MCP overview" icon="plug" href="/docs/mcp/overview">
    What MCP can and can't do, and how permissions work.
  </Card>

  <Card title="Manage API keys" icon="key" href="/docs/developers/api-key">
    Rotate or revoke the key your assistant is using.
  </Card>

  <Card title="REST API reference" icon="code" href="/docs/api-reference/introduction">
    Call the same endpoints directly from your own code.
  </Card>
</CardGroup>


## Related topics

- [Cal ID MCP Server](/docs/mcp/overview.md)
- [Cal ID MCP Tool Reference](/docs/mcp/tools.md)
- [How to Get Your Cal ID API Key](/docs/developers/api-key.md)
- [Cal ID Scheduling API Reference](/docs/api-reference/introduction.md)
