@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.
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createChartAppServer
4
- } from "../chunk-4DYPD273.js";
5
- import "../chunk-5IQ7MVUH.js";
6
- import "../chunk-PRE4CGOV.js";
4
+ } from "../chunk-7G5QBEPC.js";
5
+ import "../chunk-Z2SF3K6P.js";
6
+ import "../chunk-SKU37UVJ.js";
7
7
  export {
8
8
  createChartAppServer
9
9
  };
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadConfig
4
- } from "../chunk-V64ZQINV.js";
4
+ } from "../chunk-SDFC7PKT.js";
5
5
  import {
6
6
  createChartAppServer
7
- } from "../chunk-4DYPD273.js";
8
- import "../chunk-5IQ7MVUH.js";
9
- import "../chunk-PRE4CGOV.js";
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-5IQ7MVUH.js";
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-PRE4CGOV.js";
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-4DYPD273.js.map
516
+ //# sourceMappingURL=chunk-7G5QBEPC.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  oauthConfigSchema,
4
4
  oauthHttpsUrl
5
- } from "./chunk-PRE4CGOV.js";
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-V64ZQINV.js.map
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.5",
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 errorMsg = parsed.message || parsed.detail || (typeof parsed.error === "string" ? parsed.error : JSON.stringify(parsed.error)) || `API request failed with status ${response.status}`;
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
- parsed.code || `HTTP_${response.status}`,
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 isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
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 (!isRecord(value)) {
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 (!isRecord(value)) {
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) => isRecord(choice) && Object.keys(choice).length === 2 && isId(choice.value) && isText(choice.label)
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 (!isRecord(value)) {
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 (!isRecord(entry)) {
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 (!isRecord(entrySlots)) {
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 (!isRecord(slotEntry)) {
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 (!isRecord(entryOptions)) {
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 (!isRecord(optionEntry)) {
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 (!isRecord(choices)) {
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 (!isRecord(value)) {
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 (!isRecord(slot) || typeof slot.id !== "string") return;
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 (!isRecord(option) || typeof option.id !== "string") return;
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 (isRecord(value)) {
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-PRE4CGOV.js.map
1934
+ //# sourceMappingURL=chunk-SKU37UVJ.js.map