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

# Connect Claude, ChatGPT, Cursor, and other agents

> Point Cursor, Claude Code, VS Code, or Codex at https://api.freshtalent.ai/mcp. Same API key as REST. Eight tools.

FreshTalent's MCP server is eight tools on purpose. A REST mirror with forty endpoints makes agents stall.

The test sentence:

> Start a Target for Palantir FDEs who left at least 18 months ago. When they go Open to work, put them on my hot list.

That should become `search` → `watch` → `collect` → `events` / `subscribe`. Tool names stay `watch` / `collect`; the dashboard calls those **Targets** and **Lists**.

<Note>
  This page is the **product MCP**. It uses your API key and mutates Lists and Targets. The **Connect to Cursor / VS Code** control in the docs header is a different server — a read-only docs assistant at `https://docs.freshtalent.ai/mcp`. Do not mix them up.
</Note>

|           |                                                            |
| --------- | ---------------------------------------------------------- |
| Transport | Streamable HTTP                                            |
| URL       | `https://api.freshtalent.ai/mcp`                           |
| Auth      | `Authorization: Bearer ft_live_…` (`X-Api-Key` also works) |
| Tools     | 8                                                          |

There is no npm package and no local process to start. The host opens that URL with your key.

<Warning>
  Hosts that can send a header — Cursor, Claude Code, VS Code, Codex — take the key as-is. Claude's web and Desktop **connectors** and ChatGPT **apps** only speak OAuth, so they cannot carry a static key. Claude Desktop works through the `mcp-remote` bridge below; ChatGPT has no supported path yet.
</Warning>

## 1. Get a key

