Skip to main content
Glama
getsentry

plausible-mcp

by getsentry

plausible-mcp

MCP-Server für Plausible Analytics – Traffic, Conversions abfragen und Zeiträume aus jedem KI-Tool vergleichen, das Model Context Protocol unterstützt.

Entwickelt für Teams, die Fragen stellen möchten wie:

  • „Hat unser Deploy am Dienstag den Traffic auf /pricing beeinflusst?“

  • „Wie hoch ist die Signup-Conversion-Rate auf /blog in diesem Monat?“

  • „Wie vergleicht sich die Absprungrate dieser Woche mit der letzten Woche?“

Tools

Tool

Beschreibung

get_timeseries

Traffic- und Conversion-Metriken über die Zeit (täglich/wöchentlich/monatlich)

get_breakdown

Aufschlüsselung nach Seite, Quelle, Land, Gerät, Browser, Betriebssystem, UTM-Parametern

get_conversions

Goal-Conversion-Raten, optional pro Seite

compare_periods

Seitenvergleich zweier Datumsbereiche mit absoluten und prozentualen Differenzen

Alle Abfragetools sind schreibgeschützt und mit readOnlyHint: true annotiert.

Gehostete Bereitstellungen bieten zusätzlich send_feedback, das Feedback über den Server selbst (verwirrende Fehler, fehlende Funktionen) in das Sentry User Feedback-Postfach der Maintainer einreicht. Es wird nur registriert, wenn der Server mit Sentry läuft (enableFeedbackTool).

Related MCP server: Yandex Metrica MCP

Schnellstart

Remote (Gehostet)

Eine gehostete Instanz ist verfügbar unter https://plausible-mcp.sentry.dev.

Mit Ihrem eigenen Plausible-API-Schlüssel (beliebiger Benutzer):

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

Behalten Sie die URL vor --header. --header ist variadisch. Wenn es also zuletzt kommt, verschluckt es die URL und die CLI schlägt fehl mit error: missing required argument 'commandOrUrl'.

Oder fügen Sie es manuell zu Ihrer MCP-Client-Konfiguration hinzu (Claude Desktop, Cursor usw.):

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

Sentry-Mitarbeiter (über OAuth 2.1 + Cloudflare Access):

Der /internal-Endpunkt ist ein OAuth-2.1-Server – kein API-Schlüssel erforderlich. Fügen Sie ihn als Remote-/benutzerdefinierten Connector in jedem OAuth-fähigen MCP-Client hinzu (Cowork, Claude.ai-Connectors, Claude Desktop):

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

Der Client erkennt die OAuth-Endpunkte automatisch, führt Sie durch Sentry-SSO (Cloudflare Access), und nur @sentry.io-Identitäten erhalten Zugriff. Abfragen laufen gegen einen gemeinsamen, serverseitigen Plausible-API-Schlüssel – Sie haben nie einen Schlüssel in der Hand.

Das gehostete /internal unter plausible-mcp.sentry.dev ist nur für Sentry und kann außerhalb der Organisation nicht verwendet werden. Um /internal für eine andere Organisation auszuführen, self-hosten und ALLOWED_EMAIL_DOMAIN auf Ihre eigene Domain setzen. (Der öffentliche /mcp-Endpunkt mit eigenem Schlüssel hat keine solche Einschränkung.)

Lokal (STDIO)

Wenn Sie es lieber lokal ausführen möchten, verwenden Sie Node.js 20 oder neuer:

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

Zu Claude Code hinzufügen:

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

Oder Claude Desktop (claude_desktop_config.json):

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

Self-Hosting (Cloudflare Workers)

Stellen Sie Ihre eigene Instanz bereit:

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

