krystalview-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+ *.egg
9
+ .venv/
10
+ venv/
11
+ .env
12
+ .pytest_cache/
13
+ .mypy_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KrystalView
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: krystalview-mcp
3
+ Version: 0.1.0
4
+ Summary: KrystalView MCP Server — AI agent access to website analytics, session replay, friction scoring, and anomaly detection.
5
+ Project-URL: Homepage, https://krystalview.com
6
+ Project-URL: Documentation, https://docs.krystalview.com/integrations/mcp
7
+ Project-URL: Repository, https://github.com/McSlaine/krystalview-mcp
8
+ Author-email: KrystalView <support@krystalview.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: ai,analytics,krystalview,mcp,session-replay
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Requires-Python: >=3.10
18
+ Requires-Dist: httpx>=0.27.0
19
+ Requires-Dist: mcp[cli]>=1.0.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # KrystalView MCP Server
23
+
24
+ Give your AI agents direct access to website analytics. Query visitor sessions, investigate UX friction, analyze conversion funnels, and get anomaly alerts — all from Claude, Cursor, or any MCP-compatible client.
25
+
26
+ ## Quick Start
27
+
28
+ ### Install
29
+
30
+ ```bash
31
+ pip install krystalview-mcp
32
+ ```
33
+
34
+ ### Configure
35
+
36
+ Generate an API key in your [KrystalView console](https://app.krystalview.com) under **Settings > API Keys**.
37
+
38
+ #### Claude Desktop
39
+
40
+ Add to your `claude_desktop_config.json`:
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "krystalview": {
46
+ "command": "krystalview-mcp",
47
+ "env": {
48
+ "KRYSTALVIEW_API_KEY": "your-api-key-here"
49
+ }
50
+ }
51
+ }
52
+ }
53
+ ```
54
+
55
+ #### Claude Code
56
+
57
+ ```bash
58
+ claude mcp add krystalview -- krystalview-mcp
59
+ # Then set your API key:
60
+ export KRYSTALVIEW_API_KEY="your-api-key-here"
61
+ ```
62
+
63
+ #### Cursor
64
+
65
+ Add to your MCP settings:
66
+
67
+ ```json
68
+ {
69
+ "krystalview": {
70
+ "command": "krystalview-mcp",
71
+ "env": {
72
+ "KRYSTALVIEW_API_KEY": "your-api-key-here"
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## Available Tools
79
+
80
+ | Tool | Description |
81
+ |------|-------------|
82
+ | `get_sessions` | List/search visitor sessions with filters (device, location, friction, rage clicks) |
83
+ | `get_session_detail` | Deep dive into a specific session — full timeline, events, navigation path |
84
+ | `get_site_stats` | Aggregate performance metrics — sessions, friction, devices, top pages |
85
+ | `get_anomalies` | AI-detected anomalies with explanations (traffic spikes/drops, friction surges) |
86
+ | `get_funnels` | List defined conversion funnels |
87
+ | `get_funnel_analysis` | Step-by-step funnel conversion rates and drop-off analysis |
88
+
89
+ ## Example Prompts
90
+
91
+ Once connected, try asking your AI assistant:
92
+
93
+ - *"How's my site performing this week?"*
94
+ - *"Show me frustrated mobile users from the last 24 hours"*
95
+ - *"Why did our traffic drop yesterday?"*
96
+ - *"Where are users dropping off in the checkout funnel?"*
97
+ - *"Find sessions with rage clicks on the pricing page"*
98
+ - *"Are there any anomalies I should know about?"*
99
+
100
+ ## Environment Variables
101
+
102
+ | Variable | Required | Default | Description |
103
+ |----------|----------|---------|-------------|
104
+ | `KRYSTALVIEW_API_KEY` | Yes | — | Your KrystalView API key |
105
+ | `KRYSTALVIEW_BASE_URL` | No | `https://app.krystalview.com/api` | API base URL |
106
+ | `KRYSTALVIEW_TIMEOUT` | No | `15` | Request timeout in seconds |
107
+
108
+ ## Rate Limits
109
+
110
+ API keys have configurable rate limits (default: 60 requests per minute). Rate limit headers are included in every response. If you hit the limit, the server returns a clear error with retry timing.
111
+
112
+ ## Security
113
+
114
+ - API keys are scoped to a single site — agents can only access data for the site the key was created for
115
+ - All requests use HTTPS
116
+ - Keys can be rotated or revoked in the KrystalView console
117
+ - No data is stored by the MCP server — it proxies directly to the KrystalView API
118
+
119
+ ## License
120
+
121
+ MIT
@@ -0,0 +1,100 @@
1
+ # KrystalView MCP Server
2
+
3
+ Give your AI agents direct access to website analytics. Query visitor sessions, investigate UX friction, analyze conversion funnels, and get anomaly alerts — all from Claude, Cursor, or any MCP-compatible client.
4
+
5
+ ## Quick Start
6
+
7
+ ### Install
8
+
9
+ ```bash
10
+ pip install krystalview-mcp
11
+ ```
12
+
13
+ ### Configure
14
+
15
+ Generate an API key in your [KrystalView console](https://app.krystalview.com) under **Settings > API Keys**.
16
+
17
+ #### Claude Desktop
18
+
19
+ Add to your `claude_desktop_config.json`:
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "krystalview": {
25
+ "command": "krystalview-mcp",
26
+ "env": {
27
+ "KRYSTALVIEW_API_KEY": "your-api-key-here"
28
+ }
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ #### Claude Code
35
+
36
+ ```bash
37
+ claude mcp add krystalview -- krystalview-mcp
38
+ # Then set your API key:
39
+ export KRYSTALVIEW_API_KEY="your-api-key-here"
40
+ ```
41
+
42
+ #### Cursor
43
+
44
+ Add to your MCP settings:
45
+
46
+ ```json
47
+ {
48
+ "krystalview": {
49
+ "command": "krystalview-mcp",
50
+ "env": {
51
+ "KRYSTALVIEW_API_KEY": "your-api-key-here"
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Available Tools
58
+
59
+ | Tool | Description |
60
+ |------|-------------|
61
+ | `get_sessions` | List/search visitor sessions with filters (device, location, friction, rage clicks) |
62
+ | `get_session_detail` | Deep dive into a specific session — full timeline, events, navigation path |
63
+ | `get_site_stats` | Aggregate performance metrics — sessions, friction, devices, top pages |
64
+ | `get_anomalies` | AI-detected anomalies with explanations (traffic spikes/drops, friction surges) |
65
+ | `get_funnels` | List defined conversion funnels |
66
+ | `get_funnel_analysis` | Step-by-step funnel conversion rates and drop-off analysis |
67
+
68
+ ## Example Prompts
69
+
70
+ Once connected, try asking your AI assistant:
71
+
72
+ - *"How's my site performing this week?"*
73
+ - *"Show me frustrated mobile users from the last 24 hours"*
74
+ - *"Why did our traffic drop yesterday?"*
75
+ - *"Where are users dropping off in the checkout funnel?"*
76
+ - *"Find sessions with rage clicks on the pricing page"*
77
+ - *"Are there any anomalies I should know about?"*
78
+
79
+ ## Environment Variables
80
+
81
+ | Variable | Required | Default | Description |
82
+ |----------|----------|---------|-------------|
83
+ | `KRYSTALVIEW_API_KEY` | Yes | — | Your KrystalView API key |
84
+ | `KRYSTALVIEW_BASE_URL` | No | `https://app.krystalview.com/api` | API base URL |
85
+ | `KRYSTALVIEW_TIMEOUT` | No | `15` | Request timeout in seconds |
86
+
87
+ ## Rate Limits
88
+
89
+ API keys have configurable rate limits (default: 60 requests per minute). Rate limit headers are included in every response. If you hit the limit, the server returns a clear error with retry timing.
90
+
91
+ ## Security
92
+
93
+ - API keys are scoped to a single site — agents can only access data for the site the key was created for
94
+ - All requests use HTTPS
95
+ - Keys can be rotated or revoked in the KrystalView console
96
+ - No data is stored by the MCP server — it proxies directly to the KrystalView API
97
+
98
+ ## License
99
+
100
+ MIT
@@ -0,0 +1,32 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "krystalview-mcp"
7
+ version = "0.1.0"
8
+ description = "KrystalView MCP Server — AI agent access to website analytics, session replay, friction scoring, and anomaly detection."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ authors = [{ name = "KrystalView", email = "support@krystalview.com" }]
13
+ keywords = ["mcp", "analytics", "krystalview", "ai", "session-replay"]
14
+ classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Software Development :: Libraries",
20
+ ]
21
+ dependencies = [
22
+ "mcp[cli]>=1.0.0",
23
+ "httpx>=0.27.0",
24
+ ]
25
+
26
+ [project.scripts]
27
+ krystalview-mcp = "krystalview_mcp.server:main"
28
+
29
+ [project.urls]
30
+ Homepage = "https://krystalview.com"
31
+ Documentation = "https://docs.krystalview.com/integrations/mcp"
32
+ Repository = "https://github.com/McSlaine/krystalview-mcp"
@@ -0,0 +1,3 @@
1
+ """KrystalView MCP Server — AI agent access to website analytics."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,258 @@
1
+ """KrystalView MCP Server.
2
+
3
+ Gives AI agents direct access to website analytics — sessions, visitor
4
+ behavior, friction scores, anomalies, and funnel analysis.
5
+
6
+ Authenticates against the KrystalView API using the same API keys
7
+ generated in the KrystalView console.
8
+ """
9
+
10
+ import json
11
+ import os
12
+ from typing import Any, Optional
13
+
14
+ import httpx
15
+ from mcp.server.fastmcp import FastMCP
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Configuration
19
+ # ---------------------------------------------------------------------------
20
+
21
+ API_KEY = os.environ.get("KRYSTALVIEW_API_KEY", "")
22
+ BASE_URL = os.environ.get(
23
+ "KRYSTALVIEW_BASE_URL", "https://app.krystalview.com/api"
24
+ ).rstrip("/")
25
+ TIMEOUT = int(os.environ.get("KRYSTALVIEW_TIMEOUT", "15"))
26
+
27
+ mcp = FastMCP(
28
+ "KrystalView",
29
+ instructions=(
30
+ "KrystalView provides real-time website analytics with session replay, "
31
+ "friction scoring, anomaly detection, and funnel analysis. "
32
+ "Use these tools to investigate visitor behavior, diagnose UX issues, "
33
+ "and answer questions about site performance."
34
+ ),
35
+ )
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # HTTP helpers
39
+ # ---------------------------------------------------------------------------
40
+
41
+
42
+ def _headers() -> dict[str, str]:
43
+ return {"X-API-Key": API_KEY, "Accept": "application/json"}
44
+
45
+
46
+ async def _get(path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
47
+ """Make an authenticated GET request to the KrystalView API."""
48
+ url = f"{BASE_URL}{path}"
49
+ # Strip None values from params
50
+ if params:
51
+ params = {k: v for k, v in params.items() if v is not None}
52
+ async with httpx.AsyncClient(timeout=TIMEOUT) as client:
53
+ resp = await client.get(url, headers=_headers(), params=params)
54
+ resp.raise_for_status()
55
+ return resp.json()
56
+
57
+
58
+ def _format_error(exc: Exception) -> str:
59
+ if isinstance(exc, httpx.HTTPStatusError):
60
+ status = exc.response.status_code
61
+ if status == 401:
62
+ return "Authentication failed. Check your KRYSTALVIEW_API_KEY."
63
+ if status == 403:
64
+ return "API key does not have the required 'read' scope."
65
+ if status == 429:
66
+ retry = exc.response.headers.get("Retry-After", "?")
67
+ return f"Rate limited. Retry after {retry} seconds."
68
+ try:
69
+ detail = exc.response.json().get("detail", exc.response.text)
70
+ except Exception:
71
+ detail = exc.response.text
72
+ return f"API error {status}: {detail}"
73
+ return f"Request failed: {exc}"
74
+
75
+
76
+ # ---------------------------------------------------------------------------
77
+ # Tools
78
+ # ---------------------------------------------------------------------------
79
+
80
+
81
+ @mcp.tool()
82
+ async def get_sessions(
83
+ query: Optional[str] = None,
84
+ limit: int = 20,
85
+ offset: int = 0,
86
+ country: Optional[str] = None,
87
+ device_type: Optional[str] = None,
88
+ min_friction: Optional[int] = None,
89
+ min_duration: Optional[int] = None,
90
+ has_rage_clicks: Optional[bool] = None,
91
+ ) -> str:
92
+ """List recent visitor sessions with filtering.
93
+
94
+ Each session includes: duration, page count, entry/exit URLs, device info,
95
+ screen size, IP address, location (country/city), friction score, and
96
+ rage click count.
97
+
98
+ Use this to find sessions matching specific criteria — e.g. frustrated
99
+ mobile users, visitors from a specific country, or high-friction sessions.
100
+
101
+ Args:
102
+ query: Search entry/exit URLs (e.g. "/pricing", "/checkout")
103
+ limit: Max results (1-100, default 20)
104
+ offset: Pagination offset
105
+ country: Filter by country name
106
+ device_type: "mobile" or "desktop"
107
+ min_friction: Minimum friction score (0-10)
108
+ min_duration: Minimum session duration in seconds
109
+ has_rage_clicks: Only sessions with rage clicks
110
+ """
111
+ try:
112
+ data = await _get("/v1/api/sessions", {
113
+ "q": query,
114
+ "limit": min(limit, 100),
115
+ "offset": max(offset, 0),
116
+ "country": country,
117
+ "device_type": device_type,
118
+ "min_friction": min_friction,
119
+ "min_duration": min_duration,
120
+ "has_rage_clicks": has_rage_clicks,
121
+ })
122
+ return json.dumps(data["data"], indent=2, default=str)
123
+ except Exception as exc:
124
+ return _format_error(exc)
125
+
126
+
127
+ @mcp.tool()
128
+ async def get_session_detail(session_id: str) -> str:
129
+ """Get full details for a specific session.
130
+
131
+ Returns the complete session record including: all page visits with
132
+ timestamps, event timeline, device/browser info, IP address, geographic
133
+ location, friction breakdown, rage clicks, errors encountered, and
134
+ navigation path.
135
+
136
+ Use this to deep-dive into a specific session after finding it via
137
+ get_sessions.
138
+
139
+ Args:
140
+ session_id: The session primary key (UUID) from get_sessions results
141
+ """
142
+ try:
143
+ data = await _get(f"/v1/api/sessions/{session_id}")
144
+ return json.dumps(data["data"], indent=2, default=str)
145
+ except Exception as exc:
146
+ return _format_error(exc)
147
+
148
+
149
+ @mcp.tool()
150
+ async def get_site_stats(days: int = 7) -> str:
151
+ """Get aggregate site statistics and performance metrics.
152
+
153
+ Returns: total sessions, average duration, average friction score,
154
+ bounce rate, rage click sessions, device breakdown (desktop/mobile),
155
+ browser breakdown, top entry pages, top exit pages, daily session
156
+ counts, and friction score distribution.
157
+
158
+ Use this for an overview of site health and trends.
159
+
160
+ Args:
161
+ days: Lookback period in days (7-90, default 7)
162
+ """
163
+ try:
164
+ data = await _get("/v1/api/stats", {"days": min(max(days, 7), 90)})
165
+ return json.dumps(data["data"], indent=2, default=str)
166
+ except Exception as exc:
167
+ return _format_error(exc)
168
+
169
+
170
+ @mcp.tool()
171
+ async def get_anomalies(
172
+ limit: int = 20,
173
+ unacknowledged_only: bool = False,
174
+ ) -> str:
175
+ """Get detected anomalies for the site.
176
+
177
+ Anomalies are automatically detected when metrics deviate significantly
178
+ from their 7-day rolling average (>2 standard deviations). Types include:
179
+ traffic_spike, traffic_drop, friction_surge, and bounce_spike.
180
+
181
+ Each anomaly includes: type, severity (warning/critical), metric name,
182
+ expected vs actual values, deviation percentage, and an AI-generated
183
+ explanation of what likely caused it.
184
+
185
+ Args:
186
+ limit: Max results (1-200, default 20)
187
+ unacknowledged_only: Only show unacknowledged anomalies
188
+ """
189
+ try:
190
+ data = await _get("/v1/api/anomalies", {
191
+ "limit": min(limit, 200),
192
+ "unacknowledged": unacknowledged_only,
193
+ })
194
+ return json.dumps(data["data"], indent=2, default=str)
195
+ except Exception as exc:
196
+ return _format_error(exc)
197
+
198
+
199
+ @mcp.tool()
200
+ async def get_funnels() -> str:
201
+ """List all conversion funnels defined for this site.
202
+
203
+ Returns funnel definitions with their name, steps (URLs/patterns),
204
+ and creation date. Use the funnel ID with get_funnel_analysis to see
205
+ conversion rates and drop-off points.
206
+ """
207
+ try:
208
+ data = await _get("/v1/api/funnels")
209
+ return json.dumps(data["data"], indent=2, default=str)
210
+ except Exception as exc:
211
+ return _format_error(exc)
212
+
213
+
214
+ @mcp.tool()
215
+ async def get_funnel_analysis(funnel_id: int, days: int = 30) -> str:
216
+ """Analyze a conversion funnel — see where users drop off.
217
+
218
+ Returns step-by-step conversion rates showing how many sessions
219
+ reached each step, the conversion rate between steps, and the
220
+ overall funnel completion rate.
221
+
222
+ Use this to identify which step in a user flow (e.g. landing ->
223
+ signup -> checkout -> payment) loses the most visitors.
224
+
225
+ Args:
226
+ funnel_id: Funnel ID from get_funnels results
227
+ days: Lookback period in days (7-90, default 30)
228
+ """
229
+ try:
230
+ data = await _get(f"/v1/api/funnels/{funnel_id}/analysis", {
231
+ "days": min(max(days, 7), 90),
232
+ })
233
+ return json.dumps(data["data"], indent=2, default=str)
234
+ except Exception as exc:
235
+ return _format_error(exc)
236
+
237
+
238
+ # ---------------------------------------------------------------------------
239
+ # Entry point
240
+ # ---------------------------------------------------------------------------
241
+
242
+
243
+ def main():
244
+ """Run the KrystalView MCP server (stdio transport)."""
245
+ if not API_KEY:
246
+ import sys
247
+ print(
248
+ "Error: KRYSTALVIEW_API_KEY environment variable is required.\n"
249
+ "Generate an API key in your KrystalView console under "
250
+ "Settings > API Keys.",
251
+ file=sys.stderr,
252
+ )
253
+ sys.exit(1)
254
+ mcp.run()
255
+
256
+
257
+ if __name__ == "__main__":
258
+ main()