{
  "markdown": "<div align=\"center\">\n\n<img src=\"assets/logo.svg\" width=\"120\" alt=\"matomo-mcp logo\"/>\n\n# matomo-mcp\n\n**Talk to your Matomo Analytics.** From Claude, Cursor, VS Code, or any MCP client.\n\n[![CI](https://github.com/Liohtml/matomo-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/Liohtml/matomo-mcp/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/matomo-mcp.svg)](https://crates.io/crates/matomo-mcp)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Rust](https://img.shields.io/badge/rust-1.88%2B-orange.svg)](https://www.rust-lang.org)\n[![MCP](https://img.shields.io/badge/MCP-compatible-8A2BE2)](https://modelcontextprotocol.io)\n\n*15 curated, read-only analytics tools + a full-API escape hatch. Single binary, instant startup, context-friendly.*\n\n[Quickstart](#-quickstart) · [Clients](#-connect-your-client) · [Tools](#-tools) · [Configuration](#%EF%B8%8F-configuration) · [FAQ](#-troubleshooting)\n\n</div>\n\n---\n\n```text\nYou  ▸ How was traffic yesterday, and where did it come from?\n\nClaude ▸ Yesterday you had 14,472 visits (11,416 unique visitors, 66% bounce rate).\n         Top acquisition channels:\n         1. Organic search — 6,120 visits (Google 92%)\n         2. Direct — 4,890 visits\n         3. AI assistants — 1,204 visits (↑ 31% vs. last week)\n         Want me to break down which landing pages converted best?\n```\n\nEvery question your Matomo dashboard can answer, your AI assistant can now answer too — including follow-ups, comparisons, and \"why?\".\n\n## ✨ Why matomo-mcp?\n\n| | |\n|---|---|\n| 🎯 **Curated, not generated** | 15 hand-crafted tools modeled on real analytics questions — not 70+ auto-generated API mirrors that flood the model's context and degrade tool selection. |\n| ⚡ **Instant startup** | No introspection round-trips. One static binary, no Node, no Python, no runtime. Starts in milliseconds. |\n| 🔒 **Safe by default** | Read-only reporting tools. Token sent via POST only (never in URLs/logs), redacted from every error. TLS verification on by default. |\n| 🧠 **Context-friendly** | Row limits on every report and a hard response budget with actionable guidance — one tool call can never blow up the context window. |\n| 📡 **Real-time included** | Live visitor counters and a visit log (`matomo_realtime`) — see what's happening *right now*. |\n| 🧰 **Never a cage** | `matomo_api` reaches **any** Reporting API method (funnels, heatmaps, custom dimensions, …) when the curated tools don't cover it. |\n| 🔁 **Resilient** | Automatic retries with backoff on 429/5xx/network hiccups. Helpful, hint-annotated error messages the model can act on. |\n\n## 🚀 Quickstart\n\n### 1. Install\n\n**Prebuilt binary** (Linux, macOS, Windows) — grab it from [Releases](https://github.com/Liohtml/matomo-mcp/releases), or:\n\n```bash\n# Cargo\ncargo install matomo-mcp\n\n# From source\ncargo install --git https://github.com/Liohtml/matomo-mcp\n\n# Docker\ndocker pull ghcr.io/liohtml/matomo-mcp\n```\n\n### 2. Get a Matomo API token\n\nMatomo → **Settings** (⚙) → **Personal** → **Security** → **Auth tokens** → *Create new token*.\nView-only permissions are all it needs.\n\n### 3. Verify the connection\n\n```bash\nmatomo-mcp --url https://your-matomo.example.com --token YOUR_TOKEN --check\n```\n\n```text\n✓ Connected — Matomo version 5.2.1\n✓ Token grants access to 3 site(s):\n    #1 My Shop (https://shop.example.com)\n    #2 Blog (https://blog.example.com)\n    #3 Docs (https://docs.example.com)\n```\n\n### 4. Connect your client ⬇\n\n## 🔌 Connect your client\n\n<details>\n<summary><b>Claude Code</b></summary>\n\n```bash\nclaude mcp add matomo \\\n  --env MATOMO_URL=https://your-matomo.example.com \\\n  --env MATOMO_TOKEN=YOUR_TOKEN \\\n  --env MATOMO_DEFAULT_SITE_ID=1 \\\n  -- matomo-mcp\n```\n\n</details>\n\n<details>\n<summary><b>Claude Desktop</b></summary>\n\nAdd to `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/`, Windows: `%APPDATA%\\Claude\\`):\n\n```json\n{\n  \"mcpServers\": {\n    \"matomo\": {\n      \"command\": \"matomo-mcp\",\n      \"env\": {\n        \"MATOMO_URL\": \"https://your-matomo.example.com\",\n        \"MATOMO_TOKEN\": \"YOUR_TOKEN\",\n        \"MATOMO_DEFAULT_SITE_ID\": \"1\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Cursor</b></summary>\n\n`.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global):\n\n```json\n{\n  \"mcpServers\": {\n    \"matomo\": {\n      \"command\": \"matomo-mcp\",\n      \"env\": {\n        \"MATOMO_URL\": \"https://your-matomo.example.com\",\n        \"MATOMO_TOKEN\": \"YOUR_TOKEN\",\n        \"MATOMO_DEFAULT_SITE_ID\": \"1\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>VS Code (GitHub Copilot)</b></summary>\n\n`.vscode/mcp.json`:\n\n```json\n{\n  \"servers\": {\n    \"matomo\": {\n      \"type\": \"stdio\",\n      \"command\": \"matomo-mcp\",\n      \"env\": {\n        \"MATOMO_URL\": \"https://your-matomo.example.com\",\n        \"MATOMO_TOKEN\": \"${input:matomo-token}\",\n        \"MATOMO_DEFAULT_SITE_ID\": \"1\"\n      }\n    }\n  },\n  \"inputs\": [\n    {\n      \"id\": \"matomo-token\",\n      \"type\": \"promptString\",\n      \"description\": \"Matomo API token\",\n      \"password\": true\n    }\n  ]\n}\n```\n\n</details>\n\n<details>\n<summary><b>Windsurf / Zed / other MCP clients</b></summary>\n\nAny client that speaks MCP over stdio works with the generic shape:\n\n```json\n{\n  \"command\": \"matomo-mcp\",\n  \"args\": [],\n  \"env\": {\n    \"MATOMO_URL\": \"https://your-matomo.example.com\",\n    \"MATOMO_TOKEN\": \"YOUR_TOKEN\",\n    \"MATOMO_DEFAULT_SITE_ID\": \"1\"\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Docker (any client)</b></summary>\n\n```json\n{\n  \"mcpServers\": {\n    \"matomo\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-e\", \"MATOMO_URL\", \"-e\", \"MATOMO_TOKEN\", \"-e\", \"MATOMO_DEFAULT_SITE_ID\",\n        \"ghcr.io/liohtml/matomo-mcp\"\n      ],\n      \"env\": {\n        \"MATOMO_URL\": \"https://your-matomo.example.com\",\n        \"MATOMO_TOKEN\": \"YOUR_TOKEN\",\n        \"MATOMO_DEFAULT_SITE_ID\": \"1\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n<summary><b>Streamable HTTP — host once, connect many clients</b></summary>\n\nRun the server once (on a workstation, LAN box, or container) and point any\nnumber of MCP clients at it:\n\n```bash\nmatomo-mcp --url https://your-matomo.example.com --token YOUR_TOKEN --http 127.0.0.1:8080\n```\n\nClients connect to `http://127.0.0.1:8080/mcp` with the streamable HTTP\ntransport, e.g.:\n\n```bash\nclaude mcp add --transport http matomo http://127.0.0.1:8080/mcp\n```\n\n> [!WARNING]\n> The HTTP endpoint has no built-in authentication. Keep it bound to\n> `127.0.0.1`, or put a reverse proxy with auth (or a firewall) in front\n> before exposing it beyond localhost.\n\n</details>\n\n> [!TIP]\n> Set `MATOMO_DEFAULT_SITE_ID` and the model never has to ask which site you mean.\n> No token at hand? Try it against the public demo: `--url https://demo.matomo.cloud --default-site-id 1` (no token needed).\n\n## 🧭 Tools\n\n| Tool | Answers questions like |\n|------|------------------------|\n| `matomo_list_sites` | *\"Which sites do we track?\"* |\n| `matomo_visits_summary` | *\"How much traffic did we get last week?\"* |\n| `matomo_pages` | *\"What are our top pages? Where do people exit?\"* |\n| `matomo_referrers` | *\"Where do visitors come from? Which campaigns work? What do AI assistants send us?\"* |\n| `matomo_events` | *\"How often was the configurator opened?\"* |\n| `matomo_goals` | *\"What's our conversion rate per goal?\"* |\n| `matomo_ecommerce` | *\"Revenue this month? Best-selling products?\"* |\n| `matomo_geo` | *\"Which countries/cities do visitors come from?\"* |\n| `matomo_devices` | *\"Mobile vs. desktop? Which browsers?\"* |\n| `matomo_visit_times` | *\"When during the day/week do people visit?\"* |\n| `matomo_site_search` | *\"What do people search for on our site — and find nothing?\"* |\n| `matomo_realtime` | *\"Who's on the site right now?\"* |\n| `matomo_page_performance` | *\"Which pages load slowly?\"* |\n| `matomo_annotations` | *\"Which deploys or campaign launches line up with that traffic spike?\"* |\n| `matomo_api` | Everything else — funnels, heatmaps, custom dimensions, any `Module.action` of the Reporting API |\n\nAll tools accept `site_id`, `period` (`day`/`week`/`month`/`year`/`range`), `date`\n(`today`, `yesterday`, `2026-07-01`, `last30`, or `start,end` ranges), an optional\n`segment` (e.g. `deviceType==mobile;country==DE`), and a row `limit`.\n\n### Prompts to try\n\n- *\"Compare this week's traffic with last week — what changed and why?\"*\n- *\"Top 10 landing pages by conversions this month, with bounce rates.\"*\n- *\"Are we getting traffic from ChatGPT or Perplexity? Trend over 3 months.\"*\n- *\"Which internal searches return no results? Suggest content we should create.\"*\n- *\"Anything unusual in the visitor log right now?\"*\n\n## ⚙️ Configuration\n\n| Flag | Env | Default | Description |\n|------|-----|---------|-------------|\n| `--url` | `MATOMO_URL` | — | Matomo instance URL (sub-directory installs like `https://example.com/matomo/` work). Without it the server still starts and tool calls return setup guidance |\n| `--token` | `MATOMO_TOKEN` | — | API token (`token_auth`), view access is enough |\n| `--default-site-id` | `MATOMO_DEFAULT_SITE_ID` | — | Site used when the model doesn't specify one |\n| `--header` | `MATOMO_EXTRA_HEADERS` | — | Extra HTTP headers (`Name:Value`, repeatable / comma-separated) — for auth proxies, Zero-Trust, multi-tenant setups |\n| `--timeout-secs` | `MATOMO_TIMEOUT_SECS` | `30` | Per-request timeout |\n| `--max-response-chars` | `MATOMO_MAX_RESPONSE_CHARS` | `50000` | Response budget before truncation |\n| `--http` | `MATOMO_HTTP_BIND` | — | Serve MCP over streamable HTTP on this address instead of stdio (endpoint: `http://<addr>/mcp`) |\n| `--insecure` | `MATOMO_INSECURE` | `false` | Accept self-signed TLS certificates (explicit opt-in) |\n| `--check` | — | — | Verify URL + token + site access, then exit |\n\n## 🆚 How is this different from `FGRibreau/mcp-matomo`?\n\n[mcp-matomo](https://github.com/FGRibreau/mcp-matomo) (which inspired this project — thanks! 🙏) introspects your Matomo instance at startup and generates one MCP tool per API method. matomo-mcp takes the opposite approach:\n\n| | matomo-mcp | mcp-matomo |\n|---|---|---|\n| Tool set | 15 curated tools + escape hatch | ~70+ generated tools |\n| Model context cost | Small, stable | Large, instance-dependent |\n| Parameter types | Exact, hand-written enums/defaults | Inferred from parameter names |\n| Startup | Instant (no network I/O) | Introspection round-trips (or cached spec file) |\n| TLS verification | On by default | Disabled for introspection |\n| Sub-directory installs | ✅ | Path is overwritten |\n| Response size guard | Row limits + hard budget | — |\n| Retries on transient errors | ✅ | — |\n| Real-time (Live) tools | ✅ | — (not part of report metadata) |\n\nIf you want *every* API method as its own tool, use mcp-matomo. If you want the model to reliably pick the right tool and never flood its context, use matomo-mcp.\n\n## 🩺 Troubleshooting\n\n<details>\n<summary><b>\"site_id is required\"</b></summary>\n\nEither pass `--default-site-id 1` (recommended) or let the model call `matomo_list_sites` first.\n\n</details>\n\n<details>\n<summary><b>401 / \"cannot be authenticated\"</b></summary>\n\nRun `matomo-mcp --url ... --token ... --check`. If it fails: regenerate the token (Settings → Personal → Security), make sure it has at least **view** access to the site.\n\n</details>\n\n<details>\n<summary><b>404 or HTML instead of JSON</b></summary>\n\n`MATOMO_URL` must point at the Matomo root — the folder containing `index.php`. For `https://example.com/matomo/index.php`, use `https://example.com/matomo/`.\n\n</details>\n\n<details>\n<summary><b>Behind Cloudflare Access / OAuth2 proxy / Zero Trust?</b></summary>\n\nInject the bypass headers: `--header \"CF-Access-Client-Id:...\" --header \"CF-Access-Client-Secret:...\"` (or via `MATOMO_EXTRA_HEADERS`).\n\n</details>\n\n<details>\n<summary><b>Responses feel truncated</b></summary>\n\nThat's the context guard doing its job. Ask for fewer rows, a shorter date range, or raise `--max-response-chars`.\n\n</details>\n\n## 🗺️ Roadmap\n\n- [x] Streamable HTTP transport (`--http`, host it once, connect many clients)\n- [x] `matomo_annotations` — read & correlate deploy markers with traffic\n- [ ] Multi-instance support (one server, several Matomo installations)\n- [ ] Homebrew tap & winget manifest\n- [x] MCP registry listing (official registry via `server.json`, Glama)\n\nWant one of these sooner? [Open an issue](https://github.com/Liohtml/matomo-mcp/issues) — or a PR, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## 🛠️ Development\n\n```bash\ncargo test                                   # 37 tests, fully offline (wiremock)\ncargo clippy --all-targets -- -D warnings\ncargo run -- --url https://demo.matomo.cloud --default-site-id 1 --check\n```\n\nArchitecture and design decisions: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).\n\n## 📄 License & Credits\n\n[MIT](LICENSE). Not affiliated with or endorsed by [Matomo](https://matomo.org) — Matomo is a registered trademark of InnoCraft Ltd.\n\nBuilt with [rmcp](https://crates.io/crates/rmcp), the official Rust MCP SDK. Inspired by [FGRibreau/mcp-matomo](https://github.com/FGRibreau/mcp-matomo).\n\n- MCP Registry name: `mcp-name: io.github.Liohtml/matomo-mcp`\n\n---\n\n<div align=\"center\">\n\n**If matomo-mcp saves you a dashboard visit, a ⭐ helps others find it.**\n\n</div>\n",
  "bytes": 13244,
  "sha": "d95b8e80f33aeef8f9f0553489f61bf9bc976126da15720d95022bda9297e434",
  "repo_slug": "liohtml/matomo-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_liohtml_matomo_mcp_01215c82/readme"
}