Create a key in the [dashboard](https://freshtalent.ai) under **API Keys**. It is shown once.

<Warning>
  Keep the key in the host's secret store or `mcp.json`. Do not paste a live key into chat, a ticket, or a public repo.
</Warning>

## 2. Pick a host

<CardGroup cols={3}>
  <Card title="Cursor" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/cursor.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=743dda4e729869ee5a0ea5ec61b6fddd" href="#cursor" width="128" height="128" data-path="images/mcp/cursor.png">
    Remote URL in `mcp.json`, or the one-click install then add the Bearer header.
  </Card>

  <Card title="Claude Code" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/claude-code.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=718d11906b6b274f7e174a8181131ba1" href="#claude-code" width="128" height="128" data-path="images/mcp/claude-code.png">
    `claude mcp add --transport http` with the URL and Authorization header.
  </Card>

  <Card title="Claude" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/claude.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=a44ea9fb2ef98d93752398e08deb0e56" href="#claude" width="128" height="128" data-path="images/mcp/claude.png">
    Connectors are OAuth-only. Bridge Desktop with `mcp-remote`.
  </Card>

  <Card title="ChatGPT" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/chatgpt.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=3b334301a6c6ecbf58977c240ccb7a4e" href="#chatgpt" width="128" height="128" data-path="images/mcp/chatgpt.png">
    No static-key path yet. Apps take OAuth or no auth.
  </Card>

  <Card title="VS Code" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/vscode.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=c82f0e7005cbf2359f799c7d282ad029" href="#vs-code" width="128" height="128" data-path="images/mcp/vscode.png">
    `.vscode/mcp.json` with `type: "http"`.
  </Card>

  <Card title="Codex" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/codex.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=d7c474b6a5a15863ddf6c4acf431e944" href="#codex" width="128" height="128" data-path="images/mcp/codex.png">
    `codex mcp add` with `--url` and a bearer-token env var.
  </Card>
</CardGroup>

<Tabs>
  <Tab title="Cursor" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/cursor.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=743dda4e729869ee5a0ea5ec61b6fddd" id="cursor" width="128" height="128" data-path="images/mcp/cursor.png">
    One-click adds the URL. Then open **Customize → MCPs**, edit `freshtalent`, and set the header.

    [Install in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=freshtalent\&config=eyJ1cmwiOiJodHRwczovL2FwaS5mcmVzaHRhbGVudC5haS9tY3AifQ==)

    Some builds since the Customize migration swallow that deeplink and never show the install card. If nothing happens, write the JSON yourself.

    Or add this to `~/.cursor/mcp.json` / `.cursor/mcp.json`:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "mcpServers": {
        "freshtalent": {
          "url": "https://api.freshtalent.ai/mcp",
          "headers": {
            "Authorization": "Bearer ft_live_…"
          }
        }
      }
    }
    ```

    Reload Cursor. Ask `whoami on FreshTalent` — you should see org, plan, `search: "ok"`, and `watch.remaining` (slots for **new** Targets). `ls` / `members` still work at the cap.
  </Tab>

  <Tab title="Claude Code" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/claude-code.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=718d11906b6b274f7e174a8181131ba1" id="claude-code" width="128" height="128" data-path="images/mcp/claude-code.png">
    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    claude mcp add --transport http freshtalent https://api.freshtalent.ai/mcp \
      --header "Authorization: Bearer ft_live_…"
    ```

    Add `--scope user` if you want it in every project. Restart the session, then:

    ```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
    Call FreshTalent whoami, then search "ex-palantir FDEs, left 18mo"
    ```
  </Tab>

  <Tab title="Claude" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/claude.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=a44ea9fb2ef98d93752398e08deb0e56" id="claude" width="128" height="128" data-path="images/mcp/claude.png">
    Custom connectors on claude.ai and Claude Desktop authenticate with OAuth only. **Customize → Connectors → Add custom connector** takes a URL, and advanced settings take an OAuth client id and secret — there is no Bearer or header field. `claude_desktop_config.json` also rejects `headers` on a remote entry. A FreshTalent key is static, so that path cannot work yet.

    Bridge it with `mcp-remote` instead. In `claude_desktop_config.json` (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "mcpServers": {
        "freshtalent": {
          "command": "npx",
          "args": [
            "-y",
            "mcp-remote",
            "https://api.freshtalent.ai/mcp",
            "--header",
            "Authorization:${AUTH_HEADER}"
          ],
          "env": {
            "AUTH_HEADER": "Bearer ft_live_…"
          }
        }
      }
    }
    ```

    No space after the colon in the `--header` argument — the space lives in the env var, or Windows splits it. Fully quit and reopen Claude Desktop, then enable the server from the plus / attachments menu before you prompt.

    Claude in the browser has no bridge. Use Claude Code there.
  </Tab>

  <Tab title="ChatGPT" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/chatgpt.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=3b334301a6c6ecbf58977c240ccb7a4e" id="chatgpt" width="128" height="128" data-path="images/mcp/chatgpt.png">
    Not supported yet. ChatGPT apps accept OAuth, no auth, or mixed auth, and OpenAI is explicit that the client cannot present a custom API key. A FreshTalent key is static, so the app's auth step has nowhere to put it. See [OpenAI's developer mode and MCP apps notes](https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt).

    Two limits worth knowing for when we ship OAuth: developer mode is web-only, and write actions — `collect`, `watch`, `subscribe` — are a Business / Enterprise / Edu beta. Pro and Plus get read and fetch.

    Until then, drive FreshTalent from Claude Code, Cursor, VS Code, or Codex.
  </Tab>

  <Tab title="VS Code" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/vscode.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=c82f0e7005cbf2359f799c7d282ad029" id="vs-code" width="128" height="128" data-path="images/mcp/vscode.png">
    Create `.vscode/mcp.json` in the workspace. `${input:…}` keeps the key out of the file — VS Code prompts once and stores it:

    ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
    {
      "inputs": [
        {
          "type": "promptString",
          "id": "freshtalent-key",
          "description": "FreshTalent API key",
          "password": true
        }
      ],
      "servers": {
        "freshtalent": {
          "type": "http",
          "url": "https://api.freshtalent.ai/mcp",
          "headers": {
            "Authorization": "Bearer ${input:freshtalent-key}"
          }
        }
      }
    }
    ```

    Copilot / agent mode should list the FreshTalent tools after a reload.
  </Tab>

  <Tab title="Codex" icon="https://mintcdn.com/freshtalent/jKiX2FumVjy4xiyM/images/mcp/codex.png?fit=max&auto=format&n=jKiX2FumVjy4xiyM&q=85&s=d7c474b6a5a15863ddf6c4acf431e944" id="codex" width="128" height="128" data-path="images/mcp/codex.png">
    Export the key first, then add the server. Codex reads the Bearer token from the env var — it does not need the key in the config file.

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    export FRESHTALENT_API_KEY=ft_live_…
    codex mcp add freshtalent --url https://api.freshtalent.ai/mcp \
      --bearer-token-env-var FRESHTALENT_API_KEY
    ```

    Or in `~/.codex/config.toml`:

    ```toml theme={"theme":{"light":"github-light","dark":"github-dark"}}
    [mcp_servers.freshtalent]
    url = "https://api.freshtalent.ai/mcp"
    bearer_token_env_var = "FRESHTALENT_API_KEY"
    ```
  </Tab>
</Tabs>

### Any other MCP host

If the host speaks Streamable HTTP (most current agents do), give it the same URL and Bearer header:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "mcpServers": {
    "freshtalent": {
      "type": "http",
      "url": "https://api.freshtalent.ai/mcp",
      "headers": {
        "Authorization": "Bearer ft_live_…"
      }
    }
  }
}
```