Der Worker stellt zwei Endpunkte bereit:

  • /mcp – Bring-your-own-key. Jeder Benutzer übergibt seinen eigenen Plausible-API-Schlüssel über den Authorization: Bearer-Header. Keine gemeinsamen Geheimnisse auf dem Server erforderlich. Funktioniert mit jedem header-fähigen MCP-Client (Claude Code, Cursor, MCP Inspector).

  • /internal – Zugriffsgeschützter MCP-Endpunkt für verwaltete Connectors (Cowork, Claude.ai). Eine Cloudflare-Access-Anwendung mit Managed OAuth liegt vor dem gesamten Worker-Hostnamen (siehe Einschränkung unten): Access führt den OAuth-2.1-Handshake mit dem Client durch und leitet jede Anfrage mit einem Cf-Access-Jwt-Assertion-Header an den Worker weiter. Der Worker verifiziert diesen Header und fragt einen gemeinsamen, serverseitigen Plausible-API-Schlüssel ab. Access ist auf die E-Mail-Domain(s) in ALLOWED_EMAIL_DOMAIN beschränkt (Standard: sentry.io) – nicht an Sentry gebunden, wenn Sie self-hosten; setzen Sie es auf Ihre eigene Domain.

Da die Managed-OAuth-Anwendung den nackten Hostnamen ohne Pfad abdecken muss (Cloudflare lehnt einen Pfad ab, wenn OAuth aktiviert ist – domain can not have a path if oauth is configured), schützt sie auch /mcp. Um den Bring-your-own-key-Endpunkt /mcp öffentlich zu halten, fügen Sie eine zweite, spezifischere Access-Anwendung hinzu, die auf den /mcp-Pfad mit einer Bypass-Richtlinie beschränkt ist. Cloudflare matcht zuerst den spezifischsten Hostnamen+Pfad, sodass /mcp-Anfragen Access vollständig umgehen, während alles andere durch OAuth läuft. Beide Apps leben auf einem Hostnamen; keine separate Subdomain erforderlich.

Beta / Client-Anforderung. Cloudflare Access Managed OAuth ist in der Beta und erfordert einen MCP-Client, der RFC 8707 unterstützt (Resource Indicators). Vergewissern Sie sich, dass Ihr Connector dies unterstützt, bevor Sie sich auf diesen Pfad verlassen.

Einrichten des /internal-Endpunkts (Cloudflare Access Managed OAuth)

Der Worker führt keinen OAuth-Server – Cloudflare Access ist der Autorisierungsserver. Es gibt kein OAUTH_KV, keinen Cookie-Schlüssel und keine OAuth-Client-ID/Secret. Sie erstellen zwei Access-Anwendungen auf demselben Hostnamen.

  1. Erstellen Sie die Managed-OAuth-Anwendung über den nackten Hostnamen (Zero Trust → Access → Applications): eine Self-hosted-App oder MCP-Server-Anwendung, deren Domain plausible-mcp.sentry.dev ohne Pfad ist.

    • ⚠️ Nicht auf /internal beschränken. Sobald Managed OAuth aktiviert ist, lehnt Cloudflare jeden Pfad mit access.api.error.invalid_request: domain can not have a path if oauth is configured ab. Die App muss den gesamten Host abdecken; der Worker erzwingt die /internal-Route selbst.

    • Fügen Sie eine Access-Richtlinie (Aktion Allow) hinzu, die auf Ihre E-Mail-Domain (z. B. @acme.com) und Ihren Identitätsanbieter beschränkt.

    • Aktivieren Sie Managed OAuth (Erweiterte Einstellungen → Managed OAuth) und setzen Sie Erlaubte Redirect-URIs auf den tatsächlichen Callback Ihres Connectors – für Claude/Cowork ist das https://claude.ai/api/mcp/auth_callback. Öffentliche HTTPS-Callbacks müssen aufgeführt sein, sonst schlägt die Dynamic Client Registration mit invalid_client_metadata: redirect_uri is not allowed by the account configuration fehl; Loopback (http://localhost:*)-Callbacks sind standardmäßig erlaubt.

    • Kopieren Sie das AUD-Tag der Anwendung → dies wird CF_ACCESS_AUD.

  2. Schneiden Sie /mcp mit einer zweiten, pfadbeschränkten Bypass-Anwendung wieder heraus. Da Schritt 1 den gesamten Host abdeckt, ist /mcp (Bring-your-own-key) jetzt ebenfalls geschützt. Erstellen Sie eine weitere Self-hosted-App, Domain plausible-mcp.sentry.dev Pfad mcp, mit Managed OAuth AUS, und einer Richtlinie, deren Aktion Bypass mit dem Selektor Everyone ist.

    • Bypass ≠ Allow: Eine Allow-Richtlinie erzwingt immer noch einen interaktiven Login (der Client erhält ein HTML-302 zur Login-Seite und schlägt fehl mit Unexpected content type: text/html). Nur Bypass lässt die Anfrage ohne Authentifizierung durch, sodass die eigene Bearer-Key-Prüfung des Workers greift.

  3. Setzen Sie die Worker-Secrets:

    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 und CF_ACCESS_AUD sind keine Secrets – eine öffentliche JWKS-URL und eine Anwendungskennung – also kommen sie in [vars] in Schritt 4.

  4. Setzen Sie die [vars] in wrangler.toml:

    • CF_ACCESS_TEAM_DOMAIN – https://<team>.cloudflareaccess.com, ohne abschließenden Schrägstrich. Verifiziert die Cf-Access-Jwt-Assertion-JWKS und den Aussteller.

    • CF_ACCESS_AUD – das AUD-Tag, das Sie in Schritt 1 kopiert haben.

    • ALLOWED_EMAIL_DOMAIN – die E-Mail-Domain(s), die sich anmelden dürfen, durch Kommas getrennt, @ optional (Standard sentry.io). Wird im Code zusätzlich zur Access-Richtlinie in Schritt 1 erzwungen, also setzen Sie es auf Ihre eigene Domain – sonst wird jeder Login abgelehnt.

    • MCP_ALLOWED_HOSTNAMES – durch Kommas getrennte Hostnamen, die von den MCP-Endpunkten akzeptiert werden. Ersetzen Sie plausible-mcp.sentry.dev durch den Hostnamen Ihres Workers; behalten Sie die localhost-Einträge bei, wenn Sie wrangler dev verwenden.

    • MCP_ALLOWED_ORIGIN_HOSTNAMES – durch Kommas getrennte Browser-Origin-Hostnamen, die /internal aufrufen dürfen. Nicht-Browser-Clients senden keinen Origin-Header.

  5. Bereitstellen (npx wrangler deploy), dann einen RFC-8707-fähigen MCP-Client auf https://<your-worker-host>/internal richten.

