# NewsletterFIT MCP server

Search newsletters, sponsors, topics, companies and people across 89,000+ Substack and beehiiv newsletters from any MCP client. Read-only tools, except the Enterprise data export.

- Endpoint: `https://newsletterfit.com/mcp` (streamable HTTP, JSON-RPC 2.0, stateless; POST only)
- Auth: OAuth 2.1 sign-in (Claude.ai, ChatGPT and other connectors that take only a URL), or `Authorization: Bearer nf_live_…` API key
- Tools: 17

## Get started

1. Use a plan with API access (Pro, Intelligence or Enterprise).
2. Connectors that sign in (Claude.ai, ChatGPT) need only the URL. For an API key, open Billing → API access in the app and create one; it is shown once.
3. Add the server to your client (below), then ask: "What tools do you have from NewsletterFIT?"

### Claude.ai and Claude Desktop (connector)

Settings → Connectors → Add custom connector. Paste the URL, then sign in to NewsletterFIT and click Allow. No API key needed:

```
https://newsletterfit.com/mcp
```

### ChatGPT

Add a custom connector (developer mode) with this URL and OAuth authentication, then sign in to NewsletterFIT and allow access:

```
https://newsletterfit.com/mcp
```

### Claude Code

Run once in a terminal:

```
claude mcp add --transport http newsletterfit https://newsletterfit.com/mcp \
  --header "Authorization: Bearer nf_live_YOUR_KEY"
```

### Cursor

Add to ~/.cursor/mcp.json (or .cursor/mcp.json in a project):

```
{
  "mcpServers": {
    "newsletterfit": {
      "url": "https://newsletterfit.com/mcp",
      "headers": { "Authorization": "Bearer nf_live_YOUR_KEY" }
    }
  }
}
```

### Claude Desktop with an API key

To use an API key instead of signing in, run mcp-remote (needs Node.js). Add to claude_desktop_config.json, then restart Claude:

```
{
  "mcpServers": {
    "newsletterfit": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://newsletterfit.com/mcp",
               "--header", "Authorization:Bearer nf_live_YOUR_KEY"]
    }
  }
}
```

### Any client or curl

Streamable HTTP, JSON-RPC 2.0. Send both Accept types or the server answers 406:

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

## Authentication and scopes

**OAuth sign-in.** Connectors discover the sign-in server from the 401 challenge (RFC 9728), register themselves (RFC 7591), and use authorization code + PKCE. Users sign in to NewsletterFIT and approve the `mcp:read` scope, which allows every read tool on their plan; it never allows `create-export-tool`. Accounts need a confirmed email. Access tokens are short-lived JWTs bound to the `/mcp` resource; refresh tokens rotate.

**API keys.** Keys look like `nf_live_<keyId>_<secret>`. New keys get `search:read`, `publications:read` and `entities:read`, which can call every tool except `create-export-tool`; that one needs `exports:write` (or `mcp:use`, which allows every tool). Plan features still apply: `list-alerts-tool` needs a plan with alerts, and exports need Enterprise.

## Limits

MCP and REST share one monthly quota per account, reset on the 1st (UTC). Failed tool calls are not counted. Each tool counts against one meter, shown in the reference.

| Plan | API searches / month | API profile views / month | Exports / month |
| --- | --- | --- | --- |
| Pro | 500 | 2,500 | — |
| Intelligence | 2,000 | 10,000 | — |
| Enterprise | 2,000 | 10,000 | 200 |

Rate limit: 90 requests a minute per key, shared with REST, reported in `RateLimit-*` headers. Every successful tool result includes a `quota` object: `used`, `limit`, `remaining`, `plan`, `metric`, `period`, `resets_at`.

## Ids

Results use typed ids: `nl_` newsletter, `is_` article, `sp_` sponsor, `tp_` topic, `en_` other entity. Tool arguments accept the typed form or the bare number.

## Tools

### Search

#### `search-newsletters-tool`

Find newsletters by topic, company, brand or name. Ranked results with nl_ ids, the publicly shown subscriber figure and momentum. Start here for most questions, then open one with get-newsletter-tool or get-newsletter-intel-tool.

