Skip to main content
Glama
getsentry

plausible-mcp

by getsentry

plausible-mcp

Plausible Analytics용 MCP 서버 — Model Context Protocol을 지원하는 모든 AI 도구에서 트래픽, 전환, 기간 비교를 조회할 수 있습니다.

다음과 같은 질문을 던지고 싶은 팀을 위해 만들어졌습니다:

  • "화요일 배포가 /pricing 트래픽에 영향을 줬나요?"

  • "이번 달 /blog의 가입 전환율은 얼마인가요?"

  • "이번 주 이탈률은 지난주와 어떻게 비교되나요?"

도구

도구

설명

get_timeseries

시간에 따른 트래픽 및 전환 지표 (일별/주별/월별)

get_breakdown

페이지, 소스, 국가, 기기, 브라우저, OS, UTM 매개변수별 세분화

get_conversions

목표 전환율, 선택적으로 페이지별

compare_periods

두 날짜 범위의 나란히 비교, 절대값 및 % 변화량 포함

모든 쿼리 도구는 읽기 전용이며 readOnlyHint: true로 주석 처리되어 있습니다.

호스팅 배포에서는 추가로 send_feedback를 노출하는데, 이는 서버 자체에 대한 피드백(혼란스러운 오류, 누락된 기능)을 관리자의 Sentry User Feedback 받은 편지함으로 제출합니다. 이 도구는 서버가 Sentry로 실행될 때만 등록됩니다 (enableFeedbackTool).

Related MCP server: Yandex Metrica MCP

빠른 시작

원격 (호스팅)

호스팅 인스턴스는 https://plausible-mcp.sentry.dev 에서 사용할 수 있습니다.

자체 Plausible API 키 사용 (모든 사용자):

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 키가 필요 없습니다. OAuth 지원 MCP 클라이언트(Cowork, Claude.ai 커넥터, Claude Desktop)에서 원격/사용자 지정 커넥터로 추가하세요:

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

클라이언트는 OAuth 엔드포인트를 자동으로 발견하고, Sentry SSO(Cloudflare Access)를 통해 인증하며, @sentry.io ID만 액세스 권한을 부여받습니다. 쿼리는 공유된 서버 측 Plausible API 키로 실행됩니다 — 키를 직접 다룰 필요가 없습니다.

호스팅 /internal (plausible-mcp.sentry.dev)은 Sentry 전용이며 조직 외부에서는 사용할 수 없습니다. 다른 조직에서 /internal을 실행하려면 자체 호스팅하고 ALLOWED_EMAIL_DOMAIN을 자신의 도메인으로 설정하세요. (공개 /mcp bring-your-own-key 엔드포인트에는 그러한 제한이 없습니다.)