Fehlerbehebung. All dies sind Cloudflare-Access-Konfigurationen, nicht der Worker – eine Anfrage erreicht den Worker (und seine Sentry-Spans) erst, wenn Access sie weiterleitet:

Symptom (im Connector)

Ursache

Lösung

Couldn't register … / add an OAuth Client ID

Connector-Callback ist nicht in Erlaubte Redirect-URIs

Fügen Sie den genauen Callback hinzu (Schritt 1); lesen Sie die abgelehnte redirect_uri aus Zero Trust → Logs → Access

domain can not have a path if oauth is configured

Managed-OAuth-App auf einen Pfad beschränkt

App 1 auf den nackten Host umstellen (Schritt 1)

/mcp: Unexpected content type: text/html

/mcp-App-Richtlinie ist Allow, nicht Bypass

Setzen Sie die App-2-Richtlinienaktion auf Bypass (Schritt 2)

/mcp: OAuth 401 invalid_token

Keine /mcp-Bypass-App; die Ganz-Host-OAuth-App schützt sie

Erstellen Sie App 2 (Schritt 2)

Konfiguration

Umgebungsvariable

Erforderlich

Standard

Beschreibung

PLAUSIBLE_API_KEY

Ja (STDIO; Worker /internal)

—

Ihr Plausible-API-Schlüssel (hier erhalten). Auf dem Worker ist dies der gemeinsame Schlüssel für /internal; /mcp verwendet den eigenen Schlüssel jedes Benutzers über Bearer.

PLAUSIBLE_BASE_URL

Nein

https://plausible.io

URL Ihrer Plausible-Instanz (für selbst gehostete Installationen)

PLAUSIBLE_DEFAULT_SITE_ID

Nein

—

Standard-Site-Domain, sodass Sie nicht bei jedem Aufruf site_id übergeben müssen

CF_ACCESS_TEAM_DOMAIN

Ja (Worker /internal)

—

https://<team>.cloudflareaccess.com — verifiziert die Cf-Access-Jwt-Assertion JWKS + Issuer. Kein abschließender Schrägstrich.

CF_ACCESS_AUD

Ja (Worker /internal)

—

Das Application Audience (AUD)-Tag der Access-Anwendung — wird gegen das aud der Assertion geprüft.

