@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.
Files changed (46) hide show
  1. package/.mcp.json +6 -1
  2. package/dist/apps/server.d.ts +102 -389
  3. package/dist/apps/server.js +5 -5
  4. package/dist/apps/stdio.d.ts +1 -2
  5. package/dist/apps/stdio.js +6 -6
  6. package/dist/{bundle-TDQXWIPM.js → bundle-QJNCUMNY.js} +2 -2
  7. package/dist/{chunk-Q5EYDKSA.js → chunk-2F7V6RZR.js} +511 -107
  8. package/dist/chunk-2F7V6RZR.js.map +1 -0
  9. package/dist/{chunk-AEQTEE5C.js → chunk-AWICHHDU.js} +153 -61
  10. package/dist/chunk-AWICHHDU.js.map +1 -0
  11. package/dist/{chunk-X44C5GW2.js → chunk-CEGHG5U3.js} +59 -18
  12. package/dist/chunk-CEGHG5U3.js.map +1 -0
  13. package/dist/{chunk-233VGFHY.js → chunk-NIC5MAGC.js} +317 -147
  14. package/dist/chunk-NIC5MAGC.js.map +1 -0
  15. package/dist/{chunk-DTFYHLYN.js → chunk-S65KA3Z7.js} +26 -11
  16. package/dist/chunk-S65KA3Z7.js.map +1 -0
  17. package/dist/{chunk-PSJVYD4W.js → chunk-UYFFFAYV.js} +11722 -10560
  18. package/dist/chunk-UYFFFAYV.js.map +1 -0
  19. package/dist/{chunk-HCYZN7I3.js → chunk-VQ5G5AZV.js} +10 -7
  20. package/dist/chunk-VQ5G5AZV.js.map +1 -0
  21. package/dist/cli.d.ts +16 -15
  22. package/dist/cli.js +134 -36
  23. package/dist/cli.js.map +1 -1
  24. package/dist/custom-chart/custom-runtime.js +6 -6
  25. package/dist/custom-chart/template/chart.ts +116 -28
  26. package/dist/custom-chart/template/icon.svg +1 -1
  27. package/dist/custom-chart/template/manifest.json +66 -12
  28. package/dist/custom-chart/template/sample-data.json +21 -3
  29. package/dist/index.d.ts +1 -2
  30. package/dist/index.js +20 -10
  31. package/dist/index.js.map +1 -1
  32. package/dist/{main-VEKNKWL5.js → main-QCBVJSSR.js} +348 -155
  33. package/dist/main-QCBVJSSR.js.map +1 -0
  34. package/dist/{test-only-LJGOY2QA.js → test-only-6474NMTR.js} +12 -8
  35. package/dist/test-only-6474NMTR.js.map +1 -0
  36. package/package.json +20 -9
  37. package/dist/chunk-233VGFHY.js.map +0 -1
  38. package/dist/chunk-AEQTEE5C.js.map +0 -1
  39. package/dist/chunk-DTFYHLYN.js.map +0 -1
  40. package/dist/chunk-HCYZN7I3.js.map +0 -1
  41. package/dist/chunk-PSJVYD4W.js.map +0 -1
  42. package/dist/chunk-Q5EYDKSA.js.map +0 -1
  43. package/dist/chunk-X44C5GW2.js.map +0 -1
  44. package/dist/main-VEKNKWL5.js.map +0 -1
  45. package/dist/test-only-LJGOY2QA.js.map +0 -1
  46. /package/dist/{bundle-TDQXWIPM.js.map → bundle-QJNCUMNY.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  registerChartApps
4
- } from "./chunk-233VGFHY.js";
4
+ } from "./chunk-NIC5MAGC.js";
5
5
  import {
6
6
  PREVIEW_PATH,
7
7
  WRITE_CREATE,
@@ -9,7 +9,7 @@ import {
9
9
  registerAllPrompts,
10
10
  registerAllResources,
11
11
  registerAllTools
12
- } from "./chunk-PSJVYD4W.js";
12
+ } from "./chunk-UYFFFAYV.js";
13
13
  import {
14
14
  DatabrainApiError,
15
15
  DatabrainClient,
@@ -20,15 +20,15 @@ import {
20
20
  toolContext,
21
21
  toolError,
22
22
  toolSuccess
23
- } from "./chunk-AEQTEE5C.js";
24
- import "./chunk-Q5EYDKSA.js";
23
+ } from "./chunk-AWICHHDU.js";
24
+ import "./chunk-2F7V6RZR.js";
25
25
  import {
26
26
  FilePatStore,
27
27
  HOSTED_SCOPES,
28
28
  HostedAuthError,
29
29
  createBearerVerifier,
30
30
  principalSchema
31
- } from "./chunk-X44C5GW2.js";
31
+ } from "./chunk-CEGHG5U3.js";
32
32
 
33
33
  // src/hosted/main.ts
34
34
  import { isAbsolute } from "path";
@@ -37,16 +37,21 @@ import { pathToFileURL } from "url";
37
37
  // src/hosted/config.ts
