MCP Server
Connect AI agents to your analytics data using the Model Context Protocol (MCP). This guide covers authentication, available tools, client configuration, and integration examples.
Overview
The Model Context Protocol (MCP) is an open standard for connecting AI agents and LLMs to external data sources and tools. Agent Analytics implements an MCP server that provides AI assistants like Claude with programmatic access to web analytics data and site management capabilities.
Why MCP Matters for AI Agents
MCP enables AI assistants to:
- Query real-time analytics data across sites
- Create and manage tracked websites
- Record custom server-side events
- Access visitor metrics, pageviews, referrers, and more
- Invite team members to access analytics
Protocol Details
Agent Analytics implements MCP using:
- Protocol: JSON-RPC 2.0
- Transport: Streamable HTTP (stateless mode)
- Protocol Version:
2025-03-26 - Server Name: Agent Analytics
- Server Version: 0.0.1
The server uses MCP's Streamable HTTP transport in stateless mode, which means each request is independent with no persistent connection required. Server-Sent Events (SSE) are not supported, but batch requests are fully supported.
Authentication
All MCP requests require Bearer token authentication via the Authorization header. Use the same API key you use for REST API calls.
Authorization: Bearer <your_api_key>The token identifies your account and scopes all operations to your account's sites and data. You can generate API keys from your account dashboard.
Getting Started with MCP
Endpoint
URL: POST https://api.statscontext.com/mcp
Content-Type: application/json
Supported HTTP Methods:
POST- Send JSON-RPC 2.0 requestsDELETE- Close session (returns 204 No Content)GET- Not supported (SSE disabled, returns 405)
Initialization Handshake
Before using tools, clients must send an initialize request to establish protocol compatibility.
Request:
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "my-client",
"version": "1.0.0"
}
}
}Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-03-26",
"capabilities": {
"tools": {}
},
"serverInfo": {
"name": "Agent Analytics",
"version": "0.0.1"
}
}
}Tool Discovery
After initialization, list available tools using the tools/list method.
Request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}Response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{
"name": "query_stats",
"description": "Query analytics data for a site...",
"inputSchema": { ... }
},
{
"name": "list_sites",
"description": "List all sites...",
"inputSchema": { ... }
},
{
"name": "create_site",
"description": "Register a new site...",
"inputSchema": { ... }
},
{
"name": "get_site",
"description": "Get details for a specific site...",
"inputSchema": { ... }
},
{
"name": "track_event",
"description": "Record a custom analytics event...",
"inputSchema": { ... }
},
{
"name": "invite_user",
"description": "Send an invitation to a user...",
"inputSchema": { ... }
}
]
}
}Available Tools
1. query_stats
Query analytics data for a site. Returns comprehensive metrics including pageviews, visitors, sessions, bounce rate, duration, top pages, referrers, countries, devices, browsers, custom events, and timeseries data.
Input Schema:
{
"type": "object",
"properties": {
"site_id": {
"type": "string",
"description": "The site ID to query stats for"
},
"period": {
"type": "string",
"enum": ["today", "7d", "30d", "90d", "custom"],
"default": "7d",
"description": "Time period"
},
"metric": {
"type": "string",
"enum": [
"all",
"pageviews",
"visitors",
"sessions",
"bounce_rate",
"avg_duration",
"top_pages",
"referrers",
"countries",
"devices",
"browsers",
"custom_events",
"timeseries"
],
"default": "all",
"description": "Which metric to return"
},
"from": {
"type": "string",
"description": "Start date (YYYY-MM-DD) for custom period"
},
"to": {
"type": "string",
"description": "End date (YYYY-MM-DD) for custom period"
},
"limit": {
"type": "number",
"default": 10,
"description": "Max results for list metrics (1-100)"
}
},
"required": ["site_id"]
}Example Call:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "query_stats",
"arguments": {
"site_id": "site_abc123",
"period": "30d",
"metric": "all",
"limit": 20
}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"pageviews\": 15420,\n \"visitors\": 3241,\n \"sessions\": 4892,\n \"bounce_rate\": 0.42,\n \"avg_duration\": 185.3,\n \"top_pages\": [\n {\"path\": \"/\", \"views\": 5234},\n {\"path\": \"/blog\", \"views\": 2341}\n ],\n \"referrers\": [...],\n \"countries\": [...],\n \"devices\": {...},\n \"browsers\": {...},\n \"custom_events\": [...],\n \"timeseries\": [...]\n}"
}
]
}
}2. list_sites
List all sites registered under the authenticated account.
Input Schema:
{
"type": "object",
"properties": {}
}No parameters required.
Example Call:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "list_sites",
"arguments": {}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"sites\": [\n {\n \"id\": \"site_abc123\",\n \"account_id\": \"acc_xyz789\",\n \"domain\": \"example.com\",\n \"name\": \"My Example Site\",\n \"created_at\": \"2026-01-15T10:30:00Z\"\n },\n {\n \"id\": \"site_def456\",\n \"account_id\": \"acc_xyz789\",\n \"domain\": \"blog.example.com\",\n \"name\": \"Example Blog\",\n \"created_at\": \"2026-02-01T14:20:00Z\"\n }\n ]\n}"
}
]
}
}3. create_site
Register a new site for tracking. Returns the site details and an HTML tracking snippet to embed in your website.
Input Schema:
{
"type": "object",
"properties": {
"domain": {
"type": "string",
"description": "The domain of the site (e.g., example.com)"
},
"name": {
"type": "string",
"description": "A friendly name for the site"
}
},
"required": ["domain", "name"]
}Example Call:
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "create_site",
"arguments": {
"domain": "newsite.com",
"name": "New Site"
}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"site\": {\n \"id\": \"site_new789\",\n \"account_id\": \"acc_xyz789\",\n \"domain\": \"newsite.com\",\n \"name\": \"New Site\",\n \"created_at\": \"2026-02-10T09:15:00Z\"\n },\n \"snippet\": \"<script defer data-site-id=\\\"site_new789\\\" src=\\\"https://newsite.com/tracker.js\\\"></script>\"\n}"
}
]
}
}Error Response (Duplicate Domain):
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "Error: A site with this domain already exists in your account."
}
],
"isError": true
}
}4. get_site
Get details for a specific site.
Input Schema:
{
"type": "object",
"properties": {
"site_id": {
"type": "string",
"description": "The site ID to look up"
}
},
"required": ["site_id"]
}Example Call:
{
"jsonrpc": "2.0",
"id": 6,
"method": "tools/call",
"params": {
"name": "get_site",
"arguments": {
"site_id": "site_abc123"
}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"site\": {\n \"id\": \"site_abc123\",\n \"account_id\": \"acc_xyz789\",\n \"domain\": \"example.com\",\n \"name\": \"My Example Site\",\n \"created_at\": \"2026-01-15T10:30:00Z\"\n }\n}"
}
]
}
}5. track_event
Record a custom analytics event for a site. Use this for server-side event tracking when you can't use the client-side tracker.
Input Schema:
{
"type": "object",
"properties": {
"site_id": {
"type": "string",
"description": "The site ID to track the event for"
},
"name": {
"type": "string",
"description": "Event name (e.g., 'signup', 'purchase')"
},
"properties": {
"type": "object",
"additionalProperties": true,
"description": "Optional key-value properties for the event"
}
},
"required": ["site_id", "name"]
}Example Call:
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "track_event",
"arguments": {
"site_id": "site_abc123",
"name": "purchase",
"properties": {
"amount": 49.99,
"currency": "USD",
"product_id": "prod_123"
}
}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 7,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"event_id\": \"evt_xyz789\",\n \"success\": true\n}"
}
]
}
}6. invite_user
Send an invitation to a user's email to join your account. The invited user will receive access to the account's sites and analytics.
Input Schema:
{
"type": "object",
"properties": {
"email": {
"type": "string",
"description": "Email address to invite"
},
"role": {
"type": "string",
"enum": ["owner", "member"],
"default": "member",
"description": "Role for the invited user"
}
},
"required": ["email"]
}Example Call:
{
"jsonrpc": "2.0",
"id": 8,
"method": "tools/call",
"params": {
"name": "invite_user",
"arguments": {
"email": "teammate@example.com",
"role": "member"
}
}
}Example Response:
{
"jsonrpc": "2.0",
"id": 8,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"invitation_id\": \"inv_xyz789\",\n \"email\": \"teammate@example.com\",\n \"role\": \"member\",\n \"token\": \"a1b2c3d4e5f6...\",\n \"expires_at\": \"2026-02-18 10:30:00\",\n \"accept_url\": \"/invite/a1b2c3d4e5f6...\"\n}"
}
]
}
}Client Configuration
Claude Desktop
Add Agent Analytics to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"agent-analytics": {
"url": "https://api.statscontext.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY_HERE"
},
"transport": "http"
}
}
}After adding the configuration, restart Claude Desktop. The Agent Analytics tools will be available in all conversations.
Claude Code
For Claude Code CLI, add to your MCP configuration:
{
"mcpServers": {
"agent-analytics": {
"url": "https://api.statscontext.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY_HERE"
},
"transport": "http"
}
}
}Python Client Example
Here's a complete Python client implementation for connecting to the Agent Analytics MCP server:
import requests
import json
class AgentAnalyticsMCP:
def __init__(self, base_url: str, token: str):
self.base_url = base_url
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
self.request_id = 0
def call(self, method: str, params: dict = None) -> dict:
self.request_id += 1
payload = {
"jsonrpc": "2.0",
"id": self.request_id,
"method": method,
"params": params or {}
}
response = requests.post(self.base_url, json=payload, headers=self.headers)
return response.json()
def initialize(self):
return self.call("initialize", {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "python-client", "version": "1.0.0"}
})
def list_tools(self):
return self.call("tools/list")
def call_tool(self, name: str, arguments: dict):
return self.call("tools/call", {"name": name, "arguments": arguments})
# Usage
client = AgentAnalyticsMCP("https://api.statscontext.com/mcp", "your_api_key_here")
client.initialize()
sites = client.call_tool("list_sites", {})
print(sites)curl Examples
Quick test with curl:
curl -X POST https://api.statscontext.com/mcp \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {"name": "curl", "version": "1.0"}
}
}'curl -X POST https://api.statscontext.com/mcp \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_sites",
"arguments": {}
}
}'Batch Requests
Multiple JSON-RPC requests can be batched in a single HTTP request by sending an array of request objects. The server responds with an array of responses in the same order.
[
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
},
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_sites",
"arguments": {}
}
},
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "query_stats",
"arguments": {
"site_id": "site_abc123",
"period": "7d"
}
}
}
]Batch requests are useful for reducing network round-trips when you need to perform multiple operations.
Error Handling
JSON-RPC Error Codes
Standard JSON-RPC 2.0 errors are returned with these codes:
-32700- Parse error (invalid JSON)-32601- Method not found-32602- Invalid params (unknown tool)
Example error response:
{
"jsonrpc": "2.0",
"id": 10,
"error": {
"code": -32601,
"message": "Method not found: unknown_method"
}
}Tool-Level Errors
Tools return errors via the isError flag in the result object. These are returned as successful JSON-RPC responses (status 200) but with the isError: true flag set.
{
"jsonrpc": "2.0",
"id": 10,
"result": {
"content": [
{
"type": "text",
"text": "Error: Site not found or not owned by this account."
}
],
"isError": true
}
}Common tool errors include:
- Site not found or not owned by account
- Duplicate domain when creating a site
- Pending invitation already exists
- Invalid date format for custom periods
Security
Token Security
Account tokens provide full access to all sites and data for that account. Treat them as sensitive credentials:
- Never commit tokens to version control
- Use environment variables or secure configuration management
- Rotate tokens regularly for long-lived integrations
- Revoke tokens immediately if compromised
HTTPS Required
Always use HTTPS in production to protect tokens and data in transit. The production API endpoint enforces HTTPS.
Scope Isolation
All operations are automatically scoped to the authenticated account. Sites and data from other accounts are never accessible, even with a valid token.
Rate Limiting
Consider implementing rate limits on the client side to avoid overwhelming the server. Batch requests can help reduce the number of HTTP connections.