cubeapm-mcp 1.0.1 → 1.1.1
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/README.md +81 -13
- package/dist/index.js +89 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,7 +68,8 @@ You can now ask Claude questions like:
|
|
|
68
68
|
|
|
69
69
|
| Environment Variable | Default | Description |
|
|
70
70
|
|---------------------|---------|-------------|
|
|
71
|
-
| `
|
|
71
|
+
| `CUBEAPM_URL` | - | Full URL to CubeAPM (e.g., `https://cube.example.com`). Takes precedence over HOST/PORT settings. |
|
|
72
|
+
| `CUBEAPM_HOST` | `localhost` | CubeAPM server hostname or IP (used if CUBEAPM_URL not set) |
|
|
72
73
|
| `CUBEAPM_QUERY_PORT` | `3140` | Port for querying APIs (traces, metrics, logs) |
|
|
73
74
|
| `CUBEAPM_INGEST_PORT` | `3130` | Port for ingestion APIs |
|
|
74
75
|
|
|
@@ -89,7 +90,22 @@ You can now ask Claude questions like:
|
|
|
89
90
|
}
|
|
90
91
|
```
|
|
91
92
|
|
|
92
|
-
**Production:**
|
|
93
|
+
**Production (with full URL):**
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"mcpServers": {
|
|
97
|
+
"cubeapm": {
|
|
98
|
+
"command": "npx",
|
|
99
|
+
"args": ["-y", "cubeapm-mcp"],
|
|
100
|
+
"env": {
|
|
101
|
+
"CUBEAPM_URL": "https://cubeapm.internal.company.com"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Production (with host/port):**
|
|
93
109
|
```json
|
|
94
110
|
{
|
|
95
111
|
"mcpServers": {
|
|
@@ -143,12 +159,16 @@ You can now ask Claude questions like:
|
|
|
143
159
|
| `search_traces` | Search traces by service, environment, or custom query |
|
|
144
160
|
| `get_trace` | Fetch complete trace details by trace ID |
|
|
145
161
|
|
|
146
|
-
**Search Parameters:**
|
|
147
|
-
- `query` -
|
|
148
|
-
- `env` - Environment filter (
|
|
149
|
-
- `service` - Service name filter
|
|
150
|
-
- `start` / `end` - Time range
|
|
162
|
+
**Search Parameters (Required):**
|
|
163
|
+
- `query` - Search query (default: `*` for wildcard)
|
|
164
|
+
- `env` - Environment filter (default: `UNSET`)
|
|
165
|
+
- `service` - Service name filter (**required**, case-sensitive)
|
|
166
|
+
- `start` / `end` - Time range (RFC3339 or Unix timestamp)
|
|
167
|
+
|
|
168
|
+
**Search Parameters (Optional):**
|
|
151
169
|
- `limit` - Maximum results (default: 20)
|
|
170
|
+
- `spanKind` - Filter by span type: `server`, `client`, `consumer`, `producer`
|
|
171
|
+
- `sortBy` - Sort by: `duration` (useful for finding slow traces)
|
|
152
172
|
|
|
153
173
|
**Get Trace Parameters:**
|
|
154
174
|
- `trace_id` - Hex-encoded trace ID
|
|
@@ -160,20 +180,68 @@ You can now ask Claude questions like:
|
|
|
160
180
|
|------|-------------|
|
|
161
181
|
| `ingest_metrics_prometheus` | Send metrics in Prometheus text exposition format |
|
|
162
182
|
|
|
183
|
+
## CubeAPM Query Patterns
|
|
184
|
+
|
|
185
|
+
### Metrics Naming Conventions
|
|
186
|
+
|
|
187
|
+
CubeAPM uses specific naming conventions that differ from standard OpenTelemetry:
|
|
188
|
+
|
|
189
|
+
| What | CubeAPM Convention |
|
|
190
|
+
|------|-------------------|
|
|
191
|
+
| Metric prefix | `cube_apm_*` (e.g., `cube_apm_calls_total`, `cube_apm_latency_bucket`) |
|
|
192
|
+
| Service label | `service` (NOT `server` or `service_name`) |
|
|
193
|
+
| Common labels | `env`, `service`, `span_kind`, `status_code`, `http_code` |
|
|
194
|
+
|
|
195
|
+
### Histogram Queries (P50, P90, P95, P99)
|
|
196
|
+
|
|
197
|
+
CubeAPM uses **VictoriaMetrics-style histograms** with `vmrange` labels instead of Prometheus `le` buckets:
|
|
198
|
+
|
|
199
|
+
```promql
|
|
200
|
+
# ✅ Correct - Use histogram_quantiles() with vmrange
|
|
201
|
+
histogram_quantiles("phi", 0.95, sum by (vmrange, service) (
|
|
202
|
+
increase(cube_apm_latency_bucket{service="MyService", span_kind="server"}[5m])
|
|
203
|
+
))
|
|
204
|
+
|
|
205
|
+
# ❌ Wrong - Standard Prometheus syntax won't work
|
|
206
|
+
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_bucket[5m])))
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
> **Note:** Latency values are returned in **seconds** (0.05 = 50ms)
|
|
210
|
+
|
|
211
|
+
### Logs Label Discovery
|
|
212
|
+
|
|
213
|
+
Log labels vary by source. Use `*` query first to discover available labels:
|
|
214
|
+
|
|
215
|
+
| Source | Common Labels |
|
|
216
|
+
|--------|---------------|
|
|
217
|
+
| Lambda functions | `faas.name`, `faas.arn`, `env`, `aws.lambda_request_id` |
|
|
218
|
+
| Services | `service_name`, `level`, `host` |
|
|
219
|
+
|
|
220
|
+
```logsql
|
|
221
|
+
# Discover all labels
|
|
222
|
+
*
|
|
223
|
+
|
|
224
|
+
# Lambda function logs
|
|
225
|
+
{faas.name="my-lambda-prod"}
|
|
226
|
+
|
|
227
|
+
# Search with text filter
|
|
228
|
+
{faas.name=~".*-prod"} AND "error"
|
|
229
|
+
```
|
|
230
|
+
|
|
163
231
|
## Example Queries
|
|
164
232
|
|
|
165
233
|
### Logs
|
|
166
234
|
```
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"Query logs
|
|
235
|
+
"Show me logs from webhook-lambda-prod"
|
|
236
|
+
"Find all logs containing 'timeout' in the last hour"
|
|
237
|
+
"Query logs from Lambda functions in production"
|
|
170
238
|
```
|
|
171
239
|
|
|
172
240
|
### Metrics
|
|
173
241
|
```
|
|
174
|
-
"What's the
|
|
175
|
-
"Show me
|
|
176
|
-
"
|
|
242
|
+
"What's the P95 latency for Kratos-Prod service?"
|
|
243
|
+
"Show me error rate for all services"
|
|
244
|
+
"List all available services in CubeAPM"
|
|
177
245
|
```
|
|
178
246
|
|
|
179
247
|
### Traces
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,27 @@ const server = new McpServer({
|
|
|
25
25
|
// ============================================
|
|
26
26
|
// LOGS APIs
|
|
27
27
|
// ============================================
|
|
28
|
-
server.tool("query_logs",
|
|
28
|
+
server.tool("query_logs", `Query logs from CubeAPM using LogsQL syntax (VictoriaLogs compatible). Returns log entries matching the query.
|
|
29
|
+
|
|
30
|
+
IMPORTANT - Log Label Discovery:
|
|
31
|
+
- Labels vary by source! Use "*" query first to discover available labels
|
|
32
|
+
- Lambda logs use: faas.name, faas.arn, env, aws.lambda_request_id
|
|
33
|
+
- Service logs may use: service_name, level, host
|
|
34
|
+
- NOT all sources have "service_name" - check the _stream field in results
|
|
35
|
+
|
|
36
|
+
LogsQL Query Syntax:
|
|
37
|
+
- Wildcard (discover labels): *
|
|
38
|
+
- Stream filters: {faas.name="my-lambda-prod"}
|
|
39
|
+
- Text search: {faas.name="webhook-lambda-prod"} AND "error"
|
|
40
|
+
- Regex match: {faas.name=~".*-prod"}
|
|
41
|
+
- Negation: {faas.name!="unwanted-service"}
|
|
42
|
+
- Combine filters: {env="UNSET", faas.name=~".*-lambda.*"}
|
|
43
|
+
|
|
44
|
+
Example queries:
|
|
45
|
+
- All logs (discover structure): *
|
|
46
|
+
- Lambda logs: {faas.name="webhook-lambda-prod"}
|
|
47
|
+
- Search errors: {faas.name=~".*"} AND "error"
|
|
48
|
+
- By environment: {env="production"}`, {
|
|
29
49
|
query: z.string().describe("The log search query including stream filters (LogsQL syntax)"),
|
|
30
50
|
start: z.string().describe("Start time in RFC3339 format (e.g., 2024-01-01T00:00:00Z) or Unix timestamp in seconds"),
|
|
31
51
|
end: z.string().describe("End time in RFC3339 format or Unix timestamp in seconds"),
|
|
@@ -68,7 +88,24 @@ server.tool("query_logs", "Query logs from CubeAPM using LogsQL syntax. Returns
|
|
|
68
88
|
// ============================================
|
|
69
89
|
// METRICS APIs
|
|
70
90
|
// ============================================
|
|
71
|
-
server.tool("query_metrics_instant",
|
|
91
|
+
server.tool("query_metrics_instant", `Execute an instant query against CubeAPM metrics at a single point in time. Uses PromQL-compatible syntax (VictoriaMetrics flavor).
|
|
92
|
+
|
|
93
|
+
IMPORTANT - CubeAPM Metric Naming Conventions:
|
|
94
|
+
- Metrics use "cube_apm_" prefix (e.g., cube_apm_calls_total, cube_apm_latency_bucket)
|
|
95
|
+
- Service label is "service" (NOT "server" or "service_name")
|
|
96
|
+
- Common labels: env, service, span_kind (server|client|consumer|producer), status_code, http_code
|
|
97
|
+
|
|
98
|
+
HISTOGRAM QUERIES (P50, P90, P95, P99):
|
|
99
|
+
- CubeAPM uses VictoriaMetrics-style histograms with "vmrange" label (NOT Prometheus "le" buckets)
|
|
100
|
+
- Use histogram_quantiles() function instead of histogram_quantile()
|
|
101
|
+
- Syntax: histogram_quantiles("phi", 0.95, sum by (vmrange) (increase(cube_apm_latency_bucket{...}[5m])))
|
|
102
|
+
- Latency values are returned in SECONDS (0.05 = 50ms)
|
|
103
|
+
|
|
104
|
+
Example queries:
|
|
105
|
+
- P95 latency: histogram_quantiles("phi", 0.95, sum by (vmrange, service) (increase(cube_apm_latency_bucket{service="MyService", span_kind="server"}[5m])))
|
|
106
|
+
- Error rate: sum by (service) (increase(cube_apm_calls_total{status_code="ERROR"}[1h])) / sum by (service) (increase(cube_apm_calls_total[1h])) * 100
|
|
107
|
+
- List services: count by (service) (cube_apm_calls_total{env="UNSET"})
|
|
108
|
+
- Request count: sum by (service) (increase(cube_apm_calls_total{span_kind=~"server|consumer"}[1h]))`, {
|
|
72
109
|
query: z.string().describe("The metrics query expression (PromQL syntax)"),
|
|
73
110
|
time: z.string().describe("Evaluation timestamp in RFC3339 format or Unix timestamp in seconds"),
|
|
74
111
|
step: z.number().optional().describe("Time window in seconds for processing data"),
|
|
@@ -104,7 +141,21 @@ server.tool("query_metrics_instant", "Execute an instant query against CubeAPM m
|
|
|
104
141
|
],
|
|
105
142
|
};
|
|
106
143
|
});
|
|
107
|
-
server.tool("query_metrics_range",
|
|
144
|
+
server.tool("query_metrics_range", `Execute a range query against CubeAPM metrics over a time range. Returns time series data. Uses PromQL-compatible syntax (VictoriaMetrics flavor).
|
|
145
|
+
|
|
146
|
+
IMPORTANT - CubeAPM Metric Naming Conventions:
|
|
147
|
+
- Metrics use "cube_apm_" prefix (e.g., cube_apm_calls_total, cube_apm_latency_bucket)
|
|
148
|
+
- Service label is "service" (NOT "server" or "service_name")
|
|
149
|
+
- Common labels: env, service, span_kind (server|client|consumer|producer), status_code, http_code
|
|
150
|
+
|
|
151
|
+
HISTOGRAM QUERIES (P50, P90, P95, P99):
|
|
152
|
+
- CubeAPM uses VictoriaMetrics-style histograms with "vmrange" label (NOT Prometheus "le" buckets)
|
|
153
|
+
- Use histogram_quantiles() function instead of histogram_quantile()
|
|
154
|
+
- Syntax: histogram_quantiles("phi", 0.95, sum by (vmrange, service) (increase(cube_apm_latency_bucket{...}[5m])))
|
|
155
|
+
- Latency values are returned in SECONDS (0.05 = 50ms)
|
|
156
|
+
|
|
157
|
+
Example range query for P95 over time:
|
|
158
|
+
histogram_quantiles("phi", 0.95, sum by (vmrange, service) (increase(cube_apm_latency_bucket{service="MyService", span_kind="server"}[5m])))`, {
|
|
108
159
|
query: z.string().describe("The metrics query expression (PromQL syntax)"),
|
|
109
160
|
start: z.string().describe("Start timestamp in RFC3339 format or Unix timestamp"),
|
|
110
161
|
end: z.string().describe("End timestamp in RFC3339 format or Unix timestamp"),
|
|
@@ -147,21 +198,44 @@ server.tool("query_metrics_range", "Execute a range query against CubeAPM metric
|
|
|
147
198
|
// ============================================
|
|
148
199
|
// TRACES APIs
|
|
149
200
|
// ============================================
|
|
150
|
-
server.tool("search_traces",
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
201
|
+
server.tool("search_traces", `Search for traces in CubeAPM matching the specified criteria. Returns trace snippets with key spans.
|
|
202
|
+
|
|
203
|
+
IMPORTANT - Required Parameters:
|
|
204
|
+
- query, env, service, start, end are ALL REQUIRED by CubeAPM API
|
|
205
|
+
- Use query="*" for wildcard search
|
|
206
|
+
- Use env="UNSET" if environment is not configured
|
|
207
|
+
- Service names are case-sensitive (e.g., "Kratos-Prod" not "kratos")
|
|
208
|
+
|
|
209
|
+
Optional filters:
|
|
210
|
+
- spanKind: server, client, consumer, producer
|
|
211
|
+
- sortBy: duration (to find slow traces)
|
|
212
|
+
|
|
213
|
+
To discover available service names, first query metrics:
|
|
214
|
+
count by (service) (cube_apm_calls_total{env="UNSET"})
|
|
215
|
+
|
|
216
|
+
Example: Find slow server spans in Shopify-Prod
|
|
217
|
+
query="*", env="UNSET", service="Shopify-Prod", spanKind="server", sortBy="duration"`, {
|
|
218
|
+
query: z.string().default("*").describe("The traces search query (use * for wildcard)"),
|
|
219
|
+
env: z.string().default("UNSET").describe("Environment name (use UNSET if not configured)"),
|
|
220
|
+
service: z.string().describe("Service name to filter by (REQUIRED, case-sensitive)"),
|
|
154
221
|
start: z.string().describe("Start timestamp in RFC3339 format or Unix seconds"),
|
|
155
222
|
end: z.string().describe("End timestamp in RFC3339 format or Unix seconds"),
|
|
156
223
|
limit: z.number().optional().default(20).describe("Maximum number of traces to return"),
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
224
|
+
spanKind: z.string().optional().describe("Filter by span kind: server, client, consumer, producer"),
|
|
225
|
+
sortBy: z.string().optional().describe("Sort results by: duration"),
|
|
226
|
+
}, async ({ query, env, service, start, end, limit, spanKind, sortBy }) => {
|
|
227
|
+
const params = new URLSearchParams({
|
|
228
|
+
query,
|
|
229
|
+
env,
|
|
230
|
+
service,
|
|
231
|
+
start,
|
|
232
|
+
end,
|
|
233
|
+
limit: String(limit)
|
|
234
|
+
});
|
|
235
|
+
if (spanKind)
|
|
236
|
+
params.append("spanKind", spanKind);
|
|
237
|
+
if (sortBy)
|
|
238
|
+
params.append("sortBy", sortBy);
|
|
165
239
|
const response = await fetch(`${queryBaseUrl}/api/traces/api/v1/search?${params.toString()}`, { method: "GET" });
|
|
166
240
|
if (!response.ok) {
|
|
167
241
|
return {
|
package/package.json
CHANGED