SENTRY_DSN

Nein (Worker)

—

Sentry-DSN für die eigene Telemetrie des Workers (wrangler secret put SENTRY_DSN). Nicht gesetzt deaktiviert Sentry — verwenden Sie Ihr eigenes DSN, wenn Sie Telemetrie für eine selbst gehostete Bereitstellung wünschen.

ALLOWED_EMAIL_DOMAIN

Nein (Worker /internal)

sentry.io

Kommagetrennte E-Mail-Domain(s), die sich bei /internal anmelden dürfen. Setzen Sie dies bei Selbsthosting auf Ihre eigene Domain.

MCP_ALLOWED_HOSTNAMES

Ja (Worker)

—

Kommagetrennte Hostname-Allowlist zur Validierung der MCP-Host-Header.

MCP_ALLOWED_ORIGIN_HOSTNAMES

Nein (Worker /internal)

—

Kommagetrennte Browser-Origin-Hostnames, die /internal aufrufen dürfen. Ein vorhandener Origin wird abgelehnt, wenn die Liste leer ist.

Auf dem Worker benötigt der /mcp-Endpunkt keinen serverseitigen Schlüssel — jeder Benutzer übergibt seinen eigenen über Authorization: Bearer. Der /internal-Endpunkt wird durch Cloudflare Access Managed OAuth abgesichert und verwendet ein gemeinsames serverseitiges PLAUSIBLE_API_KEY-Geheimnis (siehe Selbsthosting).

Plausible-API

Dieser Server kapselt die Plausible Stats API v2 (POST /api/v2/query). Er funktioniert sowohl mit Plausible Cloud als auch mit selbst gehosteten Instanzen.

Unterstützte Metriken

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

Unterstützte Dimensionen

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

