Skip to main content
Glama
getsentry

plausible-mcp

by getsentry

plausible-mcp

MCP-сервер для Plausible Analytics — запрашивайте трафик, конверсии и сравнивайте временные периоды из любого ИИ-инструмента, поддерживающего Model Context Protocol.

Создан для команд, которые хотят задавать вопросы вроде:

  • «Повлиял ли наш деплой во вторник на трафик на /pricing?»

  • «Какой коэффициент конверсии в регистрацию на /blog в этом месяце?»

  • «Как показатель отказов на этой неделе соотносится с прошлой?»

Инструменты

Инструмент

Описание

get_timeseries

Метрики трафика и конверсий во времени (ежедневно/еженедельно/ежемесячно)

get_breakdown

Разбивка по странице, источнику, стране, устройству, браузеру, ОС, UTM-параметрам

get_conversions

Коэффициенты конверсии по целям, опционально по страницам

compare_periods

Сравнение двух диапазонов дат бок о бок с абсолютными и процентными дельтами

Все инструменты запросов только для чтения и аннотированы readOnlyHint: true.

Хостируемые развёртывания дополнительно предоставляют send_feedback, который отправляет отзывы о самом сервере (запутанные ошибки, отсутствующие возможности) в почтовый ящик Sentry User Feedback мейнтейнеров. Он регистрируется только тогда, когда сервер работает с Sentry (enableFeedbackTool).

Related MCP server: umami-mcp-server

Быстрый старт

Удалённо (хостинг)

Хостируемый экземпляр доступен по адресу https://plausible-mcp.sentry.dev.

С собственным ключом API Plausible (любой пользователь):

claude mcp add --transport http plausible https://plausible-mcp.sentry.dev/mcp --header "Authorization: Bearer YOUR_PLAUSIBLE_API_KEY"

Держите URL перед --header. --header вариадичен, поэтому если он идёт последним, он поглощает URL, и CLI завершается с ошибкой error: missing required argument 'commandOrUrl'.

Или добавьте вручную в конфигурацию вашего MCP-клиента (Claude Desktop, Cursor и т. д.):

{
  "mcpServers": {
    "plausible": {
      "url": "https://plausible-mcp.sentry.dev/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_PLAUSIBLE_API_KEY"
      }
    }
  }
}

Сотрудники Sentry (через OAuth 2.1 + Cloudflare Access):

Эндпоинт /internal — это сервер OAuth 2.1 — ключ API не нужен. Добавьте его как удалённый/пользовательский коннектор в любой MCP-клиент с поддержкой OAuth (Cowork, коннекторы Claude.ai, Claude Desktop):

https://plausible-mcp.sentry.dev/internal

Клиент автоматически обнаруживает эндпоинты OAuth, проводит вас через Sentry SSO (Cloudflare Access), и доступ предоставляется только идентичностям @sentry.io. Запросы выполняются с использованием общего серверного ключа API Plausible — вам никогда не нужно работать с ключом.

Хостируемый /internal на plausible-mcp.sentry.dev доступен только для Sentry и не может использоваться вне организации. Чтобы запустить /internal для другой организации, разверните самостоятельно и установите ALLOWED_EMAIL_DOMAIN на свой домен. (Публичный эндпоинт /mcp с собственным ключом не имеет таких ограничений.)

Локально (STDIO)

Если вы предпочитаете запускать локально, используйте Node.js 20 или новее:

git clone https://github.com/getsentry/plausible-mcp.git
cd plausible-mcp
pnpm install
pnpm build

Добавьте в Claude Code:

claude mcp add plausible -e PLAUSIBLE_API_KEY=your-key -- node /path/to/plausible-mcp/dist/index.js

Или в Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "plausible": {
      "command": "node",
      "args": ["/path/to/plausible-mcp/dist/index.js"],
      "env": {
        "PLAUSIBLE_API_KEY": "your-key"
      }
    }
  }
}

Самостоятельное развёртывание (Cloudflare Workers)

Разверните собственный экземпляр:

git clone https://github.com/getsentry/plausible-mcp.git
cd plausible-mcp
pnpm install
npx wrangler deploy

Worker предоставляет два эндпоинта:

  • /mcp — принесите свой ключ. Каждый пользователь передаёт свой собственный ключ API Plausible через заголовок Authorization: Bearer. На сервере не нужны общие секреты. Работает с любым MCP-клиентом, поддерживающим заголовки (Claude Code, Cursor, MCP Inspector).

  • /internal — защищённый Access MCP-эндпоинт для управляемых коннекторов (Cowork, Claude.ai). Приложение Cloudflare Access с Managed OAuth стоит перед всем хостом Worker (см. ограничение ниже): Access выполняет рукопожатие OAuth 2.1 с клиентом и пересылает каждый запрос Worker с заголовком Cf-Access-Jwt-Assertion. Worker проверяет этот заголовок и запрашивает общий серверный ключ API Plausible. Access ограничен доменом(ами) электронной почты из ALLOWED_EMAIL_DOMAIN (по умолчанию sentry.io) — не привязан к Sentry при самостоятельном развёртывании; установите свой домен.