Scope `search:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `query` | string | yes | Search query |
| `limit` | integer | no | 1–100; default 20 |
| `page` | integer | no | default 1 |

#### `search-articles-tool`

List recent articles (posts) across all tracked newsletters, or only one newsletter's when publication_id (an nl_ id) is given. Returns is_ ids, titles, dates and links, never body text. For a single newsletter, get-newsletter-articles-tool is the direct route.

Scope `publications:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `publication_id` | string | integer | no | nl_… or numeric publication id |
| `limit` | integer | no | 1–100; default 20 |
| `page` | integer | no | default 1 |

#### `search-entities-tool`

Find companies, people, guests and other entities mentioned in newsletter posts, by type and name. Returns typed ids for get-entity-tool. person and guest are separate types, so search both when looking for an individual.

Scope `entities:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `type` | string | yes | one of company, product, person, technology, topic, guest, brand, sponsor |
| `query` | string | yes |  |
| `limit` | integer | no | 1–100; default 20 |

#### `search-topics-tool`

Find topics whose name or slug contains the query. Returns slugs for get-topic-tool.

Scope `entities:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `query` | string | yes |  |
| `limit` | integer | no | 1–100; default 20 |

#### `search-sponsors-tool`

Find sponsor brands by name or slug. Returns slugs for get-sponsor-tool.

Scope `entities:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `query` | string | yes |  |
| `limit` | integer | no | 1–100; default 20 |

### Newsletters

#### `get-newsletter-tool`

Full profile of one newsletter: audience signals, publishing activity, topics and recent sponsors. Pass exactly one of slug (as in newsletterfit.com/newsletters/{slug}) or id (an nl_ id from a search).

Scope `publications:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `slug` | string | no | Publication subdomain / slug |
| `id` | string | integer | no | nl_… or numeric id |

#### `get-newsletter-articles-tool`

Recent articles from one newsletter, newest first. publication_id is an nl_ id. Metadata only, no body text.

Scope `publications:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `publication_id` | string | integer | yes | nl_… or numeric publication id |
| `limit` | integer | no | 1–100; default 20 |

#### `get-newsletter-intel-tool`

Compact intelligence summary for one newsletter (id is an nl_ id). Smaller than get-newsletter-tool; use it when comparing many newsletters.

Scope `publications:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `id` | string | integer | yes |  |

#### `get-rising-newsletters-tool`

Newsletters with sustained public subscriber growth over the last 30 days, plus Substack leaderboard climbers. Takes no arguments.

Scope `publications:read` · meter API search · read-only

No arguments.

### Articles

#### `get-article-tool`

One article by is_ id: title, date, link and the public metadata NewsletterFIT holds for it. No body text or raw HTML.

Scope `publications:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `id` | string | integer | yes |  |

### Sponsors, topics and entities

#### `get-sponsor-tool`

Sponsor profile by slug (from search-sponsors-tool or a newsletterfit.com/sponsors/{slug} URL): the newsletters and placements the brand was detected in.

Scope `entities:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `slug` | string | yes |  |

#### `list-topics-tool`

Browse the topic directory with newsletter counts, to discover topic slugs. To look up a named topic, search-topics-tool is faster.

Scope `entities:read` · meter API search · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `limit` | integer | no | 1–300; default 50 |

#### `get-topic-tool`

Topic landscape by slug (from list-topics-tool, search-topics-tool or a newsletterfit.com/topics/{slug} URL): the newsletters covering the topic.