38
38
  function loadHostedConfig(env = process.env) {
39
39
  const testOnly = env.DATABRAIN_HOSTED_TEST_ONLY === "1";
40
- if (testOnly && env.NODE_ENV === "production") throw new Error("Hosted test mode is forbidden in production.");
41
- if (env.DATABRAIN_HOSTED_TEST_ONLY && !testOnly) throw new Error("Invalid DATABRAIN_HOSTED_TEST_ONLY.");
40
+ if (testOnly && env.NODE_ENV === "production")
41
+ throw new Error("Hosted test mode is forbidden in production.");
42
+ if (env.DATABRAIN_HOSTED_TEST_ONLY && !testOnly)
43
+ throw new Error("Invalid DATABRAIN_HOSTED_TEST_ONLY.");
42
44
  const validUrl = (value, field) => {
43
45
  try {
44
46
  if (!value) throw new Error();
45
47
  const url = new URL(value);
46
- if (url.username || url.password || url.search || url.hash || url.protocol !== "https:") throw new Error();
48
+ if (url.username || url.password || url.search || url.hash || url.protocol !== "https:")
49
+ throw new Error();
47
50
  return url;
48
51
  } catch {
49
- throw new Error(`Configure ${field} as an HTTPS URL without credentials, query or fragment.`);
52
+ throw new Error(
53
+ `Configure ${field} as an HTTPS URL without credentials, query or fragment.`
54
+ );
50
55
  }
51
56
  };
52
57
  let publicValue = env.DATABRAIN_HOSTED_PUBLIC_URL;
@@ -58,10 +63,12 @@ function loadHostedConfig(env = process.env) {
58
63
  }
59
64
  const publicUrl = validUrl(publicValue, "DATABRAIN_HOSTED_PUBLIC_URL");
60
65
  validUrl(issuerValue, "DATABRAIN_HOSTED_ISSUER");
61
- if (publicUrl.pathname !== "/mcp") throw new Error("DATABRAIN_HOSTED_PUBLIC_URL must end in /mcp.");
66
+ if (publicUrl.pathname !== "/mcp")
67
+ throw new Error("DATABRAIN_HOSTED_PUBLIC_URL must end in /mcp.");
62
68
  const port = Number(env.DATABRAIN_HOSTED_PORT || "3144");
63
69
  const bind = env.DATABRAIN_HOSTED_BIND || "127.0.0.1";
64
- if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error("Invalid DATABRAIN_HOSTED_PORT.");
70
+ if (!Number.isInteger(port) || port < 1024 || port > 65535)
71
+ throw new Error("Invalid DATABRAIN_HOSTED_PORT.");
65
72
  let apiUrl;
66
73
  if (env.DATABRAIN_HOSTED_API_URL) {
67
74
  let url;
@@ -71,7 +78,9 @@ function loadHostedConfig(env = process.env) {
71
78
  url = void 0;
72
79
  }
73
80
  if (!url || !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash || url.pathname !== "/") {
74
- throw new Error("Configure DATABRAIN_HOSTED_API_URL as an origin without credentials, path, query or fragment.");
81
+ throw new Error(
82
+ "Configure DATABRAIN_HOSTED_API_URL as an origin without credentials, path, query or fragment."
83
+ );
75
84
  }
76
85
  apiUrl = url.origin;
77
86
  }
@@ -86,64 +95,11 @@ function loadHostedConfig(env = process.env) {
86
95
  }
87
96
 
88
97
  // src/hosted/http.ts
89
- import { createServer } from "http";
98
+ import {
99
+ createServer
100
+ } from "http";
90
101
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
91
102
 
92
- // src/hosted/server.ts
93
- import { AsyncLocalStorage } from "async_hooks";
94
- import { z as z2 } from "zod";
95
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
96
- import { instrument } from "@posthog/mcp";
97
- import { PostHog } from "posthog-node";
98
-
99
- // src/tools/infrastructure/create-workspace.ts
100
- import { z } from "zod";
101
- function registerCreateWorkspace(server, client) {
102
- server.tool(
103
- "create_workspace",
104
- 'Create a new workspace to connect a datasource or datamart for dashboard building. Works only when this sign-in granted "All workspaces I can access" and your role may create workspaces; the new workspace is usable on the next call.',
105
- {
106
- name: z.string().describe("Unique workspace name"),
107
- connectionType: z.enum(["DATASOURCE", "DATAMART", "MULTI_DATASOURCE"]).optional().describe("Connection type \u2014 DATASOURCE, DATAMART, or MULTI_DATASOURCE"),
108
- datasourceName: z.string().optional().describe("Datasource name (required when connectionType is DATASOURCE)"),
109
- datamartName: z.string().optional().describe("Datamart name (required when connectionType is DATAMART)"),
110
- body: z.record(z.unknown()).optional().describe("Raw API body passthrough for POST /api/v2/workspace")
111
- },
112
- WRITE_CREATE,
113
- async (params) => {
114
- try {
115
- const body = params.body ? { ...params.body } : {
116
- name: params.name,
117
- connectionType: params.connectionType,
118
- datasourceName: params.datasourceName,
119
- datamartName: params.datamartName
120
- };
121
- const result = await client.request({
122
- method: "POST",
123
- path: "/api/v2/workspace",
124
- body,
125
- auth: "service",
126
- invalidateCache: ["list_workspaces"]
127
- });
128
- if (result.error) {
129
- return toolError(`Workspace creation failed: ${stringify(result.error)}`);
130
- }
131
- return toolSuccess(
132
- `Workspace "${result.name || params.name}" created successfully.
133
-
134
- Next steps:
135
- 1. Use \`create_data_app\` to create a data app linked to this workspace
136
- 2. Build dashboards in the Databrain UI using this workspace
137
- 3. Use \`create_embed\` to embed dashboards`
138
- );
139
- } catch (err) {
140
- if (err instanceof DatabrainApiError) return err.toToolResponse();
141
- return toolError(`Unexpected error: ${err.message}`);
142
- }
143
- }
144
- );
145
- }
146
-
147
103
  // src/hosted/authorization.ts
148
104
  var TOOL_SCOPES = {
149
105
  whoami: [],
@@ -172,7 +128,11 @@ var TOOL_SCOPES = {
172
128
  create_dashboard: ["mcp:dashboards:write"],
173
129
  get_dashboard: ["mcp:dashboards:read"],
174
130
  dashboard_snapshot: ["mcp:dashboards:read"],
175
- generate_dashboard_tiles: ["mcp:dashboards:write", "mcp:query", "mcp:embeds:write"],
131
+ generate_dashboard_tiles: [
132
+ "mcp:dashboards:write",
133
+ "mcp:query",
134
+ "mcp:embeds:write"
135
+ ],
176
136
  ask_question: ["mcp:query"],
177
137
  get_semantic_layer: ["mcp:datamarts:read"],
178
138
  update_semantic_layer: ["mcp:datamarts:write"],
@@ -184,8 +144,16 @@ var TOOL_SCOPES = {
184
144
  apply_semantic_change: ["mcp:datamarts:write"],
185
145
  eval_semantic_model: ["mcp:datamarts:read", "mcp:query"],
186
146
  list_widgets: ["mcp:dashboards:read"],
187
- validate_metric_spec: ["mcp:dashboards:read", "mcp:query", "mcp:embeds:write"],
188
- create_or_update_metric_from_query: ["mcp:dashboards:write", "mcp:query", "mcp:embeds:write"],
147
+ validate_metric_spec: [
148
+ "mcp:dashboards:read",
149
+ "mcp:query",
150
+ "mcp:embeds:write"
151
+ ],
152
+ create_or_update_metric_from_query: [
153
+ "mcp:dashboards:write",
154
+ "mcp:query",
155
+ "mcp:embeds:write"
156
+ ],
189
157
  create_workspace_metric: ["mcp:dashboards:write", "mcp:query"],
190
158
  add_widget: ["mcp:dashboards:write", "mcp:embeds:write"],
191
159
  update_widget: ["mcp:dashboards:write", "mcp:embeds:write"],
@@ -213,12 +181,15 @@ var TOOL_SCOPES = {
213
181
  change_date_range: ["mcp:dashboards:read", "mcp:query"]
214
182
  };
215
183
  function requiredScopes(name) {
216
- if (!Object.hasOwn(TOOL_SCOPES, name)) throw new HostedAuthError(403, "tool_not_authorized");
184
+ if (!Object.hasOwn(TOOL_SCOPES, name))
185
+ throw new HostedAuthError(403, "tool_not_authorized");
217
186
  return TOOL_SCOPES[name];
218
187
  }
219
188
  function authorizeTool(name, principal) {
220
- if (principal.expiresAt !== void 0 && principal.expiresAt <= Date.now() / 1e3) throw new HostedAuthError(401, "invalid_token");
221
- if (requiredScopes(name).some((scope) => !principal.scopes.includes(scope))) throw new HostedAuthError(403, "insufficient_scope");
189
+ if (principal.expiresAt !== void 0 && principal.expiresAt <= Date.now() / 1e3)
190
+ throw new HostedAuthError(401, "invalid_token");
191
+ if (requiredScopes(name).some((scope) => !principal.scopes.includes(scope)))
192
+ throw new HostedAuthError(403, "insufficient_scope");
222
193
  }
223
194
  var TOOL_ARGUMENT_VALUES = {
224
195
  list_dashboards: { scope: ["auto", "data_app", "global"] }
@@ -242,7 +213,8 @@ function assertToolArguments(name, value, principal, delegated = false) {
242
213
  rest[key] = child;
243
214
  continue;
244
215
  }
245
- if (typeof child !== "string" || !allowed[key].includes(child)) throw new HostedAuthError(403, "identity_argument_forbidden");
216
+ if (typeof child !== "string" || !allowed[key].includes(child))
217
+ throw new HostedAuthError(403, "identity_argument_forbidden");
246
218
  }
247
219
  assertBoundArguments(rest, principal, { target, delegated, opaque });
248
220
  return target;
@@ -261,7 +233,9 @@ var WORKSPACE_FREE_TOOLS = /* @__PURE__ */ new Set([
261
233
  "list_custom_charts",
262
234
  "publish_custom_chart"
263
235
  ]);
264
- var WORKSPACE_SPANNING_TOOLS = /* @__PURE__ */ new Set(["list_dashboards"]);
236
+ var WORKSPACE_SPANNING_TOOLS = /* @__PURE__ */ new Set([
237
+ "list_dashboards"
238
+ ]);
265
239
  var WORKSPACE_INPUT = "workspace";
266
240
  var WorkspaceSelectionError = class extends HostedAuthError {
267
241
  constructor(status, code, reason) {
@@ -274,7 +248,9 @@ function grantedWorkspaces(principal) {
274
248
  return principal.workspaceId ? [{ id: principal.workspaceId, name: principal.workspaceName }] : [];
275
249
  }
276
250
  function grantedNames(principal) {
277
- const names = grantedWorkspaces(principal).map((item) => item.name ?? item.id);
251
+ const names = grantedWorkspaces(principal).map(
252
+ (item) => item.name ?? item.id
253
+ );
278
254
  return names.length > 20 ? `${names.slice(0, 20).join(", ")} and ${names.length - 20} more` : names.join(", ");
279
255
  }
280
256
  function findGranted(principal, key, value) {
@@ -311,7 +287,9 @@ function selectWorkspace(args, principal, keys = [WORKSPACE_INPUT, "workspaceNam
311
287
  }
312
288
  function namesWorkspace(value) {
313
289
  if (!value || typeof value !== "object") return false;
314
- return Object.entries(value).some(([key, child]) => [WORKSPACE_INPUT, "workspaceName", "workspaceId"].includes(key) && child !== void 0 || namesWorkspace(child));
290
+ return Object.entries(value).some(
291
+ ([key, child]) => [WORKSPACE_INPUT, "workspaceName", "workspaceId"].includes(key) && child !== void 0 || namesWorkspace(child)
292
+ );
315
293
  }
316
294
  function tenantAllowed(child, principal, delegated) {
317
295
  if (typeof child !== "string") return false;
@@ -357,18 +335,85 @@ function assertBoundArguments(value, principal, binding = {}) {
357
335
  }
358
336
 
359
337
  // src/hosted/server.ts
360
- var schemaInstrumentation = new PostHog("hosted-contract-only", { disabled: true });
338
+ import { AsyncLocalStorage } from "async_hooks";
339
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
340
+ import { instrument } from "@posthog/mcp";
341
+ import { PostHog } from "posthog-node";
342
+ import { z as z2 } from "zod";
343
+
344
+ // src/tools/infrastructure/create-workspace.ts
345
+ import { z } from "zod";
346
+ function registerCreateWorkspace(server, client) {
347
+ server.tool(
348
+ "create_workspace",
349
+ 'Create a new workspace to connect a datasource or datamart for dashboard building. Works only when this sign-in granted "All workspaces I can access" and your role may create workspaces; the new workspace is usable on the next call.',
350
+ {
351
+ name: z.string().describe("Unique workspace name"),
352
+ connectionType: z.enum(["DATASOURCE", "DATAMART", "MULTI_DATASOURCE"]).optional().describe(
353
+ "Connection type \u2014 DATASOURCE, DATAMART, or MULTI_DATASOURCE"
354
+ ),
355
+ datasourceName: z.string().optional().describe(
356
+ "Datasource name (required when connectionType is DATASOURCE)"
357
+ ),
358
+ datamartName: z.string().optional().describe("Datamart name (required when connectionType is DATAMART)"),
359
+ body: z.record(z.string(), z.unknown()).optional().describe("Raw API body passthrough for POST /api/v2/workspace")
360
+ },
361
+ WRITE_CREATE,
362
+ async (params) => {
363
+ try {
364
+ const body = params.body ? { ...params.body } : {
365
+ name: params.name,
366
+ connectionType: params.connectionType,
367
+ datasourceName: params.datasourceName,
368
+ datamartName: params.datamartName
369
+ };
370
+ const result = await client.request({
371
+ method: "POST",
372
+ path: "/api/v2/workspace",
373
+ body,
374
+ auth: "service",
375
+ invalidateCache: ["list_workspaces"]
376
+ });
377
+ if (result.error) {
378
+ return toolError(
379
+ `Workspace creation failed: ${stringify(result.error)}`
380
+ );
381
+ }
382
+ return toolSuccess(
383
+ `Workspace "${result.name || params.name}" created successfully.
384
+
385
+ Next steps:
386
+ 1. Use \`create_data_app\` to create a data app linked to this workspace
387
+ 2. Build dashboards in the Databrain UI using this workspace
388
+ 3. Use \`create_embed\` to embed dashboards`
389
+ );
390
+ } catch (err) {
391
+ if (err instanceof DatabrainApiError) return err.toToolResponse();
392
+ return toolError(`Unexpected error: ${err.message}`);
393
+ }
394
+ }
395
+ );
396
+ }
397
+
398
+ // src/hosted/server.ts
399
+ var schemaInstrumentation = new PostHog("hosted-contract-only", {
400
+ disabled: true
401
+ });
361
402
  var callWorkspace = new AsyncLocalStorage();
362
403
  var WORKSPACE_HINT = "Call whoami to see the workspaces this sign-in granted, then name one.";
363
404
  function workspaceError(error) {
364
- return toolError(`Error: ${error.reason} (${error.code})
405
+ return toolError(
406
+ `Error: ${error.reason} (${error.code})
365
407
 
366
- Hint: ${WORKSPACE_HINT}`);
408
+ Hint: ${WORKSPACE_HINT}`
409
+ );
367
410
  }
368
411
  function scopeError(missing) {
369
- return toolError(`Error: This connection cannot do this. It needs ${missing.join(", ")}, which your role did not allow when you connected. (INSUFFICIENT_SCOPE)
412
+ return toolError(
413
+ `Error: This connection cannot do this. It needs ${missing.join(", ")}, which your role did not allow when you connected. (INSUFFICIENT_SCOPE)
370
414
 
371
- Hint: Ask a Databrain admin for a role that allows it, then connect again. If your role allows it in a workspace you did not choose, connect again and choose that workspace.`);
415
+ Hint: Ask a Databrain admin for a role that allows it, then connect again. If your role allows it in a workspace you did not choose, connect again and choose that workspace.`
416
+ );
372
417
  }
373
418
  function onlyWorkspace(raw, target) {
374
419
  const keep = (items) => Array.isArray(items) ? items.filter((item) => {
@@ -376,12 +421,16 @@ function onlyWorkspace(raw, target) {
376
421
  return record.id === target.id || record._id === target.id || record.id === void 0 && record._id === void 0 && target.name !== void 0 && record.name === target.name;
377
422
  }) : items;
378
423
  if (Array.isArray(raw)) return keep(raw);
379
- if (raw && typeof raw === "object" && "data" in raw) return { ...raw, data: keep(raw.data) };
424
+ if (raw && typeof raw === "object" && "data" in raw)
425
+ return { ...raw, data: keep(raw.data) };
380
426
  return raw;
381
427
  }
382
428
  var HostedClient = class extends DatabrainClient {
383
429
  constructor(adapter, principal, delegation) {
384
- super({ apiUrl: "https://api.usedatabrain.com", demoDomain: "https://demo.usedatabrain.com" });
430
+ super({
431
+ apiUrl: "https://api.usedatabrain.com",
432
+ demoDomain: "https://demo.usedatabrain.com"
433
+ });
385
434
  this.adapter = adapter;
386
435
  this.principal = principal;
387
436
  this.delegation = delegation;
@@ -398,23 +447,46 @@ var HostedClient = class extends DatabrainClient {
398
447
  if (!name) throw new HostedAuthError(403, "tool_not_authorized");
399
448
  authorizeTool(name, this.principal);
400
449
  const named = callWorkspace.getStore()?.target;
401
- const target = named ?? (selectWorkspace(options.body, this.principal, ["workspaceName", "workspaceId"]) ?? selectWorkspace(options.query, this.principal, ["workspaceName", "workspaceId"]));
450
+ const target = named ?? selectWorkspace(options.body, this.principal, [
451
+ "workspaceName",
452
+ "workspaceId"
453
+ ]) ?? selectWorkspace(options.query, this.principal, [
454
+ "workspaceName",
455
+ "workspaceId"
456
+ ]);
402
457
  const delegated = this.delegation !== void 0;
403
- const opaque = options.method === "POST" && options.path === PREVIEW_PATH ? ["rows"] : options.method === "POST" && /^\/api\/v2\/custom-charts\/[a-z][a-z0-9_-]*\/bryn\/turn$/.test(options.path) ? ["draft"] : void 0;
404
- assertBoundArguments(options.body, this.principal, { target, delegated, opaque });
405
- assertBoundArguments(options.query, this.principal, { target, delegated });
458
+ const opaque = options.method === "POST" && options.path === PREVIEW_PATH ? ["rows"] : options.method === "POST" && /^\/api\/v2\/custom-charts\/[a-z][a-z0-9_-]*\/bryn\/turn$/.test(
459
+ options.path
460
+ ) ? ["draft"] : void 0;
461
+ assertBoundArguments(options.body, this.principal, {
462
+ target,
463
+ delegated,
464
+ opaque
465
+ });
466
+ assertBoundArguments(options.query, this.principal, {
467
+ target,
468
+ delegated
469
+ });
406
470
  let raw = await this.adapter.executeRequest(
407
471
  structuredClone(options),
408
472
  structuredClone(this.principal),
409
473
  this.delegation,
410
474
  target && structuredClone(target)
411
475
  );
412
- if (named && options.method === "GET" && options.path === "/api/v2/workspace") raw = onlyWorkspace(raw, named);
413
- if (!options.skipDataUnwrap && raw && typeof raw === "object" && !Array.isArray(raw) && "data" in raw && raw.data !== null && raw.data !== void 0) return raw.data;
476
+ if (named && options.method === "GET" && options.path === "/api/v2/workspace")
477
+ raw = onlyWorkspace(raw, named);
478
+ if (!options.skipDataUnwrap && raw && typeof raw === "object" && !Array.isArray(raw) && "data" in raw && raw.data !== null && raw.data !== void 0)
479
+ return raw.data;
414
480
  return raw;
415
481
  } catch (error) {
416
482
  if (error instanceof WorkspaceSelectionError) {
417
- throw new DatabrainApiError(error.status, error.code, `${error.reason} (${error.code})`, void 0, WORKSPACE_HINT);
483
+ throw new DatabrainApiError(
484
+ error.status,
485
+ error.code,
486
+ `${error.reason} (${error.code})`,
487
+ void 0,
488
+ WORKSPACE_HINT
489
+ );
418
490
  }
419
491
  const status = error instanceof HostedAuthError ? error.status : 503;
420
492
  const detail = error instanceof HostedAuthError ? error.detail : void 0;
@@ -456,37 +528,56 @@ function workspaceLine(name, input) {
456
528
  }
457
529
  function whoami(principal) {
458
530
  const granted = grantedWorkspaces(principal);
459
- return toolSuccess(JSON.stringify({
460
- status: "authenticated",
461
- activeBearer: principal.credentialType,
462
- actorKind: principal.actorKind,
463
- userId: principal.userId,
464
- companyId: principal.companyId,
465
- workspaceGrant: principal.workspaces?.mode === "all" ? "All workspaces I can access (new ones are included)" : "Only the workspaces chosen at sign-in",
466
- grantedWorkspaces: granted.map((item) => ({ id: item.id, name: item.name })),
467
- ...granted.length === 1 ? { workspaceId: granted[0].id, workspaceName: granted[0].name } : {},
468
- note: granted.length === 1 ? "Every call works in this workspace." : `Name the workspace on each call that works in one (the \`${WORKSPACE_INPUT}\` or \`workspaceName\` input): ${grantedNames(principal)}.`,
469
- oauthClientId: principal.clientId,
470
- scopes: principal.scopes
471
- }, null, 2));
531
+ return toolSuccess(
532
+ JSON.stringify(
533
+ {
534
+ status: "authenticated",
535
+ activeBearer: principal.credentialType,
536
+ actorKind: principal.actorKind,
537
+ userId: principal.userId,
538
+ companyId: principal.companyId,
539
+ workspaceGrant: principal.workspaces?.mode === "all" ? "All workspaces I can access (new ones are included)" : "Only the workspaces chosen at sign-in",
540
+ grantedWorkspaces: granted.map((item) => ({
541
+ id: item.id,
542
+ name: item.name
543
+ })),
544
+ ...granted.length === 1 ? { workspaceId: granted[0].id, workspaceName: granted[0].name } : {},
545
+ note: granted.length === 1 ? "Every call works in this workspace." : `Name the workspace on each call that works in one (the \`${WORKSPACE_INPUT}\` or \`workspaceName\` input): ${grantedNames(principal)}.`,
546
+ oauthClientId: principal.clientId,
547
+ scopes: principal.scopes
548
+ },
549
+ null,
550
+ 2
551
+ )
552
+ );
472
553
  }
473
554
  function createHostedToolServer(principal, adapter, delegation) {
474
555
  const bound = structuredClone(principal);
475
556
  const delegated = delegation !== void 0;
476
- const server = new McpServer({ name: "databrain", version: MCP_SERVER_VERSION }, {
477
- instructions: "Hosted Databrain: each request is authenticated as the signed-in user, with that user's own role in each workspace. Use whoami to see the verified identity, scopes and the workspaces this sign-in granted. When more than one workspace is granted, name the workspace on each call (the workspace or workspaceName input). Never ask for a service token or put credentials in tool arguments. Workspace and tenant access come from the bearer principal. Existing dry-run and production-confirmation rules still apply. For existing saved charts, call list_widgets with dashboardId or dashboardName and no clientId; no embed, data app or datamart is needed. Use render_metric_tile to draw a metricRef directly. Use ask_question for new data questions. Chart controls and save_chart_as_dashboard use the same workspace and role; saving requires the existing production confirmation. Hosts without MCP Apps can read the text answer."
478
- });
557
+ const server = new McpServer(
558
+ { name: "databrain", version: MCP_SERVER_VERSION },
559
+ {
560
+ instructions: "Hosted Databrain: each request is authenticated as the signed-in user, with that user's own role in each workspace. Use whoami to see the verified identity, scopes and the workspaces this sign-in granted. When more than one workspace is granted, name the workspace on each call (the workspace or workspaceName input). Never ask for a service token or put credentials in tool arguments. Workspace and tenant access come from the bearer principal. Existing dry-run and production-confirmation rules still apply. For existing saved charts, call list_widgets with dashboardId or dashboardName and no clientId; no embed, data app or datamart is needed. Use render_metric_tile to draw a metricRef directly. Use ask_question for new data questions. Chart controls and save_chart_as_dashboard use the same workspace and role; saving requires the existing production confirmation. Hosts without MCP Apps can read the text answer."
561
+ }
562
+ );
479
563
  const register = server.tool.bind(server);
480
564
  server.tool = ((...args) => {
481
565
  const name = args[0];
482
566
  const index = args.length - 1;
483
567
  const handler = args[index];
484
568
  const shape = typeof args[1] === "string" && args[2] && typeof args[2] === "object" && !("readOnlyHint" in args[2]) ? args[2] : void 0;
485
- const ownSelector = shape && ["workspaceName", "workspaceId"].find((key) => Object.hasOwn(shape, key));
569
+ const ownSelector = shape && ["workspaceName", "workspaceId"].find(
570
+ (key) => Object.hasOwn(shape, key)
571
+ );
486
572
  const addsInput = shape !== void 0 && !ownSelector && !WORKSPACE_FREE_TOOLS.has(name) && !Object.hasOwn(shape, WORKSPACE_INPUT);
487
573
  if (shape && !WORKSPACE_FREE_TOOLS.has(name)) {
488
574
  if (addsInput) {
489
- args[2] = { ...shape, [WORKSPACE_INPUT]: z2.string().min(1).max(512).optional().describe(WORKSPACE_SPANNING_TOOLS.has(name) ? "Workspace id or name. Leave it out to cover every granted workspace." : "Workspace id or name. Needed when you granted more than one workspace.") };
575
+ args[2] = {
576
+ ...shape,
577
+ [WORKSPACE_INPUT]: z2.string().min(1).max(512).optional().describe(
578
+ WORKSPACE_SPANNING_TOOLS.has(name) ? "Workspace id or name. Leave it out to cover every granted workspace." : "Workspace id or name. Needed when you granted more than one workspace."
579
+ )
580
+ };
490
581
  }
491
582
  args[1] = `${args[1]}${workspaceLine(name, addsInput ? WORKSPACE_INPUT : ownSelector)}`;
492
583
  }
@@ -496,7 +587,10 @@ function createHostedToolServer(principal, adapter, delegation) {
496
587
  const target = assertToolArguments(name, values[0], bound, delegated);
497
588
  if (name === "whoami") return whoami(bound);
498
589
  const input = values[0] && typeof values[0] === "object" ? values[0] : void 0;
499
- if (input?.projectDir !== void 0) return toolError("projectDir is not available on the hosted server. Pass chartTs, manifest, bundleCss and iconSvg to compile in memory.");
590
+ if (input?.projectDir !== void 0)
591
+ return toolError(
592
+ "projectDir is not available on the hosted server. Pass chartTs, manifest, bundleCss and iconSvg to compile in memory."
593
+ );
500
594
  if (!target && !WORKSPACE_FREE_TOOLS.has(name) && !WORKSPACE_SPANNING_TOOLS.has(name) && !namesWorkspace(input)) {
501
595
  throw new WorkspaceSelectionError(
502
596
  400,
@@ -507,18 +601,29 @@ function createHostedToolServer(principal, adapter, delegation) {
507
601
  if (input) {
508
602
  if (addsInput) delete input[WORKSPACE_INPUT];
509
603
  if (shape && target) {
510
- if (Object.hasOwn(shape, "workspaceId")) input.workspaceId = target.id;
511
- if (Object.hasOwn(shape, "workspaceName") && target.name !== void 0) input.workspaceName = target.name;
604
+ if (Object.hasOwn(shape, "workspaceId"))
605
+ input.workspaceId = target.id;
606
+ if (Object.hasOwn(shape, "workspaceName") && target.name !== void 0)
607
+ input.workspaceName = target.name;
512
608
  }
513
609
  }
514
- const result = await callWorkspace.run({ target }, () => handler(...values));
610
+ const result = await callWorkspace.run(
611
+ { target },
612
+ () => handler(...values)
613
+ );
515
614
  if (target && result?._meta?.["ui/resourceUri"]) {
516
- return { ...result, _meta: { ...result._meta, "databrain/workspace": target } };
615
+ return {
616
+ ...result,
617
+ _meta: { ...result._meta, "databrain/workspace": target }
618
+ };
517
619
  }
518
620
  return result;
519
621
  } catch (error) {
520
- if (error instanceof WorkspaceSelectionError) return workspaceError(error);
521
- return toolError("Hosted authorization denied this tool call. Check the granted scopes, workspace and tenant access.");
622
+ if (error instanceof WorkspaceSelectionError)
623
+ return workspaceError(error);
624
+ return toolError(
625
+ "Hosted authorization denied this tool call. Check the granted scopes, workspace and tenant access."
626
+ );
522
627
  }
523
628
  };
524
629
  return register(...args);
@@ -541,7 +646,10 @@ function healthPath(url) {
541
646
  return path === "/health";
542
647
  }
543
648
  function reply(res, status, body) {
544
- res.writeHead(status, { "Content-Type": "application/json", "Cache-Control": "no-store" });
649
+ res.writeHead(status, {
650
+ "Content-Type": "application/json",
651
+ "Cache-Control": "no-store"
652
+ });
545
653
  res.end(JSON.stringify(body));
546
654
  }
547
655
  async function readBody(req) {
@@ -579,7 +687,11 @@ function createHostedHttpServer(config, adapter, pats) {
579
687
  if (config.testOnly) res.setHeader("X-Databrain-Test-Only", "true");
580
688
  try {
581
689
  const localPort = server.address()?.port;
582
- if (![publicUrl.host, `127.0.0.1:${localPort}`, `localhost:${localPort}`].includes(req.headers.host || "")) {
690
+ if (![
691
+ publicUrl.host,
692
+ `127.0.0.1:${localPort}`,
693
+ `localhost:${localPort}`
694
+ ].includes(req.headers.host || "")) {
583
695
  reply(res, 403, { error: "invalid_host" });
584
696
  return;
585
697
  }
@@ -590,10 +702,15 @@ function createHostedHttpServer(config, adapter, pats) {
590
702
  if (req.headers.origin) {
591
703
  res.setHeader("Access-Control-Allow-Origin", publicUrl.origin);
592
704
  res.setHeader("Vary", "Origin");
593
- res.setHeader("Access-Control-Expose-Headers", "WWW-Authenticate, MCP-Protocol-Version");
705
+ res.setHeader(
706
+ "Access-Control-Expose-Headers",
707
+ "WWW-Authenticate, MCP-Protocol-Version"
708
+ );
594
709
  }
595
710
  const url = new URL(req.url || "/", publicUrl.origin);
596
- if (req.method === "GET" && [metadataPath, "/.well-known/oauth-protected-resource"].includes(url.pathname)) {
711
+ if (req.method === "GET" && [metadataPath, "/.well-known/oauth-protected-resource"].includes(
712
+ url.pathname
713
+ )) {
597
714
  reply(res, 200, {
598
715
  resource: config.publicUrl,
599
716
  authorization_servers: [config.issuer],
@@ -612,15 +729,24 @@ function createHostedHttpServer(config, adapter, pats) {
612
729
  return;
613
730
  }
614
731
  if (req.method === "OPTIONS") {
615
- res.setHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, OPTIONS");
616
- res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, MCP-Protocol-Version, MCP-Session-Id");
732
+ res.setHeader(
733
+ "Access-Control-Allow-Methods",
734
+ "POST, GET, DELETE, OPTIONS"
735
+ );
736
+ res.setHeader(
737
+ "Access-Control-Allow-Headers",
738
+ "Authorization, Content-Type, MCP-Protocol-Version, MCP-Session-Id"
739
+ );
617
740
  res.writeHead(204);
618
741
  res.end();
619
742
  return;
620
743
  }
621
- const authFields = req.rawHeaders.filter((_, i) => i % 2 === 0 && req.rawHeaders[i].toLowerCase() === "authorization");
744
+ const authFields = req.rawHeaders.filter(
745
+ (_, i) => i % 2 === 0 && req.rawHeaders[i].toLowerCase() === "authorization"
746
+ );
622
747
  const match = /^Bearer ([^\s]+)$/i.exec(req.headers.authorization || "");
623
- if (authFields.length !== 1 || !match) throw new HostedAuthError(401, "invalid_token");
748
+ if (authFields.length !== 1 || !match)
749
+ throw new HostedAuthError(401, "invalid_token");
624
750
  const principal = await verify(match[1]);
625
751
  if (req.method !== "POST") {
626
752
  res.setHeader("Allow", "POST, OPTIONS");
@@ -653,22 +779,40 @@ function createHostedHttpServer(config, adapter, pats) {
653
779
  if (body?.method === "tools/call" && typeof body.params?.name === "string") {
654
780
  try {
655
781
  authorizeTool(body.params.name, principal);
656
- assertToolArguments(body.params.name, body.params.arguments, principal, delegation !== void 0);
782
+ assertToolArguments(
783
+ body.params.name,
784
+ body.params.arguments,
785
+ principal,
786
+ delegation !== void 0
787
+ );
657
788
  } catch (error) {
658
789
  if (error instanceof WorkspaceSelectionError) {
659
- reply(res, 200, { jsonrpc: "2.0", id: body.id ?? null, result: workspaceError(error) });
790
+ reply(res, 200, {
791
+ jsonrpc: "2.0",
792
+ id: body.id ?? null,
793
+ result: workspaceError(error)
794
+ });
660
795
  return;
661
796
  }
662
797
  if (error instanceof HostedAuthError && error.code === "insufficient_scope") {
663
- const missing = requiredScopes(body.params.name).filter((scope) => !principal.scopes.includes(scope));
664
- reply(res, 200, { jsonrpc: "2.0", id: body.id ?? null, result: scopeError(missing) });
798
+ const missing = requiredScopes(body.params.name).filter(
799
+ (scope) => !principal.scopes.includes(scope)
800
+ );
801
+ reply(res, 200, {
802
+ jsonrpc: "2.0",
803
+ id: body.id ?? null,
804
+ result: scopeError(missing)
805
+ });
665
806
  return;
666
807
  }
667
808
  throw error;
668
809
  }
669
810
  }
670
811
  const mcp = createHostedToolServer(principal, adapter, delegation);
671
- const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: void 0, enableJsonResponse: true });
812
+ const transport = new StreamableHTTPServerTransport({
813
+ sessionIdGenerator: void 0,
814
+ enableJsonResponse: true
815
+ });
672
816
  let closed = false;
673
817
  const close = () => {
674
818
  if (!closed) {
@@ -692,8 +836,14 @@ function createHostedHttpServer(config, adapter, pats) {
692
836
  return;
693
837
  }
694
838
  const status = error instanceof HostedAuthError ? error.status : 503;
695
- if (status === 401) res.setHeader("WWW-Authenticate", `Bearer error="invalid_token", resource_metadata="${metadataUrl}"`);
696
- reply(res, status, { error: error instanceof HostedAuthError ? error.code : "temporarily_unavailable" });
839
+ if (status === 401)
840
+ res.setHeader(
841
+ "WWW-Authenticate",
842
+ `Bearer error="invalid_token", resource_metadata="${metadataUrl}"`
843
+ );
844
+ reply(res, status, {
845
+ error: error instanceof HostedAuthError ? error.code : "temporarily_unavailable"
846
+ });
697
847
  }
698
848
  });
699
849
  server.requestTimeout = 3e4;
@@ -708,7 +858,12 @@ var USER_AGENT = `databrain-mcp-server/${MCP_SERVER_VERSION} (hosted)`;
708
858
  var REQUEST_TIMEOUT_MS = 3e4;
709
859
  var FORWARDED_HEADERS = /* @__PURE__ */ new Set(["idempotency-key"]);
710
860
  var WORKSPACE_HEADER = "X-Databrain-Workspace";
711
- var GRANT_DENIALS = /* @__PURE__ */ new Set(["ROLE_NOT_ALLOWED", "WORKSPACE_CREATE_NOT_ALLOWED", "forbidden_permission", "insufficient_scope"]);
861
+ var GRANT_DENIALS = /* @__PURE__ */ new Set([
862
+ "ROLE_NOT_ALLOWED",
863
+ "WORKSPACE_CREATE_NOT_ALLOWED",
864
+ "forbidden_permission",
865
+ "insufficient_scope"
866
+ ]);
712
867
  function errorDetail(status, text, bearer) {
713
868
  let parsed;
714
869
  try {
@@ -758,16 +913,23 @@ function createProviderAdapter(config) {
758
913
  async verifyOAuth(token, resource) {
759
914
  try {
760
915
  const response = await fetch(endpoint, {
761
- headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
916
+ headers: {
917
+ Authorization: `Bearer ${token}`,
918
+ Accept: "application/json"
919
+ },
762
920
  redirect: "error",
763
921
  signal: AbortSignal.timeout(1e4)
764
922
  });
765
923
  if (!response.ok) {
766
- if (response.status === 429 || response.status >= 500) throw new HostedAuthError(503, "temporarily_unavailable");
924
+ if (response.status === 429 || response.status >= 500)
925
+ throw new HostedAuthError(503, "temporarily_unavailable");
767
926
  throw new HostedAuthError(401, "invalid_token");
768
927
  }
769
- const { issuer: _issuer, ...principal } = responseSchema.parse(await response.json());
770
- if (principal.resource !== resource || principal.credentialType !== "oauth") throw new HostedAuthError(401, "invalid_token");
928
+ const { issuer: _issuer, ...principal } = responseSchema.parse(
929
+ await response.json()
930
+ );
931
+ if (principal.resource !== resource || principal.credentialType !== "oauth")
932
+ throw new HostedAuthError(401, "invalid_token");
771
933
  return principal;
772
934
  } catch (error) {
773
935
  if (error instanceof HostedAuthError) throw error;
@@ -778,18 +940,25 @@ function createProviderAdapter(config) {
778
940
  throw new HostedAuthError(401, "pat_membership_adapter_required");
779
941
  },
780
942
  delegate(token) {
781
- const handle = Object.freeze({ kind: "hosted-delegation" });
943
+ const handle = Object.freeze({
944
+ kind: "hosted-delegation"
945
+ });
782
946
  bearers.set(handle, token);
783
947
  return handle;
784
948
  },
785
949
  async executeRequest(options, principal, delegation, workspace) {
786
950
  const bearer = delegation ? bearers.get(delegation) : void 0;
787
- if (options.auth !== "none" && !bearer) throw new HostedAuthError(503, "delegated_backend_adapter_required");
788
- if (options.auth === "none" && !options.token) throw new HostedAuthError(403, "tool_not_authorized");
789
- if (!options.path.startsWith("/") || options.path.startsWith("//")) throw new HostedAuthError(403, "tool_not_authorized");
951
+ if (options.auth !== "none" && !bearer)
952
+ throw new HostedAuthError(503, "delegated_backend_adapter_required");
953
+ if (options.auth === "none" && !options.token)
954
+ throw new HostedAuthError(403, "tool_not_authorized");
955
+ if (!options.path.startsWith("/") || options.path.startsWith("//"))
956
+ throw new HostedAuthError(403, "tool_not_authorized");
790
957
  const url = new URL(`${apiBase}${options.path}`);
791
- if (url.origin !== apiOrigin) throw new HostedAuthError(403, "tool_not_authorized");
792
- for (const [key, value] of Object.entries(options.query ?? {})) url.searchParams.set(key, value);
958
+ if (url.origin !== apiOrigin)
959
+ throw new HostedAuthError(403, "tool_not_authorized");
960
+ for (const [key, value] of Object.entries(options.query ?? {}))
961
+ url.searchParams.set(key, value);
793
962
  const headers = {
794
963
  Accept: "application/json",
795
964
  "Content-Type": "application/json",
@@ -812,7 +981,10 @@ function createProviderAdapter(config) {
812
981
  } else {
813
982
  headers.Authorization = `Bearer ${bearer}`;
814
983
  if (workspace) {
815
- if (!principal.grantedWorkspaces?.some((item) => item.id === workspace.id) && principal.workspaceId !== workspace.id) throw new HostedAuthError(403, "principal_mismatch");
984
+ if (!principal.grantedWorkspaces?.some(
985
+ (item) => item.id === workspace.id
986
+ ) && principal.workspaceId !== workspace.id)
987
+ throw new HostedAuthError(403, "principal_mismatch");
816
988
  headers[WORKSPACE_HEADER] = workspace.id;
817
989
  }
818
990
  }
@@ -830,7 +1002,10 @@ function createProviderAdapter(config) {
830
1002
  throw new HostedAuthError(
831
1003
  403,
832
1004
  "delegated_request_denied",
833
- forbidden.code === "insufficient_scope" && options.path === "/api/v2/guest-token/create" ? { ...forbidden, message: "Guest/tenant operations require mcp:embeds:write. Ask an admin for a role that allows it, then connect again." } : forbidden
1005
+ forbidden.code === "insufficient_scope" && options.path === "/api/v2/guest-token/create" ? {
1006
+ ...forbidden,
1007
+ message: "Guest/tenant operations require mcp:embeds:write. Ask an admin for a role that allows it, then connect again."
1008
+ } : forbidden
834
1009
  );
835
1010
  }
836
1011
  const status = response.status === 403 && options.responseFormat === "studio-sse" ? 403 : response.status === 401 ? 401 : response.status >= 500 ? 503 : response.status === 403 || response.status === 404 ? 404 : 400;
@@ -852,33 +1027,51 @@ async function startHosted() {
852
1027
  let adapter;
853
1028
  if (config.testOnly) {
854
1029
  const file = process.env.DATABRAIN_HOSTED_TEST_FIXTURES;
855
- if (!file || !isAbsolute(file)) throw new Error("Hosted test mode requires an absolute fixture store path.");
856
- const { createTestOnlyAdapter } = await import("./test-only-LJGOY2QA.js");
1030
+ if (!file || !isAbsolute(file))
1031
+ throw new Error(
1032
+ "Hosted test mode requires an absolute fixture store path."
1033
+ );
1034
+ const { createTestOnlyAdapter } = await import("./test-only-6474NMTR.js");
857
1035
  adapter = createTestOnlyAdapter(file);
858
1036
  } else {
859
1037
  const file = process.env.DATABRAIN_HOSTED_ADAPTER_MODULE;
860
1038
  if (!file) {
861
1039
  adapter = createProviderAdapter(config);
862
- process.stderr.write("[databrain] OAuth configured: data tools run as the signed-in user through the issuer; PAT membership requires a trusted adapter.\n");
1040
+ process.stderr.write(
1041
+ "[databrain] OAuth configured: data tools run as the signed-in user through the issuer; PAT membership requires a trusted adapter.\n"
1042
+ );
863
1043
  } else {
864
- if (!isAbsolute(file)) throw new Error("DATABRAIN_HOSTED_ADAPTER_MODULE must be an absolute path.");
1044
+ if (!isAbsolute(file))
1045
+ throw new Error(
1046
+ "DATABRAIN_HOSTED_ADAPTER_MODULE must be an absolute path."
1047
+ );
865
1048
  try {
866
1049
  adapter = (await import(pathToFileURL(file).href)).adapter;
867
1050
  } catch {
868
1051
  throw new Error("Could not load the trusted hosted adapter.");
869
1052
  }
870
1053
  }
871
- if (!adapter || ["verifyOAuth", "resolvePatGrant", "executeRequest"].some((key) => typeof adapter[key] !== "function")) throw new Error("Invalid trusted hosted adapter.");
1054
+ if (!adapter || ["verifyOAuth", "resolvePatGrant", "executeRequest"].some(
1055
+ (key) => typeof adapter[key] !== "function"
1056
+ ))
1057
+ throw new Error("Invalid trusted hosted adapter.");
872
1058
  }
873
1059
  const patPath = process.env.DATABRAIN_HOSTED_PAT_STORE;
874
- if (patPath && !isAbsolute(patPath)) throw new Error("Hosted PAT store must be an absolute path.");
875
- const server = createHostedHttpServer(config, adapter, patPath ? new FilePatStore(patPath) : void 0);
1060
+ if (patPath && !isAbsolute(patPath))
1061
+ throw new Error("Hosted PAT store must be an absolute path.");
1062
+ const server = createHostedHttpServer(
1063
+ config,
1064
+ adapter,
1065
+ patPath ? new FilePatStore(patPath) : void 0
1066
+ );
876
1067
  await new Promise((resolve, reject) => {
877
1068
  server.once("error", reject);
878
1069
  server.listen(config.port, config.bind, resolve);
879
1070
  });
880
- process.stderr.write(`[databrain] hosted HTTP ready on ${config.bind}:${config.port}/mcp${config.testOnly ? " \u2014 TEST ONLY: synthetic identity and data; no OAuth consent" : ""}
881
- `);
1071
+ process.stderr.write(
1072
+ `[databrain] hosted HTTP ready on ${config.bind}:${config.port}/mcp${config.testOnly ? " \u2014 TEST ONLY: synthetic identity and data; no OAuth consent" : ""}
1073
+ `
1074
+ );
882
1075
  const shutdown = () => {
883
1076
  server.close(() => process.exit(0));
884
1077
  setTimeout(() => {
@@ -892,4 +1085,4 @@ async function startHosted() {
892
1085
  export {
893
1086
  startHosted
894
1087
  };
895
- //# sourceMappingURL=main-VEKNKWL5.js.map
1088
+ //# sourceMappingURL=main-QCBVJSSR.js.map