@logly-uk/mcp 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/index.js +125 -0
- package/package.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Logly
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Logly MCP server
|
|
2
|
+
|
|
3
|
+
Query your [Logly](https://logly.uk) web analytics from Claude, Cursor, or any
|
|
4
|
+
[Model Context Protocol](https://modelcontextprotocol.io) client.
|
|
5
|
+
|
|
6
|
+
Logly is privacy-first web analytics — under 1 KB, cookie-free, GDPR compliant by
|
|
7
|
+
design. This server exposes your analytics over MCP so an AI assistant can answer
|
|
8
|
+
questions like *"how did traffic change this week?"* or *"where is my signup
|
|
9
|
+
funnel losing people?"* — and even hand you the install snippet for a new site.
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
- Node.js 18 or newer
|
|
14
|
+
- A Logly account and an API key — create one in **Settings → API keys** in your
|
|
15
|
+
[Logly dashboard](https://app.logly.uk). The key looks like `logly_a1b2c3...`
|
|
16
|
+
and is shown only once.
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
The server runs via `npx` — no install step needed.
|
|
21
|
+
|
|
22
|
+
### Claude Desktop
|
|
23
|
+
|
|
24
|
+
Edit `claude_desktop_config.json` (Settings → Developer → Edit Config):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"logly": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@logly-uk/mcp"],
|
|
32
|
+
"env": { "LOGLY_API_KEY": "logly_your_key_here" }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Restart Claude Desktop.
|
|
39
|
+
|
|
40
|
+
### Claude Code
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
claude mcp add logly -e LOGLY_API_KEY=logly_your_key_here -- npx -y @logly-uk/mcp
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Cursor
|
|
47
|
+
|
|
48
|
+
Add to `.cursor/mcp.json` in your project (or the global one):
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"logly": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["-y", "@logly-uk/mcp"],
|
|
56
|
+
"env": { "LOGLY_API_KEY": "logly_your_key_here" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Tools
|
|
63
|
+
|
|
64
|
+
| Tool | What it does |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `logly_list_sites` | List every site in your account with its site ID — start here. |
|
|
67
|
+
| `logly_stats` | Pageviews, sessions, visitors, bounce rate, avg duration, daily series, previous-period comparison. |
|
|
68
|
+
| `logly_breakdown` | Top pages, referrers, countries and device/browser split. |
|
|
69
|
+
| `logly_realtime` | Visitors active right now. |
|
|
70
|
+
| `logly_events` | Custom event counts. |
|
|
71
|
+
| `logly_funnels` | List a site's conversion funnels and their steps. |
|
|
72
|
+
| `logly_funnel_results` | Completion counts and drop-off per funnel step. |
|
|
73
|
+
| `logly_install_snippet` | The `<script>` tag to add Logly to a site's `<head>`. |
|
|
74
|
+
|
|
75
|
+
### Date filters
|
|
76
|
+
|
|
77
|
+
Stats tools accept a `days` window (7, 30 or 90 — defaults to 30) or an explicit
|
|
78
|
+
`from` / `to` pair (`YYYY-MM-DD`). If both are given, `from`/`to` wins.
|
|
79
|
+
|
|
80
|
+
## Environment variables
|
|
81
|
+
|
|
82
|
+
| Variable | Required | Purpose |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `LOGLY_API_KEY` | yes | Your Logly API key. |
|
|
85
|
+
| `LOGLY_API_BASE` | no | Override the API base URL (default `https://app.logly.uk`). |
|
|
86
|
+
|
|
87
|
+
## Links
|
|
88
|
+
|
|
89
|
+
- Logly — <https://logly.uk>
|
|
90
|
+
- Public API reference — <https://logly.uk/docs>
|
|
91
|
+
|
|
92
|
+
MIT licensed.
|
package/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
const BASE = process.env.LOGLY_API_BASE || "https://app.logly.uk";
|
|
7
|
+
|
|
8
|
+
async function loglyApi(path, params) {
|
|
9
|
+
const key = process.env.LOGLY_API_KEY;
|
|
10
|
+
if (!key) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"LOGLY_API_KEY is not set. Create one in Logly → Settings → API keys."
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
const url = new URL(BASE + path);
|
|
16
|
+
for (const [k, v] of Object.entries(params || {})) {
|
|
17
|
+
if (v !== undefined && v !== null && v !== "") url.searchParams.set(k, String(v));
|
|
18
|
+
}
|
|
19
|
+
const res = await fetch(url, {
|
|
20
|
+
headers: { Authorization: `Bearer ${key}`, Accept: "application/json" },
|
|
21
|
+
});
|
|
22
|
+
const text = await res.text();
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(`Logly API ${res.status} on ${path}: ${text.slice(0, 300)}`);
|
|
25
|
+
}
|
|
26
|
+
return text;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Common date filter: explicit from/to wins, otherwise a days window (default 30).
|
|
30
|
+
function range({ days, from, to }) {
|
|
31
|
+
if (from || to) return { from, to };
|
|
32
|
+
return { days: days ?? 30 };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const server = new McpServer({ name: "logly", version: "1.0.0" });
|
|
36
|
+
|
|
37
|
+
function tool(name, description, shape, fn) {
|
|
38
|
+
server.tool(name, description, shape, async (args) => {
|
|
39
|
+
try {
|
|
40
|
+
return { content: [{ type: "text", text: await fn(args || {}) }] };
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return { content: [{ type: "text", text: "Error: " + e.message }], isError: true };
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const siteArg = z.string().describe("Logly site ID (slug). Call logly_list_sites to discover it.");
|
|
48
|
+
const daysArg = z.number().int().positive().optional()
|
|
49
|
+
.describe("Days to look back: 7, 30 or 90. Defaults to 30. Ignored when 'from'/'to' are set.");
|
|
50
|
+
const fromArg = z.string().optional().describe("Range start, YYYY-MM-DD. Use together with 'to'.");
|
|
51
|
+
const toArg = z.string().optional().describe("Range end, YYYY-MM-DD. Use together with 'from'.");
|
|
52
|
+
|
|
53
|
+
tool(
|
|
54
|
+
"logly_list_sites",
|
|
55
|
+
"List every website in the authenticated Logly account with its site ID. Start here to find the site ID the other tools need.",
|
|
56
|
+
{},
|
|
57
|
+
() => loglyApi("/api/sites")
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
tool(
|
|
61
|
+
"logly_stats",
|
|
62
|
+
"Traffic totals for a site — pageviews, sessions, visitors, bounce rate, average duration — plus a daily series and a comparison against the previous period.",
|
|
63
|
+
{ site: siteArg, days: daysArg, from: fromArg, to: toArg },
|
|
64
|
+
({ site, days, from, to }) =>
|
|
65
|
+
loglyApi(`/api/sites/${encodeURIComponent(site)}/stats`, range({ days, from, to }))
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
tool(
|
|
69
|
+
"logly_breakdown",
|
|
70
|
+
"Top pages, top referrers, top countries and device/browser split for a site over the given period.",
|
|
71
|
+
{ site: siteArg, days: daysArg, from: fromArg, to: toArg },
|
|
72
|
+
({ site, days, from, to }) =>
|
|
73
|
+
loglyApi(`/api/sites/${encodeURIComponent(site)}/breakdown`, range({ days, from, to }))
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
tool(
|
|
77
|
+
"logly_realtime",
|
|
78
|
+
"Visitors currently active on a site (real-time, the last few minutes).",
|
|
79
|
+
{ site: siteArg },
|
|
80
|
+
({ site }) => loglyApi(`/api/sites/${encodeURIComponent(site)}/active`)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
tool(
|
|
84
|
+
"logly_events",
|
|
85
|
+
"Custom event counts for a site (events sent via logly('event', ...)) over the given period.",
|
|
86
|
+
{ site: siteArg, days: daysArg, from: fromArg, to: toArg },
|
|
87
|
+
({ site, days, from, to }) =>
|
|
88
|
+
loglyApi(`/api/sites/${encodeURIComponent(site)}/events`, range({ days, from, to }))
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
tool(
|
|
92
|
+
"logly_funnels",
|
|
93
|
+
"List the conversion funnels defined for a site, with their IDs and step sequences.",
|
|
94
|
+
{ site: siteArg },
|
|
95
|
+
({ site }) => loglyApi(`/api/sites/${encodeURIComponent(site)}/funnels`)
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
tool(
|
|
99
|
+
"logly_funnel_results",
|
|
100
|
+
"Completion counts and drop-off per step for one conversion funnel.",
|
|
101
|
+
{ funnel_id: z.string().describe("Funnel ID, from logly_funnels."), days: daysArg },
|
|
102
|
+
({ funnel_id, days }) =>
|
|
103
|
+
loglyApi(`/api/funnels/${encodeURIComponent(funnel_id)}/results`, { days: days ?? 30 })
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
tool(
|
|
107
|
+
"logly_install_snippet",
|
|
108
|
+
"Return the Logly tracking snippet for a site — the single <script> tag to add to the site's <head>. Works offline, no API call.",
|
|
109
|
+
{ site: siteArg },
|
|
110
|
+
({ site }) =>
|
|
111
|
+
JSON.stringify(
|
|
112
|
+
{
|
|
113
|
+
site,
|
|
114
|
+
snippet: `<script src="https://logly.uk/p.js?s=${site}" data-site="${site}" async></script>`,
|
|
115
|
+
instructions:
|
|
116
|
+
"Add this tag inside the <head> of every page. It is a single cookie-free tag — no other setup needed.",
|
|
117
|
+
},
|
|
118
|
+
null,
|
|
119
|
+
2
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const transport = new StdioServerTransport();
|
|
124
|
+
await server.connect(transport);
|
|
125
|
+
console.error("Logly MCP server running on stdio");
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@logly-uk/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Model Context Protocol server for Logly — privacy-first web analytics. Query stats, breakdowns, funnels and real-time visitors from Claude, Cursor or any MCP client.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"logly-mcp": "index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"index.js",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"start": "node index.js"
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=18"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
22
|
+
"zod": "^3.23.8"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"model-context-protocol",
|
|
27
|
+
"logly",
|
|
28
|
+
"analytics",
|
|
29
|
+
"web-analytics",
|
|
30
|
+
"privacy",
|
|
31
|
+
"claude",
|
|
32
|
+
"cursor"
|
|
33
|
+
],
|
|
34
|
+
"homepage": "https://logly.uk/mcp/"
|
|
35
|
+
}
|