An MCP server for Plausible Analytics, running on Cloudflare Workers. Ask your AI assistant questions about your site traffic instead of exporting CSVs.
Connect Plausible Analytics to Claude, Claude Code, Cursor or any MCP client. No local install, no Node.js, no Python. It runs as a remote Worker in your own Cloudflare account, so it works from mobile as well as desktop and keeps working when your laptop is closed.
"Which pages lost traffic against last month?" "What's the signup conversion rate for people who saw the pricing page?" "Is the blog actually bringing in visitors, or is it all direct?"
Covers the Stats API for reading and the Sites API for provisioning.
One click clones this repo to your GitHub and deploys it to your own Cloudflare account. Your API key stays in your Worker, never anyone else's. Free on Cloudflare's free plan.
- Before you start
- Setup — deploy, secrets, connect
- Connecting your AI assistant
- Tools
- Configuration reference
- Troubleshooting
- Why another Plausible MCP
You need three things:
- A Plausible account on the Business plan or higher. The Stats API is a Business feature. On Growth or lower, every call returns 401 and there is nothing this server can do about it.
- A Cloudflare account. The free plan is fine.
- A Plausible API key. See below.
You do not need Node.js, a terminal, or any local tooling. Everything below can be done in a browser.
- Log in to Plausible and select the team that owns the sites you want to query, using the menu in the top right.
- Click your account name, open settings, go to API Keys.
- New API Key, then choose the type:
- Stats API if you only want to read data. This is the right choice for most people.
- Sites API if you also want to create sites and goals. Requires an Enterprise plan.
- Copy the key. It is shown once and never again.
The single most common mistake: a key is scoped to the team that was selected when you created it. It cannot reach sites owned by another team, and it cannot reach sites where you are only a Guest Viewer or Guest Editor, even though you can see those sites in the dashboard. If you manage client sites owned by the client's own team, you need a key from them.
Use the Deploy to Cloudflare button at the top of this README. It forks the repo to your GitHub account and sets the Worker up for you, then redeploys on every push.
Or set it up manually
Fork this repository, then in the Cloudflare dashboard go to Compute (Workers) → Create → Import a repository. Connect GitHub, choose your fork, and set:
| Setting | Value |
|---|---|
| Branch | main |
| Build command | leave empty |
| Deploy command | npx wrangler deploy |
Check it worked by visiting https://mcp-plausible.<your-subdomain>.workers.dev/health
in a browser. It should say ok.
Prefer the command line?
npm install
npx wrangler login
npx wrangler deployPrivate (recommended for personal use). Your Plausible key is stored in the Worker and a separate access token controls who can use it. Continue to step 3.
Bring your own key. The Worker stores nothing, and each user sends their own Plausible key. Use this if you want to share the deployment with others. Skip step 3 entirely and jump to Connecting, using your Plausible key as the header value.
Generate an access token first. In PowerShell:
-join ((1..32) | ForEach-Object { '{0:x2}' -f (Get-Random -Max 256) })Or on macOS and Linux:
openssl rand -hex 32In the Cloudflare dashboard, open your Worker → Settings → Variables and Secrets. Add these, each as type Secret rather than plain text:
| Name | Value |
|---|---|
PLAUSIBLE_API_KEY |
Your Plausible key |
MCP_TOKEN |
The token you just generated |
ALLOWED_SITES |
Optional. Comma separated domains, e.g. example.com,client.co.uk |
Setting PLAUSIBLE_API_KEY switches the Worker into private mode, where MCP_TOKEN is
mandatory. The Worker refuses to serve anything if you set the key without a token,
rather than quietly exposing your analytics to anyone who finds the URL.
ALLOWED_SITES is optional but worth setting. It restricts which sites can be queried,
and putting it in as a secret keeps your client list out of a public repository.
Not strictly required, but do it. Settings → Domains & Routes → Add →
Custom domain, something like mcp-plausible.yourdomain.com.
Cloudflare's Cache API silently does nothing on workers.dev subdomains, so without a
custom domain the response cache never works and you burn through Plausible's 600
requests per hour faster than you need to.
Settings → Connectors → Add custom connector.
| Field | Value |
|---|---|
| URL | https://mcp-plausible.yourdomain.com/mcp |
| Authentication | None |
Then Add header:
| Field | Value |
|---|---|
| Header name | x-api-key |
| Value | Your MCP_TOKEN (or your Plausible key in bring-your-own-key mode) |
| Required | ✅ |
Set Authentication to None, not OAuth. This server uses an API key, not OAuth. The
authorization header is greyed out because Claude reserves it for its own OAuth
bearer token, which is why x-api-key is used instead.
claude mcp add --transport http plausible https://mcp-plausible.yourdomain.com/mcp \
--header "x-api-key: YOUR_MCP_TOKEN"Some clients cannot talk to a remote server directly. Bridge with mcp-remote:
{
"mcpServers": {
"plausible": {
"command": "npx",
"args": [
"-y", "mcp-remote",
"https://mcp-plausible.yourdomain.com/mcp",
"--header", "x-api-key:YOUR_MCP_TOKEN"
]
}
}
}Put the token in the URL instead:
https://mcp-plausible.yourdomain.com/mcp/t/YOUR_MCP_TOKEN
This works, but the token then appears in your connector settings, in logs, and in any screenshot. Prefer the header where you can.
Ask your assistant: "list my Plausible sites". You should get your sites back. Then try "how did traffic to example.com compare to last month?".
| Tool | What it does |
|---|---|
get_timeseries |
Traffic over time, bucketed by hour, day, week or month |
get_breakdown |
Break down by page, source, country, device, UTM and more |
get_conversions |
Goal conversions and rates, optionally per page or source |
compare_periods |
Two ranges side by side with deltas, including rows new or absent in one period |
run_query |
Raw Stats API v2 query for anything the above cannot express |
check_api_access, list_sites, get_site, list_goals,
list_custom_properties, list_guests.
Run check_api_access to see which teams your key can reach and whether the Sites API
is available, rather than guessing.
Off by default. To enable, set the ENABLE_WRITES variable to true in Settings →
Variables and Secrets (a plain variable, not a secret).
create_site, update_site, delete_site, create_goal, delete_goal,
create_shared_link, create_custom_property, invite_guest, remove_guest.
When writes are off, these tools are not merely refused, they are not advertised at all.
delete_site requires an explicit confirm: true, because it destroys all of a site's
data and blocks re-registering the domain for up to 48 hours.
| Name | Type | Purpose |
|---|---|---|
PLAUSIBLE_API_KEY |
Secret | Optional. Setting it switches to private mode |
MCP_TOKEN |
Secret | Required when PLAUSIBLE_API_KEY is set. Accepts a comma separated list, so you can rotate without downtime |
ALLOWED_SITES |
Secret | Optional allowlist of domains, comma separated |
ENABLE_WRITES |
Variable | true registers the Sites API write tools |
PLAUSIBLE_BASE_URL |
Variable | Only for self-hosted Plausible |
MCP_TOKEN accepts a list. Set it to old-token, new-token, update each client one at
a time, then set it back to just new-token. No downtime, no scramble.
x-api-key is recommended, but api-key, apikey, x-apikey, x-api-token,
api-token, x-auth-token and Authorization: Bearer all work, for clients that
restrict which headers you can set.
Every call returns 401 from Plausible. Almost always team scoping. Your key only
reaches sites owned by the team selected when you created it, and Guest Viewer access
does not count. Run check_api_access to see which teams the key can actually reach.
Every call returns 401 from the Worker. Your header value does not match
MCP_TOKEN. Check for a trailing space when you pasted it.
The connector shows an OAuth sign-in prompt. Authentication is set to something other than None. This server does not use OAuth.
"Query rejected before sending". The server checks Plausible's constraints before
spending a request. The message says exactly what to change. Common ones: scroll_depth
needs an event:page filter or dimension, and bounce_rate cannot be combined with
event:goal.
Results seem stale. Identical queries are cached for 3 minutes.
Numbers differ slightly between queries. Plausible selects different underlying tables depending on the metrics requested. Documented upstream, and under 1%.
No data at all for a site. Check site_id matches the domain exactly as registered
in Plausible. Run list_sites if unsure.
The Sentry team's plausible-mcp came first and is well built. This one differs in four ways:
- Runs as a remote Worker, so it needs no local install, works from mobile, and keeps working when your laptop is closed.
- Pre-flight validation. Plausible's constraints are checked before the request goes out, so you get a message saying what to change rather than a 400, and it does not spend one of your 600 hourly requests.
- Full Stats API v2 coverage. Custom properties, behavioural filters (
has_done), segments, imported data, hostname dimensions and ISO datetime ranges are all reachable. - Sites API writes, gated off by default.
npm install
npm run typecheck
npm run dev # needs a .dev.vars file, gitignored
npm run tail # live logs from the deployed workerFree and MIT licensed. Provided as-is, with no warranty of any kind and no liability accepted, as set out in LICENSE.
You deploy and run this in your own Cloudflare account, so your API keys, your usage and anything the tools do to your Plausible data remain your responsibility. Enabling the write tools means an AI assistant can create and delete sites and goals on your account, so read that section before turning them on.
Maintained in spare time, so issues and pull requests are very welcome but may not get a fast response.