로컬 (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

워커는 두 개의 엔드포인트를 노출합니다:

  • /mcp — bring-your-own-key. 각 사용자는 Authorization: Bearer 헤더를 통해 자신의 Plausible API 키를 전달합니다. 서버에 공유 비밀이 필요 없습니다. 헤더를 지원하는 모든 MCP 클라이언트(Claude Code, Cursor, MCP Inspector)에서 작동합니다.

  • /internal — 관리형 커넥터(Cowork, Claude.ai)용 Access 보호 MCP 엔드포인트. Managed OAuth가 있는 Cloudflare Access 애플리케이션이 전체 Worker 호스트 이름을 앞에서 보호합니다(아래 제약 참조): Access는 클라이언트와 OAuth 2.1 핸드셰이크를 수행하고 각 요청을 Cf-Access-Jwt-Assertion 헤더와 함께 Worker에 전달합니다. Worker는 해당 헤더를 확인하고 공유된 서버 측 Plausible API 키로 쿼리합니다. Access는 ALLOWED_EMAIL_DOMAIN의 이메일 도메인(기본값 sentry.io)으로 제한됩니다 — 자체 호스팅 시 Sentry와 관련이 없습니다; 자신의 도메인으로 설정하세요.

Managed OAuth 애플리케이션이 경로 없는 베어 호스트 이름을 덮어야 하므로(Cloudflare는 OAuth가 활성화된 경우 경로를 거부합니다 — domain can not have a path if oauth is configured), /mcp도 함께 보호됩니다. bring-your-own-key /mcp 엔드포인트를 공개로 유지하려면 /mcp 경로에 Bypass 정책이 있는 두 번째, 더 구체적인 Access 애플리케이션을 추가하세요. Cloudflare는 가장 구체적인 호스트 이름+경로를 먼저 매칭하므로 /mcp 요청은 Access를 완전히 우회하고 나머지는 모두 OAuth를 통과합니다. 두 앱 모두 하나의 호스트 이름에 있습니다. 별도의 하위 도메인이 필요하지 않습니다.

베타 / 클라이언트 요구 사항. Cloudflare Access Managed OAuth는 베타이며 **RFC 8707](https://datatracker.ietf.org/doc/html/rfc8707)(리소스 표시자)을 지원하는 MCP 클라이언트가 필요합니다. 이 경로에 의존하기 전에 커넥터가 이를 지원하는지 확인하세요.

/internal 엔드포인트 설정 (Cloudflare Access Managed OAuth)

Worker는 OAuth 서버를 실행하지 않습니다 — Cloudflare Access가 권한 부여 서버입니다. OAUTH_KV, 쿠키 키, OAuth 클라이언트 ID/비밀번호가 없습니다. 동일한 호스트 이름에 두 개의 Access 애플리케이션을 만듭니다.

  1. 베어 호스트 이름에 Managed OAuth 애플리케이션 생성 (Zero Trust → Access → Applications): 도메인이 plausible-mcp.sentry.dev이고 경로가 없는 자체 호스팅 앱 또는 MCP 서버 애플리케이션을 만듭니다.

    • ⚠️ /internal로 범위를 지정하지 마세요. Managed OAuth가 활성화되면 Cloudflare는 access.api.error.invalid_request: domain can not have a path if oauth is configured 오류로 모든 경로를 거부합니다. 앱은 전체 호스트여야 합니다. Worker가 /internal 경로를 자체적으로 강제합니다.

    • 이메일 도메인(예: @acme.com)과 ID 공급자로 제한하는 Access 정책(작업 Allow)을 추가하세요.

    • Managed OAuth 활성화 (고급 설정 → Managed OAuth) 및 허용된 리디렉션 URI를 커넥터의 실제 콜백으로 설정 — Claude/Cowork의 경우 https://claude.ai/api/mcp/auth_callback입니다. 공개 HTTPS 콜백은 반드시 나열되어야 합니다. 그렇지 않으면 Dynamic Client Registration이 invalid_client_metadata: redirect_uri is not allowed by the account configuration 오류로 실패합니다. 루프백(http://localhost:*) 콜백은 기본적으로 허용됩니다.

    • 애플리케이션의 AUD 태그를 복사 → 이것이 CF_ACCESS_AUD가 됩니다.

  2. 두 번째, 경로 범위의 Bypass 애플리케이션으로 /mcp를 다시 분리합니다. 1단계가 전체 호스트를 덮으므로 /mcp(bring-your-own-key)도 이제 보호됩니다. 도메인 plausible-mcp.sentry.dev 경로 mcp, Managed OAuth OFF, 선택기 Everyone 이 있는 작업이 Bypass 인 정책을 가진 또 다른 자체 호스팅 앱을 만듭니다.

    • Bypass ≠ Allow: Allow 정책은 여전히 대화형 로그인을 강제합니다(클라이언트는 로그인 페이지로 HTML 302를 받고 Unexpected content type: text/html 오류로 실패합니다). Bypass만 인증 없이 요청을 통과시키므로 Worker 자체의 Bearer 키 검사가 적용됩니다.

  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는 비밀이 아닙니다 — 공개 JWKS URL과 애플리케이션 식별자이므로 4단계의 [vars]에 넣습니다.

  4. wrangler.toml에 [vars] 설정:

    • CF_ACCESS_TEAM_DOMAIN — https://<team>.cloudflareaccess.com, 끝에 슬래시 없음. Cf-Access-Jwt-Assertion JWKS 및 발급자를 확인합니다.

    • CF_ACCESS_AUD — 1단계에서 복사한 AUD 태그.

    • ALLOWED_EMAIL_DOMAIN — 로그인 허용 이메일 도메인(쉼표로 구분, @ 선택 사항, 기본값 sentry.io). 1단계의 Access 정책 외에도 코드에서 강제되므로 자신의 도메인으로 설정하세요. 그렇지 않으면 모든 로그인이 거부됩니다.

    • MCP_ALLOWED_HOSTNAMES — MCP 엔드포인트가 허용하는 호스트 이름(쉼표로 구분). plausible-mcp.sentry.dev를 Worker의 호스트 이름으로 바꾸세요. wrangler dev를 사용하는 경우 localhost 항목을 유지하세요.

    • MCP_ALLOWED_ORIGIN_HOSTNAMES — /internal을 호출할 수 있는 브라우저 Origin 호스트 이름(쉼표로 구분). 비브라우저 클라이언트는 Origin 헤더를 보내지 않습니다.

  5. 배포 (npx wrangler deploy) 후 RFC 8707 지원 MCP 클라이언트를 https://<your-worker-host>/internal로 지정하세요.

문제 해결. 다음은 모두 Cloudflare Access 구성 문제이지 Worker 문제가 아닙니다 — 요청은 Access가 전달한 후에만 Worker(및 해당 Sentry 스팬)에 도달합니다:

커넥터의 증상

원인

해결 방법

Couldn't register … / add an OAuth Client ID

커넥터 콜백이 허용된 리디렉션 URI에 없음

정확한 콜백 추가(1단계); Zero Trust → Logs → Access에서 거부된 redirect_uri 읽기

domain can not have a path if oauth is configured

Managed OAuth 앱이 경로로 범위 지정됨

앱 1을 베어 호스트로 재범위 지정(1단계)

/mcp: Unexpected content type: text/html

/mcp 앱 정책이 Allow이고 Bypass가 아님

앱 2 정책 작업을 Bypass로 설정(2단계)

/mcp: OAuth 401 invalid_token

/mcp 우회 앱이 없음; 전체 호스트 OAuth 앱이 이를 게이트함

앱 2 생성(2단계)

구성

환경 변수

필수 여부

기본값

설명

PLAUSIBLE_API_KEY

예 (STDIO; Worker /internal)

—

Plausible API 키 (여기서 발급). Worker에서는 /internal용 공유 키이며, /mcp는 각 사용자가 Bearer를 통해 자신의 키를 사용합니다.

PLAUSIBLE_BASE_URL

아니요

https://plausible.io

Plausible 인스턴스의 URL (자체 호스팅용)

PLAUSIBLE_DEFAULT_SITE_ID

아니요

—

기본 사이트 도메인. 매 호출마다 site_id를 전달하지 않아도 됩니다.

CF_ACCESS_TEAM_DOMAIN

예 (Worker /internal)

—

https://<team>.cloudflareaccess.com — Cf-Access-Jwt-Assertion JWKS 및 발급자(issuer)를 검증합니다. 끝에 슬래시를 붙이지 마세요.

CF_ACCESS_AUD

예 (Worker /internal)

—

Access 애플리케이션의 Application Audience (AUD) 태그 — assertion의 aud와 대조됩니다.

SENTRY_DSN

아니요 (Worker)

—

Worker 자체 텔레메트리용 Sentry DSN (wrangler secret put SENTRY_DSN). 설정하지 않으면 Sentry가 비활성화됩니다 — 자체 호스팅 배포에서 텔레메트리를 원한다면 자신의 DSN을 사용하세요.

ALLOWED_EMAIL_DOMAIN

아니요 (Worker /internal)

sentry.io

/internal에 로그인할 수 있는 쉼표로 구분된 이메일 도메인 목록. 자체 호스팅 시 자신의 도메인으로 설정하세요.

MCP_ALLOWED_HOSTNAMES

예 (Worker)

—

MCP Host 헤더 검증에 사용되는 쉼표로 구분된 호스트네임 허용 목록.

MCP_ALLOWED_ORIGIN_HOSTNAMES

아니요 (Worker /internal)

—

/internal 호출이 허용되는 쉼표로 구분된 브라우저 Origin 호스트네임 목록. 목록이 비어 있으면 Origin이 있는 요청은 거부됩니다.

Worker에서 /mcp 엔드포인트는 서버 측 키가 필요 없습니다 — 각 사용자가 Authorization: Bearer를 통해 자신의 키를 전달합니다. /internal 엔드포인트는 Cloudflare Access Managed OAuth로 보호되며 공유 서버 측 PLAUSIBLE_API_KEY 시크릿을 사용합니다 (자체 호스팅 참조).

Plausible API

이 서버는 Plausible Stats API v2 (POST /api/v2/query)를 래핑합니다. Plausible Cloud 및 자체 호스팅 인스턴스 모두에서 작동합니다.

지원되는 메트릭

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 지리 디멘전은 사람이 읽을 수 있는 이름(예: "Canada")을 반환하며, 일반 visit:country/region/city는 ISO/Geoname 코드를 반환합니다.

필터링

모든 쿼리 도구는 property_filters를 허용합니다. 이름과 달리 이는 내장 디멘전뿐만 아니라 커스텀 이벤트 속성으로도 필터링합니다. 각 항목은 { "property", "operator", "values" } 형식입니다:

  • property — 내장 디멘전(예: visit:channel, visit:source, event:page) 또는 속성 이름 그대로의 커스텀 속성("plan"은 event:props:plan을 대상으로 함).

  • operator — is, is_not, contains, contains_not (기본값 is). event:goal은 is와 contains만 지원합니다.

  • 여러 항목은 AND로 결합되며, page/goal 단축 매개변수도 마찬가지입니다. 동일한 호출에서 단축 매개변수와 property_filters로 동시에 event:page/event:goal을 대상으로 하면 거부됩니다 — 둘 중 하나만 사용하세요.

예를 들어, 유기 검색 트래픽의 상위 페이지: get_breakdown에 dimension: "event:page" 및 property_filters: [{ "property": "visit:channel", "values": ["Organic Search"] }]를 전달합니다.

커스텀 속성

사이트는 자체 커스텀 이벤트 속성을 전송하며, event:props:<name> 형식으로 주소가 지정됩니다. 이는 사이트별로 다르므로 고정된 목록이 없습니다.

  • 커스텀 속성으로 세분화: get_breakdown에 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 (자체 키 사용) — 완전히 익명입니다. 도구 입력 및 출력은 기록되지 않으며(해당 데이터는 호출자와 호출자 자신의 키에 속함), 신원이 첨부되지 않고, 수집 시 추론된 클라이언트 IP는 제거됩니다 (src/redaction.ts). 운영 텔레메트리만 남습니다: 도구 이름, 스팬 타이밍, 실패.

  • /internal (SSO 게이트) — 속성이 부여됩니다. 요청에는 인증된 @sentry.io 이메일(Sentry.setUser)이 포함되며, 공유 서버 측 키에 대한 속성 추적 및 남용 추적을 위해 도구 입력/출력이 기록됩니다 (recordToolIO).

Authorization / Cookie / Cf-Access-Jwt-Assertion 헤더는 두 경로 모두에서 스팬에서 제거됩니다. 이중 안전장치로, Sentry 프로젝트의 Security & Privacy 설정에서 **IP 주소 저장 방지(Prevent Storing of IP Addresses)**를 활성화하세요.

라이선스

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

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
    -