Поскольку приложение Managed OAuth должно покрывать голый хост без пути (Cloudflare отклоняет путь, когда OAuth включён — domain can not have a path if oauth is configured), оно также закрывает /mcp. Чтобы оставить публичный эндпоинт /mcp с собственным ключом, вы добавляете второе, более специфичное приложение Access, ограниченное путём /mcp с политикой Bypass. Cloudflare сопоставляет наиболее специфичный хост+путь первым, поэтому запросы /mcp полностью обходят Access, а всё остальное проходит через OAuth. Оба приложения живут на одном хосте; отдельный поддомен не требуется.

Бета / требование к клиенту. Cloudflare Access Managed OAuth находится в бете и требует MCP-клиент, поддерживающий RFC 8707 (индикаторы ресурсов). Прежде чем полагаться на этот путь, убедитесь, что ваш коннектор его поддерживает.

Настройка эндпоинта /internal (Cloudflare Access Managed OAuth)

Worker не запускает OAuth-сервер — Cloudflare Access является сервером авторизации. Нет OAUTH_KV, нет ключа cookie и нет идентификатора/секрета OAuth-клиента. Вы создаёте два приложения Access на одном хосте.

  1. Создайте приложение Managed OAuth на голом хосте (Zero Trust → Access → Applications): самостоятельно размещённое приложение или приложение MCP-сервера, чей домен — plausible-mcp.sentry.dev без пути.

    • ⚠️ Не ограничивайте его /internal. Как только Managed OAuth включён, Cloudflare отклоняет любой путь с access.api.error.invalid_request: domain can not have a path if oauth is configured. Приложение должно охватывать весь хост; Worker сам обеспечивает маршрут /internal.

    • Добавьте политику Access (действие Allow), ограничивающую ваш домен электронной почты (например, @acme.com) и поставщика удостоверений.

    • Включите Managed OAuth (Advanced settings → Managed OAuth) и установите Allowed redirect URIs на фактический callback вашего коннектора — для Claude/Cowork это https://claude.ai/api/mcp/auth_callback. Публичные HTTPS-callback обязательно должны быть указаны, иначе Dynamic Client Registration завершится с ошибкой invalid_client_metadata: redirect_uri is not allowed by the account configuration; loopback (http://localhost:*) callback разрешены по умолчанию.

    • Скопируйте AUD-тег приложения → он станет CF_ACCESS_AUD.

  2. Выделите /mcp обратно с помощью второго приложения Bypass, ограниченного путём. Поскольку шаг 1 покрывает весь хост, /mcp (принесите свой ключ) теперь тоже закрыт. Создайте ещё одно самостоятельно размещённое приложение, домен plausible-mcp.sentry.dev путь mcp, с Managed OAuth OFF и политикой, чьё действие — Bypass с селектором Everyone.

    • BypassAllow: политика Allow всё равно принуждает к интерактивному входу (клиент получает HTML 302 на страницу входа и завершается с ошибкой Unexpected content type: text/html). Только Bypass пропускает запрос без аутентификации, поэтому применяется собственная проверка Bearer-ключа Worker.

  3. Установите секреты Worker:

    npx wrangler secret put PLAUSIBLE_API_KEY          # shared key for /internal queries
    npx wrangler secret put SENTRY_DSN                 # optional — the Worker's own telemetry

    CF_ACCESS_TEAM_DOMAIN и CF_ACCESS_AUDне секреты — публичный URL JWKS и идентификатор приложения — поэтому они помещаются в [vars] на шаге 4.

  4. Установите [vars] в wrangler.toml:

    • CF_ACCESS_TEAM_DOMAINhttps://<team>.cloudflareaccess.com, без завершающего слэша. Проверяет JWKS и издателя Cf-Access-Jwt-Assertion.

    • CF_ACCESS_AUD — AUD-тег, скопированный на шаге 1.

    • ALLOWED_EMAIL_DOMAIN — домен(ы) электронной почты, которым разрешён вход, через запятую, @ необязателен (по умолчанию sentry.io). Применяется в коде в дополнение к политике Access на шаге 1, поэтому установите свой домен — иначе каждый вход будет отклонён.

    • MCP_ALLOWED_HOSTNAMES — разделённые запятыми имена хостов, принимаемые MCP-эндпоинтами. Замените plausible-mcp.sentry.dev на хост вашего Worker; сохраните записи localhost, если используете wrangler dev.

    • MCP_ALLOWED_ORIGIN_HOSTNAMES — разделённые запятыми имена хостов браузерного Origin, которым разрешено вызывать /internal. Небраузерные клиенты не отправляют заголовок Origin.

  5. Разверните (npx wrangler deploy), затем укажите MCP-клиенту с поддержкой RFC 8707 на https://<your-worker-host>/internal.

