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

# MCP Server

> Connect Claude Desktop, Cursor, claude.ai, or any MCP-compatible client to Alex and query your candidates, jobs, and interview data in natural language.

Alex hosts a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server at `https://mcp.alex.com/mcp`. Any MCP-compatible client can connect to it and let users query Alex with natural language — search candidates, summarize pipelines, pull interview reports, ask product questions — without writing custom integration code.

The server is **read-only**. It exposes the same data surfaces an authenticated user can see in `app.alex.com`, scoped to whichever Alex companies the authenticated identity has access to.

## What you can ask

* "Who are my top 10 candidates for the Senior Backend Engineer role?"
* "Summarize last month's interviews — completion rate, average score, decisions."
* "What's the candidate pipeline for the Atlanta Sales Lead position?"
* "Pull the interview report for [jane@acme.com](mailto:jane@acme.com)."
* "How do I integrate Alex with Bullhorn?" *(answered from Alex documentation)*

## Authentication

The server accepts two auth methods, both passed as `Authorization: Bearer <token>`:

| Method                                    | Best for                                                               | Notes                                                                                                         |
| ----------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| **Sign in with Alex** (OAuth 2.1 + Auth0) | claude.ai, Claude Desktop, Cursor — anywhere a user is at the keyboard | Standard OAuth flow; the token is tied to an Alex user and grants access to every company they're a member of |
| **API key**                               | Programmatic clients, scripts, server-to-server agents                 | Single shared key per company, no expiry; one key = one company                                               |

### Sign in with Alex (OAuth)

Recommended for end-user clients. The MCP client discovers the OAuth flow automatically via `https://mcp.alex.com/.well-known/oauth-authorization-server`, then redirects through the Alex login screen at Auth0. After sign-in, the client receives access and refresh tokens tied to that Alex user.

#### claude.ai

1. **Settings → Connectors → Add custom connector.**
2. Server URL: `https://mcp.alex.com/mcp`.
3. **Connect.** claude.ai walks you through the Alex login.
4. The connector lights up; Alex tools appear in any new chat's tools menu.

#### Claude Desktop

Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json theme={null}
{
  "mcpServers": {
    "alex": {
      "url": "https://mcp.alex.com/mcp"
    }
  }
}
```

Quit and reopen Claude Desktop. On first connect it discovers OAuth, runs the Alex login flow, and persists the token.

#### Cursor

`~/.cursor/mcp.json`:

```json theme={null}
{
  "mcpServers": {
    "alex": {
      "url": "https://mcp.alex.com/mcp"
    }
  }
}
```

#### Token lifetime

Access tokens expire after one hour. Refresh tokens last seven days and rotate on use. Clients handle the refresh automatically; you'll only re-authenticate if the refresh token expires (week of inactivity) or you remove the connector.

### API key

Use this for non-interactive clients — scripts, server-to-server agents, anywhere there isn't a human to walk through OAuth.

1. In `app.alex.com`, **Settings → API Keys**, generate a key (or ask your Alex admin).
2. Pass it as a Bearer token:

```bash theme={null}
curl -X POST https://mcp.alex.com/mcp \
  -H "Authorization: Bearer YOUR_ALEX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

Claude Desktop and Cursor accept API keys directly in the config block as a fallback to OAuth:

```json theme={null}
{
  "mcpServers": {
    "alex": {
      "url": "https://mcp.alex.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_ALEX_API_KEY" }
    }
  }
}
```

<Warning>
  An API key has full read access to your company's data. Treat it like a password. Rotate any time in Settings.
</Warning>

## Multi-company access

Some Alex users belong to more than one company (commonly: staffing agencies that operate multiple Alex tenants). When you sign in via OAuth, the resulting token covers **every active company the user is a member of**.

Most tools accept an optional `companyId` argument:

* **Omit it** → the tool defaults to your "primary" / first-listed company. Convenient when there's only one.
* **Pass it explicitly** → scopes the call to that specific company. Useful when a user has multiple memberships and asks "show me Acme's open jobs vs. Beta's".

To discover what's accessible, call the [`listCompanies` tool](/api-reference/mcp/tools#listcompanies). The LLM can also use it implicitly: when a user asks about "Acme", the model calls `listCompanies`, finds the matching `companyId`, and includes it in the next tool call.

API-key auth is single-company by definition — one key authenticates as one company, and `companyId` is fixed.

## Discovery endpoints

For programmatic clients building against the server:

| Endpoint                                      | Purpose                                                                                           |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `GET /.well-known/oauth-authorization-server` | RFC 8414 authorization-server metadata (issuer, endpoints, supported methods)                     |
| `GET /.well-known/oauth-protected-resource`   | RFC 9728 protected-resource metadata (which authorization servers issue tokens for this resource) |
| `POST /oauth/register`                        | RFC 7591 dynamic client registration                                                              |
| `GET /oauth/authorize`                        | OAuth authorization endpoint (redirects to Auth0)                                                 |
| `POST /oauth/token`                           | OAuth token endpoint (authorization\_code + refresh\_token grants)                                |
| `POST /mcp`                                   | MCP JSON-RPC endpoint (Streamable HTTP transport)                                                 |
| `GET /healthz`                                | Liveness probe                                                                                    |

Unauthenticated requests to `/mcp` respond with `WWW-Authenticate: Bearer realm="https://mcp.alex.com", resource_metadata="https://mcp.alex.com/.well-known/oauth-protected-resource"` so clients can discover OAuth on first contact.

## Security model

* **Per-request authorization.** Every `/mcp` request re-validates the token: for OAuth, we re-confirm the user's company memberships against the database on each call, so revoking a user's access takes effect within (at most) one access-token TTL.
* **Strict company scoping.** A non-admin user can only call tools with `companyId` values present in their token's company list. Tools server-side scope every database query by `companyId`.
* **Tokens are short-lived.** Access tokens expire after 1 hour; refresh tokens after 7 days. Compromise blast radius is bounded.
* **All HTTPS, all the time.** TLS via Let's Encrypt; HSTS enabled.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Claude doesn't see any Alex tools">
    Check that your config is valid JSON and restart your client fully (Cmd-Q on macOS). The tools panel in any chat should list `searchCandidates`, `getJobDetails`, etc.
  </Accordion>

  <Accordion title="`401 unauthorized` when calling tools">
    For OAuth: your access token may have expired. Disconnect and reconnect from your client's connector settings.
    For API key: the key is invalid or has been revoked. Generate a new one in `app.alex.com → Settings → API Keys`.
  </Accordion>

  <Accordion title="OAuth flow ends with 'No active Alex account is associated with this email'">
    The email you signed into Auth0 with doesn't match an active Alex user, or the user has been soft-deleted. Confirm with your Alex admin that the user exists and is active.
  </Accordion>

  <Accordion title="Tool call says 'companyId is not in your accessible companies'">
    The LLM passed a `companyId` you don't have access to. Have it call `listCompanies` first to see what's available, then retry with one of those IDs.
  </Accordion>

  <Accordion title="Tool calls hang or time out">
    Searches over very large candidate pools can take up to 60 seconds. Increase your client's tool-call timeout if you're hitting limits.
  </Accordion>
</AccordionGroup>