Die Geographie-Dimensionen *_name geben menschenlesbare Namen zurück (z. B. „Kanada"); die einfachen visit:country/region/city geben ISO-/Geoname-Codes zurück.

Filtern

Jedes Query-Tool akzeptiert property_filters, die — trotz des Namens — sowohl nach eingebauten Dimensionen als auch nach benutzerdefinierten Event-Eigenschaften filtern. Jeder Eintrag ist { "property", "operator", "values" }:

  • property — eine eingebaute Dimension (z. B. visit:channel, visit:source, event:page) oder eine benutzerdefinierte Eigenschaft mit ihrem bloßen Namen ("plan" zielt auf event:props:plan).

  • operator — is, is_not, contains, contains_not (Standard is). event:goal unterstützt nur is und contains.

  • Mehrere Einträge werden mit UND verknüpft, ebenso wie die Kurzparameter page/goal. Die gleichzeitige Verwendung von event:page/event:goal über einen Kurzparameter und property_filters im selben Aufruf wird abgelehnt — verwenden Sie entweder das eine oder das andere.

Beispiel: Top-Seiten für organischen Suchverkehr: get_breakdown mit dimension: "event:page" und property_filters: [{ "property": "visit:channel", "values": ["Organic Search"] }].

Benutzerdefinierte Eigenschaften

Sites senden ihre eigenen benutzerdefinierten Event-Eigenschaften, adressiert als event:props:<name>. Diese sind site-spezifisch, daher gibt es keine feste Liste.

  • Aufschlüsselung nach einer benutzerdefinierten Eigenschaft: Übergeben Sie get_breakdown eine dimension von event:props:<name> (z. B. event:props:plan).

  • Filtern nach einer benutzerdefinierten Eigenschaft über property_filters mit dem bloßen Namen, z. B. [{ "property": "plan", "operator": "is", "values": ["pro"] }].

Entwicklung

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

Testen mit MCP Inspector

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

LLM-Evals

Überprüft, ob das Modell das richtige Tool für natürlichsprachliche Analysefragen auswählt. Läuft über OpenRouter, sodass jedes Tool-Calling-Modell funktioniert — der Standard ist 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

Architektur

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 hat keine MCP-Abhängigkeit und kann eigenständig verwendet werden.

Beobachtbarkeit & Datenerfassung

Der Worker meldet an Sentry mit einer endpunktabhängigen Datenschutz-Haltung:

  • /mcp (Bring-your-own-key) — vollständig anonym. Tool-Eingaben und -Ausgaben werden nicht erfasst (diese Daten gehören dem Aufrufer und seinem eigenen Schlüssel), es wird keine Identität angehängt, und die vom Ingest abgeleitete Client-IP wird entfernt (src/redaction.ts). Es verbleibt nur operative Telemetrie: Tool-Namen, Span-Zeiten und Fehler.

  • /internal (SSO-geschützt) — attribuiert. Anfragen tragen die authentifizierte @sentry.io-E-Mail (Sentry.setUser), und Tool-Eingaben/-Ausgaben werden erfasst (recordToolIO) für Attribuierung und Missbrauchs-Nachverfolgung auf dem gemeinsamen serverseitigen Schlüssel.

Authorization- / Cookie- / Cf-Access-Jwt-Assertion-Header werden auf beiden Pfaden aus Spans entfernt. Als zusätzliche Absicherung aktivieren Sie Prevent Storing of IP Addresses in den Security & Privacy-Einstellungen des Sentry-Projekts.

Lizenz

MIT — siehe 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

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered. The description adds that the result contains aggregate values for each period plus absolute and percentage deltas, which is genuinely useful behavioral context beyond the annotations.

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, front-loaded with the core comparison purpose and ending with the return shape. Every sentence 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?

With a full schema, an output schema, and annotations present, the description only needs to convey purpose, usage context and return nature, all of which it does. Nothing essential for correct invocation is missing.

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% and the description adds no parameter-level detail (no date-format syntax, no metric defaults, no filter semantics). Baseline 3 is appropriate when the schema fully documents the seven parameters.

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?

States a specific verb and resource: 'Compare metrics between two date ranges side by side.' The comparison semantics clearly distinguish it from siblings like get_timeseries and get_breakdown, which retrieve rather than diff two periods.

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?

'Ideal for before/after deploy analysis' gives a concrete usage context that tells the agent when this tool is the right pick. It stops short of naming exclusions or the sibling tools to prefer for single-period retrieval, so it is clear context without routing rules.

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.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered. The description adds no behavioral context beyond that — nothing about result limits, default metric selection, ordering, or how entries are combined.

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 short sentences, front-loaded with the core action and followed by the use case. No filler, no repetition of the title.

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?

An output schema exists and all 7 parameters are fully described in the schema, so the description need not cover return values. It covers purpose and a use case adequately; only route-to-sibling guidance is absent.

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 coverage is 100%, so every parameter including dimension enums and format examples is already documented in the schema. The description's dimension examples (page, traffic source, country, device) loosely map to schema values but add no syntax or format detail beyond it. Baseline 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?

States a specific verb+resource (break down metrics by a dimension) and gives concrete example dimensions (page, traffic source, country, device) plus example goals (top pages, sources). It never names or contrasts its siblings (get_timeseries, get_conversions, compare_periods), so it stops short of a 5.

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?

'Use to find top pages, sources, or segment traffic' implies the use case but gives no when-not conditions and points to no alternative tool. An agent must infer that breakdown-by-dimension is the right choice over timeseries or comparison, which the description does not address.

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.5/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered and the bar is lower. The description adds only the page-breakdown capability and says nothing about result shape, pagination, or rate limits beyond what structured fields provide.

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

Conciseness4/5

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

Two short sentences, capability front-loaded with the optional breakdown as a secondary clause. No waste, though it is quite terse for a six-parameter analytics tool.

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?

With annotations, a full output schema, and 100% schema description coverage, the description only needs to convey the tool's scope, which it does. Minor gaps around filtering/segmentation guidance are acceptable given the rich structured fields.

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 six parameters (including goal, page, property_filters, breakdown_by_page) are already documented in the schema. The description adds no syntax or format detail beyond that, so baseline 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?

States a specific verb+resource: goal conversion rates and counts, plus a page-breakdown capability. It distinguishes itself reasonably from siblings like get_timeseries and get_breakdown by scoping to conversions, though it never names an alternative directly.

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?

Usage is only implied: use this when you need conversion metrics, optionally per page. There is no explicit when-to-use versus when-to-prefer get_breakdown or compare_periods, and no exclusions or prerequisites are stated.

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.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so safety and idempotency are covered. The description adds no behavioral context beyond that (no mention of pagination, granularity defaults, or result volume), and the output schema handles the return shape, so a baseline 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?

Two short sentences, front-loaded with the primary purpose and followed by the usage cue. No filler or redundancy.

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?

For a read-only timeseries tool with a full output schema and 100% parameter coverage, the description covers purpose and one use case adequately. It is slightly thin on when to prefer it over compare_periods or get_breakdown, which keeps it from a 5.

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% with rich inline docs for goal, page, metrics, date_range, granularity and property_filters. The description adds no parameter meaning beyond the schema, so the baseline 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?

States a specific verb and resource (get traffic/conversion metrics over time) plus the scope (site or specific page), which clearly separates it from get_breakdown and compare_periods. It does not explicitly name the sibling tools, so the differentiation is implied rather than stated.

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?

'Use to spot trends and changes around deploys' gives one concrete use case, implying time-series analysis rather than aggregation. But there is no when-not guidance and no routing to siblings like compare_periods for period-over-period analysis, so usage is only partially covered.

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.

  1. 4 tool updatesv0.9.0
    • Changedcompare_periods8 fields changed
      • removedOutput schema / properties / deltas / additionalProperties / properties / absolute / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / deltas / additionalProperties / properties / absolute / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / deltas / additionalProperties / properties / percent / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / deltas / additionalProperties / properties / percent / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / period_a / properties / metrics / additionalProperties / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / period_a / properties / metrics / additionalProperties / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / period_b / properties / metrics / additionalProperties / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / period_b / properties / metrics / additionalProperties / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_breakdown4 fields changed
      • removedOutput schema / properties / results / items / properties / dimensions / items / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "number"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / dimensions / items / type
        Added value: +[
        +  "string",
        +  "number"
        +]
      • removedOutput schema / properties / results / items / properties / metrics / items / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / metrics / items / type
        Added value: +[
        +  "number",
        +  "string",
        +  "null"
        +]
    • Changedget_conversions4 fields changed
      • removedOutput schema / properties / results / items / properties / dimensions / items / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "number"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / dimensions / items / type
        Added value: +[
        +  "string",
        +  "number"
        +]
      • removedOutput schema / properties / results / items / properties / metrics / items / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / metrics / items / type
        Added value: +[
        +  "number",
        +  "string",
        +  "null"
        +]
    • Changedget_timeseries4 fields changed
      • removedOutput schema / properties / results / items / properties / dimensions / items / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "number"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / dimensions / items / type
        Added value: +[
        +  "string",
        +  "number"
        +]
      • removedOutput schema / properties / results / items / properties / metrics / items / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / metrics / items / type
        Added value: +[
        +  "number",
        +  "string",
        +  "null"
        +]
  2. 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
  3. 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"
  4. 4 tool updatesv0.5.1
    • First observedcompare_periods
    • First observedget_breakdown
    • First observedget_conversions
    • First observedget_timeseries

TDQS

A3.7/5.0

Scored across 4 tools

Disambiguation4/5

The four tools have largely distinct purposes: time series trends, dimension breakdowns, goal conversions, and period comparisons. However, get_conversions can break down by page, which overlaps slightly with get_breakdown, though descriptions clarify the focus on goals.

Naming Consistency5/5

All tool names follow a clear verb_noun pattern in snake_case: get_timeseries, get_breakdown, get_conversions, compare_periods. Minor deviation in verb (get_ vs compare_) is appropriate and predictable.

Tool Count4/5

Four tools are well within the typical 3-15 range and each covers a distinct analytical need. It is slightly thin for a full analytics surface (e.g., no site listing or realtime), but not problematic for a focused metrics server.

Completeness3/5

Core analytical queries are covered, but there are notable gaps such as listing available sites, retrieving site metadata, or accessing realtime/current visitors. For a read-only analytics server, these omissions could force agents to work around missing context.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    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
    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
    390 npm
    4
    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
    22 npm
    MIT
  • F
    license
    B
    quality
    C
    maintenance
    A read-only stdio-based MCP server that provides tools to query Plausible Analytics data, including listing sites, fetching statistics with metrics/dimensions/filters, and getting realtime visitor counts.
    3
    -