Устранение неполадок. Всё это — конфигурация Cloudflare Access, а не Worker — запрос достигает Worker (и его Sentry-спанов) только после того, как Access перешлёт его:

Симптом (в коннекторе)

Причина

Исправление

Couldn't register … / add an OAuth Client ID

Callback коннектора отсутствует в Allowed redirect URIs

Добавьте точный callback (шаг 1); прочитайте отклонённый redirect_uri из Zero Trust → Logs → Access

domain can not have a path if oauth is configured

Приложение Managed OAuth ограничено путём

Переопределите область приложения 1 на голый хост (шаг 1)

/mcp: Unexpected content type: text/html

Политика приложения /mcpAllow, а не Bypass

Установите действие политики приложения 2 на Bypass (шаг 2)

/mcp: OAuth 401 invalid_token

Нет приложения bypass для /mcp; его закрывает OAuth-приложение всего хоста

Создайте приложение 2 (шаг 2)

Конфигурация

Переменная окружения

Обязательная

По умолчанию

Описание

PLAUSIBLE_API_KEY

Да (STDIO; Worker /internal)

Ваш API-ключ Plausible (получить здесь). На Worker это общий ключ для /internal; /mcp принимает собственный ключ каждого пользователя через Bearer.

PLAUSIBLE_BASE_URL

Нет

https://plausible.io

URL вашего экземпляра Plausible (для self-hosted)

PLAUSIBLE_DEFAULT_SITE_ID

Нет

Домен сайта по умолчанию, чтобы не передавать site_id при каждом вызове

CF_ACCESS_TEAM_DOMAIN

Да (Worker /internal)

https://<team>.cloudflareaccess.com — проверяет JWKS + издателя Cf-Access-Jwt-Assertion. Без завершающего слэша.

CF_ACCESS_AUD

Да (Worker /internal)

Тег Application Audience (AUD) приложения Access — проверяется по aud утверждения.

SENTRY_DSN

Нет (Worker)

Sentry DSN для собственной телеметрии Worker (wrangler secret put SENTRY_DSN). Если не задан, Sentry отключён — используйте свой DSN, если нужна телеметрия на self-hosted развёртывании.

ALLOWED_EMAIL_DOMAIN

Нет (Worker /internal)

sentry.io

Разрешённые домены email (через запятую) для входа в /internal. При self-hosting укажите свой домен.

MCP_ALLOWED_HOSTNAMES

Да (Worker)

Разрешённый список hostname (через запятую) для проверки заголовков MCP Host.

MCP_ALLOWED_ORIGIN_HOSTNAMES

Нет (Worker /internal)

Разрешённые hostname браузерного Origin (через запятую) для вызова /internal. При пустом списке присутствующий Origin отклоняется.

На Worker конечной точке /mcp не нужен серверный ключ — каждый пользователь передаёт свой через Authorization: Bearer. Конечная точка /internal защищена Cloudflare Access Managed OAuth и использует общий серверный секрет PLAUSIBLE_API_KEY (см. self-hosting).

Plausible API

Этот сервер оборачивает Plausible Stats API v2 (POST /api/v2/query). Он работает как с Plausible Cloud, так и с self-hosted экземплярами.

Поддерживаемые метрики

visitors, visits, pageviews, views_per_visit, bounce_rate, visit_duration, events, scroll_depth, percentage, conversion_rate, group_conversion_rate, average_revenue, total_revenue, time_on_page

Поддерживаемые измерения

event:page, event:goal, event:hostname, visit:entry_page, visit:exit_page, visit:source, visit:referrer, visit:channel, visit:utm_medium, visit:utm_source, visit:utm_campaign, visit:utm_content, visit:utm_term, visit:device, visit:browser, visit:browser_version, visit:os, visit:os_version, visit:country, visit:region, visit:city, visit:country_name, visit:region_name, visit:city_name

Географические измерения *_name возвращают человекочитаемые названия (например, «Канада»); обычные visit:country/region/city возвращают коды ISO/Geoname.

Фильтрация

Каждый инструмент запроса принимает property_filters, который — несмотря на название — фильтрует как по встроенным измерениям, так и по пользовательским свойствам событий. Каждая запись — { "property", "operator", "values" }:

  • property — встроенное измерение (например, visit:channel, visit:source, event:page) или пользовательское свойство по его имени без префикса ("plan" обращается к event:props:plan).

  • operatoris, is_not, contains, contains_not (по умолчанию is). event:goal поддерживает только is и contains.

  • Несколько записей объединяются по AND, как и параметры-сокращения page/goal. Обращение к event:page/event:goal одновременно через сокращение и property_filters в одном вызове отклоняется — используйте что-то одно.

