# Dunbar

> 14 MCP tools so any AI agent — Claude Code, Cursor, Claude Desktop,
> ChatGPT — can read your LinkedIn, find mutuals, send messages, and
> search 200M prospects. You write the playbook in plain English. Your
> agent runs it.

- Site: https://www.getdunbar.ai
- MCP URL: https://www.getdunbar.ai/api/mcp
- Docs: https://www.getdunbar.ai/v3/docs
- Pricing: 1 credit = 1¢. Most calls cost 1 credit; heavy + paid-API
  calls cost 5. Volume bonuses at $25 (+5%), $100 (+10%), $500 (+20%).
  Credits never expire.

## Quickstart

1. Sign up at https://www.getdunbar.ai/signup.
2. Generate an API key at https://www.getdunbar.ai/v3/app/account.
3. Connect your LinkedIn (one-time OAuth, no password sharing).
4. Wire the MCP server into your agent client (snippets below).
5. Hand the agent a workflow — plain-English instructions on how you
   do outreach. The agent reads it, calls Dunbar tools to do the work.
6. Add credits when prompted ($5 = 500 credits, never expire).

## Connect a client

Replace `YOUR_KEY` with an API key from https://www.getdunbar.ai/v3/app/account.

### Claude Code (CLI)

```
claude mcp add dunbar --transport http https://www.getdunbar.ai/api/mcp \
  --header "Authorization: Bearer YOUR_KEY"
```

### Cursor

In `~/.cursor/mcp.json` (or per-project `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "dunbar": {
      "url": "https://www.getdunbar.ai/api/mcp",
      "headers": { "Authorization": "Bearer YOUR_KEY" }
    }
  }
}
```

### Claude Desktop (API key + shim)

Claude Desktop doesn't pass headers natively, so use the
`mcp-remote` stdio shim:

```json
{
  "mcpServers": {
    "dunbar": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://www.getdunbar.ai/api/mcp",
        "--header", "Authorization:Bearer YOUR_KEY"
      ]
    }
  }
}
```

### Claude Desktop (OAuth, no key needed)

```json
{
  "mcpServers": {
    "dunbar": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://www.getdunbar.ai/api/mcp"]
    }
  }
}
```

## Common flows

Most tools chain — one returns the input the next one needs.

### Cold outreach to people at a specific company

1. `organization_search` — `name: "Stripe"` → returns `id`
2. `people_search` — `organizationIds: [id], titles: [...]` → returns
   `linkedinUrl` for each match
3. `get_profile` — `profileUrl: linkedinUrl` → returns `provider_id`
4. `send_connection_request` — with `providerId` and a personalized
   note (≤200 chars)

### Warm intro through a mutual

1. `get_profile` of the target → `provider_id`
2. `find_mutuals` → list of mutuals with their URNs
3. `send_message` to a mutual asking for the intro

### Cold outreach by title only

1. `people_search` — `titles, locations` → `linkedinUrl` per match
2. `get_profile` → `provider_id`
3. `send_connection_request` with personalized note

### Watch for replies, follow up

1. `list_inbox_events` — poll every minute for new replies / accepts
2. `get_conversation` — for each new reply, read the thread
3. `send_message` — respond

### Stay above water on credits

1. `account_status` — read `credits.balance` + `credits.lowBalance`
2. `topup_credits` — if low, returns a Stripe URL the user clicks

## Tool reference

### Free (read-only, lookups, orchestration)

- `account_status` — Free — LinkedIn connection status, sends-today vs daily cap (50), credit balance + pricing, and any in-flight batch jobs. Cheap — call freely at session start, and before find_mutuals_batch to check `batches.inflight`.
- `list_connections` — Free — Paginated list of the user's first-degree LinkedIn connections from the local DB. Fast, no Unipile call.
- `connection_status` — Free — Returns 'connected' | 'pending' | 'none' for any profile URL. Call BEFORE send_connection_request to avoid duplicates.
- `list_inbox_events` — Free — Recent LinkedIn events — replies, accepts/declines. Cheap polling source — fine to call every minute.
- `fetch_skill` — Free — Fetch a Dunbar workflow file by its getdunbar.ai/s/<user>/<slug> URL. For chaining workflows.
- `topup_credits` — Free — Returns a Stripe Checkout URL the user opens. The agent cannot complete the payment.
- `get_batch` — Free — Poll the status + results of a batch job (e.g. from find_mutuals_batch). Free — call every 30–60s while running. Returns output.results once status === succeeded.
- `cancel_batch` — Free — Stop an in-progress batch and refund credits for unstarted profiles. The currently-running profile counts as work done.

### 1 credit (standard paid calls)

- `get_profile` — 1 credit — Full LinkedIn profile data + provider_id (URN). Use BEFORE drafting a personalized message.
- `get_conversation` — 1 credit — Message history of a 1:1 LinkedIn conversation by chat_id. Newest-last with sender + timestamps.
- `cancel_connection` — 1 credit — Withdraw a pending LinkedIn invitation. No safety check — cancellation always allowed.
- `send_connection_request` — 1 credit · 50/day cap — Send a LinkedIn connection request with optional ≤200-char note. Counts against 50/day. Requires providerId from get_profile.
- `send_message` — 1 credit · 50/day cap — Send a LinkedIn DM. Either chatId (existing thread) or providerId (new chat). Rate-limited 50/day, dedup-protected per target.

### 5 credits (heavy / external API)

- `find_mutuals` — 5 credits — Mutual LinkedIn connections between user and a target profile. Slow (5–30s typical, up to 120s). Don't loop — use find_mutuals_batch for >1 profile.
- `find_mutuals_batch` — 5 credits — Queue a find_mutuals run for up to 20 profiles. 5 cr/profile reserved up front. Returns a jobId — poll get_batch(jobId) to get status + results. One batch in flight per user.
- `organization_search` — 5 credits — Look up companies by name. Returns id, domain, LinkedIn URL, industry, employees. The id feeds people_search — free-text names don't filter reliably.
- `people_search` — 5 credits — 200M+ person prospect database by titles + organizationIds + locations. Returns linkedinUrl per match — feed into get_profile.

## Safety + rate limits (server-enforced)

- 50 send_message + send_connection_request per 24h rolling window
- 7-day dedup per target profile
- Errors return as `{ ok: false, reason: "rate_limit: ..." | "dedup: ..." }`
- Pre-deduction with refund on tool throw — failed calls don't burn credits
- LinkedIn session held by Dunbar; agent never sees your password
- Account deletion cascades to all v3_* tables (no orphaned data)

## Pricing

- 1 credit = 1¢. Pay-as-you-go, never expires.
- $5 = 500 credits (no bonus, "starter")
- $25 = 2,625 credits (+5% bonus)
- $100 = 11,000 credits (+10% bonus)
- $500 = 60,000 credits (+20% bonus)
- Custom amounts get the same tiered bonus by dollar bracket
- Auto top-up: set a threshold + amount, we charge a saved card off-session

## Errors

- `insufficient_credits` — call `topup_credits` (free) to send the
  user a Stripe checkout URL
- `rate_limited` — back off; the response includes `retryAfterSec`
- `search_provider_error` — try narrower filters
- `no_linkedin_account` — user hasn't connected LinkedIn yet (point
  them to https://www.getdunbar.ai/v3/app/account)
- `missing_filter` (people_search) — pass at least one of titles,
  organizationIds, locations, or keywords

## Contact

Questions? team@getdunbar.ai
