Skip to main content
Glama
rampstackco

@rampstack/umami-mcp

by rampstackco
README.md
# @rampstack/umami-mcp

A read-only [Model Context Protocol](https://modelcontextprotocol.io) server for
[Umami Cloud](https://umami.is) analytics. It exposes your Umami website data to
MCP clients (Claude Code, Claude Desktop, and others) as a small set of GET-only
tools.

Read-only by construction: the server makes exactly one kind of network call, an
authenticated HTTP GET against the Umami Cloud API. There is no write path in the
code, so no tool can create, edit, or delete anything in your Umami account.

## Install

One line for Claude Code (user scope):

```bash
claude mcp add umami --scope user \
  --env UMAMI_API_KEY=your_key_here \
  -- npx -y @rampstack/umami-mcp
```

Claude Desktop (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "umami": {
      "command": "npx",
      "args": ["-y", "@rampstack/umami-mcp"],
      "env": {
        "UMAMI_API_KEY": "your_key_here"
      }
    }
  }
}
```

### Environment

| Variable         | Required | Default                     | Notes                                             |
| ---------------- | -------- | --------------------------- | ------------------------------------------------- |
| `UMAMI_API_KEY`  | yes      | none                        | Umami Cloud API key. The server exits if missing. |
| `UMAMI_API_BASE` | no       | `https://api.umami.is/v1`   | Override for a regional base, e.g. `.../v1/eu`.    |

Get a key from the Umami Cloud dashboard under **Settings -> API keys**. The key
is passed to Umami in the `x-umami-api-key` header
([docs](https://docs.umami.is/docs/cloud/api-key)).

## Tools

All tools take dates as ISO 8601 or epoch milliseconds. Naive datetimes (no
timezone) are treated as UTC. Every time-scoped response echoes the resolved
`{ startAt, endAt }` epoch window so you can verify the exact window queried.

| Tool             | Purpose                                                                              |
| ---------------- | ------------------------------------------------------------------------------------ |
| `list_websites`  | id, name, domain for every site on the account. Call first to get `website_id`.      |
| `get_stats`      | visitors, visits, pageviews, bounces, totaltime + previous period + computed deltas. |
| `get_pageviews`  | pageviews/sessions timeseries, bucketed by `day` or `hour`.                          |
| `get_metrics`    | top values for one dimension (`url`, `referrer`, `browser`, `os`, `device`, `country`, `event`). |
| `get_event_data` | custom event-data properties (plan-gated; see below).                                |
| `cohort_report`  | one call: stats + top 10 urls + top 10 referrers + top 10 events over a range.       |

`cohort_report` accepts a `range` of `24h`, `7d`, `30d`, `90d`, or an ISO
`start/end` pair like `2026-01-01/2026-02-01`.

### Note on metric types

Umami's current docs label the URL dimension `path`. This server exposes it as
`url`, the long-standing alias the API still accepts, matching the Umami web UI
vocabulary. Other dimensions (`referrer`, `browser`, `os`, `device`, `country`,
`event`) map directly.

### Note on event-data

The `get_event_data` tool calls the Umami `event-data` endpoints, which are gated
by account plan. On tiers where they are not exposed, the tool returns a clear
note (not fabricated data) and points you to `get_metrics` with `type=event` for
event counts, which is available everywhere.

## Troubleshooting

**Every call fails with "Network error reaching Umami" / `fetch failed`.** The
server never reached the Umami API — this is a transport error, not an API
response. Check the unwrapped `cause` code in the message:

- `UNABLE_TO_VERIFY_LEAF_SIGNATURE` (or another certificate error) means a TLS
  interceptor — antivirus (e.g. AVG, Kaspersky) or a corporate proxy (Zscaler,
  Netskope) — is re-signing HTTPS with a root CA that lives in the OS trust
  store. Node ships its own CA bundle and ignores the OS store by default, so it
  rejects the chain. Fix it by telling Node to trust the OS store:

  ```bash
  claude mcp add umami --scope user -- node --use-system-ca /path/to/dist/index.js
  ```

  `--use-system-ca` (Node 20.6+/22+) trusts the Windows/macOS certificate store
  where the interceptor's root CA is installed. Prefer this over exporting the CA
  by hand, and never disable verification with `NODE_TLS_REJECT_UNAUTHORIZED=0` —
  that would send your API key over an unverified connection.

- `ENOTFOUND` / `ECONNREFUSED` / `ETIMEDOUT` point at DNS or connectivity to the
  configured `UMAMI_API_BASE`, not a certificate problem.

## Security

- **Read-only by construction.** The client exposes a single `get()` method;
  there is no POST/PUT/DELETE anywhere in the source.
- **GET-only.** Every tool maps to a documented Umami GET endpoint.
- **Key stays local.** `UMAMI_API_KEY` is read from your environment and sent
  only in the `x-umami-api-key` request header. It is never logged, never
  written to disk, and never included in error messages.
- **No telemetry.** The server makes no calls other than to the Umami API base
  you configure.
- **MIT licensed.**

> The Umami Cloud API key has account-wide read scope. If you manage analytics
> for multiple clients, use a separate Umami team or account per client rather
> than one key that can read them all.

## Development

Requires Node 20+.

```bash
npm install
npm run build   # tsc -> dist/
npm test        # compiles and runs the node:test suite (mocked fetch, no live API)
```

Tests never make live API calls and never reference a real key.

## Publishing

This package is not yet published. To publish (maintainer action):

```bash
npm run build
npm publish --access public
```

## License

MIT. See [LICENSE](./LICENSE).

TDQS

A3.8/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing websites, summary stats, pageview timeseries, top dimension values, custom event data, and a combined cohort report. Overlap is minimal and descriptions clarify boundaries.

Naming Consistency4/5

Most tools follow the 'verb_noun' pattern (list_websites, get_stats, get_pageviews, get_metrics, get_event_data), but 'cohort_report' breaks the pattern with a noun_noun format, causing a minor inconsistency.

Tool Count5/5

With 6 tools, the server is well-scoped for an analytics API. Each tool serves a distinct analysis need without redundancy or bloat.

Completeness5/5

The tool set covers all core analytics queries: listing websites, aggregate stats, timeseries pageviews, top metrics, event data, and a combined snapshot. No obvious gaps for read-only analytics.

Maintenance

ActivitySlowing
ResponsivenessNo issues