@infinitedusky/indusk-mcp 1.4.5 → 1.5.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.
|
@@ -95,7 +95,6 @@ export async function extensionsEnable(projectRoot, names) {
|
|
|
95
95
|
console.info(` ${name}: enabled (built-in)`);
|
|
96
96
|
runHook(projectRoot, name, "on_init");
|
|
97
97
|
installSkill(projectRoot, name);
|
|
98
|
-
installMcpServer(projectRoot, name);
|
|
99
98
|
continue;
|
|
100
99
|
}
|
|
101
100
|
console.info(` ${name}: not found — use 'extensions add ${name} --from <source>' for third-party`);
|
|
@@ -466,54 +465,6 @@ function runHook(projectRoot, name, hook) {
|
|
|
466
465
|
console.info(` ${name}: ${hook} hook failed`);
|
|
467
466
|
}
|
|
468
467
|
}
|
|
469
|
-
function installMcpServer(projectRoot, name) {
|
|
470
|
-
const extPath = join(extensionsDir(projectRoot), `${name}.json`);
|
|
471
|
-
const manifest = loadExtension(extPath);
|
|
472
|
-
if (!manifest?.mcp_server)
|
|
473
|
-
return;
|
|
474
|
-
const mcpJsonPath = join(projectRoot, ".mcp.json");
|
|
475
|
-
let mcpConfig = {};
|
|
476
|
-
if (existsSync(mcpJsonPath)) {
|
|
477
|
-
try {
|
|
478
|
-
mcpConfig = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
479
|
-
}
|
|
480
|
-
catch {
|
|
481
|
-
mcpConfig = {};
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
if (!mcpConfig.mcpServers)
|
|
485
|
-
mcpConfig.mcpServers = {};
|
|
486
|
-
if (mcpConfig.mcpServers[name]) {
|
|
487
|
-
console.info(` ${name}: .mcp.json entry already exists`);
|
|
488
|
-
}
|
|
489
|
-
else {
|
|
490
|
-
const serverConfig = {};
|
|
491
|
-
const srv = manifest.mcp_server;
|
|
492
|
-
if (srv.type)
|
|
493
|
-
serverConfig.type = srv.type;
|
|
494
|
-
if (srv.url)
|
|
495
|
-
serverConfig.url = srv.url;
|
|
496
|
-
if (srv.command)
|
|
497
|
-
serverConfig.command = srv.command;
|
|
498
|
-
if (srv.args)
|
|
499
|
-
serverConfig.args = srv.args;
|
|
500
|
-
if (srv.headers)
|
|
501
|
-
serverConfig.headers = srv.headers;
|
|
502
|
-
if (srv.env)
|
|
503
|
-
serverConfig.env = srv.env;
|
|
504
|
-
mcpConfig.mcpServers[name] = serverConfig;
|
|
505
|
-
writeFileSync(mcpJsonPath, JSON.stringify(mcpConfig, null, "\t") + "\n");
|
|
506
|
-
console.info(` ${name}: added to .mcp.json`);
|
|
507
|
-
}
|
|
508
|
-
// Print setup instructions if any
|
|
509
|
-
if (manifest.mcp_server.setup_instructions) {
|
|
510
|
-
console.info(`\n Setup required for ${name}:`);
|
|
511
|
-
for (const instruction of manifest.mcp_server.setup_instructions) {
|
|
512
|
-
console.info(` ${instruction}`);
|
|
513
|
-
}
|
|
514
|
-
console.info("");
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
468
|
function installSkill(projectRoot, name) {
|
|
518
469
|
const extPath = join(extensionsDir(projectRoot), `${name}.json`);
|
|
519
470
|
const manifest = loadExtension(extPath);
|
|
@@ -17,6 +17,20 @@ function run(cmd, options) {
|
|
|
17
17
|
return "";
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
+
function ensureGitignoreMcpJson(projectRoot) {
|
|
21
|
+
const gitignorePath = join(projectRoot, ".gitignore");
|
|
22
|
+
if (existsSync(gitignorePath)) {
|
|
23
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
24
|
+
if (content.includes(".mcp.json"))
|
|
25
|
+
return;
|
|
26
|
+
writeFileSync(gitignorePath, `${content.trimEnd()}\n\n# MCP config (contains auth tokens)\n.mcp.json\n`);
|
|
27
|
+
console.info(" updated: .gitignore (added .mcp.json)");
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
writeFileSync(gitignorePath, "# MCP config (contains auth tokens)\n.mcp.json\n");
|
|
31
|
+
console.info(" created: .gitignore (with .mcp.json)");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
20
34
|
function createCgcIgnore(projectRoot) {
|
|
21
35
|
const ignorePath = join(projectRoot, ".cgcignore");
|
|
22
36
|
if (existsSync(ignorePath)) {
|
|
@@ -101,56 +115,45 @@ export async function init(projectRoot, options = {}) {
|
|
|
101
115
|
mkdirSync(planningDir, { recursive: true });
|
|
102
116
|
console.info(" create: planning/");
|
|
103
117
|
}
|
|
104
|
-
// 4. Set up
|
|
118
|
+
// 4. Set up MCP servers via claude mcp add
|
|
105
119
|
console.info("\n[MCP config]");
|
|
120
|
+
// Check which servers already exist
|
|
106
121
|
const mcpJsonPath = join(projectRoot, ".mcp.json");
|
|
107
|
-
|
|
108
|
-
command: "npx",
|
|
109
|
-
args: ["@infinitedusky/indusk-mcp", "serve"],
|
|
110
|
-
env: { PROJECT_ROOT: "." },
|
|
111
|
-
};
|
|
112
|
-
const cgcEntry = {
|
|
113
|
-
command: "cgc",
|
|
114
|
-
args: ["mcp", "start"],
|
|
115
|
-
env: {
|
|
116
|
-
DATABASE_TYPE: "falkordb-remote",
|
|
117
|
-
FALKORDB_HOST: "falkordb.orb.local",
|
|
118
|
-
FALKORDB_GRAPH_NAME: projectName,
|
|
119
|
-
},
|
|
120
|
-
};
|
|
122
|
+
let existingServers = new Set();
|
|
121
123
|
if (existsSync(mcpJsonPath)) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (!existing.mcpServers.indusk || force) {
|
|
126
|
-
existing.mcpServers.indusk = induskEntry;
|
|
127
|
-
console.info(` ${existing.mcpServers.indusk ? "overwrite" : "add"}: .mcp.json indusk entry`);
|
|
128
|
-
updated = true;
|
|
124
|
+
try {
|
|
125
|
+
const existing = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
126
|
+
existingServers = new Set(Object.keys(existing.mcpServers || {}));
|
|
129
127
|
}
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
catch { }
|
|
129
|
+
}
|
|
130
|
+
// Add indusk MCP server (no secrets)
|
|
131
|
+
if (!existingServers.has("indusk") || force) {
|
|
132
|
+
try {
|
|
133
|
+
execSync(`claude mcp add -t stdio -s project -e PROJECT_ROOT=. -- indusk npx @infinitedusky/indusk-mcp serve`, { cwd: projectRoot, stdio: "pipe", timeout: 10000 });
|
|
134
|
+
console.info(" added: indusk MCP server (via claude mcp add)");
|
|
132
135
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
console.info(
|
|
136
|
-
updated = true;
|
|
136
|
+
catch {
|
|
137
|
+
console.info(" failed: could not add indusk MCP server — run manually:");
|
|
138
|
+
console.info(' claude mcp add -t stdio -s project -e PROJECT_ROOT=. -- indusk npx @infinitedusky/indusk-mcp serve');
|
|
137
139
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
console.info(" skip: indusk MCP server (already exists)");
|
|
143
|
+
}
|
|
144
|
+
// Add codegraphcontext MCP server (no secrets)
|
|
145
|
+
if (!existingServers.has("codegraphcontext") || force) {
|
|
146
|
+
try {
|
|
147
|
+
execSync(`claude mcp add -t stdio -s project -e DATABASE_TYPE=falkordb-remote -e FALKORDB_HOST=falkordb.orb.local -e FALKORDB_GRAPH_NAME=${projectName} -- codegraphcontext cgc mcp start`, { cwd: projectRoot, stdio: "pipe", timeout: 10000 });
|
|
148
|
+
console.info(` added: codegraphcontext MCP server (graph: ${projectName})`);
|
|
140
149
|
}
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
catch {
|
|
151
|
+
console.info(" failed: could not add codegraphcontext MCP server — run manually:");
|
|
152
|
+
console.info(` claude mcp add -t stdio -s project -e DATABASE_TYPE=falkordb-remote -e FALKORDB_HOST=falkordb.orb.local -e FALKORDB_GRAPH_NAME=${projectName} -- codegraphcontext cgc mcp start`);
|
|
143
153
|
}
|
|
144
154
|
}
|
|
145
155
|
else {
|
|
146
|
-
|
|
147
|
-
mcpServers: {
|
|
148
|
-
indusk: induskEntry,
|
|
149
|
-
codegraphcontext: cgcEntry,
|
|
150
|
-
},
|
|
151
|
-
};
|
|
152
|
-
writeFileSync(mcpJsonPath, `${JSON.stringify(mcpJson, null, "\t")}\n`);
|
|
153
|
-
console.info(" create: .mcp.json (indusk + codegraphcontext)");
|
|
156
|
+
console.info(" skip: codegraphcontext MCP server (already exists)");
|
|
154
157
|
}
|
|
155
158
|
// 5. Generate .vscode/settings.json
|
|
156
159
|
console.info("\n[Editor]");
|
|
@@ -255,6 +258,7 @@ export async function init(projectRoot, options = {}) {
|
|
|
255
258
|
}
|
|
256
259
|
// 8. Create .cgcignore (always overwrite — package-owned)
|
|
257
260
|
createCgcIgnore(projectRoot);
|
|
261
|
+
ensureGitignoreMcpJson(projectRoot);
|
|
258
262
|
// 9. Run on_init hooks from enabled extensions
|
|
259
263
|
console.info("\n[Extension Hooks]");
|
|
260
264
|
const { getEnabledExtensions } = await import("../../lib/extension-loader.js");
|
|
@@ -278,43 +282,9 @@ export async function init(projectRoot, options = {}) {
|
|
|
278
282
|
console.info(` ${ext.manifest.name}: ${result.slice(0, 100)}`);
|
|
279
283
|
}
|
|
280
284
|
}
|
|
281
|
-
// Print
|
|
282
|
-
if (ext.manifest.mcp_server) {
|
|
283
|
-
|
|
284
|
-
let hasMcpEntry = false;
|
|
285
|
-
if (existsSync(mcpJsonPath)) {
|
|
286
|
-
try {
|
|
287
|
-
const mcpConfig = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
288
|
-
hasMcpEntry = !!mcpConfig?.mcpServers?.[ext.manifest.name];
|
|
289
|
-
}
|
|
290
|
-
catch { }
|
|
291
|
-
}
|
|
292
|
-
if (!hasMcpEntry) {
|
|
293
|
-
const srv = ext.manifest.mcp_server;
|
|
294
|
-
const config = {};
|
|
295
|
-
if (srv.type)
|
|
296
|
-
config.type = srv.type;
|
|
297
|
-
if (srv.url)
|
|
298
|
-
config.url = srv.url;
|
|
299
|
-
if (srv.command)
|
|
300
|
-
config.command = srv.command;
|
|
301
|
-
if (srv.args)
|
|
302
|
-
config.args = srv.args;
|
|
303
|
-
if (srv.headers)
|
|
304
|
-
config.headers = srv.headers;
|
|
305
|
-
if (srv.env)
|
|
306
|
-
config.env = srv.env;
|
|
307
|
-
console.info(`\n ${ext.manifest.name}: add this to .mcp.json:\n`);
|
|
308
|
-
console.info(` "${ext.manifest.name}": ${JSON.stringify(config, null, " ")}\n`);
|
|
309
|
-
if (srv.setup_instructions) {
|
|
310
|
-
for (const instruction of srv.setup_instructions) {
|
|
311
|
-
console.info(` ${instruction}`);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
console.info(` ${ext.manifest.name}: .mcp.json entry exists`);
|
|
317
|
-
}
|
|
285
|
+
// Print setup instructions for extensions with mcp_server
|
|
286
|
+
if (ext.manifest.mcp_server?.setup_instructions) {
|
|
287
|
+
console.info(`\n ${ext.manifest.name}: MCP server setup needed — see .claude/skills/${ext.manifest.name}/SKILL.md for instructions`);
|
|
318
288
|
}
|
|
319
289
|
}
|
|
320
290
|
if (enabledExts.length === 0) {
|
|
@@ -180,41 +180,10 @@ export async function update(projectRoot) {
|
|
|
180
180
|
cpSync(builtinSkill, targetSkill);
|
|
181
181
|
console.info(` added: ${name} skill`);
|
|
182
182
|
}
|
|
183
|
-
// Print
|
|
183
|
+
// Print setup reference for extensions with mcp_server
|
|
184
184
|
const manifest = loadExtension(enabledManifest);
|
|
185
|
-
if (manifest?.mcp_server) {
|
|
186
|
-
|
|
187
|
-
let hasMcpEntry = false;
|
|
188
|
-
if (existsSync(mcpJsonPath)) {
|
|
189
|
-
try {
|
|
190
|
-
const mcpConfig = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
|
|
191
|
-
hasMcpEntry = !!mcpConfig?.mcpServers?.[name];
|
|
192
|
-
}
|
|
193
|
-
catch { }
|
|
194
|
-
}
|
|
195
|
-
if (!hasMcpEntry) {
|
|
196
|
-
const srv = manifest.mcp_server;
|
|
197
|
-
const config = {};
|
|
198
|
-
if (srv.type)
|
|
199
|
-
config.type = srv.type;
|
|
200
|
-
if (srv.url)
|
|
201
|
-
config.url = srv.url;
|
|
202
|
-
if (srv.command)
|
|
203
|
-
config.command = srv.command;
|
|
204
|
-
if (srv.args)
|
|
205
|
-
config.args = srv.args;
|
|
206
|
-
if (srv.headers)
|
|
207
|
-
config.headers = srv.headers;
|
|
208
|
-
if (srv.env)
|
|
209
|
-
config.env = srv.env;
|
|
210
|
-
console.info(`\n ${name}: add this to .mcp.json:\n`);
|
|
211
|
-
console.info(` "${name}": ${JSON.stringify(config, null, " ")}\n`);
|
|
212
|
-
if (srv.setup_instructions) {
|
|
213
|
-
for (const instruction of srv.setup_instructions) {
|
|
214
|
-
console.info(` ${instruction}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
185
|
+
if (manifest?.mcp_server?.setup_instructions) {
|
|
186
|
+
console.info(` ${name}: MCP server setup — see .claude/skills/${name}/SKILL.md`);
|
|
218
187
|
}
|
|
219
188
|
}
|
|
220
189
|
console.info(`\n${extUpdated} updated, ${extCurrent} current.`);
|
|
@@ -14,53 +14,151 @@ Dash0 provides access to your OpenTelemetry data — logs, traces, and metrics
|
|
|
14
14
|
- Installed via `brew install dash0hq/dash0-cli/dash0`
|
|
15
15
|
- Auto-detects Claude Code and enables agent mode (JSON output, no prompts)
|
|
16
16
|
- Use for: log queries, trace lookups, PromQL metrics, dashboard management, asset deployment
|
|
17
|
+
- **All query commands require `--experimental` flag**
|
|
17
18
|
- Key commands:
|
|
18
|
-
- `dash0 logs query` — search logs
|
|
19
|
-
- `dash0 traces get <trace-id>` — fetch trace details
|
|
20
|
-
- `dash0 metrics instant --query 'sum(...)'` — PromQL queries
|
|
19
|
+
- `dash0 --experimental logs query --from now-1h` — search logs (default time range is very narrow, always specify `--from`)
|
|
20
|
+
- `dash0 --experimental traces get <trace-id>` — fetch trace details by ID (no search/query for traces — use logs to find trace IDs first)
|
|
21
|
+
- `dash0 --experimental metrics instant --query 'sum(...)'` — PromQL queries
|
|
21
22
|
- `dash0 dashboards list` — view dashboards
|
|
22
23
|
- `dash0 apply -f assets.yaml` — deploy dashboards, views, checks (GitOps)
|
|
23
24
|
|
|
24
25
|
## When to Use Dash0
|
|
25
26
|
|
|
26
|
-
- **Test failures**: query recent traces to see what happened in the service during the test
|
|
27
|
+
- **Test failures**: query recent logs/traces to see what happened in the service during the test
|
|
27
28
|
- **Debugging production issues**: search logs for errors, find related traces by trace ID
|
|
28
29
|
- **Performance investigation**: query metrics (PromQL) to check latency, throughput, error rates
|
|
29
30
|
- **Deployment verification**: check traces and error rates after deploying a change
|
|
30
31
|
- **During /work verification**: if a verification step involves checking service health, query Dash0
|
|
31
32
|
- **Dashboard management**: use the CLI to create/update dashboards from YAML definitions
|
|
32
33
|
|
|
34
|
+
## MCP Tools Reference
|
|
35
|
+
|
|
36
|
+
The MCP server provides 23 tools. The key ones for debugging:
|
|
37
|
+
|
|
38
|
+
### Logs
|
|
39
|
+
- **`getLogRecords`** — Query logs with filters, time range, pagination. Returns summary table.
|
|
40
|
+
- Always pass `dataset: "dev"` for our environment
|
|
41
|
+
- `timeRange` requires ISO timestamps: `{"from": "...", "to": "..."}`
|
|
42
|
+
- `filters`: `[{"key": "service.name", "operator": "is", "value": "game-server"}]`
|
|
43
|
+
- `logAttributeKeys`: specify which attributes to show in the table (e.g. `["service.name", "otel.scope.name"]`)
|
|
44
|
+
- Returns log record IDs for drilling into full details
|
|
45
|
+
- **`getFullLogRecord`** — Get ALL attributes of a single log record by ID. Use this to see custom attributes (roomCode, walletAddress, agent name, etc.) that aren't in the summary table.
|
|
46
|
+
- **`getLogCorrelations`** — Find patterns and correlations in logs
|
|
47
|
+
|
|
48
|
+
### Traces
|
|
49
|
+
- **`getSpans`** — Search for spans (traces) with filters and time range
|
|
50
|
+
- **`getTraceDetails`** — Get full trace tree by trace ID, including hierarchy, events, and comparison to similar spans
|
|
51
|
+
- **`getSpanCorrelations`** — Find patterns in spans
|
|
52
|
+
|
|
53
|
+
### Services
|
|
54
|
+
- **`getServiceCatalog`** — All services with RED metrics (requests, errors, duration) and dependency map
|
|
55
|
+
- **`getServiceDetails`** — Deep dive into a single service
|
|
56
|
+
|
|
57
|
+
### Metrics
|
|
58
|
+
- **`promql`** — Run PromQL queries
|
|
59
|
+
- **`getMetricCatalog`** — List available metrics
|
|
60
|
+
- **`getMetricDetails`** — Details on a specific metric
|
|
61
|
+
|
|
62
|
+
### Other
|
|
63
|
+
- **`getAttributeKeys`** / **`getAttributeValues`** — Discover what attributes exist in the data
|
|
64
|
+
- **`listDashboards`** / **`listDatasets`** — List dashboards and datasets
|
|
65
|
+
- **`getFailedChecks`** / **`getFailedCheckDetails`** — View check failures
|
|
66
|
+
- **`searchKnowledgeBase`** — Search Dash0 documentation
|
|
67
|
+
|
|
68
|
+
### MCP Usage Pattern
|
|
69
|
+
```
|
|
70
|
+
1. getLogRecords → find the log summary, get log record IDs
|
|
71
|
+
2. getFullLogRecord → drill into a specific log for all attributes
|
|
72
|
+
3. If log has traceId → getTraceDetails to see the full request chain
|
|
73
|
+
4. getServiceCatalog → see all services, error rates, dependencies
|
|
74
|
+
```
|
|
75
|
+
|
|
33
76
|
## When to Use MCP vs CLI
|
|
34
77
|
|
|
35
78
|
| Task | Use |
|
|
36
79
|
|------|-----|
|
|
37
|
-
| Query logs during a session | MCP
|
|
38
|
-
|
|
|
80
|
+
| Query logs during a session | MCP `getLogRecords` (preferred) or CLI |
|
|
81
|
+
| Get full log details with all attributes | MCP `getFullLogRecord` (by log record ID) |
|
|
82
|
+
| Search traces by service or ID | MCP `getSpans` or CLI `traces get <id>` |
|
|
83
|
+
| Get full trace hierarchy | MCP `getTraceDetails` (preferred) |
|
|
39
84
|
| Run PromQL metrics query | Either — MCP for simple, CLI for complex |
|
|
40
85
|
| Deploy dashboard from YAML | CLI (`dash0 apply -f`) |
|
|
41
|
-
| Diagnose a failing service | MCP
|
|
86
|
+
| Diagnose a failing service | MCP `getServiceCatalog` → `getLogRecords` → `getFullLogRecord` |
|
|
42
87
|
| CI/CD observability checks | CLI (scriptable, agent mode) |
|
|
43
|
-
|
|
|
88
|
+
| Discover available attributes | MCP `getAttributeKeys` / `getAttributeValues` |
|
|
89
|
+
|
|
90
|
+
## CLI Usage Patterns
|
|
91
|
+
|
|
92
|
+
### Query logs
|
|
93
|
+
```bash
|
|
94
|
+
# Always use --experimental and --from (default range is too narrow)
|
|
95
|
+
source ~/.zshrc # ensure DASH0_API_TOKEN is available
|
|
96
|
+
dash0 --experimental logs query --from now-1h --limit 10
|
|
97
|
+
|
|
98
|
+
# Filter by service
|
|
99
|
+
dash0 --experimental logs query --from now-1h --filter "service.name is game-server"
|
|
100
|
+
|
|
101
|
+
# Filter by severity
|
|
102
|
+
dash0 --experimental logs query --from now-1h --filter "otel.log.severity.range is_one_of ERROR WARN"
|
|
103
|
+
|
|
104
|
+
# CSV output for readability
|
|
105
|
+
dash0 --experimental logs query --from now-1h -o csv
|
|
106
|
+
|
|
107
|
+
# Include custom columns
|
|
108
|
+
dash0 --experimental logs query --from now-1h -o csv \
|
|
109
|
+
--column time --column severity --column service.name --column body
|
|
110
|
+
|
|
111
|
+
# JSON output (OTLP format)
|
|
112
|
+
dash0 --experimental logs query --from now-1h -o json --limit 5
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Get trace details
|
|
116
|
+
```bash
|
|
117
|
+
# Traces don't have a search/query — you need a trace ID
|
|
118
|
+
# Get trace IDs from logs first, then fetch the trace:
|
|
119
|
+
dash0 --experimental traces get <trace-id>
|
|
120
|
+
|
|
121
|
+
# Follow span links to related traces
|
|
122
|
+
dash0 --experimental traces get <trace-id> --follow-span-links
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Authentication
|
|
126
|
+
The CLI uses profiles. If auth fails, ensure the profile has the token:
|
|
127
|
+
```bash
|
|
128
|
+
dash0 config profiles list # check existing profiles
|
|
129
|
+
dash0 config profiles create dev \
|
|
130
|
+
--api-url https://api.europe-west4.gcp.dash0.com \
|
|
131
|
+
--auth-token $DASH0_API_TOKEN \
|
|
132
|
+
--dataset dev
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If the profile exists but auth still fails, pass `--auth-token` explicitly:
|
|
136
|
+
```bash
|
|
137
|
+
dash0 --experimental logs query --auth-token "$DASH0_API_TOKEN" \
|
|
138
|
+
--api-url "https://api.europe-west4.gcp.dash0.com" \
|
|
139
|
+
--dataset dev --from now-1h
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Important:** Claude Code's shell may not have `DASH0_API_TOKEN` loaded. Run `source ~/.zshrc` before any `dash0` command if you get auth errors.
|
|
44
143
|
|
|
45
144
|
## Setup
|
|
46
145
|
|
|
47
|
-
### MCP Server
|
|
146
|
+
### MCP Server
|
|
48
147
|
|
|
49
148
|
**Important:** The Dash0 MCP server is a remote hosted service, not an npm package. Do not use `npx` or install anything for the MCP server. You only need a URL and an auth token.
|
|
50
149
|
|
|
51
|
-
|
|
150
|
+
Add the MCP server via the Claude Code CLI:
|
|
52
151
|
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"Authorization": "Bearer YOUR_AUTH_TOKEN"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
152
|
+
```bash
|
|
153
|
+
source ~/.zshrc # ensure DASH0_API_TOKEN is available
|
|
154
|
+
claude mcp add -t http -s project \
|
|
155
|
+
-H "Authorization: Bearer $DASH0_API_TOKEN" \
|
|
156
|
+
-- dash0 "https://api.YOUR_REGION.dash0.com/mcp"
|
|
61
157
|
```
|
|
62
158
|
|
|
63
|
-
|
|
159
|
+
**Important:** The type is `http` (not `streamable-http` or `streamableHttp`). Get your auth token from Dash0: Organization Settings > Auth Tokens. The URL is your Dash0 API endpoint + `/mcp`.
|
|
160
|
+
|
|
161
|
+
**Never manually edit `.mcp.json`** — always use `claude mcp add`.
|
|
64
162
|
|
|
65
163
|
### CLI
|
|
66
164
|
|
|
@@ -69,8 +167,9 @@ brew tap dash0hq/dash0-cli https://github.com/dash0hq/dash0-cli
|
|
|
69
167
|
brew install dash0hq/dash0-cli/dash0
|
|
70
168
|
|
|
71
169
|
dash0 config profiles create dev \
|
|
72
|
-
--api-url https://api.
|
|
73
|
-
--auth-token YOUR_AUTH_TOKEN
|
|
170
|
+
--api-url https://api.europe-west4.gcp.dash0.com \
|
|
171
|
+
--auth-token YOUR_AUTH_TOKEN \
|
|
172
|
+
--dataset dev
|
|
74
173
|
```
|
|
75
174
|
|
|
76
175
|
The CLI auto-detects Claude Code sessions and switches to agent mode (JSON output, no confirmation prompts, structured errors on stderr).
|
|
@@ -79,14 +178,13 @@ The CLI auto-detects Claude Code sessions and switches to agent mode (JSON outpu
|
|
|
79
178
|
|
|
80
179
|
### During verification
|
|
81
180
|
When a verification step involves checking that a service is working correctly, don't just check the HTTP status — query Dash0 for:
|
|
82
|
-
- Recent error
|
|
83
|
-
- Error rate metrics before and after your change
|
|
181
|
+
- Recent error logs for the service: `dash0 --experimental logs query --from now-15m --filter "service.name is game-server" --filter "otel.log.severity.range is_one_of ERROR WARN"`
|
|
84
182
|
- Log entries matching the feature you modified
|
|
85
183
|
|
|
86
184
|
### During debugging
|
|
87
185
|
When something fails:
|
|
88
|
-
1. Check logs first —
|
|
89
|
-
2. Find the trace —
|
|
186
|
+
1. Check logs first — `dash0 --experimental logs query --from now-1h --filter "otel.log.severity.range is_one_of ERROR WARN" -o csv`
|
|
187
|
+
2. Find the trace — look for trace IDs in log entries, then `dash0 --experimental traces get <trace-id>`
|
|
90
188
|
3. Check metrics — is this a new problem or an existing one? Compare error rates over time.
|
|
91
189
|
|
|
92
190
|
### During retrospective
|
|
@@ -98,3 +196,10 @@ Query Dash0 for metrics that show the impact of the plan:
|
|
|
98
196
|
## Connecting to OpenTelemetry
|
|
99
197
|
|
|
100
198
|
Dash0 ingests standard OpenTelemetry data. If your services already export OTLP telemetry, point the OTLP exporter at Dash0's endpoint. See [Dash0 docs](https://www.dash0.com/documentation/dash0) for setup per language.
|
|
199
|
+
|
|
200
|
+
## Known Issues
|
|
201
|
+
|
|
202
|
+
- **CLI `--experimental` required**: All query commands (logs, traces, metrics) require the `--experimental` flag. This will change when these commands become stable.
|
|
203
|
+
- **Default time range is narrow**: Always specify `--from` when querying logs. Without it, you may get empty results.
|
|
204
|
+
- **No trace search**: The CLI can only fetch traces by ID (`traces get <id>`), not search for them. Find trace IDs in log entries first.
|
|
205
|
+
- **Profile auth may not load in Claude Code shell**: Run `source ~/.zshrc` before `dash0` commands if auth fails.
|