Reload, then confirm the eight tools appear. If the host only accepts a local stdio command, bridge it with `mcp-remote` the way the Claude tab does. If it only does OAuth, it cannot carry a FreshTalent key yet.

## 3. Prompt that actually works

Paste this after install:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
You have FreshTalent MCP. Person ids are LinkedIn slugs. Pages are `{total,count,offset,has_more,rows:[{slug,s}]}`. Hold slugs and the echoed query; do not re-fetch a page you already have.

1. Call whoami. `search` is always ok. `watch.remaining` is slots for **new** targets only — `watch ls` / `members` still work at the cap.
2. search nl="ex-palantir FDEs, left 18mo" limit=15
3. collect action=create name="hot" (ignore error if it exists)
4. collect action=add list="hot" slugs=[the top 5 slugs] stage="to-contact"
5. watch action=query query=<the echoed query from step 2>  (name is a label, not keywords — omit it)
6. events since="24h" type="open_to_work"

Call get kind=person only when the `{slug,s}` row is not enough. Page with offset and stop when has_more is false or you have enough to act. Prefer subscribe, or events with an explicit type, over dumping the firehose. `watch` members can take **up to 24h** — keep using search until `watch members` has rows.

Do not invent Cypher. The MCP `watch` tool adapts the echoed query object; it does not pass it directly to REST `app_query`. Target discovery uses a different schema and is not an exact replay of the graph search. See [Search query compatibility](/api-reference/targets/create#search-query-compatibility).
```

## Tools

The eight tools are the same four product families as the dashboard.

<CardGroup cols={2}>
  <Card title="Search" icon="search">
    `search`, `get`, `expand` — people, one object, coworkers / similar / company orbit.
  </Card>

  <Card title="Lists" icon="list">
    `collect` — `ls`, `create`, `show`, `add`, `stage`, `remove`, `delete`.
  </Card>

  <Card title="Targets" icon="radar">
    `watch` — `ls`, `company`, `query`, `show`, `members`, `admit`.
  </Card>

  <Card title="Monitoring" icon="activity">
    `events` and `subscribe` — firehose plus email / Slack destinations.
  </Card>
</CardGroup>

| Tool        | Dashboard                | What it does                                                                                                                                                                                                                                                                                                                                                             |
| ----------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `search`    | Search                   | People. `nl` and/or filters. Default 15 `{slug,s}` rows + echoed `query`. Page with `offset`. `view=ids` for slugs only.                                                                                                                                                                                                                                                 |
| `get`       | Search / Lists / Targets | Person is a lean dossier. Company / list / watch return identity and counts — members page via `collect` / `watch` / `expand`. Pass a LinkedIn company URL for an exact company; a bare name resolves to the best match by headcount.                                                                                                                                    |
| `expand`    | Companies                | Paged `{slug,s}` rows: `coworkers`, `similar`, or one company-orbit `side` (`current` or `leavers`).                                                                                                                                                                                                                                                                     |
| `collect`   | Lists                    | `ls` (name + `n`), `create`, `show` (paged rows with `stage`), `add`, `stage`, `remove` (one person), `delete` (the whole list). Writes return a receipt. Stages: `to-contact` (To contact), `contacted`, `responded`, `passed`.                                                                                                                                         |
| `watch`     | Targets                  | `ls` (name, kind, status counts), `company` (Monitor Company Network), `query` (Find people from the echoed search query; `name` is a label, not keywords), `show` (id/name/counts/job — not the REST blob), `members` (paged rows), `admit` (Accept), `delete` (the Target). Members can take **up to 24h** — keep `search` until they appear. Writes return a receipt. |
| `events`    | Monitoring               | Firehose of List members and **Monitored** Target members as `{id,slug,type,s,at}`. `since=24h`, optional `type`, `list`, cursor. Default 15.                                                                                                                                                                                                                            |
| `subscribe` | Settings → Notifications | Fields + email / Slack (graph-wide). Stored webhook URL is not a Gateway push.                                                                                                                                                                                                                                                                                           |
| `whoami`    | —                        | Org, plan, `search: "ok"`, watch slots, Slack. `watch.remaining` is for **new** Targets only.                                                                                                                                                                                                                                                                            |

## What comes back

Collection reads are minified JSON, not pretty-printed REST envelopes:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{"total":1284,"count":15,"offset":0,"has_more":true,"query":{"company":"palantir"},"rows":[{"slug":"derek-morrow","s":"Derek Morrow · FDE, Anduril · palantir 50mo · exploring"}]}
```

Writes return a receipt (`{"ok":true,"added":5}`), not the resource. Page with `offset` until `has_more` is false, or stop when you have enough to act.

## Example: search tool call

What the host should send:

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "nl": "ex-palantir FDEs, left 18mo",
  "limit": 15
}
```

Optional structured fields on the same tool (or any other people-search filter — extra properties are allowed): `company`, `role_family` (`forward-deployed-engineer` | `founding-engineer` | `software-engineer` | `deployment-strategist`), `company_left_min_months_ago`, `open_to_work`, `between_roles`, `exploring`, `github_hireable`, `location`, `skills`, `languages`, `certifications` (JSON array string of up to 10 distinct trimmed terms).

Certification filters apply to graph people search. People Target discovery does not support them, so a `watch` request adapted from a certification-filtered search is rejected; save and replay that query through Search instead.

## If it does not connect

| What you see                           | What it usually is                                                                                                                          |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401 / unauthorized                     | Missing or revoked key. Recreate under **API Keys**. Header must be `Authorization: Bearer ft_live_…`.                                      |
| Tools never appear                     | Host still pointed at a local command, or you installed the docs assistant (`docs.freshtalent.ai/mcp`) instead of `api.freshtalent.ai/mcp`. |
| Claude connector will not authenticate | Web and Desktop connectors are OAuth-only. Use the `mcp-remote` bridge, or Claude Code.                                                     |
| ChatGPT has nowhere to put the key     | Expected. ChatGPT apps do OAuth or no auth; a static key is not supported yet.                                                              |

## Connect an ATS or CRM

For Greenhouse / Ashby / HubSpot, skip the agent and poll events: [ATS & CRM](/connect/ats-crm).
