Skip to main content
Glama
umami-analytics-mcp

umami-analytics-mcp

by matious89pl

umami-analytics-mcp

Security-first Model Context Protocol server for Umami analytics β€” Umami Cloud and self-hosted (v3). Set up, analyze, report on, and (when you allow it) administer your Umami instance from any MCP client.

CI License: MIT

  • πŸš€ Local-first β€” npx umami-analytics-mcp, zero build step, ~2 runtime deps.

  • ☁️ Or host it β€” deploy to Vercel (one Web function) or run the bundled Docker HTTP server. One shared core, three transports.

  • πŸ”’ Credential-safe β€” secrets live in env only; never placed in tool arguments, outputs, or logs (two-layer redaction). Remote endpoints are bearer-gated and fail closed.

  • 🎚️ Least privilege β€” read-only by default; write and admin tiers are opt-in; destructive ops (delete/reset) are double-gated.

  • πŸ“Š Comprehensive β€” full Umami v3 surface: stats, metrics, events, sessions, reports (funnel, retention, journey, attribution, revenue, UTM, web-vitals), segments, teams, share links, event ingestion, and self-hosted user administration.


Contents


Related MCP server: Umami MCP Server

Quickstart (local / npx)

No install required. Point your MCP client at:

npx -y umami-analytics-mcp

…with credentials supplied via environment variables. For Umami Cloud, create an API key at Dashboard β†’ Settings β†’ API keys and set UMAMI_API_KEY. For self-hosted, set UMAMI_API_URL + UMAMI_USERNAME + UMAMI_PASSWORD. See MCP client setup for copy-paste configs.

By default the server is read-only (32 analytics tools). Opt into writes/admin explicitly β€” see Capability tiers.


Configuration

All configuration is via environment variables (secrets) and optional CLI flags (non-secrets).

Variable

Mode

Description

UMAMI_API_KEY

Cloud

Umami Cloud API key (selects Cloud mode).

UMAMI_CLOUD_REGION

Cloud

us or eu (optional regional base URL).

UMAMI_API_URL

self-hosted

Instance base URL, e.g. https://stats.example.com (/api appended).

UMAMI_USERNAME / UMAMI_PASSWORD

self-hosted

Login credentials β†’ bearer token (cached, auto-renewed on 401).

UMAMI_TEAM_ID

both

Scope website listings to a team (optional).

UMAMI_DEFAULT_TIMEZONE

both

IANA tz for time-series tools (default UTC).

UMAMI_ENABLE_WRITE

both

1 to expose create/update + send_event tools.

UMAMI_ENABLE_ADMIN

both

1 to expose user-management tools (self-hosted only).

UMAMI_ALLOW_DESTRUCTIVE

both

1 β€” also required to expose delete/reset tools.

MCP_AUTH_TOKEN

remote

Shared-secret bearer required by the Vercel/HTTP endpoints.

Self-hosted instances that issue API keys can use UMAMI_API_URL + UMAMI_API_KEY instead of username/password.

Surrounding quotes are stripped from values defensively. For local use you can keep settings in a file and load them with --env-file:

npx umami-analytics-mcp --env-file .env.local

Run npx umami-analytics-mcp --help for the full flag list.


Capability tiers

The server exposes only the tools for the tiers you enable, layered on top of Umami's own role-based access (the API still enforces your account's real permissions β€” tiers just decide which tools are even visible).

Tier

Enable with

Adds

Example tools

read

(always on)

analytics & reporting

get_stats, get_metrics, report_funnel, list_sessions

write

UMAMI_ENABLE_WRITE=1

mutations + ingestion

create_website, send_event, add_team_member

admin

UMAMI_ENABLE_ADMIN=1 (self-hosted)

user administration

create_user, set_user_role

destructive

UMAMI_ALLOW_DESTRUCTIVE=1 (+ write/admin)

delete / reset

delete_website, reset_website, delete_user

Tool counts: 32 read β†’ 46 with write β†’ 52 with destructive β†’ 58 at full tier on self-hosted. On Cloud the admin tier is automatically disabled (Umami Cloud has no user-admin API) and the server explains why at startup. Destructive tools carry MCP destructiveHint annotations so clients can warn before running them.


MCP client setup

Claude Desktop / Cursor (claude_desktop_config.json / .cursor/mcp.json)

{
  "mcpServers": {
    "umami": {
      "command": "npx",
      "args": ["-y", "umami-analytics-mcp"],
      "env": {
        "UMAMI_API_KEY": "your_cloud_api_key"
        // self-hosted instead:
        // "UMAMI_API_URL": "https://stats.example.com",
        // "UMAMI_USERNAME": "admin",
        // "UMAMI_PASSWORD": "β€’β€’β€’β€’β€’β€’",
        // opt into writes:
        // "UMAMI_ENABLE_WRITE": "1"
      }
    }
  }
}

