@databrainhq/mcp-server 0.3.0-rc.13 → 0.3.0-rc.14
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/.mcp.json +6 -1
- package/dist/apps/server.d.ts +102 -389
- package/dist/apps/server.js +5 -5
- package/dist/apps/stdio.d.ts +1 -2
- package/dist/apps/stdio.js +6 -6
- package/dist/{bundle-TDQXWIPM.js → bundle-QJNCUMNY.js} +2 -2
- package/dist/{chunk-Q5EYDKSA.js → chunk-2F7V6RZR.js} +511 -107
- package/dist/chunk-2F7V6RZR.js.map +1 -0
- package/dist/{chunk-AEQTEE5C.js → chunk-AWICHHDU.js} +153 -61
- package/dist/chunk-AWICHHDU.js.map +1 -0
- package/dist/{chunk-X44C5GW2.js → chunk-CEGHG5U3.js} +59 -18
- package/dist/chunk-CEGHG5U3.js.map +1 -0
- package/dist/{chunk-233VGFHY.js → chunk-NIC5MAGC.js} +317 -147
- package/dist/chunk-NIC5MAGC.js.map +1 -0
- package/dist/{chunk-DTFYHLYN.js → chunk-S65KA3Z7.js} +26 -11
- package/dist/chunk-S65KA3Z7.js.map +1 -0
- package/dist/{chunk-PSJVYD4W.js → chunk-UYFFFAYV.js} +11722 -10560
- package/dist/chunk-UYFFFAYV.js.map +1 -0
- package/dist/{chunk-HCYZN7I3.js → chunk-VQ5G5AZV.js} +10 -7
- package/dist/chunk-VQ5G5AZV.js.map +1 -0
- package/dist/cli.d.ts +16 -15
- package/dist/cli.js +134 -36
- package/dist/cli.js.map +1 -1
- package/dist/custom-chart/custom-runtime.js +6 -6
- package/dist/custom-chart/template/chart.ts +116 -28
- package/dist/custom-chart/template/icon.svg +1 -1
- package/dist/custom-chart/template/manifest.json +66 -12
- package/dist/custom-chart/template/sample-data.json +21 -3
- package/dist/index.d.ts +1 -2
- package/dist/index.js +20 -10
- package/dist/index.js.map +1 -1
- package/dist/{main-VEKNKWL5.js → main-QCBVJSSR.js} +348 -155
- package/dist/main-QCBVJSSR.js.map +1 -0
- package/dist/{test-only-LJGOY2QA.js → test-only-6474NMTR.js} +12 -8
- package/dist/test-only-6474NMTR.js.map +1 -0
- package/package.json +20 -9
- package/dist/chunk-233VGFHY.js.map +0 -1
- package/dist/chunk-AEQTEE5C.js.map +0 -1
- package/dist/chunk-DTFYHLYN.js.map +0 -1
- package/dist/chunk-HCYZN7I3.js.map +0 -1
- package/dist/chunk-PSJVYD4W.js.map +0 -1
- package/dist/chunk-Q5EYDKSA.js.map +0 -1
- package/dist/chunk-X44C5GW2.js.map +0 -1
- package/dist/main-VEKNKWL5.js.map +0 -1
- package/dist/test-only-LJGOY2QA.js.map +0 -1
- /package/dist/{bundle-TDQXWIPM.js.map → bundle-QJNCUMNY.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isId,
|
|
4
4
|
readTemplateFiles,
|
|
5
5
|
validateManifest
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2F7V6RZR.js";
|
|
7
7
|
|
|
8
8
|
// src/utils/errors.ts
|
|
9
9
|
var DatabrainApiError = class extends Error {
|
|
@@ -36,9 +36,19 @@ var DatabrainApiError = class extends Error {
|
|
|
36
36
|
formatDetails() {
|
|
37
37
|
if (this.status < 400 || this.status >= 500) return "";
|
|
38
38
|
if (!this.details || typeof this.details !== "object") return "";
|
|
39
|
-
const skipKeys = /* @__PURE__ */ new Set([
|
|
39
|
+
const skipKeys = /* @__PURE__ */ new Set([
|
|
40
|
+
"message",
|
|
41
|
+
"detail",
|
|
42
|
+
"error",
|
|
43
|
+
"code",
|
|
44
|
+
"data",
|
|
45
|
+
"hint",
|
|
46
|
+
"retryable"
|
|
47
|
+
]);
|
|
40
48
|
const extra = {};
|
|
41
|
-
for (const [k, v] of Object.entries(
|
|
49
|
+
for (const [k, v] of Object.entries(
|
|
50
|
+
this.details
|
|
51
|
+
)) {
|
|
42
52
|
if (skipKeys.has(k)) continue;
|
|
43
53
|
if (v === null || v === void 0) continue;
|
|
44
54
|
extra[k] = v;
|
|
@@ -143,7 +153,8 @@ var logger = {
|
|
|
143
153
|
var package_default = {
|
|
144
154
|
name: "@databrainhq/mcp-server",
|
|
145
155
|
mcpName: "com.usedatabrain/mcp-server",
|
|
146
|
-
version: "0.3.0-rc.
|
|
156
|
+
version: "0.3.0-rc.14",
|
|
157
|
+
packageManager: "pnpm@12.3.4",
|
|
147
158
|
description: "MCP server for Databrain embedded analytics - connect databases, create datamarts, configure embeds, and generate frontend code",
|
|
148
159
|
type: "module",
|
|
149
160
|
bin: {
|
|
@@ -161,13 +172,16 @@ var package_default = {
|
|
|
161
172
|
".mcp.json"
|
|
162
173
|
],
|
|
163
174
|
scripts: {
|
|
164
|
-
build: "tsup && node scripts/copy-custom-chart-assets.mjs",
|
|
175
|
+
build: "tsup && node scripts/build-declarations.mjs && node scripts/copy-custom-chart-assets.mjs",
|
|
165
176
|
dev: "tsx src/index.ts",
|
|
166
177
|
test: "vitest run",
|
|
167
178
|
"test:watch": "vitest",
|
|
168
179
|
"test:live": "vitest run tests/integration/prompt-flows.test.ts",
|
|
169
|
-
lint: "
|
|
170
|
-
|
|
180
|
+
lint: "biome check .",
|
|
181
|
+
"lint:fix": "biome check --write .",
|
|
182
|
+
format: "biome format --write .",
|
|
183
|
+
typecheck: "tsc --noEmit",
|
|
184
|
+
prepublishOnly: "pnpm run build"
|
|
171
185
|
},
|
|
172
186
|
keywords: [
|
|
173
187
|
"mcp",
|
|
@@ -182,16 +196,23 @@ var package_default = {
|
|
|
182
196
|
"@posthog/mcp": "^0.10.7",
|
|
183
197
|
esbuild: "0.27.3",
|
|
184
198
|
fflate: "0.8.3",
|
|
185
|
-
"posthog-node": "
|
|
199
|
+
"posthog-node": "5.60.1",
|
|
186
200
|
yaml: "^2.9.1",
|
|
187
|
-
zod: "^
|
|
201
|
+
zod: "^4.1.12"
|
|
188
202
|
},
|
|
189
203
|
devDependencies: {
|
|
204
|
+
"@biomejs/biome": "2.5.15",
|
|
205
|
+
"@microsoft/api-extractor": "7.59.4",
|
|
190
206
|
"@types/node": "^25.3.5",
|
|
191
207
|
tsup: "^8.4.0",
|
|
192
208
|
tsx: "^4.19.0",
|
|
193
|
-
typescript: "
|
|
194
|
-
vitest: "^
|
|
209
|
+
typescript: "7.0.2",
|
|
210
|
+
vitest: "^4.1.12"
|
|
211
|
+
},
|
|
212
|
+
overrides: {
|
|
213
|
+
"@posthog/core": "1.61.2",
|
|
214
|
+
"@posthog/types": "1.418.0",
|
|
215
|
+
rollup: "4.66.0"
|
|
195
216
|
},
|
|
196
217
|
publishConfig: {
|
|
197
218
|
access: "public"
|
|
@@ -201,7 +222,7 @@ var package_default = {
|
|
|
201
222
|
url: "git+https://github.com/databrainhq/mcp-server.git"
|
|
202
223
|
},
|
|
203
224
|
engines: {
|
|
204
|
-
node: ">=
|
|
225
|
+
node: ">=20.0.0"
|
|
205
226
|
}
|
|
206
227
|
};
|
|
207
228
|
|
|
@@ -210,18 +231,25 @@ var MCP_SERVER_VERSION = package_default.version;
|
|
|
210
231
|
|
|
211
232
|
// src/custom-chart/studio.ts
|
|
212
233
|
import { z } from "zod";
|
|
213
|
-
var studioCell = z.union([
|
|
234
|
+
var studioCell = z.union([
|
|
235
|
+
z.string().max(4096),
|
|
236
|
+
z.number().finite(),
|
|
237
|
+
z.boolean(),
|
|
238
|
+
z.null()
|
|
239
|
+
]);
|
|
214
240
|
var studioDraftSchema = z.object({
|
|
215
241
|
code: z.string().max(64e3),
|
|
216
242
|
css: z.string().max(32e3),
|
|
217
|
-
manifest: z.record(z.unknown()),
|
|
243
|
+
manifest: z.record(z.string(), z.unknown()),
|
|
218
244
|
sampleData: z.object({
|
|
219
|
-
columns: z.array(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
245
|
+
columns: z.array(
|
|
246
|
+
z.object({
|
|
247
|
+
id: z.string(),
|
|
248
|
+
label: z.string(),
|
|
249
|
+
type: z.enum(["string", "number", "boolean"]),
|
|
250
|
+
slotId: z.string().optional()
|
|
251
|
+
}).strict()
|
|
252
|
+
).max(64),
|
|
225
253
|
rows: z.array(z.array(studioCell)).max(200)
|
|
226
254
|
}).strict(),
|
|
227
255
|
name: z.string().max(256),
|
|
@@ -237,7 +265,8 @@ function parseStudioStream(text) {
|
|
|
237
265
|
const line = frame.split(/\r?\n/).filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trimStart()).join("\n");
|
|
238
266
|
if (!line || line === "[DONE]") continue;
|
|
239
267
|
const event = JSON.parse(line);
|
|
240
|
-
if (event.type === "session" && typeof event.sessionId === "string")
|
|
268
|
+
if (event.type === "session" && typeof event.sessionId === "string")
|
|
269
|
+
sessionId = event.sessionId;
|
|
241
270
|
if (event.type === "error") failure = true;
|
|
242
271
|
if (event.type === "tool_execution_end" && event.name === "update_custom_chart" && event.status === "completed" && event.result?.kind === "applied") {
|
|
243
272
|
draft = studioDraftSchema.parse(event.result.draft);
|
|
@@ -247,7 +276,8 @@ function parseStudioStream(text) {
|
|
|
247
276
|
return { draft, sessionId, applied: !!draft };
|
|
248
277
|
}
|
|
249
278
|
async function editWithBryn(client, input) {
|
|
250
|
-
if (!client.isHosted())
|
|
279
|
+
if (!client.isHosted())
|
|
280
|
+
return { available: false, draft: input.draft, applied: false };
|
|
251
281
|
try {
|
|
252
282
|
const result = await client.request({
|
|
253
283
|
method: "POST",
|
|
@@ -265,7 +295,12 @@ async function editWithBryn(client, input) {
|
|
|
265
295
|
timeoutMs: 18e4,
|
|
266
296
|
noRetryOnTimeout: true
|
|
267
297
|
});
|
|
268
|
-
return {
|
|
298
|
+
return {
|
|
299
|
+
available: true,
|
|
300
|
+
draft: result.draft ?? input.draft,
|
|
301
|
+
applied: result.applied,
|
|
302
|
+
sessionId: result.sessionId
|
|
303
|
+
};
|
|
269
304
|
} catch (error) {
|
|
270
305
|
if (error instanceof DatabrainApiError && error.status === 404) {
|
|
271
306
|
return { available: false, draft: input.draft, applied: false };
|
|
@@ -301,6 +336,10 @@ var TtlCache = class {
|
|
|
301
336
|
}
|
|
302
337
|
};
|
|
303
338
|
|
|
339
|
+
// src/utils/tool-context.ts
|
|
340
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
341
|
+
var toolContext = new AsyncLocalStorage();
|
|
342
|
+
|
|
304
343
|
// src/client/error-body.ts
|
|
305
344
|
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
306
345
|
var str = (v) => typeof v === "string" && v.trim() ? v : void 0;
|
|
@@ -324,10 +363,6 @@ function parseErrorBody(body) {
|
|
|
324
363
|
return { message: str(body.error) };
|
|
325
364
|
}
|
|
326
365
|
|
|
327
|
-
// src/utils/tool-context.ts
|
|
328
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
329
|
-
var toolContext = new AsyncLocalStorage();
|
|
330
|
-
|
|
331
366
|
// src/client/oauth-client-credentials.ts
|
|
332
367
|
import { z as z2 } from "zod";
|
|
333
368
|
var oauthHttpsUrl = z2.string().refine((value) => {
|
|
@@ -367,7 +402,9 @@ var TOKEN_TIMEOUT_MS = 1e4;
|
|
|
367
402
|
var FAILURE_COOLDOWN_MS = 3e4;
|
|
368
403
|
var MAX_REFRESH_SKEW_MS = 6e4;
|
|
369
404
|
function authError() {
|
|
370
|
-
return new Error(
|
|
405
|
+
return new Error(
|
|
406
|
+
"OAuth token acquisition failed. Check the configured issuer, client credentials, resource and scopes."
|
|
407
|
+
);
|
|
371
408
|
}
|
|
372
409
|
var OAuthClientCredentials = class {
|
|
373
410
|
config;
|
|
@@ -386,7 +423,8 @@ var OAuthClientCredentials = class {
|
|
|
386
423
|
return "configured";
|
|
387
424
|
}
|
|
388
425
|
async getToken() {
|
|
389
|
-
if (this.cached && Date.now() < this.cached.renewAt)
|
|
426
|
+
if (this.cached && Date.now() < this.cached.renewAt)
|
|
427
|
+
return this.cached.value;
|
|
390
428
|
if (this.pending) return this.pending;
|
|
391
429
|
if (Date.now() < this.retryAt) throw authError();
|
|
392
430
|
this.cached = void 0;
|
|
@@ -402,11 +440,13 @@ var OAuthClientCredentials = class {
|
|
|
402
440
|
if (this.tokenEndpoint) return this.tokenEndpoint;
|
|
403
441
|
const issuer = new URL(this.config.issuer);
|
|
404
442
|
const path = issuer.pathname.replace(/\/$/, "");
|
|
405
|
-
const candidates = [
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
443
|
+
const candidates = [
|
|
444
|
+
.../* @__PURE__ */ new Set([
|
|
445
|
+
`${issuer.origin}/.well-known/oauth-authorization-server${path}`,
|
|
446
|
+
`${issuer.origin}/.well-known/openid-configuration${path}`,
|
|
447
|
+
`${issuer.origin}${path}/.well-known/openid-configuration`
|
|
448
|
+
])
|
|
449
|
+
];
|
|
410
450
|
for (const url of candidates) {
|
|
411
451
|
const response = await fetch(url, {
|
|
412
452
|
headers: { Accept: "application/json" },
|
|
@@ -417,7 +457,9 @@ var OAuthClientCredentials = class {
|
|
|
417
457
|
if (!response.ok) throw authError();
|
|
418
458
|
const metadata = metadataSchema.parse(await response.json());
|
|
419
459
|
if (metadata.issuer !== this.config.issuer) throw authError();
|
|
420
|
-
const methods = metadata.token_endpoint_auth_methods_supported ?? [
|
|
460
|
+
const methods = metadata.token_endpoint_auth_methods_supported ?? [
|
|
461
|
+
"client_secret_basic"
|
|
462
|
+
];
|
|
421
463
|
if (!methods.includes(this.config.authMethod)) throw authError();
|
|
422
464
|
if (metadata.grant_types_supported && !metadata.grant_types_supported.includes("client_credentials")) {
|
|
423
465
|
throw authError();
|
|
@@ -459,7 +501,8 @@ var OAuthClientCredentials = class {
|
|
|
459
501
|
if (token.expires_in !== void 0) {
|
|
460
502
|
const lifetimeMs = token.expires_in * 1e3;
|
|
461
503
|
const expiresAt = startedAt + lifetimeMs;
|
|
462
|
-
if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt)
|
|
504
|
+
if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt)
|
|
505
|
+
throw authError();
|
|
463
506
|
this.cached = {
|
|
464
507
|
value: token.access_token,
|
|
465
508
|
renewAt: expiresAt - Math.min(MAX_REFRESH_SKEW_MS, lifetimeMs * 0.1)
|
|
@@ -491,7 +534,9 @@ var DatabrainClient = class {
|
|
|
491
534
|
registerSecret(config.apiToken);
|
|
492
535
|
if (config.oauth) {
|
|
493
536
|
if (!oauthHttpsUrl.safeParse(config.apiUrl).success) {
|
|
494
|
-
throw new Error(
|
|
537
|
+
throw new Error(
|
|
538
|
+
"OAuth requires an HTTPS Databrain API URL without userinfo or fragments."
|
|
539
|
+
);
|
|
495
540
|
}
|
|
496
541
|
this.oauth = new OAuthClientCredentials(config.oauth);
|
|
497
542
|
this.config = Object.freeze({ ...config });
|
|
@@ -528,11 +573,16 @@ var DatabrainClient = class {
|
|
|
528
573
|
*/
|
|
529
574
|
getActiveAuth() {
|
|
530
575
|
if (this.oauth) {
|
|
531
|
-
if (this.oauthFallback)
|
|
532
|
-
|
|
576
|
+
if (this.oauthFallback)
|
|
577
|
+
return { source: "service-token", oauthFallback: true };
|
|
578
|
+
return {
|
|
579
|
+
source: "oauth-client-credentials",
|
|
580
|
+
status: this.oauth.getStatus()
|
|
581
|
+
};
|
|
533
582
|
}
|
|
534
583
|
if (this.config.serviceToken) return { source: "service-token" };
|
|
535
|
-
if (this.runtimeApiToken || this.config.apiToken)
|
|
584
|
+
if (this.runtimeApiToken || this.config.apiToken)
|
|
585
|
+
return { source: "api-token" };
|
|
536
586
|
return { source: "none" };
|
|
537
587
|
}
|
|
538
588
|
async getToken(auth) {
|
|
@@ -551,7 +601,10 @@ var DatabrainClient = class {
|
|
|
551
601
|
"OAuth token acquisition failed. Check the configured issuer, client credentials, resource and scopes."
|
|
552
602
|
);
|
|
553
603
|
}
|
|
554
|
-
if (!this.oauthFallback)
|
|
604
|
+
if (!this.oauthFallback)
|
|
605
|
+
logger.warn(
|
|
606
|
+
"OAuth unavailable; using the configured static service token."
|
|
607
|
+
);
|
|
555
608
|
this.oauthFallback = true;
|
|
556
609
|
}
|
|
557
610
|
}
|
|
@@ -639,7 +692,9 @@ var DatabrainClient = class {
|
|
|
639
692
|
);
|
|
640
693
|
}
|
|
641
694
|
const errorBody = await response.text();
|
|
642
|
-
logger.warn(
|
|
695
|
+
logger.warn(
|
|
696
|
+
`[API Error] ${options.method} ${options.path} status=${response.status} body=${errorBody.slice(0, 500)}`
|
|
697
|
+
);
|
|
643
698
|
let parsed = {};
|
|
644
699
|
try {
|
|
645
700
|
parsed = JSON.parse(errorBody);
|
|
@@ -657,11 +712,14 @@ var DatabrainClient = class {
|
|
|
657
712
|
);
|
|
658
713
|
const isTransient = envelope.retryable !== void 0 ? envelope.retryable && (response.status === 429 || response.status >= 500) : response.status === 429 || response.status >= 500 && !NON_TRANSIENT_PATTERNS.some((p) => errorMsg.includes(p));
|
|
659
714
|
if (isTransient && attempt < MAX_RETRIES) {
|
|
660
|
-
const delay = Math.min(1e3 *
|
|
661
|
-
logger.warn(
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
715
|
+
const delay = Math.min(1e3 * 2 ** (attempt - 1), 8e3);
|
|
716
|
+
logger.warn(
|
|
717
|
+
`Retrying in ${delay}ms (attempt ${attempt}/${MAX_RETRIES})`,
|
|
718
|
+
{
|
|
719
|
+
status: response.status,
|
|
720
|
+
path: options.path
|
|
721
|
+
}
|
|
722
|
+
);
|
|
665
723
|
await new Promise((r) => setTimeout(r, delay));
|
|
666
724
|
lastError = error;
|
|
667
725
|
continue;
|
|
@@ -683,8 +741,10 @@ var DatabrainClient = class {
|
|
|
683
741
|
} catch (err) {
|
|
684
742
|
if (err instanceof DatabrainApiError) throw err;
|
|
685
743
|
if (attempt < MAX_RETRIES && err?.name === "TimeoutError" && !options.noRetryOnTimeout) {
|
|
686
|
-
const delay = Math.min(1e3 *
|
|
687
|
-
logger.warn(`Request timed out, retrying in ${delay}ms`, {
|
|
744
|
+
const delay = Math.min(1e3 * 2 ** (attempt - 1), 8e3);
|
|
745
|
+
logger.warn(`Request timed out, retrying in ${delay}ms`, {
|
|
746
|
+
path: options.path
|
|
747
|
+
});
|
|
688
748
|
await new Promise((r) => setTimeout(r, delay));
|
|
689
749
|
lastError = err;
|
|
690
750
|
continue;
|
|
@@ -797,7 +857,12 @@ function apiProblems(err) {
|
|
|
797
857
|
}
|
|
798
858
|
function planUpload(key, existing, versionsKnown) {
|
|
799
859
|
if (!existing) {
|
|
800
|
-
return {
|
|
860
|
+
return {
|
|
861
|
+
action: "create chart",
|
|
862
|
+
key,
|
|
863
|
+
nextVersionNumber: 1,
|
|
864
|
+
summary: `will create chart custom:${key} (version 1, status private)`
|
|
865
|
+
};
|
|
801
866
|
}
|
|
802
867
|
const count = typeof versionsKnown === "number" ? versionsKnown : typeof existing.versionsCount === "number" ? existing.versionsCount : void 0;
|
|
803
868
|
const next = count !== void 0 ? count + 1 : NaN;
|
|
@@ -813,9 +878,28 @@ function planUpload(key, existing, versionsKnown) {
|
|
|
813
878
|
|
|
814
879
|
// src/custom-chart/scaffold.ts
|
|
815
880
|
var DEFAULT_SLOTS = [
|
|
816
|
-
{
|
|
817
|
-
|
|
818
|
-
|
|
881
|
+
{
|
|
882
|
+
id: "category",
|
|
883
|
+
label: "Category",
|
|
884
|
+
role: "dimension",
|
|
885
|
+
types: ["string"],
|
|
886
|
+
required: true,
|
|
887
|
+
description: "One bar per value."
|
|
888
|
+
},
|
|
889
|
+
{
|
|
890
|
+
id: "value",
|
|
891
|
+
label: "Value",
|
|
892
|
+
role: "measure",
|
|
893
|
+
types: ["number"],
|
|
894
|
+
required: true
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
id: "target",
|
|
898
|
+
label: "Target",
|
|
899
|
+
role: "measure",
|
|
900
|
+
types: ["number"],
|
|
901
|
+
required: false
|
|
902
|
+
}
|
|
819
903
|
];
|
|
820
904
|
function scaffoldProject(input) {
|
|
821
905
|
const template = readTemplateFiles();
|
|
@@ -830,7 +914,11 @@ function scaffoldProject(input) {
|
|
|
830
914
|
}
|
|
831
915
|
const name = typeof input.name === "string" ? input.name.trim() : "";
|
|
832
916
|
if (name.length === 0 || name.length > 256) {
|
|
833
|
-
problems.push({
|
|
917
|
+
problems.push({
|
|
918
|
+
code: "manifest.name.invalid",
|
|
919
|
+
path: "/name",
|
|
920
|
+
message: "name must be 1 to 256 characters."
|
|
921
|
+
});
|
|
834
922
|
}
|
|
835
923
|
const manifest = {
|
|
836
924
|
schemaVersion: 2,
|
|
@@ -846,8 +934,12 @@ function scaffoldProject(input) {
|
|
|
846
934
|
packageJson.name = input.key;
|
|
847
935
|
const files = {};
|
|
848
936
|
for (const [file, content] of Object.entries(template)) {
|
|
849
|
-
if (file === "manifest.json")
|
|
850
|
-
|
|
937
|
+
if (file === "manifest.json")
|
|
938
|
+
files[file] = `${JSON.stringify(manifest, null, 2)}
|
|
939
|
+
`;
|
|
940
|
+
else if (file === "package.json")
|
|
941
|
+
files[file] = `${JSON.stringify(packageJson, null, 2)}
|
|
942
|
+
`;
|
|
851
943
|
else files[file] = content;
|
|
852
944
|
}
|
|
853
945
|
return {
|
|
@@ -859,8 +951,6 @@ function scaffoldProject(input) {
|
|
|
859
951
|
}
|
|
860
952
|
|
|
861
953
|
export {
|
|
862
|
-
oauthHttpsUrl,
|
|
863
|
-
oauthConfigSchema,
|
|
864
954
|
DatabrainApiError,
|
|
865
955
|
toolError,
|
|
866
956
|
stringify,
|
|
@@ -871,9 +961,11 @@ export {
|
|
|
871
961
|
registerSecret,
|
|
872
962
|
redactSecrets,
|
|
873
963
|
logger,
|
|
874
|
-
parseErrorBody,
|
|
875
|
-
MCP_SERVER_VERSION,
|
|
876
964
|
toolContext,
|
|
965
|
+
MCP_SERVER_VERSION,
|
|
966
|
+
parseErrorBody,
|
|
967
|
+
oauthHttpsUrl,
|
|
968
|
+
oauthConfigSchema,
|
|
877
969
|
DatabrainClient,
|
|
878
970
|
CustomChartsApi,
|
|
879
971
|
createCustomChartsApi,
|
|
@@ -881,4 +973,4 @@ export {
|
|
|
881
973
|
planUpload,
|
|
882
974
|
scaffoldProject
|
|
883
975
|
};
|
|
884
|
-
//# sourceMappingURL=chunk-
|
|
976
|
+
//# sourceMappingURL=chunk-AWICHHDU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/errors.ts","../src/utils/logger.ts","../package.json","../src/version.ts","../src/custom-chart/studio.ts","../src/utils/cache.ts","../src/utils/tool-context.ts","../src/client/error-body.ts","../src/client/oauth-client-credentials.ts","../src/client/databrain-client.ts","../src/api/custom-charts-api.ts","../src/custom-chart/api.ts","../src/custom-chart/scaffold.ts"],"sourcesContent":["export class DatabrainApiError extends Error {\n constructor(\n public readonly status: number,\n public readonly code: string,\n message: string,\n public readonly details?: unknown,\n /** The server's own next step for this error class, when it sent one. */\n public readonly serverHint?: string,\n public readonly retryable?: boolean\n ) {\n super(message);\n this.name = 'DatabrainApiError';\n }\n\n toToolResponse(): {\n content: Array<{ type: 'text'; text: string }>;\n isError: true;\n } {\n const parts = [`Error: ${this.message}`];\n const detailDump = this.formatDetails();\n if (detailDump) parts.push(detailDump);\n const hint = this.serverHint ? `Hint: ${this.serverHint}` : this.hint();\n if (hint) parts.push(hint);\n return {\n content: [{ type: 'text', text: parts.join('\\n\\n') }],\n isError: true,\n };\n }\n\n /**\n * Surface API-returned details for 4xx errors so the LLM can recover or\n * report the real reason (validation messages, field names, etc.). Skips\n * fields already collapsed into `message`/`code`, and skips 5xx where the\n * payload usually isn't actionable.\n */\n private formatDetails(): string {\n if (this.status < 400 || this.status >= 500) return '';\n if (!this.details || typeof this.details !== 'object') return '';\n\n const skipKeys = new Set([\n 'message',\n 'detail',\n 'error',\n 'code',\n 'data',\n 'hint',\n 'retryable',\n ]);\n const extra: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(\n this.details as Record<string, unknown>\n )) {\n if (skipKeys.has(k)) continue;\n if (v === null || v === undefined) continue;\n extra[k] = v;\n }\n if (Object.keys(extra).length === 0) return '';\n try {\n return `API details: ${JSON.stringify(extra)}`;\n } catch {\n return '';\n }\n }\n\n private hint(): string {\n // dashboard_snapshot: the API's own reasons, so the generic status hints below do not mislead.\n if (this.code === 'OAUTH_SIGN_IN_REQUIRED') {\n return 'Hint: Snapshots draw as a signed-in Databrain user. Connect this AI app with a Databrain sign-in (the hosted connector, or /mcp in Claude Code); a service token cannot take them.';\n }\n if (this.code === 'RENDER_IN_PROGRESS') {\n return 'Hint: Your other snapshot is still rendering. Wait a few seconds, then call the tool again.';\n }\n if (\n this.code === 'SNAPSHOT_TIMEOUT' ||\n this.code === 'SNAPSHOT_TOO_LARGE'\n ) {\n return 'Hint: Ask for one chart with metricId, or a smaller width.';\n }\n if (this.code === 'UNAUTHORIZED_ORIGIN') {\n return 'Hint: The embed origin is not on the allowed domains list. Add the domain to the allowed domains in the Databrain settings; the token itself is fine.';\n }\n if (this.status === 401 || this.status === 403) {\n if (this.code === 'OAUTH_API_ERROR') {\n return 'Hint: Check that the backend accepts the configured OAuth issuer and resource, and that the service principal has permission for this operation. Static fallback applies only to token acquisition failures.';\n }\n if (\n this.code === 'INVALID_SERVICE_TOKEN' ||\n this.code === 'MISSING_SERVICE_TOKEN' ||\n this.message.toLowerCase().includes('service token')\n ) {\n return 'Hint: The service token (DATABRAIN_SERVICE_TOKEN) is invalid, expired, or missing. It must be set in the MCP server config (not at runtime). Check Settings > Service Tokens in the Databrain UI.';\n }\n return 'Hint: The per-data-app API token is invalid or expired. Use `create_api_token` to generate a new one. Do not ask the user — manage tokens via MCP tools.';\n }\n if (this.status === 400) {\n return 'Hint: The request was invalid. Check parameter values match expected types and formats. Use the corresponding list tool to verify IDs and names.';\n }\n if (this.status === 404) {\n return 'Hint: The requested resource was not found. Verify the ID or name is correct using the corresponding list tool.';\n }\n if (this.status === 409) {\n return 'Hint: The request conflicts with the current resource state. Read the error above, inspect the resource, and retry after resolving it.';\n }\n if (this.status === 422) {\n return 'Hint: The request parameters are invalid. Check the required fields and their formats.';\n }\n if (this.status === 429) {\n return 'Hint: API rate limit reached. Wait a moment and try again.';\n }\n if (this.status >= 500) {\n return 'Hint: The Databrain API is experiencing issues. Try again in a few moments.';\n }\n return '';\n }\n}\n\nexport function toolError(message: string): {\n content: Array<{ type: 'text'; text: string }>;\n isError: true;\n} {\n return {\n content: [{ type: 'text', text: message }],\n isError: true,\n };\n}\n\nexport function stringify(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\nexport function toolSuccess(text: string): {\n content: Array<{ type: 'text'; text: string }>;\n} {\n return {\n content: [{ type: 'text', text }],\n };\n}\n","const LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 } as const;\ntype LogLevel = keyof typeof LOG_LEVELS;\n\nconst currentLevel: LogLevel =\n (process.env.DATABRAIN_LOG_LEVEL as LogLevel) || 'warn';\n\n/**\n * Credentials the process holds. Every log line is scrubbed of them before it\n * reaches stderr, because an API error body can quote the Authorization\n * header back and stderr is a terminal, a CI log or the MCP host's log.\n */\nconst secrets = new Set<string>();\n\nexport function registerSecret(value: string | undefined | null): void {\n if (typeof value === 'string' && value.length >= 8) secrets.add(value);\n}\n\nexport function redactSecrets(text: string): string {\n let out = text;\n for (const secret of secrets) out = out.split(secret).join('[redacted]');\n return out;\n}\n\nfunction log(level: LogLevel, message: string, data?: unknown): void {\n if (LOG_LEVELS[level] < LOG_LEVELS[currentLevel]) return;\n const line = `[databrain-mcp] [${level.toUpperCase()}] ${message}`;\n const text = data !== undefined ? `${line} ${JSON.stringify(data)}` : line;\n process.stderr.write(`${redactSecrets(text)}\\n`);\n}\n\nexport const logger = {\n debug: (msg: string, data?: unknown) => log('debug', msg, data),\n info: (msg: string, data?: unknown) => log('info', msg, data),\n warn: (msg: string, data?: unknown) => log('warn', msg, data),\n error: (msg: string, data?: unknown) => log('error', msg, data),\n};\n","{\n \"name\": \"@databrainhq/mcp-server\",\n \"mcpName\": \"com.usedatabrain/mcp-server\",\n \"version\": \"0.3.0-rc.14\",\n \"packageManager\": \"pnpm@12.3.4\",\n \"description\": \"MCP server for Databrain embedded analytics - connect databases, create datamarts, configure embeds, and generate frontend code\",\n \"type\": \"module\",\n \"bin\": {\n \"mcp-server\": \"dist/index.js\",\n \"databrain-mcp-server\": \"dist/index.js\",\n \"databrain-mcp-chart-apps\": \"dist/apps/stdio.js\",\n \"databrain\": \"dist/cli.js\"\n },\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"files\": [\n \"dist\",\n \"skills\",\n \".claude-plugin\",\n \".mcp.json\"\n ],\n \"scripts\": {\n \"build\": \"tsup && node scripts/build-declarations.mjs && node scripts/copy-custom-chart-assets.mjs\",\n \"dev\": \"tsx src/index.ts\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:live\": \"vitest run tests/integration/prompt-flows.test.ts\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"format\": \"biome format --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"prepublishOnly\": \"pnpm run build\"\n },\n \"keywords\": [\n \"mcp\",\n \"databrain\",\n \"embedded-analytics\",\n \"ai\",\n \"model-context-protocol\"\n ],\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@modelcontextprotocol/sdk\": \"^1.32.1\",\n \"@posthog/mcp\": \"^0.10.7\",\n \"esbuild\": \"0.27.3\",\n \"fflate\": \"0.8.3\",\n \"posthog-node\": \"5.60.1\",\n \"yaml\": \"^2.9.1\",\n \"zod\": \"^4.1.12\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"2.5.15\",\n \"@microsoft/api-extractor\": \"7.59.4\",\n \"@types/node\": \"^25.3.5\",\n \"tsup\": \"^8.4.0\",\n \"tsx\": \"^4.19.0\",\n \"typescript\": \"7.0.2\",\n \"vitest\": \"^4.1.12\"\n },\n \"overrides\": {\n \"@posthog/core\": \"1.61.2\",\n \"@posthog/types\": \"1.418.0\",\n \"rollup\": \"4.66.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/databrainhq/mcp-server.git\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n }\n}\n","import packageJson from '../package.json';\n\n// tsup embeds this package.json value in dist while tsx resolves the same file\n// during development. The handshake and request headers therefore share the\n// package version without maintaining a second release string.\nexport const MCP_SERVER_VERSION = packageJson.version;\n","import { z } from 'zod';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { DatabrainApiError } from '../utils/errors.js';\n\nconst studioCell = z.union([\n z.string().max(4096),\n z.number().finite(),\n z.boolean(),\n z.null(),\n]);\nexport const studioDraftSchema = z\n .object({\n code: z.string().max(64_000),\n css: z.string().max(32_000),\n manifest: z.record(z.string(), z.unknown()),\n sampleData: z\n .object({\n columns: z\n .array(\n z\n .object({\n id: z.string(),\n label: z.string(),\n type: z.enum(['string', 'number', 'boolean']),\n slotId: z.string().optional(),\n })\n .strict()\n )\n .max(64),\n rows: z.array(z.array(studioCell)).max(200),\n })\n .strict(),\n name: z.string().max(256),\n description: z.string().max(500),\n iconSvg: z.string().max(16_384),\n })\n .strict();\nexport type StudioDraft = z.infer<typeof studioDraftSchema>;\n\n/** Accept only the studio's domain result, never general SSE data or credentials. */\nexport function parseStudioStream(text: string): {\n draft?: StudioDraft;\n sessionId?: string;\n applied: boolean;\n} {\n if (text.length > 4 * 1024 * 1024) throw new Error('Studio stream too large');\n let draft: StudioDraft | undefined;\n let sessionId: string | undefined;\n let failure = false;\n for (const frame of text.split(/\\r?\\n\\r?\\n/)) {\n const line = frame\n .split(/\\r?\\n/)\n .filter((l) => l.startsWith('data:'))\n .map((l) => l.slice(5).trimStart())\n .join('\\n');\n if (!line || line === '[DONE]') continue;\n const event = JSON.parse(line);\n if (event.type === 'session' && typeof event.sessionId === 'string')\n sessionId = event.sessionId;\n if (event.type === 'error') failure = true;\n if (\n event.type === 'tool_execution_end' &&\n event.name === 'update_custom_chart' &&\n event.status === 'completed' &&\n event.result?.kind === 'applied'\n ) {\n draft = studioDraftSchema.parse(event.result.draft);\n }\n }\n if (failure && !draft) throw new Error('Bryn did not complete an edit');\n return { draft, sessionId, applied: !!draft };\n}\n\n/** Only absence permits the old authoring path. An auth denial or outage is not absence. */\nexport async function editWithBryn(\n client: DatabrainClient,\n input: {\n key: string;\n workspaceId: string;\n message: string;\n draft: StudioDraft;\n sessionId?: string;\n }\n): Promise<{\n available: boolean;\n draft: StudioDraft;\n sessionId?: string;\n applied: boolean;\n}> {\n // Bryn requires a signed-in session. A stdio service token is still valid for\n // the existing authoring API; do not send it to a session-only route.\n if (!client.isHosted())\n return { available: false, draft: input.draft, applied: false };\n try {\n const result = await client.request<ReturnType<typeof parseStudioStream>>({\n method: 'POST',\n path: `/api/v2/custom-charts/${encodeURIComponent(input.key)}/bryn/turn`,\n auth: 'service',\n body: {\n workspaceId: input.workspaceId,\n message: input.message,\n draft: input.draft,\n sessionId: input.sessionId,\n mode: 'build',\n viewingOldVersion: false,\n },\n responseFormat: 'studio-sse',\n timeoutMs: 180_000,\n noRetryOnTimeout: true,\n });\n return {\n available: true,\n draft: result.draft ?? input.draft,\n applied: result.applied,\n sessionId: result.sessionId,\n };\n } catch (error) {\n if (error instanceof DatabrainApiError && error.status === 404) {\n return { available: false, draft: input.draft, applied: false };\n }\n throw error;\n }\n}\n","interface CacheEntry<T> {\n value: T;\n expiresAt: number;\n}\n\nexport class TtlCache {\n private store = new Map<string, CacheEntry<unknown>>();\n\n get<T>(key: string): T | undefined {\n const entry = this.store.get(key);\n if (!entry) return undefined;\n if (Date.now() > entry.expiresAt) {\n this.store.delete(key);\n return undefined;\n }\n return entry.value as T;\n }\n\n set<T>(key: string, value: T, ttlMs: number): void {\n this.store.set(key, { value, expiresAt: Date.now() + ttlMs });\n }\n\n invalidateByPrefix(prefix: string): void {\n for (const key of this.store.keys()) {\n if (key.startsWith(prefix)) {\n this.store.delete(key);\n }\n }\n }\n\n clear(): void {\n this.store.clear();\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\n\n/**\n * Per-tool-call intent metadata. Set when an MCP tool handler runs (see\n * registerAllTools, which wraps every handler), and read by DatabrainClient to\n * tag outbound API requests with X-Databrain-MCP-* headers. The backend\n * (mcpTracking) records these so usage can be attributed to a specific tool and\n * workflow intent — letting us see, e.g., embedding vs internal-analytics flows.\n */\nexport interface ToolCallContext {\n /** The MCP tool name being executed, e.g. 'create_workspace_metric'. */\n tool: string;\n /** Coarse domain bucket, e.g. 'embedding' | 'internal_analytics'. */\n category: string;\n /** Use-case bucket, e.g. 'sql_to_workspace_metric'. */\n workflowIntent: string;\n /** How the request was initiated; 'tool_call' for MCP tool invocations. */\n inputMode: string;\n}\n\nexport const toolContext = new AsyncLocalStorage<ToolCallContext>();\n","/**\n * Reads a Databrain error body into one shape. The backend sends the same\n * envelope `{ code, message, hint, retryable, details }` in three places:\n * flat (`{ code, message }`), under `error` (public REST, datasource API) and\n * under `data.error` (the externalApis routes, which also send `error` as a\n * plain string). Reading only the flat form dropped the code and hint.\n */\nexport interface ParsedErrorBody {\n code?: string;\n message?: string;\n hint?: string;\n retryable?: boolean;\n details?: unknown;\n}\n\nconst isRecord = (v: unknown): v is Record<string, unknown> =>\n typeof v === 'object' && v !== null && !Array.isArray(v);\n\nconst str = (v: unknown): string | undefined =>\n typeof v === 'string' && v.trim() ? v : undefined;\n\nconst fromEnvelope = (v: unknown): ParsedErrorBody | undefined => {\n if (!isRecord(v)) return undefined;\n const out: ParsedErrorBody = {\n code: str(v.code),\n message: str(v.message) ?? str(v.detail),\n hint: str(v.hint),\n retryable: typeof v.retryable === 'boolean' ? v.retryable : undefined,\n details: v.details,\n };\n return out.code || out.message || out.hint ? out : undefined;\n};\n\nexport function parseErrorBody(body: unknown): ParsedErrorBody {\n if (!isRecord(body)) return {};\n const nested =\n fromEnvelope(isRecord(body.data) ? body.data.error : undefined) ??\n fromEnvelope(body.error) ??\n fromEnvelope(body);\n if (nested) {\n return { ...nested, message: nested.message ?? str(body.error) };\n }\n return { message: str(body.error) };\n}\n","import { z } from 'zod';\n\n// Validate without transforming: issuer identity uses exact string comparison.\nexport const oauthHttpsUrl = z.string().refine((value) => {\n try {\n const url = new URL(value);\n return (\n url.protocol === 'https:' && !url.username && !url.password && !url.hash\n );\n } catch {\n return false;\n }\n}, 'OAuth URLs must use HTTPS without userinfo or fragments');\n\nexport const oauthConfigSchema = z.object({\n issuer: oauthHttpsUrl.refine((value) => {\n try {\n return !new URL(value).search;\n } catch {\n return false;\n }\n }, 'OAuth issuer must not contain a query'),\n clientId: z.string().min(1),\n clientSecret: z.string().min(1),\n resource: oauthHttpsUrl,\n scope: z.string().min(1).optional(),\n authMethod: z\n .enum(['client_secret_basic', 'client_secret_post'])\n .default('client_secret_basic'),\n});\n\nexport type OAuthConfig = z.infer<typeof oauthConfigSchema>;\n\nconst metadataSchema = z.object({\n issuer: z.string(),\n token_endpoint: oauthHttpsUrl,\n token_endpoint_auth_methods_supported: z.array(z.string()).optional(),\n grant_types_supported: z.array(z.string()).optional(),\n});\nconst tokenSchema = z.object({\n access_token: z.string().regex(/^[A-Za-z0-9\\-._~+/]+=*$/),\n token_type: z.string().refine((value) => value.toLowerCase() === 'bearer'),\n expires_in: z.number().finite().positive().optional(),\n});\n\nconst TOKEN_TIMEOUT_MS = 10_000;\nconst FAILURE_COOLDOWN_MS = 30_000;\nconst MAX_REFRESH_SKEW_MS = 60_000;\n\nfunction authError(): Error {\n // Never retain an IdP body, a fetch error, or a schema error as a cause:\n // those can contain credentials and are serialized by callers/telemetry.\n return new Error(\n 'OAuth token acquisition failed. Check the configured issuer, client credentials, resource and scopes.'\n );\n}\n\n/** One immutable credential/issuer/resource binding per MCP process client. */\nexport class OAuthClientCredentials {\n private readonly config: OAuthConfig;\n private tokenEndpoint?: string;\n private cached?: { value: string; renewAt: number };\n private pending?: Promise<string>;\n private retryAt = 0;\n\n constructor(config: OAuthConfig) {\n // Also validate programmatic callers; do not expose invalid values in errors.\n const parsed = oauthConfigSchema.safeParse(config);\n if (!parsed.success) throw authError();\n this.config = Object.freeze(parsed.data);\n }\n\n getStatus(): 'configured' | 'ready' | 'unavailable' {\n if (this.cached && Date.now() < this.cached.renewAt) return 'ready';\n if (this.retryAt > 0) return 'unavailable';\n return 'configured';\n }\n\n async getToken(): Promise<string> {\n if (this.cached && Date.now() < this.cached.renewAt)\n return this.cached.value;\n if (this.pending) return this.pending;\n if (Date.now() < this.retryAt) throw authError();\n\n this.cached = undefined;\n this.pending = this.acquire()\n .catch(() => {\n this.retryAt = Date.now() + FAILURE_COOLDOWN_MS;\n throw authError();\n })\n .finally(() => {\n this.pending = undefined;\n });\n return this.pending;\n }\n\n private async discoverTokenEndpoint(signal: AbortSignal): Promise<string> {\n if (this.tokenEndpoint) return this.tokenEndpoint;\n const issuer = new URL(this.config.issuer);\n const path = issuer.pathname.replace(/\\/$/, '');\n const candidates = [\n ...new Set([\n `${issuer.origin}/.well-known/oauth-authorization-server${path}`,\n `${issuer.origin}/.well-known/openid-configuration${path}`,\n `${issuer.origin}${path}/.well-known/openid-configuration`,\n ]),\n ];\n\n for (const url of candidates) {\n // No credentials, cookies, API headers, or redirects during discovery.\n const response = await fetch(url, {\n headers: { Accept: 'application/json' },\n redirect: 'error',\n signal,\n });\n if (response.status === 404 || response.status === 405) continue;\n if (!response.ok) throw authError();\n const metadata = metadataSchema.parse(await response.json());\n if (metadata.issuer !== this.config.issuer) throw authError();\n const methods = metadata.token_endpoint_auth_methods_supported ?? [\n 'client_secret_basic',\n ];\n if (!methods.includes(this.config.authMethod)) throw authError();\n if (\n metadata.grant_types_supported &&\n !metadata.grant_types_supported.includes('client_credentials')\n ) {\n throw authError();\n }\n this.tokenEndpoint = metadata.token_endpoint;\n return this.tokenEndpoint;\n }\n throw authError();\n }\n\n private async acquire(): Promise<string> {\n // One time budget covers all discovery attempts and token acquisition.\n const signal = AbortSignal.timeout(TOKEN_TIMEOUT_MS);\n const endpoint = await this.discoverTokenEndpoint(signal);\n const body = new URLSearchParams({\n grant_type: 'client_credentials',\n resource: this.config.resource,\n });\n if (this.config.scope) body.set('scope', this.config.scope);\n const headers: Record<string, string> = {\n Accept: 'application/json',\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n if (this.config.authMethod === 'client_secret_post') {\n body.set('client_id', this.config.clientId);\n body.set('client_secret', this.config.clientSecret);\n } else {\n // RFC 6749 2.3.1: form-encode EACH value before constructing Basic auth.\n const encode = (value: string) =>\n new URLSearchParams({ value }).toString().slice(6);\n headers.Authorization = `Basic ${Buffer.from(`${encode(this.config.clientId)}:${encode(this.config.clientSecret)}`).toString('base64')}`;\n }\n\n const startedAt = Date.now();\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: body.toString(),\n redirect: 'error',\n signal,\n });\n if (!response.ok) throw authError();\n const token = tokenSchema.parse(await response.json());\n if (token.expires_in !== undefined) {\n const lifetimeMs = token.expires_in * 1000;\n const expiresAt = startedAt + lifetimeMs;\n if (!Number.isFinite(expiresAt) || Date.now() >= expiresAt)\n throw authError();\n this.cached = {\n value: token.access_token,\n renewAt: expiresAt - Math.min(MAX_REFRESH_SKEW_MS, lifetimeMs * 0.1),\n };\n }\n // With no expires_in, use the token for this call only. No JWT decoding,\n // assumed lifetime, refresh_token grant, disk storage, or background timer.\n this.retryAt = 0;\n return token.access_token;\n }\n}\n","import { parseStudioStream } from '../custom-chart/studio.js';\nimport { TtlCache } from '../utils/cache.js';\nimport type { Config } from '../utils/config.js';\nimport { DatabrainApiError } from '../utils/errors.js';\nimport { logger, registerSecret } from '../utils/logger.js';\nimport { toolContext } from '../utils/tool-context.js';\nimport { MCP_SERVER_VERSION } from '../version.js';\nimport { parseErrorBody } from './error-body.js';\nimport {\n OAuthClientCredentials,\n oauthHttpsUrl,\n} from './oauth-client-credentials.js';\nimport type { RequestOptions } from './types.js';\n\nconst MCP_USER_AGENT = `databrain-mcp-server/${MCP_SERVER_VERSION}`;\n\nconst MAX_RETRIES = 3;\nconst REQUEST_TIMEOUT_MS = 30_000;\n\nconst NON_TRANSIENT_PATTERNS = [\n 'out of context',\n 'Definition not found',\n 'not a data question',\n 'Query generation failed',\n 'not found',\n 'not authenticated',\n 'Invalid Service Token',\n 'service token',\n];\n\nexport class DatabrainClient {\n private cache = new TtlCache();\n private runtimeApiToken: string | undefined;\n private readonly oauth?: OAuthClientCredentials;\n private oauthFallback = false;\n\n constructor(private config: Config) {\n registerSecret(config.serviceToken);\n registerSecret(config.apiToken);\n if (config.oauth) {\n if (!oauthHttpsUrl.safeParse(config.apiUrl).success) {\n throw new Error(\n 'OAuth requires an HTTPS Databrain API URL without userinfo or fragments.'\n );\n }\n this.oauth = new OAuthClientCredentials(config.oauth);\n // Prevent later mutation of a caller-owned config from moving credentials\n // or the resource bearer to another API/issuer within this client session.\n this.config = Object.freeze({ ...config });\n }\n }\n\n hasApiToken(): boolean {\n return !!(this.runtimeApiToken || this.config.apiToken);\n }\n\n /** The hosted composition supplies a signed-in identity, unlike local API credentials. */\n isHosted(): boolean {\n return false;\n }\n\n setRuntimeApiToken(token: string): void {\n registerSecret(token);\n this.runtimeApiToken = token;\n logger.info('Runtime API token set for this session');\n }\n\n getServiceToken(): string | undefined {\n return this.config.serviceToken;\n }\n\n getApiUrl(): string {\n return this.config.apiUrl;\n }\n\n getDemoDomain(): string {\n return this.config.demoDomain;\n }\n\n /**\n * Describes which credential is currently used as the bearer for outgoing\n * API calls. Used by `whoami` so the LLM can give the user a truthful answer.\n */\n getActiveAuth():\n | { source: 'service-token'; oauthFallback?: boolean }\n | {\n source: 'oauth-client-credentials';\n status: 'configured' | 'ready' | 'unavailable';\n }\n | { source: 'api-token' }\n | { source: 'none' } {\n if (this.oauth) {\n if (this.oauthFallback)\n return { source: 'service-token', oauthFallback: true };\n return {\n source: 'oauth-client-credentials',\n status: this.oauth.getStatus(),\n };\n }\n if (this.config.serviceToken) return { source: 'service-token' };\n if (this.runtimeApiToken || this.config.apiToken)\n return { source: 'api-token' };\n return { source: 'none' };\n }\n\n private async getToken(\n auth: 'service' | 'api' | 'none'\n ): Promise<string | undefined> {\n if (auth === 'none') return undefined;\n if (auth === 'service') {\n if (this.oauth) {\n try {\n const token = await this.oauth.getToken();\n this.oauthFallback = false;\n return token;\n } catch {\n if (!this.config.serviceToken) {\n throw new DatabrainApiError(\n 0,\n 'OAUTH_TOKEN_ERROR',\n 'OAuth token acquisition failed. Check the configured issuer, client credentials, resource and scopes.'\n );\n }\n if (!this.oauthFallback)\n logger.warn(\n 'OAuth unavailable; using the configured static service token.'\n );\n this.oauthFallback = true;\n }\n }\n return this.config.serviceToken;\n }\n return this.runtimeApiToken || this.config.apiToken;\n }\n\n async request<T>(options: RequestOptions): Promise<T> {\n return this.requestInternal<T>(options);\n }\n\n private async requestInternal<T>(options: RequestOptions): Promise<T> {\n const usesOAuth =\n !!this.oauth && options.auth === 'service' && !options.token;\n // An OAuth renewal can switch to a differently scoped static principal.\n // Do not serve/store service response caches across that auth boundary.\n const cacheAllowed = !usesOAuth;\n // Invalidate caches first\n if (options.invalidateCache) {\n for (const prefix of options.invalidateCache) {\n this.cache.invalidateByPrefix(prefix);\n }\n }\n\n // Check cache\n if (cacheAllowed && options.cacheKey && options.cacheTtlMs) {\n const cached = this.cache.get<T>(options.cacheKey);\n if (cached !== undefined) {\n logger.debug(`Cache hit: ${options.cacheKey}`);\n return cached;\n }\n }\n\n let token = options.token ?? (await this.getToken(options.auth));\n if (options.auth !== 'none' && !options.token && !token) {\n if (options.auth === 'service') {\n throw new DatabrainApiError(\n 401,\n 'MISSING_SERVICE_TOKEN',\n 'DATABRAIN_SERVICE_TOKEN is required for this operation (org-level token for discovery and data app management). It must be set in the MCP server configuration — do not ask the user for it at runtime.'\n );\n }\n throw new DatabrainApiError(\n 401,\n 'MISSING_API_TOKEN',\n 'A per-data-app API token is required for this embedding operation but none is configured. ' +\n 'Call `create_api_token` to generate one, or `set_api_token` if you already have the value. Do not ask the user for this token — create it via the MCP tools.'\n );\n }\n\n // Build URL\n let url = `${this.config.apiUrl}${options.path}`;\n if (options.query) {\n const params = new URLSearchParams(options.query);\n url += `?${params.toString()}`;\n }\n\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n if (usesOAuth && attempt > 1) token = await this.getToken(options.auth);\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': MCP_USER_AGENT,\n 'X-Databrain-Client': MCP_USER_AGENT,\n ...options.headers,\n };\n // Tag the call with the active tool's intent so backend telemetry can\n // attribute usage (embedding vs internal analytics, per-tool). Present\n // only when invoked from within a tool handler (see registry wrapper).\n const ctx = toolContext.getStore();\n if (ctx) {\n headers['X-Databrain-MCP-Tool'] = ctx.tool;\n headers['X-Databrain-MCP-Tool-Category'] = ctx.category;\n headers['X-Databrain-MCP-Workflow-Intent'] = ctx.workflowIntent;\n headers['X-Databrain-MCP-Input-Mode'] = ctx.inputMode;\n }\n if (token) {\n // Guest-token endpoints (auth: 'none' with a minted token) read the\n // token from `x-plugin-token` and require a whitelisted Origin.\n // DATABRAIN_DOMAINS includes `usedatabrain.com`, so `mcp.usedatabrain.com`\n // passes the whitelist without needing a per-company config.\n if (options.auth === 'none') {\n headers['x-plugin-token'] = token;\n headers['Origin'] = 'https://mcp.usedatabrain.com';\n } else {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: AbortSignal.timeout(options.timeoutMs || REQUEST_TIMEOUT_MS),\n ...(usesOAuth ? { redirect: 'error' as const } : {}),\n });\n\n if (!response.ok) {\n // An untrusted API can echo credentials in its error body. Keep\n // OAuth errors body-free in both tool output and telemetry. Never\n // retry/downgrade a backend denial with the static service token.\n if (usesOAuth) {\n throw new DatabrainApiError(\n response.status,\n 'OAUTH_API_ERROR',\n `Databrain API request failed with status ${response.status} using configured service credentials.`\n );\n }\n const errorBody = await response.text();\n logger.warn(\n `[API Error] ${options.method} ${options.path} status=${response.status} body=${errorBody.slice(0, 500)}`\n );\n let parsed: unknown = {};\n try {\n parsed = JSON.parse(errorBody);\n } catch {\n // not JSON\n }\n\n const envelope = parseErrorBody(parsed);\n const errorMsg =\n envelope.message ||\n `API request failed with status ${response.status}`;\n const error = new DatabrainApiError(\n response.status,\n envelope.code || `HTTP_${response.status}`,\n errorMsg,\n parsed,\n envelope.hint,\n envelope.retryable\n );\n\n // Retry on 429 or 5xx (but not when the error is clearly non-transient)\n // The server's own retryable flag wins over the status heuristic.\n const isTransient =\n envelope.retryable !== undefined\n ? envelope.retryable &&\n (response.status === 429 || response.status >= 500)\n : response.status === 429 ||\n (response.status >= 500 &&\n !NON_TRANSIENT_PATTERNS.some((p) => errorMsg.includes(p)));\n if (isTransient && attempt < MAX_RETRIES) {\n const delay = Math.min(1000 * 2 ** (attempt - 1), 8000);\n logger.warn(\n `Retrying in ${delay}ms (attempt ${attempt}/${MAX_RETRIES})`,\n {\n status: response.status,\n path: options.path,\n }\n );\n await new Promise((r) => setTimeout(r, delay));\n lastError = error;\n continue;\n }\n\n throw error;\n }\n\n const text = await response.text();\n let data = (\n options.responseFormat === 'studio-sse'\n ? parseStudioStream(text)\n : text\n ? JSON.parse(text)\n : {}\n ) as T;\n\n // Databrain API wraps most responses in { data: ... } — unwrap automatically\n if (\n !options.skipDataUnwrap &&\n data &&\n typeof data === 'object' &&\n !Array.isArray(data) &&\n 'data' in data\n ) {\n const inner = (data as Record<string, unknown>).data;\n if (inner !== null && inner !== undefined) {\n data = inner as unknown as T;\n }\n }\n\n // Store in cache\n if (cacheAllowed && options.cacheKey && options.cacheTtlMs) {\n this.cache.set(options.cacheKey, data, options.cacheTtlMs);\n }\n\n return data;\n } catch (err) {\n if (err instanceof DatabrainApiError) throw err;\n\n if (\n attempt < MAX_RETRIES &&\n (err as Error)?.name === 'TimeoutError' &&\n !options.noRetryOnTimeout\n ) {\n const delay = Math.min(1000 * 2 ** (attempt - 1), 8000);\n logger.warn(`Request timed out, retrying in ${delay}ms`, {\n path: options.path,\n });\n await new Promise((r) => setTimeout(r, delay));\n lastError = err as Error;\n continue;\n }\n\n throw new DatabrainApiError(\n 0,\n 'NETWORK_ERROR',\n usesOAuth\n ? 'Failed to connect to Databrain API using configured service credentials.'\n : `Failed to connect to Databrain API: ${(err as Error).message}`\n );\n }\n }\n\n throw (\n lastError ||\n new DatabrainApiError(0, 'UNKNOWN', 'Request failed after retries')\n );\n }\n}\n","import type { DatabrainClient } from '../client/databrain-client.js';\nimport type { CustomChartBundle, Problem } from '../custom-chart/types.js';\n\n/**\n * Service-token custom chart API (brief section 5), mounted by the backend\n * under /api/mcp/custom-charts. Company scope comes from the token; nothing\n * here sends a company or tenant selector.\n */\nexport const CUSTOM_CHARTS_PATH = '/api/mcp/custom-charts';\nconst LIST_CACHE_KEY = 'list_custom_charts';\n\nexport interface CustomChartVersionSummary {\n id: string;\n versionNumber: number;\n contentHash: string;\n sizeBytes?: number;\n createdAt?: string;\n createdBy?: string | null;\n [key: string]: unknown;\n}\n\nexport interface CustomChartSummary {\n id: string;\n key: string;\n name: string;\n description?: string | null;\n status: 'private' | 'published' | string;\n chartType?: string;\n publishedVersionId?: string | null;\n previewVersionId?: string | null;\n publishedVersionNumber?: number | null;\n previewVersionNumber?: number | null;\n versionsCount?: number;\n iconSvg?: string;\n createdBy?: string | null;\n createdAt?: string;\n updatedAt?: string;\n [key: string]: unknown;\n}\n\nexport interface CustomChartDetail extends CustomChartSummary {\n versions?: CustomChartVersionSummary[];\n}\n\nexport interface ValidateResponse {\n ok: boolean;\n problems: Problem[];\n contentHash?: string;\n sizeBytes?: number;\n}\n\nexport interface UploadResponse {\n chart: CustomChartSummary;\n version: CustomChartVersionSummary;\n created: 'chart' | 'version' | 'none';\n}\n\nexport interface UploadBody extends CustomChartBundle {\n name?: string;\n description?: string;\n}\n\nconst encodeKey = (key: string): string => encodeURIComponent(key);\n\nexport class CustomChartsApi {\n constructor(private readonly client: DatabrainClient) {}\n\n async list(): Promise<CustomChartSummary[]> {\n const response = await this.client.request<\n { charts?: CustomChartSummary[] } | CustomChartSummary[]\n >({\n method: 'GET',\n path: CUSTOM_CHARTS_PATH,\n auth: 'service',\n cacheKey: LIST_CACHE_KEY,\n cacheTtlMs: 30_000,\n });\n if (Array.isArray(response)) return response;\n return Array.isArray(response?.charts) ? response.charts : [];\n }\n\n async get(key: string): Promise<CustomChartDetail> {\n const response = await this.client.request<\n { chart?: CustomChartDetail } | CustomChartDetail\n >({\n method: 'GET',\n path: `${CUSTOM_CHARTS_PATH}/${encodeKey(key)}`,\n auth: 'service',\n });\n const wrapped = response as { chart?: CustomChartDetail };\n return wrapped.chart ? wrapped.chart : (response as CustomChartDetail);\n }\n\n /** Never persists. The server repeats every client side check. */\n async validate(body: UploadBody): Promise<ValidateResponse> {\n const response = await this.client.request<ValidateResponse>({\n method: 'POST',\n path: `${CUSTOM_CHARTS_PATH}/validate`,\n auth: 'service',\n body,\n timeoutMs: 60_000,\n });\n return {\n ok: response.ok === true,\n problems: Array.isArray(response.problems) ? response.problems : [],\n contentHash: response.contentHash,\n sizeBytes: response.sizeBytes,\n };\n }\n\n /** Creates the chart (first upload) or a preview version; idempotent on contentHash. */\n async upload(body: UploadBody): Promise<UploadResponse> {\n return this.client.request<UploadResponse>({\n method: 'POST',\n path: CUSTOM_CHARTS_PATH,\n auth: 'service',\n body,\n timeoutMs: 60_000,\n invalidateCache: [LIST_CACHE_KEY],\n });\n }\n\n async bundle(key: string, versionId: string): Promise<CustomChartBundle> {\n return this.client.request<CustomChartBundle>({\n method: 'GET',\n path: `${CUSTOM_CHARTS_PATH}/${encodeKey(key)}/versions/${encodeURIComponent(versionId)}/bundle`,\n auth: 'service',\n });\n }\n\n async publish(\n key: string,\n versionId?: string\n ): Promise<{ chart: CustomChartSummary }> {\n return this.client.request<{ chart: CustomChartSummary }>({\n method: 'POST',\n path: `${CUSTOM_CHARTS_PATH}/${encodeKey(key)}/publish`,\n auth: 'service',\n body: versionId ? { versionId } : {},\n invalidateCache: [LIST_CACHE_KEY],\n });\n }\n\n async discardPreview(key: string): Promise<{ chart: CustomChartSummary }> {\n return this.client.request<{ chart: CustomChartSummary }>({\n method: 'POST',\n path: `${CUSTOM_CHARTS_PATH}/${encodeKey(key)}/discard-preview`,\n auth: 'service',\n body: {},\n invalidateCache: [LIST_CACHE_KEY],\n });\n }\n}\n","import type { CustomChartSummary } from '../api/custom-charts-api.js';\nimport { CustomChartsApi } from '../api/custom-charts-api.js';\nimport type { DatabrainClient } from '../client/databrain-client.js';\nimport { DatabrainApiError } from '../utils/errors.js';\nimport type { Problem } from './types.js';\n\nexport {\n CUSTOM_CHARTS_PATH,\n type CustomChartDetail,\n type CustomChartSummary,\n CustomChartsApi,\n type CustomChartVersionSummary,\n type UploadBody,\n type UploadResponse,\n type ValidateResponse,\n} from '../api/custom-charts-api.js';\n\nexport function createCustomChartsApi(\n client: DatabrainClient\n): CustomChartsApi {\n return new CustomChartsApi(client);\n}\n\n/** The backend error body is { error: { code, message, problems? } }. Pull the problems out. */\nexport function apiProblems(err: unknown): Problem[] {\n if (!(err instanceof DatabrainApiError)) return [];\n const details = err.details as\n | { error?: { problems?: unknown }; problems?: unknown }\n | undefined;\n const list = details?.error?.problems ?? details?.problems;\n if (!Array.isArray(list)) return [];\n return list.filter(\n (item): item is Problem =>\n !!item &&\n typeof item === 'object' &&\n typeof (item as Problem).code === 'string' &&\n typeof (item as Problem).message === 'string'\n );\n}\n\nexport interface UploadPlan {\n action: 'create chart' | 'create version' | 'no change';\n key: string;\n existing?: CustomChartSummary;\n nextVersionNumber: number;\n summary: string;\n}\n\n/**\n * What an apply will do, computed from the chart list (brief section 8):\n * \"will create chart\" when the key is new, \"will create version n\" when the\n * chart exists. The content-hash replay (\"none\") is only known to the server.\n */\nexport function planUpload(\n key: string,\n existing: CustomChartSummary | undefined,\n versionsKnown?: number\n): UploadPlan {\n if (!existing) {\n return {\n action: 'create chart',\n key,\n nextVersionNumber: 1,\n summary: `will create chart custom:${key} (version 1, status private)`,\n };\n }\n const count =\n typeof versionsKnown === 'number'\n ? versionsKnown\n : typeof existing.versionsCount === 'number'\n ? existing.versionsCount\n : undefined;\n const next = count !== undefined ? count + 1 : NaN;\n const label = Number.isFinite(next) ? `version ${next}` : 'the next version';\n return {\n action: 'create version',\n key,\n existing,\n nextVersionNumber: Number.isFinite(next) ? next : 0,\n summary: `will create ${label} of custom:${key} in preview (status stays ${existing.status}; the published version keeps serving until you publish)`,\n };\n}\n","import { readTemplateFiles } from './assets.js';\nimport { isId, validateManifest } from './manifest.js';\nimport type { CustomChartOption, CustomChartSlot, Problem } from './types.js';\n\n/**\n * A chart project is the template folder with manifest.json and package.json\n * rewritten for the requested key, name, slots and options. Every other file\n * is copied verbatim so that the guide, the types and the sample chart stay\n * byte identical to what the tests exercise.\n */\nexport interface ScaffoldInput {\n key: string;\n name: string;\n description?: string;\n slots?: CustomChartSlot[];\n options?: CustomChartOption[];\n}\n\nexport interface ScaffoldResult {\n ok: boolean;\n problems: Problem[];\n files: Record<string, string>;\n nextStep: string;\n}\n\nconst DEFAULT_SLOTS: CustomChartSlot[] = [\n {\n id: 'category',\n label: 'Category',\n role: 'dimension',\n types: ['string'],\n required: true,\n description: 'One bar per value.',\n },\n {\n id: 'value',\n label: 'Value',\n role: 'measure',\n types: ['number'],\n required: true,\n },\n {\n id: 'target',\n label: 'Target',\n role: 'measure',\n types: ['number'],\n required: false,\n },\n];\n\nexport function scaffoldProject(input: ScaffoldInput): ScaffoldResult {\n const template = readTemplateFiles();\n const templateManifest = JSON.parse(template['manifest.json']) as {\n slots: CustomChartSlot[];\n options: CustomChartOption[];\n };\n const problems: Problem[] = [];\n if (!isId(input.key)) {\n problems.push({\n code: 'manifest.id.invalid',\n path: '/id',\n message:\n 'key must match ^[a-z][a-z0-9_-]{0,63}$ (lowercase letters, digits, _ and -).',\n });\n }\n const name = typeof input.name === 'string' ? input.name.trim() : '';\n if (name.length === 0 || name.length > 256) {\n problems.push({\n code: 'manifest.name.invalid',\n path: '/name',\n message: 'name must be 1 to 256 characters.',\n });\n }\n\n const manifest: Record<string, unknown> = {\n schemaVersion: 2,\n id: input.key,\n name,\n version: '1.0.0',\n ...(input.description ? { description: input.description } : {}),\n slots:\n input.slots && input.slots.length > 0\n ? input.slots\n : (templateManifest.slots ?? DEFAULT_SLOTS),\n options: input.options ?? templateManifest.options,\n };\n problems.push(...validateManifest(manifest));\n\n const packageJson = JSON.parse(template['package.json']) as Record<\n string,\n unknown\n >;\n packageJson.name = input.key;\n\n const files: Record<string, string> = {};\n for (const [file, content] of Object.entries(template)) {\n if (file === 'manifest.json')\n files[file] = `${JSON.stringify(manifest, null, 2)}\\n`;\n else if (file === 'package.json')\n files[file] = `${JSON.stringify(packageJson, null, 2)}\\n`;\n else files[file] = content;\n }\n\n return {\n ok: problems.length === 0,\n problems,\n files,\n nextStep:\n 'Write these files into a folder, edit chart.ts, then run `databrain custom-chart validate` and ' +\n '`databrain custom-chart build`. Upload with `databrain custom-chart upload` or the custom_chart_upload tool.',\n };\n}\n"],"mappings":"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","names":["z"]}
|