Например, топ страниц по органическому поисковому трафику: get_breakdown с dimension: "event:page" и property_filters: [{ "property": "visit:channel", "values": ["Organic Search"] }].

Пользовательские свойства

Сайты отправляют свои пользовательские свойства событий, адресуемые как event:props:<name>. Они специфичны для сайта, поэтому фиксированного списка нет.

  • Разбивка по пользовательскому свойству: передайте get_breakdown dimension вида event:props:<name> (например, event:props:plan).

  • Фильтрация по пользовательскому свойству через property_filters с именем без префикса, например [{ "property": "plan", "operator": "is", "values": ["pro"] }].

Разработка

pnpm install
pnpm build         # TypeScript compilation
pnpm test          # Run unit + integration tests
pnpm test:watch    # Watch mode

Тестирование с MCP Inspector

pnpm build
PLAUSIBLE_API_KEY=your-key npx @modelcontextprotocol/inspector node dist/index.js

LLM-оценки

Проверяет, что модель выбирает правильный инструмент для вопросов по аналитике на естественном языке. Запускается через OpenRouter, поэтому подходит любая модель с поддержкой вызова инструментов — по умолчанию anthropic/claude-sonnet-5:

OPENROUTER_API_KEY=sk-or-... pnpm eval
OPENROUTER_MODEL=openai/gpt-5 OPENROUTER_API_KEY=sk-or-... pnpm eval  # try another model

Архитектура

src/
├── index.ts              # STDIO entry point (local use)
├── worker.ts             # Cloudflare Worker entry point (remote)
├── env.ts                # Worker environment bindings
├── cf-access.ts          # Verifies the Cloudflare Access assertion on /internal
├── server.ts             # Creates McpServer, registers all tools
├── plausible.ts          # PlausibleClient — standalone API client
├── schemas.ts            # Shared Zod schemas and filter helpers
├── errors.ts             # UserFacingError and tool-error reporting
├── telemetry.ts          # Pure classifiers — route, MCP request kind, client family
├── mcp-telemetry.ts      # Records MCP client info onto the active span
├── redaction.ts          # Strips PII from Sentry events on the BYOK path
└── tools/
    ├── get-timeseries.ts
    ├── get-breakdown.ts
    ├── get-conversions.ts
    ├── compare-periods.ts
    └── send-feedback.ts

PlausibleClient не имеет зависимостей от MCP и может использоваться автономно.

Наблюдаемость и сбор данных

Worker отправляет отчёты в Sentry с режимом конфиденциальности, зависящим от конечной точки:

  • /mcp (bring-your-own-key) — полностью анонимный. Входные и выходные данные инструментов не записываются (эти данные принадлежат вызывающему и его собственному ключу), личность не привязывается, а определённый при приёме IP клиента удаляется (src/redaction.ts). Остаётся только операционная телеметрия: имена инструментов, тайминги спанов и сбои.

  • /internal (за SSO) — атрибутированный. Запросы несут аутентифицированный email @sentry.io (Sentry.setUser), а входные/выходные данные инструментов записываются (recordToolIO) для атрибуции и отслеживания злоупотреблений на общем серверном ключе.

Заголовки Authorization / Cookie / Cf-Access-Jwt-Assertion удаляются из спанов на обоих путях. В качестве дополнительной страховки включите Prevent Storing of IP Addresses в настройках Security & Privacy проекта Sentry.

Лицензия

MIT — см. LICENSE.

Available Tools

4 tools
compare_periodsCompare PeriodsA
Read-onlyIdempotent

Compare metrics between two date ranges side by side. Ideal for before/after deploy analysis. Returns aggregate values for each period plus the delta (absolute and %).

ParametersJSON Schema
NameRequiredDescriptionDefault
goalNoFilter by goal name (e.g. Signup, Purchase)
pageNoFilter by page path. Exact match by default, use * as trailing wildcard (e.g. /blog*)
metricsNoMetrics to return. Defaults vary by tool.
site_idYesPlausible site domain (e.g. example.com). Required.
period_aYesFirst date range, e.g. "2024-01-01,2024-01-07" or "7d"
period_bYesSecond date range, e.g. "2024-01-08,2024-01-14" or "7d"
property_filtersNoFilter results by built-in dimensions or custom event properties, e.g. [{ "property": "visit:channel", "operator": "is", "values": ["Organic Search"] }] or [{ "property": "plan", "values": ["pro"] }]. Entries are combined with AND.

Output Schema