Claude Code

claude mcp add umami \
  -e UMAMI_API_KEY=your_cloud_api_key \
  -- npx -y umami-analytics-mcp

VS Code (.vscode/mcp.json)

{
  "servers": {
    "umami": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "umami-analytics-mcp"],
      "env": { "UMAMI_API_KEY": "your_cloud_api_key" }
    }
  }
}

Remote hosting

Both remote transports require MCP_AUTH_TOKEN; without it they reject every request (fail closed). Clients authenticate with Authorization: Bearer <MCP_AUTH_TOKEN>.

Deploy to Vercel

The repo ships a single Web function at api/mcp.ts (no Next.js required).

  1. Push this repo to GitHub and Import it in Vercel.

  2. Set Environment Variables: your Umami credentials (UMAMI_API_KEY or UMAMI_API_URL+UMAMI_USERNAME+UMAMI_PASSWORD), optional tier flags, and a strong MCP_AUTH_TOKEN.

  3. Deploy. Your endpoint is https://<deployment>.vercel.app/api/mcp.

  4. Harden: enable Vercel Deployment Protection (locks preview URLs) and Firewall.

Connect a Streamable-HTTP-capable client to the URL with the bearer header. stdio-only clients bridge via:

npx mcp-remote https://<deployment>.vercel.app/api/mcp \
  --header "Authorization: Bearer $MCP_AUTH_TOKEN"

Docker / self-host

Runs the framework-free standalone HTTP server (umami-mcp-http):

docker build -t umami-mcp .
docker run --rm -p 8787:8787 \
  -e UMAMI_API_KEY=your_cloud_api_key \
  -e MCP_AUTH_TOKEN=$(openssl rand -hex 32) \
  umami-mcp
# β†’ endpoint at http://localhost:8787/mcp  (health: /health)

Or without Docker: MCP_AUTH_TOKEN=… UMAMI_API_KEY=… npx -y umami-analytics-mcp umami-mcp-http (bin umami-mcp-http). Set HOST, PORT, optional MCP_ALLOWED_HOSTS (enables DNS-rebinding protection), or MCP_ALLOW_INSECURE=1 for localhost-only unauthenticated dev.


Security model

  • Secrets in env only. Never committed, never passed as flags, never persisted. The self-hosted bearer token is cached in memory and re-fetched on 401.

  • Never logged or echoed. A redaction layer scrubs secrets by key and by literal value from every log line, error, and tool result. get_me and user/admin responses are sanitized of token/authKey/shareToken. stdio diagnostics go to stderr only (stdout is the JSON-RPC channel).

  • Remote endpoints are auth-gated and fail closed β€” constant-time bearer comparison; no MCP_AUTH_TOKEN β‡’ all requests rejected.

  • Least privilege by default β€” read-only unless you opt in; destructive operations double-gated and annotated.

  • No third-party credential collection. Run your own instance of this server. Never point credentials at someone else's hosted MCP endpoint.

See SECURITY.md for the full threat model and disclosure policy.


Tool reference

list_websites Β· get_website Β· get_website_daterange Β· get_active_visitors Β· get_realtime Β· get_stats Β· get_pageviews Β· get_metrics Β· get_website_values Β· get_events Β· get_event_data Β· list_sessions Β· get_session Β· get_session_activity Β· get_session_stats Β· get_session_properties Β· report_funnel Β· report_retention Β· report_journey Β· report_goals Β· report_attribution Β· report_revenue Β· report_utm Β· report_breakdown Β· list_reports Β· get_report Β· list_segments Β· get_segment Β· list_teams Β· get_team Β· get_team_members Β· get_me

create_website Β· update_website Β· manage_website_share Β· transfer_website Β· send_event Β· create_team Β· update_team Β· join_team Β· add_team_member Β· update_team_member Β· create_segment Β· update_segment Β· create_report Β· update_report

Destructive (also needs UMAMI_ALLOW_DESTRUCTIVE): delete_website Β· reset_website Β· delete_team Β· remove_team_member Β· delete_segment Β· delete_report

list_users Β· get_user Β· create_user Β· update_user Β· set_user_role

Destructive: delete_user

Every tool returns a concise text summary plus a typed structuredContent payload, and accepts flexible date ranges (range: "7d" | "today" | "this-month", or explicit startAt/endAt).


Prompts & resources

Prompts (server-side, teach correct tool-chaining): analytics_report, traffic_overview, top_pages, acquisition_channels, realtime_check, funnel_analysis, retention_analysis, audience_insights, compare_periods.

Resources: umami://websites, umami://website/{id}, umami://me (sanitized).


