OP3 MCP Server & CLI README

The full upstream README, mirrored for reference. Install config, tool schemas, adoption signals and our own overview live on the OP3 MCP Server & CLI listing page.

OP3

OP3 MCP

Stars License npm Downloads YouTube X LinkedIn

OP3 sits in front of the audio file, so it counts every download whatever app made it.

That is why its numbers differ from Apple's or Spotify's, which each report only their own listeners.

22 tools, including unique listeners, retention cohorts and episode benchmark curves that OP3's own API does not expose.

Built and maintained by Navid Moazzez. Built on Slipway, which turns one definition of each tool into the MCP server and the CLI.

Claude Code using the OP3 MCP server

Two ways to use it

Command line

op3-cli runs every tool as a command. Agents that run commands, like Claude Code, Codex and OpenCode, use it on their own, and you can type the same commands in a terminal, a script or a cron job:

Terminal
npm install -g @thenavidm/op3-mcp-cli
op3-cli                                   # every command
op3-cli op3-global-app-share --agent
op3-cli op3-get-show --identifier https://feeds.example.com/show.xml
op3-cli op3-show-downloads --help
op3-cli which listener retention          # find the command for a task

Every command reads OP3's public data, so nothing asks for --confirm. --agent is JSON on one line for scripts and agents, and --select a,b.c keeps only the fields you name.

op3-cli schema <command> prints the exact JSON Schema an MCP client receives for that tool.

MCP server, for AI agents

op3-mcp is what Claude Code, Claude Desktop, Cursor and the rest launch. You never run it by hand:

Terminal
claude mcp add op3 -- npx -y @thenavidm/op3-mcp-cli

In Claude Desktop, the .mcpb extension installs on a double click. Section 4 has every other client.

Contents

  1. What you can ask it
  2. Quick install
  3. Setup
  4. Connect your client
  5. Check it worked
  6. What it costs to have connected
  7. Tools
  8. Reading the numbers
  9. Your data
  10. Troubleshooting

1. What you can ask it πŸ’¬

  • How many downloads did my podcast get this month?
  • How many actual people is that, not downloads?
  • Are my listeners coming back, or is it a new audience every month?
  • Is this week's episode tracking ahead or behind my usual?
  • Where in the world is my audience, down to the state?
  • Which podcast apps do my listeners use, and is that unusual?
  • Compare my show against these three others.
  • What day and hour do most downloads happen?
  • Which of my episodes share the same listeners?
  • OP3 shows nothing for my feed. What is wrong?

The one that is impossible without this server is the second. Every podcast analytics dashboard reports downloads. A download is an app fetching a file, not a person, and one listener whose app re-requests across three days counts three times. OP3's raw rows carry a privacy-preserving per-listener hash, so unique listeners, returning listeners and retention can be computed from them. None of OP3's own aggregated endpoints expose that, and this server does.

2. Quick install ⚑

Node 22 or newer. Nothing else.

Terminal
npx -y @thenavidm/op3-mcp-cli@latest --version

That is the whole install. npx fetches it on demand, so there is nothing to update later: with @latest, a new version reaches you the next time your client starts the server.

To build from source instead:

bash
git clone https://github.com/thenavidm/op3-mcp-cli.git
cd op3-mcp
npm install
npm run build
npm test
node dist/index.js --version

3. Setup πŸ”‘

You can skip this. The server works with no credential at all, because OP3 publishes a shared preview token and that is what it falls back to. It is rate limited and OP3 can withdraw it, so get your own before relying on it.

Have an agent do it

The agent cannot sign in to OP3 for you. What it can do is walk you through it and wire up the config.

Paste this into Claude Code, Cursor, or any agent with terminal access:

Code
Help me set up the OP3 MCP server.

1. Open https://op3.dev/api/keys and tell me what to click to create an
   API key and its bearer token.
2. Stop and wait for me to paste the token back.
3. Add the server to my MCP client config with that token as OP3_TOKEN.
4. Run the doctor command and tell me whether it worked.

Or do it yourself

  1. Go to op3.dev/api/keys.
  2. Create an API key and copy its bearer token.
  3. Set it as OP3_TOKEN in your client config, as in section 4.