Scope `entities:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `slug` | string | yes |  |

#### `get-entity-tool`

One entity (company, person, guest, topic) by type and the typed id from search-entities-tool, with where it is mentioned. person and guest are separate types.

Scope `entities:read` · meter API profile view · read-only

| Argument | Type | Required | Notes |
| --- | --- | --- | --- |
| `type` | string | yes |  |
| `id` | string | yes |  |

### Your account

#### `list-alerts-tool`

List the key owner's monitoring alerts. Read-only: alerts are created and edited in the app. Needs a plan that includes alerts.

Scope `alerts:read` · meter API search · read-only

No arguments.

#### `list-watchlist-tool`

List the key owner's watchlist of newsletters. Read-only: entries are added and removed in the app.

Scope `watchlist:read` · meter API search · read-only

No arguments.

### Data export

#### `create-export-tool`

Enterprise only. JSON snapshot of the last 14 days: publications, articles, entities and the links between them, without article text or raw files. The full snapshot is in structuredContent; the text part is only a summary.

Scope `exports:write` · meter Export · creates data

No arguments.

## Errors

| Where | Code | Meaning | What to do |
| --- | --- | --- | --- |
| HTTP 401, JSON-RPC -32001 | `unauthorized` | Missing, malformed or revoked API key. The response carries a WWW-Authenticate challenge. | Send Authorization: Bearer nf_live_… with an active key. |
| HTTP 403, JSON-RPC -32003 | `insufficient_scope` | The OAuth token was granted without mcp:read. | Reconnect and approve access. |
| HTTP 403, JSON-RPC -32003 | `email_unverified` | The signed-in account has not confirmed its email. | Confirm the email, then reconnect. |
| Tool result, isError | `invalid_params` | A required argument is missing or empty. The message names it. | Fix the arguments; do not retry unchanged. |
| Tool result, isError | `quota_exceeded` | The monthly meter for this tool is used up. Includes upgrade_url. | Stop calling tools on that meter until the 1st of next month (UTC), or upgrade. |
| Tool result, isError | `entitlement_required` | The plan has no API access (Free, or a trial that ended), or lacks the tool's feature (alerts, exports). The connection itself still works. Includes upgrade_url. | Tell the user; upgrade at /pricing. Retrying will not help. |
| Tool result, isError | `missing_scope` | The key lacks the tool's scope; required names it. Such tools are also left out of tools/list. | Use a key with that scope. |
| Tool result, isError | `not_found` | No newsletter, article, sponsor, topic or entity with that id or slug. | Check the id prefix, or search again. |
| Tool result, isError | `validation_error` | An argument has the wrong form. | Fix the arguments; do not retry unchanged. |
| Tool result, isError | `internal_error` | Something failed on our side. Includes request_id. | Retry later; quote the request_id to support if it persists. |
| HTTP 429 | `rate_limited` | More than 90 requests a minute on this key (shared with REST). | Wait for RateLimit-Reset seconds, then retry. |

## Guidance for agents

- Search first, then open one result: search-newsletters-tool, then get-newsletter-tool or get-newsletter-intel-tool.
- Use get-newsletter-intel-tool when comparing many newsletters; it is the smallest profile.
- Keep limit small (5–20). Ask for more pages only when the user needs them.
- Every successful result includes quota (used, limit, remaining, resets_at). Check remaining before long loops.
- Ids are typed (nl_ newsletter, is_ article, sp_ sponsor, tp_ topic, en_ entity). Pass them back exactly as returned; bare numeric ids also work.
- Audience figures are what the platform shows publicly, often rounded. Say so when you quote them.
- When a tool returns isError, read the code and message. Retrying the same call will fail the same way.

## Common workflows

- **Find newsletters to sponsor:** search-newsletters-tool (topic) → get-newsletter-intel-tool for each candidate → get-newsletter-tool for the shortlist.
- **Check who a brand sponsors:** search-sponsors-tool (brand) → get-sponsor-tool (slug).
- **Track a company in the press:** search-entities-tool (type company) → get-entity-tool → get-article-tool for the mentions that matter.
- **Map a topic:** search-topics-tool → get-topic-tool → get-newsletter-intel-tool for the top newsletters.
- **Spot growth:** get-rising-newsletters-tool → get-newsletter-tool for the ones in the user's market.

## Not supported yet

- Creating or editing alerts and watchlists; use the app.
- MCP resources and prompts; tools only.

## Machine-readable

- [This page as Markdown](https://newsletterfit.com/docs/mcp.md)
- [Tool schemas (JSON)](https://newsletterfit.com/api/v1/mcp-tools.json)
- [Agent authentication](https://newsletterfit.com/auth.md)
- [Agent identity (AID)](https://newsletterfit.com/.well-known/agent.json)
- [MCP server card](https://newsletterfit.com/.well-known/mcp/server-card.json)
- [REST API reference](https://newsletterfit.com/docs/api)
- [REST API reference as Markdown](https://newsletterfit.com/docs/api.md)
- [OpenAPI 3.1](https://newsletterfit.com/api/v1/openapi.yaml)

Support: support@newsletterfit.com