Development

npm install
npm run build        # tsup β†’ dist/{cli,http,server}.js
npm test             # vitest (58 tests)
npm run typecheck    # tsc --noEmit
npm run inspect      # MCP Inspector against the stdio CLI

Architecture: a single registerAll(server, ctx) core (src/server.ts) is shared by the stdio CLI (src/bin/cli.ts), the standalone HTTP server (src/http/server.ts), and the Vercel function (api/mcp.ts) β€” so the tool surface never drifts between local and hosted modes. See the design spec.

License

MIT Β© Mateusz Siatrak

Available Tools

32 tools
get_active_visitorsGet active visitorsA
Read-only

Current real-time active visitor count for a website (visitors in the last few minutes).

Inputs: websiteId (required). Returns: data, visitors, websiteId

get_event_dataExplore custom event-dataA
Read-only

Explore custom event properties. select chooses the view: 'events' (event names), 'fields' (all fields), 'properties' (property keys), 'values' (values for a property β€” pass propertyName), or 'stats' (counts). Optionally scope by eventName.

Inputs: select (required), websiteId (required), endAt, range, +3 more. Returns: data, select, websiteId

get_eventsGet event activityA
Read-only

Custom-event activity over time for a website, bucketed by unit. Returns a time series of event counts. For a ranked list of event names use get_metrics(type='event').

Inputs: websiteId (required), unit, endAt, range, +2 more. Returns: data, endAt, startAt, websiteId

get_meGet current accountA
Read-only

Return the authenticated account's profile: id, username, role, isAdmin, and teams. Credentials/tokens are stripped from the response.

Inputs: no named parameters. Returns: user, deployment

get_metricsGet metric breakdownC
Read-only

Top-N breakdown of a website by a single dimension (type) over a date range. Returns ranked { x: value, y: count } rows. Use type=event for custom-event counts. url is an alias for path.

Inputs: type (required), websiteId (required), os, tag, +17 more. Returns: data, type, count, websiteId

get_pageviewsGet pageviews time seriesB
Read-only

Pageviews and sessions over time, bucketed by unit. Returns { pageviews: [{x,y}], sessions: [{x,y}] } where x is the bucket timestamp and y the count.

Inputs: websiteId (required), os, tag, url, +16 more. Returns: endAt, startAt, sessions, pageviews, +1 more

get_realtimeGet realtime activityA
Read-only

Richer real-time snapshot for a website (recent events/sessions/series). Availability varies by Umami version; falls back gracefully.

Inputs: websiteId (required). Returns: data, websiteId

get_reportGet saved reportA
Read-only

Fetch a saved report's full definition (type, parameters) by ID.

Inputs: reportId (required). Returns: data

get_segmentGet segmentA
Read-only

Fetch a single segment/cohort definition by ID.

Inputs: segmentId (required), websiteId (required). Returns: data

get_sessionGet sessionA
Read-only

Fetch a single visitor session's details by session ID.

Inputs: sessionId (required), websiteId (required). Returns: data

get_session_activityGet session activityB
Read-only

Ordered pageview/event timeline for a single session (createdAt, urlPath, referrer, eventType, eventName) β€” effectively a data-level session replay.

Inputs: sessionId (required), websiteId (required), endAt, range, +1 more. Returns: data, count, sessionId

get_session_propertiesGet session propertiesA
Read-only

List the custom properties attached to a single session (set via identify calls).

Inputs: sessionId (required), websiteId (required). Returns: data, sessionId

get_session_statsGet session statsA
Read-only

Aggregate session totals over a date range: pageviews, visitors, visits, countries, events β€” a session-centric overview.

Inputs: websiteId (required), os, tag, url, +14 more. Returns: endAt, stats, startAt, websiteId

get_statsGet website statsA
Read-only

Aggregate metrics for a website over a date range: pageviews, visitors (unique sessions), visits, bounces (single-pageview sessions), and totaltime (seconds). Includes a previous-period comparison by default.

Inputs: websiteId (required), os, tag, url, +15 more. Returns: endAt, stats, startAt, websiteId

get_teamGet teamA
Read-only

Fetch a single team's metadata by ID.

Inputs: teamId (required). Returns: team

get_team_membersGet team membersA
Read-only

List members of a team and their roles (team-owner, team-manager, team-member, team-view-only).

Inputs: teamId (required), page, search, pageSize. Returns: data, count

get_websiteGet websiteA
Read-only

Fetch one website's metadata (name, domain, share settings, createdAt) by ID.

Inputs: websiteId (required). Returns: website

get_website_daterangeGet website data rangeA
Read-only

Return the earliest and latest timestamps for which a website has analytics data. Use this to choose a valid window before querying stats/metrics.

