Clicky MCP Server
# 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
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose targeting different analytics dimensions: domain visitors, page traffic, top pages, total visitors, and traffic sources. There is no overlap in functionality, making it easy for an agent to select the correct tool without confusion.
All tool names follow a consistent verb_noun pattern with 'get_' prefix and descriptive nouns (e.g., get_domain_visitors, get_page_traffic). This uniformity enhances readability and predictability across the toolset.
With 5 tools, the server is well-scoped for analytics retrieval, covering key metrics like visitors, pages, and traffic sources. Each tool earns its place without being overly sparse or bloated, fitting typical use cases effectively.
The toolset provides comprehensive read-only coverage for analytics data, including filtering and segmentation options. A minor gap exists in lacking write or configuration tools (e.g., setting up analytics), but this is reasonable for a data retrieval-focused server, and agents can work around this limitation.