ParametersJSON Schema
NameRequiredDescription
deltasYesPer-metric change from period_a to period_b (absolute and percent)
period_aYes
period_bYes

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint, so the safety profile is covered structurally. The description adds useful behavioral context by specifying the return semantics ('aggregate values for each period plus the delta (absolute and %)'). It does not contradict the annotations, but it omits nuances like metric defaulting or how filters are combined, which the schema covers.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with zero filler. The core purpose is front-loaded, the use case follows, and the return format closes it. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter tool with 100% schema coverage, an output schema, and rich annotations, the description adequately conveys the essential scope, use case, and return format. However, it does not mention the optional filter (property_filters) or metric defaulting behavior, leaving the agent dependent on the schema for those details — reasonable, but slightly short of fully self-sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description reinforces the core parameters by mentioning 'two date ranges' (period_a/period_b) and 'metrics', and maps naturally to those fields. It adds little beyond the schema, which is acceptable given the schema's completeness.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Compare'), a specific resource ('metrics between two date ranges'), and the side-by-side comparison framing that distinguishes it from siblings (get_timeseries, get_breakdown, get_conversions). It also names the return shape (aggregate values plus delta), so an agent can identify this tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit use case ('Ideal for before/after deploy analysis') that helps an agent decide when to invoke it. However, it does not name the sibling tools or state when NOT to use it (e.g., for time-series trends or single-period breakdowns), leaving the differentiation to inference from tool names rather than explicit routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_breakdownGet BreakdownA
Read-onlyIdempotent

Break down metrics by a dimension: page, traffic source, country, device, etc. Use to find top pages, sources, or segment traffic.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoFilter by page path. Exact match by default, use * as trailing wildcard (e.g. /blog*)
limitNoMax results to return
metricsNoMetrics to return. Defaults vary by tool.
site_idYesPlausible site domain (e.g. example.com). Required.
dimensionYesDimension to group results by: a standard dimension (e.g. event:page, visit:source), or a custom event property as "event:props:<name>" (e.g. event:props:plan).
date_rangeYesDate range: "7d", "30d", "12mo", "month", "year", "all", or "YYYY-MM-DD,YYYY-MM-DD"
property_filtersNoFilter results by built-in dimensions or custom event properties, e.g. [{ "property": "visit:channel", "operator": "is", "values": ["Organic Search"] }] or [{ "property": "plan", "values": ["pro"] }]. Entries are combined with AND.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metricsYesMetric keys, in the order they appear in each row's `metrics` array
resultsYesOne row per dimension-value combination returned by Plausible
dimensionsYesDimension keys, in the order they appear in each row's `dimensions` array

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=true, covering the safety and repeatability profile. The description adds no behavioral details (e.g., pagination, limits, or mutation effects). Since annotations cover safety, the bar is lower, but the description contributes no extra behavioral context beyond the generic 'break down' phrasing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero waste. The core action is front-loaded ('Break down metrics by a dimension'), followed by a practical usage note. Every element earns its place; no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having 7 parameters, all are described in the schema, and an output schema exists (as per context signals). The description provides enough context for an agent to know when to call this tool, relying on the schema for parameter details and the output schema for return structure. It could mention limits or filters, but those are already in the schema. The description is adequate for this complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all 7 parameters have detailed descriptions in the schema. The tool description mentions 'dimension' generically and the purpose, but doesn't add any parameter-specific information beyond the schema. With high schema coverage, the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb and resource: 'Break down metrics by a dimension' and lists example dimensions (page, source, country). It conveys the purpose without tautology. While it doesn't explicitly differentiate from siblings like get_timeseries or get_conversions, the concept of dimension-based grouping is distinct enough for an agent to infer usage.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context: 'Use to find top pages, sources, or segment traffic.' It tells the agent when to apply the tool, but doesn't explicitly state when not to use it or name alternative tools. This matches the 'clear context, no exclusions' tier.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_conversionsGet ConversionsA
Read-onlyIdempotent

Get goal conversion rates and counts. Can break down by page to see which pages drive conversions.

ParametersJSON Schema
NameRequiredDescriptionDefault
goalNoFilter by goal name (e.g. Signup, Purchase)
pageNoFilter by page path. Exact match by default, use * as trailing wildcard (e.g. /blog*)
site_idYesPlausible site domain (e.g. example.com). Required.
date_rangeYesDate range: "7d", "30d", "12mo", "month", "year", "all", or "YYYY-MM-DD,YYYY-MM-DD"
property_filtersNoFilter results by built-in dimensions or custom event properties, e.g. [{ "property": "visit:channel", "operator": "is", "values": ["Organic Search"] }] or [{ "property": "plan", "values": ["pro"] }]. Entries are combined with AND.
breakdown_by_pageNoIf true, shows conversion rate per page

Output Schema