Inputs: websiteId (required). Returns: data

get_website_valuesGet distinct field valuesA
Read-only

List the distinct values seen for a column over a date range β€” useful to discover valid filter values (e.g. all browsers or countries) before filtering other queries.

Inputs: type (required), websiteId (required), endAt, range, +2 more. Returns: data, type, websiteId

list_reportsList saved reportsA
Read-only

List saved reports (funnels, goals, journeys, etc.), optionally scoped to a website.

Inputs: page, search, pageSize, websiteId. Returns: data, count

list_segmentsList segments & cohortsA
Read-only

List saved segments and cohorts defined for a website.

Inputs: websiteId (required), page, search, pageSize. Returns: data, count, websiteId

list_sessionsList sessionsB
Read-only

Paginated list of individual visitor sessions over a date range (id, browser, os, device, geo, screen, visits, views, firstAt/lastAt). Supports search + filters.

Inputs: websiteId (required), os, tag, url, +17 more. Returns: data, count, websiteId

list_teamsList teamsA
Read-only

List teams you belong to (id, name, role). Available on both Cloud and self-hosted.

Inputs: page, search, pageSize. Returns: data, count

list_websitesList websitesA
Read-only

List every website you can access (including team sites). CALL THIS FIRST β€” every other tool needs a website ID from here. Returns id, name, domain, createdAt.

Inputs: page, search, pageSize, includeTeams. Returns: data, count

report_attributionAttribution reportA
Read-only

Conversion attribution. model is first-click or last-click; type is the target dimension; step the target value.

Inputs: step (required), type (required), model (required), websiteId (required), +4 more. Returns: data

report_breakdownBreakdown reportC
Read-only

Multi-dimensional breakdown across one or more fields (e.g. ['country','browser']).

Inputs: fields (required), websiteId (required), os, tag, +15 more. Returns: data

report_funnelFunnel reportA
Read-only

Conversion funnel across an ordered list of steps. Each step is { type: 'path' | 'event', value }. window is the conversion window (hours).

Inputs: steps (required), websiteId (required), os, tag, +16 more. Returns: data

report_goalsGoals reportB
Read-only

Progress toward one or more goals. Each goal is { type: 'event' | 'path', value }. Computed per goal against Umami's /reports/goal endpoint.

Inputs: goals (required), websiteId (required), os, tag, +15 more. Returns: data

report_journeyUser journey reportA
Read-only

Most common navigation paths through the site, up to steps deep (2–7). Optionally pin a start or end step.

Inputs: websiteId (required), endAt, range, steps, +3 more. Returns: data

report_retentionRetention reportA
Read-only

Cohort retention over the selected period (how many users return on subsequent days).

Inputs: websiteId (required), endAt, range, startAt, +1 more. Returns: data

report_revenueRevenue reportA
Read-only

Revenue analytics over the period (requires revenue events configured in Umami). currency is required (e.g. USD).

Inputs: currency (required), websiteId (required), unit, endAt, +4 more. Returns: data

report_utmUTM reportC
Read-only

Breakdown of traffic by UTM parameters (source, medium, campaign, content, term).

Inputs: websiteId (required), os, tag, url, +14 more. Returns: data

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 32 tools

    Disambiguation4/5

    Most tools have distinct purposes, but the high number (32) and some similar-sounding names (e.g., get_events vs get_metrics for events, get_realtime vs get_active_visitors) may cause confusion. Descriptions are clear enough to differentiate, but an agent might misselect without careful reading.

    Naming Consistency5/5

    All tools follow a consistent verb_noun pattern in snake_case: get_*, list_*, report_*. This is a predictable and clear naming scheme that helps an agent quickly grasp the tool's action and subject.

    Tool Count3/5

    With 32 tools, the surface is heavy. While the analytics domain is broad and many tools serve distinct analytical needs, the count exceeds the 'heavy' threshold (16-25). Some tools could potentially be consolidated (e.g., report_* tools share similar structure).

    Completeness5/5

    The tool set covers the full analytics lifecycle: website and team metadata, time-series data, event tracking, session details, real-time, saved reports, segments, and various report types (funnels, goals, retention, etc.). It includes utility tools like get_website_daterange and get_website_values for validation. No obvious gaps for a read-only analytics server.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Read-only MCP server for Umami analytics. It talks to the Umami REST API directly over HTTP, supporting self-hosted and cloud setups.
      8
      8 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      MCP server for Umami Analytics that provides read-only tools to query website stats, events, sessions, reports, and more, enabling natural language analytics queries.
      25 npm
      3
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      A read-only MCP server for Umami analytics, enabling natural language queries of website stats, traffic trends, events, sessions, and analytics reports.
      13
      10 npm
      1
      Elastic 2.0