Content
# Clicky MCP Server
A Model Context Protocol (MCP) server that exposes [Clicky](https://clicky.com) web analytics as 12 tools for AI assistants — visitor counts, top pages, traffic sources, campaigns, bounce rate, search terms, real-time visitors, and more. See the [Tool reference](#tool-reference) for the full list.
---
## Quick start
You need:
- **Node.js 20+** installed (`node --version`)
- A **Clicky Site ID and Site Key** — find both at https://clicky.com/user/preferences/site under "Info" (you'll paste these into a local `.env` file, never into the chat)
- An **MCP-capable AI agent** — Claude Code, Claude Desktop, Codex, opencode, Cursor, Cline, …
MCP servers are installed *by* your agent, not started by hand — so the fastest setup is to hand the job over. Copy the block below and paste it to your agent:
```
Install the Clicky MCP server for me. It's a stdio MCP server, so the same definition works in any MCP host (Claude Code, Claude Desktop, Codex, opencode, Cursor, Cline, …) — register it using your host's own mechanism; only the config format differs, and you know your host better than this doc does.
1. Clone and build:
git clone https://github.com/colintoh/clicky-mcp.git
cd clicky-mcp && npm install && npm run build
Confirm the build produced dist/index.js. If it's missing, stop and show me
the build output instead of continuing.
2. Set up credentials WITHOUT putting them in this chat:
cp .env.example .env
Then tell me to open clicky-mcp/.env in my editor and paste my Clicky Site ID
and Site Key there myself (from https://clicky.com/user/preferences/site,
under "Info"). Do NOT ask me to paste the keys here, and do NOT read or print
.env — the server loads it at startup; the keys must never enter this chat.
3. Register it with this stdio server definition (no credentials in the host
config — the server reads them from .env):
command: absolute path to node — run `which node`; a bare "node" or a
relative path will fail
args: ["<absolute-path>/clicky-mcp/dist/index.js"]
transport: stdio
Add it with your host's own mechanism. One-line references if helpful:
- Claude Code: `claude mcp add clicky-analytics -- <node> <path>/clicky-mcp/dist/index.js`
- JSON hosts (Claude Desktop, Cursor, Cline, …): a "clicky-analytics"
entry under "mcpServers" with command + args (no env block needed)
- Codex (~/.codex/config.toml): [mcp_servers.clicky-analytics] with the
same command + args
If the host needs a restart to load new servers (Claude Desktop needs a full
Cmd-Q quit, not just closing the window), tell me to do that.
4. Verify: confirm your host lists a "clicky-analytics" server exposing 12 tools.
```
> **Why no `npm start`?** MCP stdio servers aren't standalone daemons — your agent's MCP host spawns the server as a subprocess on demand and talks to it over stdin/stdout. There's nothing to "start" yourself, which is also why setup is "tell your agent" rather than "run a command."
---
## Date parameters
Every date-aware tool accepts **either** an explicit date range **or** a Clicky relative-date keyword — but not both:
- **Explicit**: `start_date` + `end_date`, both `YYYY-MM-DD`, range ≤ 31 days.
- **Keyword**: `date_range`, one of `today`, `yesterday`, `last-7-days`, `last-30-days`, `this-week`, `last-week`, `this-month`, `last-month`, `this-year`, `last-year`.
Example:
```json
{ "date_range": "last-7-days" }
```
---
## Tool reference
All 12 tools, alphabetical-ish by use case.
### get_total_visitors
Total visitor counts for a period.
- `start_date` / `end_date` **or** `date_range`
### get_actions
Total pageviews/actions for a period.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
### get_bounce_rate
Bounce rate and average time-on-site for a period.
- `start_date` / `end_date` **or** `date_range`
### get_visitors_online
Real-time visitor count and segmentation. Takes no parameters.
### get_top_pages
Most popular pages for a period.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
### get_page_traffic
Traffic data for a specific page URL.
- `url` (string, **required**)
- `start_date` / `end_date` **or** `date_range`
### get_traffic_sources
Traffic sources breakdown — optionally filter by page URL.
- `start_date` / `end_date` **or** `date_range`
- `page_url` (string, optional) — full URL or path
### get_referring_domains
Top referring domains sending traffic.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
### get_campaigns
Traffic grouped by campaign tag (`utm_campaign` or Clicky campaign tracking). Only tagged inbound traffic appears here — untagged organic/direct traffic does not.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
- `include_keywords` (boolean, optional) — also return campaign keyword/term tags
### get_domain_visitors
Visitor data filtered by referrer domain, with optional segmentation.
- `domain` (string, **required**)
- `start_date` / `end_date` **or** `date_range`
- `segments` (array, optional) — `["pages", "visitors"]`. Defaults to `["visitors"]`.
- `limit` (number, optional, max 1000)
### get_searches
Top search terms that brought visitors.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
### get_countries
Visitor breakdown by country.
- `start_date` / `end_date` **or** `date_range`
- `limit` (number, optional, max 1000)
---
## API limits
Imposed by Clicky, not by this server:
- Maximum explicit date range: **31 days**
- Maximum results per request: **1,000 items**
- One simultaneous request per IP per site ID
---
## Troubleshooting
**"Claude Desktop doesn't see the server."** Check the spawn log at `~/Library/Logs/Claude/mcp-server-clicky-analytics.log`. The most common cause is `node` not being on Claude Desktop's launchd PATH — fix by replacing `"command": "node"` with the absolute path from `which node`. The second-most-common cause is forgetting to fully quit Claude Desktop (`⌘Q`, not just close the window).
**"Date range cannot exceed 31 days."** That's a Clicky API limit, not us. Either narrow the range or use a `date_range` keyword like `last-30-days`.
---
## Local development
For working *on* the server, not just using it.
```bash
npm install # install deps
npm run dev # run with tsx, watching for changes (used for local testing only)
npm run build # compile TS to dist/
npm test # 46 unit tests, offline, no credentials needed
npm run test:integration # live API smoke test (requires .env or env vars)
```
Credentials come from a `.env` file in the project root — copy the template and fill in your values:
```bash
cp .env.example .env
```
```
CLICKY_SITE_ID=your_site_id
CLICKY_SITE_KEY=your_site_key
```
`.env` is gitignored, and it's the recommended way to supply credentials for **both** local dev and MCP hosts: it keeps your keys out of host config files and out of any agent chat. The server resolves `.env` relative to its own location, so it's found no matter what working directory the host launches it from, and it only loads `.env` when the credentials aren't already in the environment. You can still pass `CLICKY_SITE_ID`/`CLICKY_SITE_KEY` via the host's `env` block or `--site-id`/`--site-key` args if you prefer.
A pre-push git hook in `.githooks/pre-push` auto-runs `npm test` before any push that updates the remote `main` branch, so a regression can't slip out unnoticed. It's installed automatically by the `prepare` npm script after `npm install`. Pushes to feature branches are not gated. Bypass in an emergency with `git push --no-verify`.
### Project structure
```
clicky-mcp/
├── src/
│ ├── index.ts # MCP server + tool dispatcher
│ ├── clicky-client.ts # Clicky HTTP API client
│ ├── date-utils.ts # Shared date param builder
│ └── tools/ # One file per tool
├── test/ # node:test unit tests
├── scripts/verify.mjs # Live API smoke runner
├── .githooks/pre-push # Auto-installed test gate for main
├── package.json
├── tsconfig.json
└── README.md
```
---
## License
MIT