ParametersJSON Schema
NameRequiredDescription
metricsYesMetric keys, in the order they appear in each row's `metrics` array
resultsYesOne row per dimension-value combination returned by Plausible
dimensionsYesDimension keys, in the order they appear in each row's `dimensions` array

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=true, covering the safety profile. The description adds the functional behavior of page-level breakdown, but does not disclose any additional behavioral traits such as rate limits, data freshness, or pagination. Since annotations cover the core safety aspects, a 3 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences with no redundant content. The primary purpose is stated first, followed by a single distinguishing capability. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the existence of an output schema (not shown) that presumably describes return values, the description does not need to explain response format. The description covers the core functionality and the key optional breakdown feature. For a tool with 6 parameters but only 2 required, this is sufficient; the schema fills in the parameter details, and the annotations cover safety.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all parameters including 'breakdown_by_page', 'goal', and 'page' are documented in the schema. The description's mention of 'can break down by page' adds a slight contextual hint but largely repeats what the schema already provides. Thus, the added value over the schema is minimal, warranting the baseline 3.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Get') and resource ('goal conversion rates and counts'), and adds the distinguishing capability 'Can break down by page to see which pages drive conversions.' This clearly separates it from sibling tools like get_timeseries or get_breakdown, which focus on different aggregations or dimensions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no explicit guidance on when to use this tool versus the sibling tools (get_timeseries, get_breakdown, compare_periods). It does not mention alternatives or exclude specific use cases, leaving the agent to infer usage from the schema and context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_timeseriesGet TimeseriesA
Read-onlyIdempotent

Get traffic and conversion metrics over time for a site or specific page. Use to spot trends and changes around deploys.

ParametersJSON Schema
NameRequiredDescriptionDefault
goalNoFilter by goal name (e.g. Signup, Purchase)
pageNoFilter by page path. Exact match by default, use * as trailing wildcard (e.g. /blog*)
metricsNoMetrics to return. Defaults vary by tool.
site_idYesPlausible site domain (e.g. example.com). Required.
date_rangeYesDate range: "7d", "30d", "12mo", "month", "year", "all", or "YYYY-MM-DD,YYYY-MM-DD"
granularityNoTime bucket sizeday
property_filtersNoFilter results by built-in dimensions or custom event properties, e.g. [{ "property": "visit:channel", "operator": "is", "values": ["Organic Search"] }] or [{ "property": "plan", "values": ["pro"] }]. Entries are combined with AND.

Output Schema