You do not need to own a podcast. The token reads public OP3 data, which covers every show that has the OP3 prefix on its feed.

To revoke

Delete the key at op3.dev/api/keys. It stops working immediately.

If you want your own show in here

Your podcast needs the OP3 prefix on its episode audio URLs. That is a change to your feed, not to this server, and it is documented at op3.dev/setup. Until a listener downloads an episode through the prefix, OP3 has no data for your show and neither does this.

4. Connect your client πŸ”Œ

The long version, every step with what to do when one fails, is in INSTALL.md.

OP3_TOKEN is optional in every block below. Leave it out to use OP3's preview token.

Claude Code

Terminal
claude mcp add op3 \
  -e OP3_TOKEN=your-token \
  -- npx -y @thenavidm/op3-mcp-cli@latest

Add --scope user to make it available in every project rather than just this one.

Claude Desktop

The short way: download the .mcpb extension from the latest release and double-click it. It carries its own dependencies, so there is no config file to edit and nothing to install first. It asks for an OP3 token, which is optional.

The long way, if you would rather edit the config yourself:

PlatformConfig path
macOS~/Library/Application Support/Claude/claude_desktop_config.json
Windows%APPDATA%\Claude\claude_desktop_config.json
config.json
{
  "mcpServers": {
    "op3": {
      "command": "npx",
      "args": ["-y", "@thenavidm/op3-mcp-cli@latest"],
      "env": { "OP3_TOKEN": "your-token" }
    }
  }
}

Tip Claude Desktop does not inherit your shell PATH. If npx is not found, use the absolute path from which npx.

Quit Claude Desktop completely and reopen it.

claude.ai on the web

claude.ai runs a connector from Anthropic's cloud rather than your machine, so it cannot launch a local command. It needs a public HTTPS URL.

Run the server over HTTP:

Terminal
npx -y @thenavidm/op3-mcp-cli@latest --http --port 8000

Host it somewhere with a public HTTPS URL, then in claude.ai go to Customize, Connectors, +, Add custom connector, paste the URL and click Add.

On Team and Enterprise plans an owner adds it first under Organization settings, Connectors, then each member enables it under Customize, Connectors.

It binds to 127.0.0.1 by default, which is all a tunnel or a proxy on the same machine needs. To accept connections from outside the machine, set OP3_HTTP_HOST=0.0.0.0 together with OP3_HTTP_TOKEN, a bearer token every request must send: without one, the server refuses to listen beyond this machine.

Cursor

.cursor/mcp.json, same JSON shape as Claude Desktop, key mcpServers.

Windsurf

~/.codeium/windsurf/mcp_config.json, key mcpServers.

VS Code

.vscode/mcp.json. The key is servers, not mcpServers, and each entry takes "type": "stdio".

config.json
{
  "servers": {
    "op3": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@thenavidm/op3-mcp-cli@latest"],
      "env": { "OP3_TOKEN": "your-token" }
    }
  }
}

Codex CLI

~/.codex/config.toml:

toml
[mcp_servers.op3]
command = "npx"
args = ["-y", "@thenavidm/op3-mcp-cli@latest"]

[mcp_servers.op3.env]
OP3_TOKEN = "your-token"

Gemini CLI

~/.gemini/settings.json, key mcpServers.

Everything else

Any stdio MCP client takes the same three things: the command npx, the args, and the env block.

Docker

Terminal
docker build -t op3-mcp .
docker run --rm -i -e OP3_TOKEN=your-token op3-mcp

5. Check it worked 🩺

Terminal
npx -y @thenavidm/op3-mcp-cli@latest doctor

It tests the token against the cheapest OP3 endpoint, tests the raw query endpoints separately because they fail for their own reasons, and prints the settings in force.

SymptomCause
doctor says the token was rejectedThe key was deleted at op3.dev/api/keys, or OP3_TOKEN has a stray space
Every show lookup returns not foundThe podcast does not have the OP3 prefix on its feed. Run op3_verify_prefix
Rolled-up tools work, raw ones time outThe window is too wide. Narrow it, or raise OP3_REQUEST_TIMEOUT_MS
Numbers do not match the OP3 dashboardRolled-up figures lag by about a day. Check the asof field
npx not found in Claude DesktopDesktop does not inherit your shell PATH. Use the absolute path

