AI integrations (MCP)
Let an AI assistant explore and manage your Rybbit analytics through the hosted Model Context Protocol server
Rybbit includes a hosted Model Context Protocol (MCP) endpoint. It gives an AI assistant read and write access to your analytics: exploring traffic and behavior data, and managing sites, goals, funnels, organization members, teams, and user profiles — through the same API the dashboard uses, with the same access checks, roles, and rate limits.
Your MCP client connects to Rybbit over HTTPS and sends your API key with each protocol request. Rybbit verifies the key before processing any message, and every tool call is authorized against the key user's role and site access.
Connect a client
1. Create an API key
- Open Settings → Account in Rybbit.
- Create a key in the API Keys section.
- Copy it immediately. Rybbit only shows a new key once.
A key created without permissions can do everything its user can do. To hand an agent a narrower credential, create the key with scoped permissions (POST /api/user/api-keys with a permissions object, e.g. {"analytics": ["read"], "goals": ["read", "write"]}): the MCP tool list and every API call are then limited to those resource:action scopes. write implies read on the same resource, and scopes never elevate — org admin/owner requirements still apply. Deleting the key revokes the connection.
2. Add the endpoint
Use this Streamable HTTP URL for Rybbit Cloud:
https://app.rybbit.io/api/mcpFor a self-hosted installation, replace the host with your configured BASE_URL:
https://analytics.example.com/api/mcpConfigure your client to send this header on every request:
Authorization: Bearer <RYBBIT_API_KEY>MCP clients use different configuration formats. A typical remote-server configuration has this shape:
{
"mcpServers": {
"rybbit": {
"url": "https://app.rybbit.io/api/mcp",
"headers": {
"Authorization": "Bearer <RYBBIT_API_KEY>"
}
}
}
}Use your client's secret or environment-variable support when available instead of saving the key in a file. Query-string API keys are not accepted by the MCP endpoint.
Or connect with OAuth
Clients that support the MCP authorization flow can skip API keys entirely: add the endpoint URL with no headers, and the client discovers Rybbit's authorization server through the standard well-known metadata (/.well-known/oauth-protected-resource), registers itself, and opens a browser window for you to log in and approve access. The resulting access token acts with your user's role, exactly like an API key would.
OAuth grants support the same resource:action scopes as API keys (advertised in scopes_supported). A grant that requests only the standard OIDC scopes is unrestricted; a grant that requests custom scopes like analytics:read is limited to them. The requesting client controls which scopes it asks for — consent is currently approve-or-deny as a whole.
Self-hosted instances need the OAuth tables created once before OAuth clients can connect: run npm run db:push in
server/ after upgrading. API-key authentication works regardless.
3. Start with context
Ask the assistant to call list_sites, or prompt it with something like:
List my Rybbit sites, summarize last month's traffic for the docs site, and create a goal for signups.
list_sites returns the numeric site_id and organization_id required by the other tools, plus the key's role in each organization. It does not return API keys or member email addresses.
Available tools
Analytics (read)
| Tool | Returns |
|---|---|
get_overview | Sessions, pageviews, users, pages per session, bounce rate, and session duration |
get_overview_timeseries | The overview KPIs bucketed over time |
get_breakdown | Sessions broken down by one dimension (pages, referrers, countries, devices, UTM, ...) |
get_live_stats | Visitors active on the site right now |
get_event_names | Custom event names tracked on the site with counts |
get_errors | JavaScript errors grouped by name/message with occurrence counts |
get_web_vitals | Core Web Vitals percentiles (LCP, CLS, INP, FCP, TTFB) |
get_retention | User retention cohort table |
get_journeys | Most common page-to-page navigation paths |
Sites
| Tool | Does |
|---|---|
list_sites | List organizations and sites the key can access (call this first) |
get_site | One site's full configuration |
create_site | Add a new site to an organization (admin) |
update_site_config | Change site settings: name, domain, tracking features, exclusions, tags (admin) |
delete_site | Permanently delete a site and its data (admin, destructive) |
Goals & funnels
| Tool | Does |
|---|---|
get_goals | Conversion goals with conversion stats |
create_goal | Create a path, event, or autocapture goal |
update_goal | Replace a goal's definition |
delete_goal | Permanently delete a goal (destructive) |
get_funnels | Saved funnel definitions |
analyze_funnel | Compute an ad-hoc funnel without saving it |
save_funnel | Save a funnel, or update one by passing funnel_id |
delete_funnel | Permanently delete a saved funnel (destructive) |
People
| Tool | Does |
|---|---|
get_users | Person inventory with per-user aggregates and traits (sortable, searchable) |
get_user | One person's profile: traits, linked devices, vitals, locations |
identify_user | Link an anonymous device to your user ID and merge traits |
update_user_traits | Replace a person's traits wholesale |
delete_user | GDPR erasure of one person's analytics data (admin, destructive) |
Organization & teams
| Tool | Does |
|---|---|
list_members | Organization members with roles, site access, and teams |
add_member | Add an existing Rybbit user to the organization (admin) |
update_member_site_access | Restrict a member to specific sites (admin) |
list_teams | Teams with members and site access |
create_team | Create a team (admin) |
update_team | Rename a team or replace its members/sites (admin) |
delete_team | Permanently delete a team (admin, destructive) |
Raw data & SQL
| Tool | Does |
|---|---|
get_sessions | Recent visitor sessions with full attribution |
get_session | One session's detail plus its event timeline |
get_events | Raw recent events, newest first |
get_query_schema | The ClickHouse schema and rules for run_query |
run_query | Read-only ClickHouse SQL against the site-scoped scoped_events table |
Analytics tools accept optional time inputs (start_date/end_date with an IANA time_zone, or past_minutes) and the same filters as the dashboard. Omitting time inputs queries all time.
Permissions and roles
The MCP surface mirrors the REST API's permission model:
- Read tools work for any member with access to the site.
- Write tools need at least member-level site access (goals, funnels,
identify_user,update_user_traits,save_funnel). - Tools marked (admin) require the API key's user to hold the admin or owner role in the organization;
add_membercan grant theownerrole only from an owner's key. The REST layer enforces all of this — an underprivileged key gets a 403 with an explanatory message.
To give an assistant a read-only or read-mostly view, create a scoped API key (see step 1): grant only the resource:action scopes it needs — e.g. {"analytics": ["read"], "sessions": ["read"]} for a reporting agent. The MCP tool list is filtered to those scopes, and any out-of-scope call returns 403 { "error": "Insufficient scope", "required": "goals:write" }. Alternatively, connecting with a member-role user's key hides nothing but refuses every call requiring the admin/owner role.
OAuth clients request scopes through the standard grant. Rybbit advertises the same resource:action scopes in its discovery metadata; a grant carrying no custom scopes (or only the standard OIDC scopes) is treated as full access, for backward compatibility.
Destructive tools
delete_goal, delete_funnel, delete_site, delete_team, and delete_user permanently destroy data and are marked with the MCP destructiveHint annotation, so well-behaved clients ask for confirmation before invoking them. delete_site and delete_user (the GDPR-erasure path) also remove recorded events and replays, with erasure completing asynchronously.
Data and security boundary
- The API key is verified before any MCP message is processed, and each tool call re-runs the corresponding REST route's own access checks, role requirements, and rate limits.
- The surface returns whatever the REST API returns for your role — including session-level records and, where a site has IP tracking enabled, visitor IP addresses. Connect only AI clients you trust with that data, and use a separate, revocable API key per integration.
- Text originating in tracked traffic (page titles, paths, referrers, event names, traits) is stripped of control and bidi-override characters. AI clients should still treat these values as untrusted data, never as instructions.
run_queryis restricted to a read-only, site-scoped table with row and execution-time caps.- The server does not contain an AI model or send analytics to an AI provider. Data only leaves Rybbit in response to the MCP client you configure.
- The endpoint is stateless. Each HTTP request is independently authenticated.
Troubleshooting
- 401 Unauthorized: The client did not send a Bearer credential, or the key/token is invalid, expired, or revoked. OAuth-capable clients re-authenticate automatically via the
WWW-Authenticatechallenge. - OAuth login loop or "table does not exist" (self-hosted): Run
npm run db:pushinserver/to create the OAuth tables, then retry. - 403 in tool results: The key's user lacks access to that site or organization — or the tool requires an org admin/owner role. Check the
rolefield inlist_sites. - 403 "Insufficient scope": The credential was created without the
resource:actionscope this tool needs (therequiredfield names it). Use a key or OAuth grant that includes it. - 429 Too Many Requests: The API key exceeded its plan's rate limit.
- 503 Service Unavailable: Rybbit could not verify the key. Retry the request; do not replace a known-valid key based on this response.
- 405 Method Not Allowed on GET: This is expected. The stateless endpoint accepts MCP messages over
POST. - Site access error: Call
list_sitesagain. Membership or site permissions may have changed.