@metrone-io/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/dist/index.d.ts +2 -0
- package/dist/index.js +153 -0
- package/package.json +32 -0
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var API_KEY = process.env.METRONE_API_KEY;
|
|
8
|
+
var ENDPOINT = process.env.METRONE_ENDPOINT ?? "https://api.metrone.io";
|
|
9
|
+
if (!API_KEY) {
|
|
10
|
+
console.error("METRONE_API_KEY environment variable is required");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
async function apiGet(path, params) {
|
|
14
|
+
const url = new URL(path, ENDPOINT);
|
|
15
|
+
if (params) {
|
|
16
|
+
for (const [k, v] of Object.entries(params)) {
|
|
17
|
+
if (v !== void 0 && v !== "") url.searchParams.set(k, v);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const res = await fetch(url.toString(), {
|
|
21
|
+
headers: { "X-Api-Key": API_KEY }
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
const body = await res.text();
|
|
25
|
+
throw new Error(`Metrone API error ${res.status}: ${body}`);
|
|
26
|
+
}
|
|
27
|
+
return res.json();
|
|
28
|
+
}
|
|
29
|
+
async function apiPost(path, body) {
|
|
30
|
+
const url = new URL(path, ENDPOINT);
|
|
31
|
+
const res = await fetch(url.toString(), {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers: { "X-Api-Key": API_KEY, "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify(body)
|
|
35
|
+
});
|
|
36
|
+
if (!res.ok) {
|
|
37
|
+
const text = await res.text();
|
|
38
|
+
throw new Error(`Metrone API error ${res.status}: ${text}`);
|
|
39
|
+
}
|
|
40
|
+
return res.json();
|
|
41
|
+
}
|
|
42
|
+
function textResult(data) {
|
|
43
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
44
|
+
}
|
|
45
|
+
var server = new McpServer({ name: "metrone", version: "1.0.0" });
|
|
46
|
+
server.tool(
|
|
47
|
+
"metrone_get_stats",
|
|
48
|
+
{
|
|
49
|
+
days: z.number().optional(),
|
|
50
|
+
from: z.string().optional(),
|
|
51
|
+
to: z.string().optional()
|
|
52
|
+
},
|
|
53
|
+
async ({ days, from, to }) => {
|
|
54
|
+
const params = {};
|
|
55
|
+
if (days !== void 0) params.days = String(days);
|
|
56
|
+
if (from) params.from = from;
|
|
57
|
+
if (to) params.to = to;
|
|
58
|
+
return textResult(await apiGet("/v1/api/stats", params));
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
server.tool(
|
|
62
|
+
"metrone_get_events",
|
|
63
|
+
{
|
|
64
|
+
days: z.number().optional(),
|
|
65
|
+
limit: z.number().optional(),
|
|
66
|
+
event_type: z.string().optional(),
|
|
67
|
+
source: z.string().optional()
|
|
68
|
+
},
|
|
69
|
+
async ({ days, limit, event_type, source }) => {
|
|
70
|
+
const params = {};
|
|
71
|
+
if (days !== void 0) params.days = String(days);
|
|
72
|
+
if (limit !== void 0) params.limit = String(limit);
|
|
73
|
+
if (event_type) params.event_type = event_type;
|
|
74
|
+
if (source) params.source = source;
|
|
75
|
+
return textResult(await apiGet("/v1/api/events", params));
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
server.tool(
|
|
79
|
+
"metrone_get_pages",
|
|
80
|
+
{
|
|
81
|
+
days: z.number().optional(),
|
|
82
|
+
limit: z.number().optional()
|
|
83
|
+
},
|
|
84
|
+
async ({ days, limit }) => {
|
|
85
|
+
const params = {};
|
|
86
|
+
if (days !== void 0) params.days = String(days);
|
|
87
|
+
if (limit !== void 0) params.limit = String(limit);
|
|
88
|
+
return textResult(await apiGet("/v1/api/pages", params));
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
server.tool(
|
|
92
|
+
"metrone_get_sources",
|
|
93
|
+
{ days: z.number().optional() },
|
|
94
|
+
async ({ days }) => {
|
|
95
|
+
const params = {};
|
|
96
|
+
if (days !== void 0) params.days = String(days);
|
|
97
|
+
return textResult(await apiGet("/v1/api/sources", params));
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
server.tool(
|
|
101
|
+
"metrone_get_live",
|
|
102
|
+
{},
|
|
103
|
+
async (_args) => textResult(await apiGet("/v1/api/live"))
|
|
104
|
+
);
|
|
105
|
+
server.tool(
|
|
106
|
+
"metrone_track_event",
|
|
107
|
+
{
|
|
108
|
+
event_type: z.string(),
|
|
109
|
+
source: z.string().optional(),
|
|
110
|
+
event_name: z.string().optional(),
|
|
111
|
+
page_url: z.string().optional(),
|
|
112
|
+
properties: z.record(z.string(), z.any()).optional()
|
|
113
|
+
},
|
|
114
|
+
async ({ event_type, source, event_name, page_url, properties }) => {
|
|
115
|
+
const payload = {
|
|
116
|
+
api_key: API_KEY,
|
|
117
|
+
event_type,
|
|
118
|
+
source: source ?? "assistant"
|
|
119
|
+
};
|
|
120
|
+
if (event_name) payload.event_name = event_name;
|
|
121
|
+
if (page_url) payload.page_url = page_url;
|
|
122
|
+
if (properties) payload.properties = properties;
|
|
123
|
+
return textResult(await apiPost("/v1/api/events", payload));
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
server.tool(
|
|
127
|
+
"metrone_track_ai_call",
|
|
128
|
+
{
|
|
129
|
+
call_id: z.string(),
|
|
130
|
+
provider: z.string(),
|
|
131
|
+
duration: z.number().optional(),
|
|
132
|
+
intent: z.string().optional(),
|
|
133
|
+
outcome: z.string().optional(),
|
|
134
|
+
properties: z.record(z.string(), z.any()).optional()
|
|
135
|
+
},
|
|
136
|
+
async ({ call_id, provider, duration, intent, outcome, properties }) => {
|
|
137
|
+
const payload = {
|
|
138
|
+
api_key: API_KEY,
|
|
139
|
+
event_type: "ai_call",
|
|
140
|
+
source: "voice",
|
|
141
|
+
ai_call_id: call_id,
|
|
142
|
+
ai_provider: provider
|
|
143
|
+
};
|
|
144
|
+
if (duration !== void 0) payload.ai_duration_sec = duration;
|
|
145
|
+
if (intent) payload.ai_intent = intent;
|
|
146
|
+
if (properties || outcome) {
|
|
147
|
+
payload.properties = { ...properties, ...outcome && { outcome } };
|
|
148
|
+
}
|
|
149
|
+
return textResult(await apiPost("/v1/api/events", payload));
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
var transport = new StdioServerTransport();
|
|
153
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@metrone-io/mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Metrone MCP server — expose analytics to AI agents via Model Context Protocol",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"metrone-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"dev": "tsup --watch",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"clean": "rimraf dist",
|
|
15
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
16
|
+
},
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
26
|
+
"zod": "^4.3.6"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"tsup": "^8.0.0",
|
|
30
|
+
"typescript": "^5.3.2"
|
|
31
|
+
}
|
|
32
|
+
}
|