ParametersJSON Schema
NameRequiredDescription
metricsYesMetric keys, in the order they appear in each row's `metrics` array
resultsYesOne row per dimension-value combination returned by Plausible
dimensionsYesDimension keys, in the order they appear in each row's `dimensions` array

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, and idempotentHint=true, covering the tool's safety and repeatability. The description adds the scope of 'for a site or specific page' and the purpose of spotting trends, which is contextually useful but does not disclose additional behavioral details like aggregation behavior, output formatting, or rate limits. Since annotations cover the core profile, a neutral score of 3 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the primary action and followed by a specific intended use case. There is zero waste; each sentence earns its place. It is concise and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (7 parameters) but fully documented schema and an output schema (indicated by context signals), the description is sufficient. It clearly states what the tool returns (metrics over time) and a typical use case. No critical missing information prevents an agent from invoking it correctly, though it could mention that it can be filtered by page or custom properties, but that is already in the schema. Overall, it is complete enough for this read‑only analytics tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% — every parameter (site_id, date_range, goals, page, metrics, granularity, property_filters) is described in the input schema with types, defaults, and examples. The description adds no extra parameter information, so it does not exceed the baseline of 3. It neither clarifies nor complicates the parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Get traffic and conversion metrics over time for a site or specific page.' It identifies the resource (metrics) and the temporal context, making its purpose unambiguous. However, it does not explicitly distinguish itself from sibling tools like get_breakdown or compare_periods, though the 'over time' phrasing implies a time-series focus. This is clear but not fully differentiated from alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a concrete use case: 'Use to spot trends and changes around deploys.' This gives clear context for when the tool is appropriate. It does not, however, mention when not to use it or point to alternative tools for other scenarios, so it lacks explicit exclusions that would earn a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 4 tool updatesv0.7.2
    • Changedcompare_periods1 field changed
      • addedInput schema / properties / property_filters / items / properties / values / items / maxLength
        Added value: +1024
    • Changedget_breakdown1 field changed
      • addedInput schema / properties / property_filters / items / properties / values / items / maxLength
        Added value: +1024
    • Changedget_conversions1 field changed
      • addedInput schema / properties / property_filters / items / properties / values / items / maxLength
        Added value: +1024
    • Changedget_timeseries1 field changed
      • addedInput schema / properties / property_filters / items / properties / values / items / maxLength
        Added value: +1024
  2. 4 tool updatesv0.7.1
    • Changedcompare_periods5 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / properties / property_filters
        Added value: +{
        +  "description": "Filter results by built-in dimensions or custom event properties, e.g. [{ \"property\": \"visit:channel\", \"operator\": \"is\", \"values\": [\"Organic Search\"] }] or [{ \"property\": \"plan\", \"values\": [\"pro\"] }]. Entries are combined with AND.",
        +  "items": {
        +    "properties": {
        +      "operator": {
        +        "default": "is",
        +        "description": "Match operator: is, is_not, contains, contains_not (default: is)",
        +        "enum": [
        +          "is",
        +          "is_not",
        +          "contains",
        +          "contains_not"
        +        ],
        +        "type": "string"
        +      },
        +      "property": {
        +        "description": "What to filter on: a built-in dimension (e.g. \"visit:channel\", \"visit:source\", \"event:page\") or a custom event property as its bare name (e.g. \"plan\" targets event:props:plan)",
        +        "maxLength": 312,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "values": {
        +        "description": "One or more values to match the property against",
        +        "items": {
        +          "type": "string"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "property",
        +      "values"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / site_id / description
        Previous value: -"Plausible site domain (e.g. example.com). Uses PLAUSIBLE_DEFAULT_SITE_ID if omitted."New value: +"Plausible site domain (e.g. example.com). Required."
      • changedInput schema / required
        Previous value: -[
        -  "period_a",
        -  "period_b"
        -]New value: +[
        +  "site_id",
        +  "period_a",
        +  "period_b"
        +]
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedget_breakdown9 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / properties / dimension / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "event:page",
        +      "event:goal",
        +      "event:hostname",
        +      "visit:entry_page",
        +      "visit:exit_page",
        +      "visit:source",
        +      "visit:referrer",
        +      "visit:channel",
        +      "visit:utm_medium",
        +      "visit:utm_source",
        +      "visit:utm_campaign",
        +      "visit:utm_content",
        +      "visit:utm_term",
        +      "visit:device",
        +      "visit:browser",
        +      "visit:browser_version",
        +      "visit:os",
        +      "visit:os_version",
        +      "visit:country",
        +      "visit:region",
        +      "visit:city",
        +      "visit:country_name",
        +      "visit:region_name",
        +      "visit:city_name"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "maxLength": 312,
        +    "minLength": 13,
        +    "pattern": "^event:props:",
        +    "type": "string"
        +  }
        +]
      • changedInput schema / properties / dimension / description
        Previous value: -"Dimension to group results by"New value: +"Dimension to group results by: a standard dimension (e.g. event:page, visit:source), or a custom event property as \"event:props:<name>\" (e.g. event:props:plan)."
      • removedInput schema / properties / dimension / enum
        Removed value: -[
        -  "event:page",
        -  "event:goal",
        -  "event:hostname",
        -  "visit:entry_page",
        -  "visit:exit_page",
        -  "visit:source",
        -  "visit:referrer",
        -  "visit:channel",
        -  "visit:utm_medium",
        -  "visit:utm_source",
        -  "visit:utm_campaign",
        -  "visit:utm_content",
        -  "visit:utm_term",
        -  "visit:device",
        -  "visit:browser",
        -  "visit:browser_version",
        -  "visit:os",
        -  "visit:os_version",
        -  "visit:country",
        -  "visit:region",
        -  "visit:city",
        -  "visit:country_name",
        -  "visit:region_name",
        -  "visit:city_name"
        -]
      • removedInput schema / properties / dimension / type
        Removed value: -"string"
      • addedInput schema / properties / property_filters
        Added value: +{
        +  "description": "Filter results by built-in dimensions or custom event properties, e.g. [{ \"property\": \"visit:channel\", \"operator\": \"is\", \"values\": [\"Organic Search\"] }] or [{ \"property\": \"plan\", \"values\": [\"pro\"] }]. Entries are combined with AND.",
        +  "items": {
        +    "properties": {
        +      "operator": {
        +        "default": "is",
        +        "description": "Match operator: is, is_not, contains, contains_not (default: is)",
        +        "enum": [
        +          "is",
        +          "is_not",
        +          "contains",
        +          "contains_not"
        +        ],
        +        "type": "string"
        +      },
        +      "property": {
        +        "description": "What to filter on: a built-in dimension (e.g. \"visit:channel\", \"visit:source\", \"event:page\") or a custom event property as its bare name (e.g. \"plan\" targets event:props:plan)",
        +        "maxLength": 312,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "values": {
        +        "description": "One or more values to match the property against",
        +        "items": {
        +          "type": "string"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "property",
        +      "values"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / site_id / description
        Previous value: -"Plausible site domain (e.g. example.com). Uses PLAUSIBLE_DEFAULT_SITE_ID if omitted."New value: +"Plausible site domain (e.g. example.com). Required."
      • changedInput schema / required
        Previous value: -[
        -  "date_range",
        -  "dimension"
        -]New value: +[
        +  "site_id",
        +  "date_range",
        +  "dimension"
        +]
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedget_conversions5 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / properties / property_filters
        Added value: +{
        +  "description": "Filter results by built-in dimensions or custom event properties, e.g. [{ \"property\": \"visit:channel\", \"operator\": \"is\", \"values\": [\"Organic Search\"] }] or [{ \"property\": \"plan\", \"values\": [\"pro\"] }]. Entries are combined with AND.",
        +  "items": {
        +    "properties": {
        +      "operator": {
        +        "default": "is",
        +        "description": "Match operator: is, is_not, contains, contains_not (default: is)",
        +        "enum": [
        +          "is",
        +          "is_not",
        +          "contains",
        +          "contains_not"
        +        ],
        +        "type": "string"
        +      },
        +      "property": {
        +        "description": "What to filter on: a built-in dimension (e.g. \"visit:channel\", \"visit:source\", \"event:page\") or a custom event property as its bare name (e.g. \"plan\" targets event:props:plan)",
        +        "maxLength": 312,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "values": {
        +        "description": "One or more values to match the property against",
        +        "items": {
        +          "type": "string"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "property",
        +      "values"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / site_id / description
        Previous value: -"Plausible site domain (e.g. example.com). Uses PLAUSIBLE_DEFAULT_SITE_ID if omitted."New value: +"Plausible site domain (e.g. example.com). Required."
      • changedInput schema / required
        Previous value: -[
        -  "date_range"
        -]New value: +[
        +  "site_id",
        +  "date_range"
        +]
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedget_timeseries5 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / properties / property_filters
        Added value: +{
        +  "description": "Filter results by built-in dimensions or custom event properties, e.g. [{ \"property\": \"visit:channel\", \"operator\": \"is\", \"values\": [\"Organic Search\"] }] or [{ \"property\": \"plan\", \"values\": [\"pro\"] }]. Entries are combined with AND.",
        +  "items": {
        +    "properties": {
        +      "operator": {
        +        "default": "is",
        +        "description": "Match operator: is, is_not, contains, contains_not (default: is)",
        +        "enum": [
        +          "is",
        +          "is_not",
        +          "contains",
        +          "contains_not"
        +        ],
        +        "type": "string"
        +      },
        +      "property": {
        +        "description": "What to filter on: a built-in dimension (e.g. \"visit:channel\", \"visit:source\", \"event:page\") or a custom event property as its bare name (e.g. \"plan\" targets event:props:plan)",
        +        "maxLength": 312,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "values": {
        +        "description": "One or more values to match the property against",
        +        "items": {
        +          "type": "string"
        +        },
        +        "minItems": 1,
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "property",
        +      "values"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / site_id / description
        Previous value: -"Plausible site domain (e.g. example.com). Uses PLAUSIBLE_DEFAULT_SITE_ID if omitted."New value: +"Plausible site domain (e.g. example.com). Required."
      • changedInput schema / required
        Previous value: -[
        -  "date_range"
        -]New value: +[
        +  "site_id",
        +  "date_range"
        +]
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
  3. 4 tool updatesv0.5.1
    • First observedcompare_periods
    • First observedget_breakdown
    • First observedget_conversions
    • First observedget_timeseries

TDQS

A4.1/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: timeseries, breakdown by dimensions, conversions, and period comparison. There is no overlap or ambiguity about which tool to use for a given analytics query.

Naming Consistency5/5

All tools follow a consistent verb_noun pattern, with 'get_' prefix for three tools and 'compare_' for the fourth, both using an action verb followed by a descriptive noun. This makes the tool surface predictable and easy to navigate.

Tool Count5/5

With 4 tools, the server is well-scoped for an analytics metrics use case. It covers the primary needs without being bloated or sparse, fitting the typical 3-15 tool range.

Completeness5/5

The tool set covers time-series analysis, dimensional breakdowns, conversion tracking, and period-to-period comparisons, which together handle the core analytics workflows. There are no obvious dead ends or missing operations for the stated purpose.

Maintenance

ActivityActive
ResponsivenessWithin a week

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    MCP server that provides read access to Plausible Analytics data with natural-language date resolution, enabling users to query analytics like 'yesterday' or 'last week' without needing to know exact date formats.
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    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.
    30
    3
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for Yandex Metrica analytics: query web analytics metrics, goals, conversions, and raw API data using natural language from AI clients like Claude and Cursor.
    8
    113
    1
    MIT
  • A
    license
    B
    quality
    F
    maintenance
    MCP server for Plausible Analytics, enabling querying of traffic, conversions, sources, and device breakdowns from any MCP-compatible AI assistant.
    12
    53
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/getsentry/plausible-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server