@databrainhq/mcp-server 0.3.0-rc.5 → 0.3.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/server.js +3 -3
- package/dist/apps/stdio.js +4 -4
- package/dist/{chunk-4DYPD273.js → chunk-7G5QBEPC.js} +3 -3
- package/dist/{chunk-V64ZQINV.js → chunk-SDFC7PKT.js} +2 -2
- package/dist/{chunk-PRE4CGOV.js → chunk-SKU37UVJ.js} +55 -24
- package/dist/chunk-SKU37UVJ.js.map +1 -0
- package/dist/{chunk-5IQ7MVUH.js → chunk-Z2SF3K6P.js} +5 -3
- package/dist/{chunk-5IQ7MVUH.js.map → chunk-Z2SF3K6P.js.map} +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.js +4 -4
- package/dist/{main-Q6XT4O46.js → main-NGBJJTV6.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-PRE4CGOV.js.map +0 -1
- /package/dist/{chunk-4DYPD273.js.map → chunk-7G5QBEPC.js.map} +0 -0
- /package/dist/{chunk-V64ZQINV.js.map → chunk-SDFC7PKT.js.map} +0 -0
- /package/dist/{main-Q6XT4O46.js.map → main-NGBJJTV6.js.map} +0 -0
package/dist/apps/server.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
createChartAppServer
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-7G5QBEPC.js";
|
|
5
|
+
import "../chunk-Z2SF3K6P.js";
|
|
6
|
+
import "../chunk-SKU37UVJ.js";
|
|
7
7
|
export {
|
|
8
8
|
createChartAppServer
|
|
9
9
|
};
|
package/dist/apps/stdio.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadConfig
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-SDFC7PKT.js";
|
|
5
5
|
import {
|
|
6
6
|
createChartAppServer
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-7G5QBEPC.js";
|
|
8
|
+
import "../chunk-Z2SF3K6P.js";
|
|
9
|
+
import "../chunk-SKU37UVJ.js";
|
|
10
10
|
|
|
11
11
|
// src/apps/stdio.ts
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -22,13 +22,13 @@ import {
|
|
|
22
22
|
saveDraftAsDashboard,
|
|
23
23
|
viewSchema,
|
|
24
24
|
workspacesForDatamart
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-Z2SF3K6P.js";
|
|
26
26
|
import {
|
|
27
27
|
DatabrainApiError,
|
|
28
28
|
DatabrainClient,
|
|
29
29
|
MCP_SERVER_VERSION,
|
|
30
30
|
toolContext
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-SKU37UVJ.js";
|
|
32
32
|
|
|
33
33
|
// src/apps/server.ts
|
|
34
34
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -513,4 +513,4 @@ function createChartAppServer(config, backend) {
|
|
|
513
513
|
export {
|
|
514
514
|
createChartAppServer
|
|
515
515
|
};
|
|
516
|
-
//# sourceMappingURL=chunk-
|
|
516
|
+
//# sourceMappingURL=chunk-7G5QBEPC.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
oauthConfigSchema,
|
|
4
4
|
oauthHttpsUrl
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SKU37UVJ.js";
|
|
6
6
|
|
|
7
7
|
// src/utils/config.ts
|
|
8
8
|
import { z, ZodError } from "zod";
|
|
@@ -72,4 +72,4 @@ export {
|
|
|
72
72
|
DEFAULT_POSTHOG_HOST,
|
|
73
73
|
loadConfig
|
|
74
74
|
};
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-SDFC7PKT.js.map
|
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
// src/utils/errors.ts
|
|
4
4
|
var DatabrainApiError = class extends Error {
|
|
5
|
-
constructor(status, code, message, details) {
|
|
5
|
+
constructor(status, code, message, details, serverHint, retryable) {
|
|
6
6
|
super(message);
|
|
7
7
|
this.status = status;
|
|
8
8
|
this.code = code;
|
|
9
9
|
this.details = details;
|
|
10
|
+
this.serverHint = serverHint;
|
|
11
|
+
this.retryable = retryable;
|
|
10
12
|
this.name = "DatabrainApiError";
|
|
11
13
|
}
|
|
12
14
|
toToolResponse() {
|
|
13
15
|
const parts = [`Error: ${this.message}`];
|
|
14
16
|
const detailDump = this.formatDetails();
|
|
15
17
|
if (detailDump) parts.push(detailDump);
|
|
16
|
-
const hint = this.hint();
|
|
18
|
+
const hint = this.serverHint ? `Hint: ${this.serverHint}` : this.hint();
|
|
17
19
|
if (hint) parts.push(hint);
|
|
18
20
|
return {
|
|
19
21
|
content: [{ type: "text", text: parts.join("\n\n") }],
|
|
@@ -29,7 +31,7 @@ var DatabrainApiError = class extends Error {
|
|
|
29
31
|
formatDetails() {
|
|
30
32
|
if (this.status < 400 || this.status >= 500) return "";
|
|
31
33
|
if (!this.details || typeof this.details !== "object") return "";
|
|
32
|
-
const skipKeys = /* @__PURE__ */ new Set(["message", "detail", "error", "code"]);
|
|
34
|
+
const skipKeys = /* @__PURE__ */ new Set(["message", "detail", "error", "code", "data", "hint", "retryable"]);
|
|
33
35
|
const extra = {};
|
|
34
36
|
for (const [k, v] of Object.entries(this.details)) {
|
|
35
37
|
if (skipKeys.has(k)) continue;
|
|
@@ -44,6 +46,9 @@ var DatabrainApiError = class extends Error {
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
hint() {
|
|
49
|
+
if (this.code === "UNAUTHORIZED_ORIGIN") {
|
|
50
|
+
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.";
|
|
51
|
+
}
|
|
47
52
|
if (this.status === 401 || this.status === 403) {
|
|
48
53
|
if (this.code === "OAUTH_API_ERROR") {
|
|
49
54
|
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.";
|
|
@@ -123,7 +128,7 @@ var logger = {
|
|
|
123
128
|
// package.json
|
|
124
129
|
var package_default = {
|
|
125
130
|
name: "@databrainhq/mcp-server",
|
|
126
|
-
version: "0.3.0-rc.
|
|
131
|
+
version: "0.3.0-rc.6",
|
|
127
132
|
description: "MCP server for Databrain embedded analytics - connect databases, create datamarts, configure embeds, and generate frontend code",
|
|
128
133
|
type: "module",
|
|
129
134
|
bin: {
|
|
@@ -214,6 +219,29 @@ var TtlCache = class {
|
|
|
214
219
|
}
|
|
215
220
|
};
|
|
216
221
|
|
|
222
|
+
// src/client/error-body.ts
|
|
223
|
+
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
224
|
+
var str = (v) => typeof v === "string" && v.trim() ? v : void 0;
|
|
225
|
+
var fromEnvelope = (v) => {
|
|
226
|
+
if (!isRecord(v)) return void 0;
|
|
227
|
+
const out = {
|
|
228
|
+
code: str(v.code),
|
|
229
|
+
message: str(v.message) ?? str(v.detail),
|
|
230
|
+
hint: str(v.hint),
|
|
231
|
+
retryable: typeof v.retryable === "boolean" ? v.retryable : void 0,
|
|
232
|
+
details: v.details
|
|
233
|
+
};
|
|
234
|
+
return out.code || out.message || out.hint ? out : void 0;
|
|
235
|
+
};
|
|
236
|
+
function parseErrorBody(body) {
|
|
237
|
+
if (!isRecord(body)) return {};
|
|
238
|
+
const nested = fromEnvelope(isRecord(body.data) ? body.data.error : void 0) ?? fromEnvelope(body.error) ?? fromEnvelope(body);
|
|
239
|
+
if (nested) {
|
|
240
|
+
return { ...nested, message: nested.message ?? str(body.error) };
|
|
241
|
+
}
|
|
242
|
+
return { message: str(body.error) };
|
|
243
|
+
}
|
|
244
|
+
|
|
217
245
|
// src/utils/tool-context.ts
|
|
218
246
|
import { AsyncLocalStorage } from "async_hooks";
|
|
219
247
|
var toolContext = new AsyncLocalStorage();
|
|
@@ -531,14 +559,17 @@ var DatabrainClient = class {
|
|
|
531
559
|
parsed = JSON.parse(errorBody);
|
|
532
560
|
} catch {
|
|
533
561
|
}
|
|
534
|
-
const
|
|
562
|
+
const envelope = parseErrorBody(parsed);
|
|
563
|
+
const errorMsg = envelope.message || `API request failed with status ${response.status}`;
|
|
535
564
|
const error = new DatabrainApiError(
|
|
536
565
|
response.status,
|
|
537
|
-
|
|
566
|
+
envelope.code || `HTTP_${response.status}`,
|
|
538
567
|
errorMsg,
|
|
539
|
-
parsed
|
|
568
|
+
parsed,
|
|
569
|
+
envelope.hint,
|
|
570
|
+
envelope.retryable
|
|
540
571
|
);
|
|
541
|
-
const isTransient = response.status === 429 || response.status >= 500 && !NON_TRANSIENT_PATTERNS.some((p) => errorMsg.includes(p));
|
|
572
|
+
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));
|
|
542
573
|
if (isTransient && attempt < MAX_RETRIES) {
|
|
543
574
|
const delay = Math.min(1e3 * Math.pow(2, attempt - 1), 8e3);
|
|
544
575
|
logger.warn(`Retrying in ${delay}ms (attempt ${attempt}/${MAX_RETRIES})`, {
|
|
@@ -669,7 +700,7 @@ var V2_OPTION_EXTRA_KEYS = {
|
|
|
669
700
|
var TRANSLATION_KEYS = ["name", "description", "slots", "options"];
|
|
670
701
|
var SLOT_TRANSLATION_KEYS = ["label", "description"];
|
|
671
702
|
var OPTION_TRANSLATION_KEYS = ["label", "group", "choices"];
|
|
672
|
-
var
|
|
703
|
+
var isRecord2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
673
704
|
var isId = (value) => typeof value === "string" && ID_PATTERN.test(value) && !FORBIDDEN_IDS.includes(value);
|
|
674
705
|
var isText = (value, max = MAX_TEXT) => typeof value === "string" && value.length > 0 && value.length <= max;
|
|
675
706
|
var isTranslationText = (value) => typeof value === "string" && value.length <= MAX_TEXT;
|
|
@@ -704,7 +735,7 @@ var Collector = class {
|
|
|
704
735
|
}
|
|
705
736
|
};
|
|
706
737
|
function validateSlot(c, value, path, v2) {
|
|
707
|
-
if (!
|
|
738
|
+
if (!isRecord2(value)) {
|
|
708
739
|
c.add("manifest.slot.invalid", path, "A slot must be an object.");
|
|
709
740
|
return;
|
|
710
741
|
}
|
|
@@ -734,7 +765,7 @@ function validateSlot(c, value, path, v2) {
|
|
|
734
765
|
}
|
|
735
766
|
}
|
|
736
767
|
function validateOption(c, value, path, v2) {
|
|
737
|
-
if (!
|
|
768
|
+
if (!isRecord2(value)) {
|
|
738
769
|
c.add("manifest.option.invalid", path, "An option must be an object.");
|
|
739
770
|
return;
|
|
740
771
|
}
|
|
@@ -799,7 +830,7 @@ function validateOption(c, value, path, v2) {
|
|
|
799
830
|
case "select": {
|
|
800
831
|
const choices = value.choices;
|
|
801
832
|
const choicesOk = Array.isArray(choices) && choices.length > 0 && choices.length <= MAX_CHOICES && choices.every(
|
|
802
|
-
(choice) =>
|
|
833
|
+
(choice) => isRecord2(choice) && Object.keys(choice).length === 2 && isId(choice.value) && isText(choice.label)
|
|
803
834
|
) && new Set(choices.map((choice) => choice.value)).size === choices.length;
|
|
804
835
|
if (!choicesOk) {
|
|
805
836
|
c.add("manifest.option.choices", `${path}/choices`, `choices is a list of 1 to ${MAX_CHOICES} distinct { value, label } pairs; a value follows the id rule.`);
|
|
@@ -821,7 +852,7 @@ function validateOption(c, value, path, v2) {
|
|
|
821
852
|
}
|
|
822
853
|
function validateTranslations(c, value, slots, options) {
|
|
823
854
|
const path = "/translations";
|
|
824
|
-
if (!
|
|
855
|
+
if (!isRecord2(value)) {
|
|
825
856
|
c.add("manifest.translations.invalid", path, "translations is an object keyed by language code.");
|
|
826
857
|
return;
|
|
827
858
|
}
|
|
@@ -831,7 +862,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
831
862
|
c.add("manifest.translations.language", langPath, `"${language}" is not a language code like "fr" or "pt-BR".`);
|
|
832
863
|
continue;
|
|
833
864
|
}
|
|
834
|
-
if (!
|
|
865
|
+
if (!isRecord2(entry)) {
|
|
835
866
|
c.add("manifest.translations.invalid", langPath, "A translation is an object with optional name, description, slots and options.");
|
|
836
867
|
continue;
|
|
837
868
|
}
|
|
@@ -843,7 +874,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
843
874
|
}
|
|
844
875
|
if (Object.hasOwn(entry, "slots")) {
|
|
845
876
|
const entrySlots = entry.slots;
|
|
846
|
-
if (!
|
|
877
|
+
if (!isRecord2(entrySlots)) {
|
|
847
878
|
c.add("manifest.translations.invalid", `${langPath}/slots`, "slots is an object keyed by slot id.");
|
|
848
879
|
} else {
|
|
849
880
|
for (const [slotId, slotEntry] of Object.entries(entrySlots)) {
|
|
@@ -852,7 +883,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
852
883
|
c.add("manifest.translations.slot", slotPath, `"${slotId}" is not a slot id in this manifest.`);
|
|
853
884
|
continue;
|
|
854
885
|
}
|
|
855
|
-
if (!
|
|
886
|
+
if (!isRecord2(slotEntry)) {
|
|
856
887
|
c.add("manifest.translations.invalid", slotPath, "A slot translation is an object with optional label and description.");
|
|
857
888
|
continue;
|
|
858
889
|
}
|
|
@@ -867,7 +898,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
867
898
|
}
|
|
868
899
|
if (Object.hasOwn(entry, "options")) {
|
|
869
900
|
const entryOptions = entry.options;
|
|
870
|
-
if (!
|
|
901
|
+
if (!isRecord2(entryOptions)) {
|
|
871
902
|
c.add("manifest.translations.invalid", `${langPath}/options`, "options is an object keyed by option id.");
|
|
872
903
|
} else {
|
|
873
904
|
for (const [optionId, optionEntry] of Object.entries(entryOptions)) {
|
|
@@ -877,7 +908,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
877
908
|
c.add("manifest.translations.option", optionPath, `"${optionId}" is not an option id in this manifest.`);
|
|
878
909
|
continue;
|
|
879
910
|
}
|
|
880
|
-
if (!
|
|
911
|
+
if (!isRecord2(optionEntry)) {
|
|
881
912
|
c.add("manifest.translations.invalid", optionPath, "An option translation is an object with optional label, group and choices.");
|
|
882
913
|
continue;
|
|
883
914
|
}
|
|
@@ -889,7 +920,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
889
920
|
}
|
|
890
921
|
if (!Object.hasOwn(optionEntry, "choices")) continue;
|
|
891
922
|
const choices = optionEntry.choices;
|
|
892
|
-
if (!
|
|
923
|
+
if (!isRecord2(choices)) {
|
|
893
924
|
c.add("manifest.translations.invalid", `${optionPath}/choices`, "choices is an object keyed by choice value.");
|
|
894
925
|
continue;
|
|
895
926
|
}
|
|
@@ -908,7 +939,7 @@ function validateTranslations(c, value, slots, options) {
|
|
|
908
939
|
}
|
|
909
940
|
function validateManifest(value) {
|
|
910
941
|
const c = new Collector();
|
|
911
|
-
if (!
|
|
942
|
+
if (!isRecord2(value)) {
|
|
912
943
|
c.add("manifest.invalid", "", "manifest.json must be a JSON object.");
|
|
913
944
|
return c.problems;
|
|
914
945
|
}
|
|
@@ -944,7 +975,7 @@ function validateManifest(value) {
|
|
|
944
975
|
slots.forEach((slot, index) => validateSlot(c, slot, `/slots/${index}`, v2));
|
|
945
976
|
const seen = /* @__PURE__ */ new Set();
|
|
946
977
|
slots.forEach((slot, index) => {
|
|
947
|
-
if (!
|
|
978
|
+
if (!isRecord2(slot) || typeof slot.id !== "string") return;
|
|
948
979
|
if (seen.has(slot.id)) {
|
|
949
980
|
c.add("manifest.slot.duplicate", `/slots/${index}/id`, `Slot id "${slot.id}" is used more than once.`);
|
|
950
981
|
}
|
|
@@ -960,7 +991,7 @@ function validateManifest(value) {
|
|
|
960
991
|
options.forEach((option, index) => validateOption(c, option, `/options/${index}`, v2));
|
|
961
992
|
const seen = /* @__PURE__ */ new Set();
|
|
962
993
|
options.forEach((option, index) => {
|
|
963
|
-
if (!
|
|
994
|
+
if (!isRecord2(option) || typeof option.id !== "string") return;
|
|
964
995
|
if (seen.has(option.id)) {
|
|
965
996
|
c.add("manifest.option.duplicate", `/options/${index}/id`, `Option id "${option.id}" is used more than once.`);
|
|
966
997
|
}
|
|
@@ -1012,7 +1043,7 @@ var manifestSchema = z2.object({
|
|
|
1012
1043
|
});
|
|
1013
1044
|
function sortKeys(value) {
|
|
1014
1045
|
if (Array.isArray(value)) return value.map((item) => sortKeys(item));
|
|
1015
|
-
if (
|
|
1046
|
+
if (isRecord2(value)) {
|
|
1016
1047
|
const out = {};
|
|
1017
1048
|
for (const key of Object.keys(value).sort()) out[key] = sortKeys(value[key]);
|
|
1018
1049
|
return out;
|
|
@@ -1900,4 +1931,4 @@ export {
|
|
|
1900
1931
|
apiProblems,
|
|
1901
1932
|
planUpload
|
|
1902
1933
|
};
|
|
1903
|
-
//# sourceMappingURL=chunk-
|
|
1934
|
+
//# sourceMappingURL=chunk-SKU37UVJ.js.map
|