# MCP server

HappyFetch is also an [MCP](https://modelcontextprotocol.io) server. Connect it to Claude Code, Cursor,
VS Code or any other MCP client, and your agent can look up companies and search the web as tools.
The tools call the same endpoints as the API, with your API key: the same prices, the same cache and
the same automatic refunds, and every call shows up in the console with its request id.

## Connect

The server is one URL, over Streamable HTTP:

```text
https://api.happyfetch.net/mcp
```

Send your API key the way the API takes it, as `Authorization: Bearer YOUR_API_KEY` (or in
`X-Api-Key`). A client that takes only a URL, like Claude's custom connectors, can put the key in the URL
instead: `https://api.happyfetch.net/mcp?apiKey=YOUR_API_KEY`. Create a key in the console under **API keys**:
[https://app.happyfetch.net/keys](https://app.happyfetch.net/keys). Listing the tools works without a key; calling them needs one.

### Claude (web, desktop and mobile)

In Claude, open **Settings > Connectors**, choose **Add custom connector**, name it HappyFetch, and use
this URL:

```text
https://api.happyfetch.net/mcp?apiKey=YOUR_API_KEY
```

The key is part of the URL, so create one just for this connector. If the URL ever leaks, revoke that key
in the console and add the connector again with a new one. We never write the key from a URL to our logs.

### Claude Code

```bash
claude mcp add --transport http happyfetch https://api.happyfetch.net/mcp \
  --header "Authorization: Bearer $HAPPYFETCH_API_KEY"
```

Add `--scope user` to use it in every project.

### Cursor

In `~/.cursor/mcp.json`, or `.cursor/mcp.json` for one project:

```json
{
  "mcpServers": {
    "happyfetch": {
      "url": "https://api.happyfetch.net/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}
```

Keep a file that holds your key out of your repository.

### VS Code

In `.vscode/mcp.json`. VS Code asks for the key once and stores it for you:

```json
{
  "inputs": [
    { "type": "promptString", "id": "happyfetch-key", "description": "HappyFetch API key", "password": true }
  ],
  "servers": {
    "happyfetch": {
      "type": "http",
      "url": "https://api.happyfetch.net/mcp",
      "headers": { "Authorization": "Bearer ${input:happyfetch-key}" }
    }
  }
}
```

### Other clients

Any client that speaks Streamable HTTP and can send a header works: point it at `https://api.happyfetch.net/mcp` and add
the `Authorization` header. The server speaks protocol revision 2026-07-28 and the 2025 revisions
(2025-11-25, 2025-06-18 and 2025-03-26), and answers every request with plain JSON.

A client that takes only a URL works with `?apiKey=` in it, as in Claude above. A client that only starts
local servers can reach it through the [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) bridge:

```json
{
  "mcpServers": {
    "happyfetch": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.happyfetch.net/mcp", "--header", "Authorization:${HAPPYFETCH_AUTH}"],
      "env": { "HAPPYFETCH_AUTH": "Bearer YOUR_API_KEY" }
    }
  }
}
```

## Tools

| Tool | What it does | Same as |
|---|---|---|
| `company_lookup` | A company's complete profile, from its LinkedIn company URL, slug, numeric id or URN. | [`POST /v1/company`](/docs/company) |
| `domain_lookup` | The company behind a website, with the same profile. | [`POST /v1/domain`](/docs/domain) |
| `web_search` | Web search results as JSON: a title, URL and snippet for every result. | [`POST /v1/search`](/docs/search) |
| `cache_check` | Free: whether we hold a copy of a company, how old it is, and what a lookup would cost now. | [`POST /v1/cache`](/docs/cache) |
| `get_pricing` | Free, and works without a key: prices per call, credit packs and free credits. | [`GET /v1/pricing`](/docs/billing) |

The lookups and the search take the same arguments as their endpoints, `max_age` included, plus an
optional `idempotency_key`: send the same key when your agent retries a call, and the retry gets the
stored answer back instead of being charged again.

A tool costs exactly what its endpoint costs: see the [price per call](/pricing), or ask the
`get_pricing` tool.

## What a tool returns

The endpoint's complete JSON response, `data` and `meta`, as text for the model and as structured
content for your code. `meta.credits_charged` says what the call cost and `meta.credits_remaining`
what's left.

When a call fails, the result is marked as an error and carries the same error body as the API: a
stable `code`, a `message` and `retryable`, and the [error catalog](/docs/errors) explains each code.
A call we can't complete is refunded automatically, exactly as over HTTP.

## Good to know

- Every tool call is an API call made with your key. It appears under **Requests** in the console,
  and it shares the key's [rate limit](/docs/rate-limits) and your workspace's credits.
- The server keeps no sessions: each request stands alone, so a reconnect costs nothing and loses
  nothing.