6. What it costs to have connected

Both surfaces are the same program with the same 22 tools. The difference is when the model pays for them. Measured in Claude Code:

MCP serverCLI
Every message, with every tool loaded9,000 tokensnothing
Every message, Claude Code's default1,000 tokensnothing
When OP3 comes upnothing more, or the tools it picks3,400 tokens for SKILL.md, once
20 messages with OP3 in 1, every tool loaded180,000 tokens3,400 tokens

Claude Code's tool search is on by default: it sends only the tool names and the server instructions, and loads a tool's full definition when the model reaches for it. An app that loads every tool up front pays the first line on every message, whether OP3 comes up or not. With the skill added, Claude Code also lists its one-line description, about 190 tokens.

To spend less, turn the server off when you are not using it, which in Claude Code is the /mcp panel. Or install the CLI and add the server on the days it earns its place.

Measured on 2026-10-05 against 1.2.2, with Claude Code 2.1.286 on Claude Opus 5.5 (one short prompt with and without the server connected, once with ENABLE_TOOL_SEARCH=false and once with the default, the difference read from the API's own usage figures; SKILL.md the same way) and Codex 0.159.3 on gpt-6.1-sol:

Cost1.2.22.0.0
Claude Code, every tool loaded, every message9,7849,031
Claude Code's default, tool search, every message1,0301,026
SKILL.md, read once3,3843,424
Codex over the CLI, one task, median of five84,24261,677
Codex over MCP, the same task, median of five78,38178,341

The task was "find the command that compares listener retention between two periods, and the flags it requires". Every tool loaded costs less because each tool no longer repeats $schema, additionalProperties and an execution block. Over the CLI, every 1.2.2 run read the general help, the command list and the command's help, three requests that each carry the conversation so far; which answers with the command's help when one command fits well ahead of the rest, so 4 of five 2.0.0 runs needed two. Over MCP, Codex answered from the tool list without calling a tool, and read about 40,000 input tokens in one run of five on each version and about 78,000 in the rest. SKILL.md costs 40 more because it lists which and exit code 1. Other apps and models count tokens a little differently, and tool-list characters divided by four are not API usage.

7. Tools πŸ› οΈ

Every tool is a read. Nothing here changes anything.

Finding a show

ToolDoes
op3_resolve_showAny identifier to an OP3 show uuid. Takes a feed URL and encodes it for you
op3_get_showShow title, uuid, podcast guid, stats page, optionally the episode list
op3_list_episodesEpisodes with OP3 episode ids and publication dates, searchable by title

Downloads, from OP3's rolled-up data

Fast. Prefer these whenever they answer the question.

ToolDoes
op3_show_downloadsMonthly downloads, the week-by-week breakdown, and the weekly average
op3_episode_downloadsDownloads at 1, 3, 7 and 30 days after publication, plus all-time
op3_compare_showsSeveral shows ranked side by side, in one request

Audience, from the raw rows

The tools OP3's own API cannot give you.

ToolDoes
op3_audience_summaryUnique listeners against downloads, and the ratio between them
op3_new_vs_returningFirst-time against repeat listeners, over a baseline you choose
op3_listener_retentionCohort carry-over between two periods, as two separate rates
op3_episode_overlapWhich episodes share an audience, and how much

Where and how

ToolDoes
op3_geographyDownloads and listeners by continent, country, region, metro or timezone
op3_app_sharePodcast apps, over any window rather than OP3's fixed three months
op3_device_breakdownAll four dimensions at once: agent type, app, device type, device
op3_global_app_shareApp market share across every show OP3 measures
op3_benchmark_appsThis show against that global mix, indexed so 100 is average

Over time

ToolDoes
op3_download_trendDownloads and listeners by day, week or month, with a growth rate
op3_listening_patternsHour of day and day of week, in UTC
op3_episode_curveOne episode against the show's median at the same age

Discovery and setup

ToolDoes
op3_recent_transcriptsEpisodes across OP3 that carry a podcast:transcript tag
op3_verify_prefixWhether OP3 is receiving downloads for a feed, and what is wrong if not
op3_query_downloadsRaw download rows, every filter OP3 offers. The escape hatch
op3_query_hitsRaw request log across OP3. A verification surface, not an analytics one

8. Reading the numbers πŸ“Š

The part worth more than the upstream API docs. All of it was found by probing the live API, because OP3's OpenAPI document declares no response schemas.

A download is not a person. It is an app fetching a file. Podcast analytics across the industry quotes downloads, and a show with a loyal audience whose apps re-request looks larger than a show with more actual listeners. op3_audience_summary gives both numbers and the ratio.

Episodes are not comparable on totals. An older episode has had longer to accumulate downloads. op3_episode_curve compares at equal age against the show's own median, and excludes episodes younger than the horizon from that median so a three-day-old episode does not drag a thirty-day comparison down.

App share on its own says almost nothing. Nearly every show's biggest app is Apple Podcasts, because Apple is around 38% of all podcast listening. A show at 40% Apple is under-indexed. op3_benchmark_apps divides by the global share so the number means something.

bots does more than add bots. With it off, OP3 applies its published download calculation, which deduplicates repeat requests. With it on you get raw request rows. On one probe the same window returned 213 against 345, and only 79 of the difference were bot rows.

Rolled-up figures lag about a day. They carry an asof date. That is why they will not match a live dashboard exactly.

An empty episode list is normal for a small show. OP3's daily rollup has not covered it yet. The show-level total may still be there.

Metro codes are US-only. They are a US broadcast concept. Use level=region for a worldwide breakdown.

Raw download rows come back oldest first. OP3 offers no way to reverse that on this endpoint, so a limit takes the earliest rows in the window. Narrow the window to see recent activity rather than raising the limit.

Some shows cannot be filtered by episode. OP3 derives the episode id from the episode audio URL, so a host that regenerates those URLs leaves historical rows carrying ids that no longer appear in the feed. Checked across three shows, two matched exactly and one had no overlap at all. op3_episode_curve detects this and says so rather than returning silent zeros.

The raw endpoints are scans, not indexes. Two rows took 2790ms when probed. Cost grows with the window. The server pages with a continuation token, caps what it will pull, and labels any result that was cut short, because a truncated result presented as complete makes every rate computed from it wrong.

9. Your data πŸ”

There is no backend. The server runs on your machine, talks to op3.dev, and stores nothing on disk.

Responses are cached in memory for five minutes so an agent asking several questions about one show does not pay for the same scan repeatedly. That cache dies with the process. Set OP3_CACHE_TTL_MS=0 to disable it.

Per-listener identifiers never leave the server. OP3's raw row carries audienceId and hashedIpAddress. Both are aggregated over inside the process and stripped from anything returned. Every audience figure is a count, a rate or a distribution.

This is deliberate. OP3 exists to be a privacy-preserving analytics service, and a wrapper that streamed stable per-listener keys into a model context would undo that. op3_query_downloads can emit a shortened, non-reversible label if you need to tell rows apart by listener, and it is off by default.

Third-party text. Show and episode titles come from arbitrary RSS feeds. Anyone can publish a podcast, so that text is attacker-controlled and reaches the model inside a tool result. The server neutralises fence-breaking and tells the model in its instructions to treat it as data. That raises the cost of an injection rather than removing it. The real reason the blast radius is small is that this server is read-only and reaches nothing but OP3.

Settings

VariableDefaultDoes
OP3_TOKENpreview tokenYour bearer token from op3.dev/api/keys
OP3_API_KEYunsetAccepted as an alias for OP3_TOKEN
OP3_REQUEST_TIMEOUT_MS45000Per-request deadline
OP3_MIN_REQUEST_INTERVAL_MS150Spacing between requests
OP3_MAX_RETRIES3Retries on 429 and 5xx
OP3_MAX_ROWS50000Cap on rows any one analysis pulls
OP3_MAX_PAGES40Cap on continuation pages
OP3_CACHE_TTL_MS300000Response cache lifetime, 0 disables
OP3_USER_AGENTop3-mcpSent on every request
OP3_BASE_URLhttps://op3.dev/api/1OP3 API root, leave alone unless you proxy it
OP3_HTTP_PORT8787Port for --http
OP3_HTTP_HOST127.0.0.1Bind address for --http; anything but this machine needs OP3_HTTP_TOKEN
OP3_HTTP_TOKENnoneRequire this bearer token on HTTP requests
OP3_HTTP_ALLOWED_ORIGINSnoneComma-separated browser origins allowed to call --http; a page from any other site is refused
OP3_SURFACEfullsearch lists three tools that find, describe and run the rest
OP3_TOOL_TIMEOUT_MSnoneGive up on any tool after this long
OP3_DEBUG01 prints debug lines on stderr

10. Troubleshooting πŸ”§

Run doctor first. It names the problem in one command.

Terminal
npx -y @thenavidm/op3-mcp-cli@latest doctor
SymptomCause and fix
"OP3 has nothing at /shows/..."The show has no OP3 prefix on its feed. Run op3_verify_prefix, then op3.dev/setup
Downloads are zero but the show existsThe prefix was added recently and nothing has come through. Widen the lookback
Every row is a botThe prefix works but no listener has downloaded yet
A tool times outThe window is too wide for a scan. Narrow it or raise OP3_REQUEST_TIMEOUT_MS
A result says it was truncatedA cap stopped the pull. Narrow the window, or raise OP3_MAX_ROWS
op3_episode_curve returns zeros with a warningThe host regenerates episode URLs, so episode ids do not line up. Show-level tools still work
Rate limited on the preview tokenIt is shared. Get your own at op3.dev/api/keys

FAQ ❓

What is an MCP server?

An MCP server is a standard way to give an AI assistant tools it can actually call. Model Context Protocol is the agreement they speak, so any MCP client connects to any MCP server. This one exposes 22 read-only tools over OP3.

What is the CLI?

op3-cli is the same program as the MCP server, run as commands. AI agents that run commands, like Claude Code, Codex and OpenCode, use it on their own, and you can type the same commands in a terminal, a script or a cron job. Every tool is a command with dashes, so op3_show_downloads runs as op3-cli op3-show-downloads.

Should I use the MCP server or the CLI?

Use the MCP server in an app with no terminal, like Claude Desktop's chat. Use the CLI anywhere commands run: an agent like Claude Code, Codex or OpenCode, a script or a cron job. The MCP server's tools take up context on every message, and the CLI costs nothing until it runs.

Do I need a podcast?

It does not. The token reads public OP3 data, which covers every show that has the prefix on its feed.

Do I need an OP3 account?

You do not need an account, though you should get a token. Without one the server uses OP3's shared preview token, which is rate limited.

Does this work with my hosting platform?

It works with any podcast whose feed carries the OP3 prefix, whoever hosts it.

Why are the numbers different from Apple or Spotify?

Those report only their own listeners. OP3 sits in front of the audio file, so it sees every download regardless of app.

Can it write anything?

It does not. OP3's API is read-only and so is this.

Is my listener data exposed to the model?

It does not. Per-listener identifiers are aggregated inside the server and stripped from every response.

Why is it slow sometimes?

The raw endpoints are scans. Cost grows with the window. The rolled-up tools answer in milliseconds; prefer them.

Does it work with claude.ai?

It works over the HTTP transport, which needs a public HTTPS URL. See section 4.

How do I update it?

With @latest in the install line, the next published version reaches you the next time your client starts the server.

Questions

Run into a problem or have a question? Open an issue and I will help.

About the author πŸ‘‹

Navid Moazzez is a leading AI business strategist, and the host of the AI Creator Summit, watched by 100,000+ creators. He helps creators and founders master AI and build their own AI Operating System (AI OS) to automate their business and life. He creates useful free tools, MCP servers and CLIs that creators and founders can use in their own workflows.

Links

If this is useful, star the repo and come say hi on X.

Dependencies

LibraryLicenseWhat it does
SlipwayApache-2.0The MCP server and the CLI from one definition of each tool
MCP TypeScript SDKApache-2.0The MCP protocol and its transports, through Slipway
zodMITTool argument schemas and validation

Nothing else. The OP3 client, the pagination, the aggregation and the time handling are all built in.

License

MIT. Free to use, modify, and share.

Not affiliated with, endorsed by, or connected to the Open Podcast Prefix Project.


© 2026 Navid Media. Made with ❀️ by Navid Moazzez.