@databrainhq/mcp-server 0.3.0-rc.2 → 0.3.0-rc.4

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.
@@ -24,7 +24,7 @@ var logger = {
24
24
  // package.json
25
25
  var package_default = {
26
26
  name: "@databrainhq/mcp-server",
27
- version: "0.3.0-rc.2",
27
+ version: "0.3.0-rc.4",
28
28
  description: "MCP server for Databrain embedded analytics - connect databases, create datamarts, configure embeds, and generate frontend code",
29
29
  type: "module",
30
30
  bin: {
@@ -577,6 +577,7 @@ import { z as z2 } from "zod";
577
577
  var CHART_URI = "ui://databrain/chart-tile";
578
578
  var KPI_URI = "ui://databrain/kpi-tile";
579
579
  var APP_MIME = "text/html;profile=mcp-app";
580
+ var RESOURCE_URI_META_KEY = "ui/resourceUri";
580
581
  var PAGE_SIZE = 50;
581
582
  var MAX_RESULT_CHARS = 125e3;
582
583
  var id = z2.string().trim().min(1).max(256);
@@ -639,6 +640,9 @@ function firstRows(value) {
639
640
  }
640
641
 
641
642
  // src/apps/feature.ts
643
+ function appMeta(visibility) {
644
+ return { ui: { resourceUri: CHART_URI, visibility }, [RESOURCE_URI_META_KEY]: CHART_URI };
645
+ }
642
646
  var enabled = /* @__PURE__ */ new WeakSet();
643
647
  function enableChartApps(server) {
644
648
  enabled.add(server);
@@ -647,75 +651,95 @@ function hasChartApps(server) {
647
651
  return enabled.has(server);
648
652
  }
649
653
  function tagChartTool(server, tool) {
650
- if (hasChartApps(server)) tool.update({ _meta: { ui: { resourceUri: CHART_URI, visibility: ["model", "app"] } } });
654
+ if (hasChartApps(server)) tool.update({ _meta: appMeta(["model", "app"]) });
651
655
  }
652
656
  function chartResult(summary, payload) {
653
- return bounded({ content: [{ type: "text", text: summary }], structuredContent: payload });
657
+ return bounded({
658
+ content: [{ type: "text", text: summary }],
659
+ structuredContent: payload,
660
+ _meta: appMeta(["model", "app"])
661
+ });
654
662
  }
655
663
 
656
664
  // src/tools/tool-metadata.ts
657
665
  var DEFAULT_TOOL_META = {
658
666
  category: "discovery",
659
- workflowIntent: "other"
667
+ workflowIntent: "other",
668
+ // Fail closed: an unregistered/unclassified tool is treated as a commit
669
+ // until someone deliberately marks it read or view.
670
+ effect: "commit"
660
671
  };
661
672
  var TOOL_METADATA = {
662
673
  // Identity / discovery
663
- whoami: { category: "discovery", workflowIntent: "discovery" },
674
+ whoami: { category: "discovery", workflowIntent: "discovery", effect: "read" },
664
675
  // Infrastructure / data setup
665
- list_datasources: { category: "infrastructure", workflowIntent: "setup_data" },
666
- discover_datasource_schema: { category: "infrastructure", workflowIntent: "setup_data" },
667
- list_datamarts: { category: "infrastructure", workflowIntent: "setup_data" },
668
- list_workspaces: { category: "infrastructure", workflowIntent: "setup_data" },
669
- sync_datasource: { category: "infrastructure", workflowIntent: "setup_data" },
670
- create_datamart: { category: "infrastructure", workflowIntent: "setup_data" },
676
+ list_datasources: { category: "infrastructure", workflowIntent: "setup_data", effect: "read" },
677
+ discover_datasource_schema: { category: "infrastructure", workflowIntent: "setup_data", effect: "read" },
678
+ list_datamarts: { category: "infrastructure", workflowIntent: "setup_data", effect: "read" },
679
+ list_workspaces: { category: "infrastructure", workflowIntent: "setup_data", effect: "read" },
680
+ // Triggers a backend sync job that refreshes stored schema metadata — a real mutation, not a read.
681
+ sync_datasource: { category: "infrastructure", workflowIntent: "setup_data", effect: "commit" },
682
+ // dry_run is the default, but mode:"apply" performs a real POST that creates the datamart.
683
+ create_datamart: { category: "infrastructure", workflowIntent: "setup_data", effect: "commit" },
671
684
  // Embedding — data apps & tokens
672
- list_data_apps: { category: "embedding", workflowIntent: "embed_dashboard" },
673
- list_tenants: { category: "embedding", workflowIntent: "embed_dashboard" },
674
- create_data_app: { category: "embedding", workflowIntent: "embed_dashboard" },
675
- list_api_tokens: { category: "embedding", workflowIntent: "embed_dashboard" },
676
- create_api_token: { category: "embedding", workflowIntent: "embed_dashboard" },
677
- rotate_api_token: { category: "embedding", workflowIntent: "embed_dashboard" },
685
+ list_data_apps: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
686
+ list_tenants: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
687
+ create_data_app: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
688
+ list_api_tokens: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
689
+ create_api_token: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
690
+ rotate_api_token: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
678
691
  // Embedding — embed management
679
- create_embed: { category: "embedding", workflowIntent: "embed_dashboard" },
680
- list_embeds: { category: "embedding", workflowIntent: "embed_dashboard" },
681
- get_embed_details: { category: "embedding", workflowIntent: "embed_dashboard" },
682
- update_embed: { category: "embedding", workflowIntent: "embed_dashboard" },
683
- customize_embed_theme: { category: "embedding", workflowIntent: "embed_dashboard" },
684
- get_demo_link: { category: "embedding", workflowIntent: "embed_dashboard" },
692
+ create_embed: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
693
+ list_embeds: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
694
+ get_embed_details: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
695
+ update_embed: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
696
+ // Persists theme/access config on the embed record — a real write, not a display-only tweak.
697
+ customize_embed_theme: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
698
+ // Mints and returns a live guest token embedded in the demo URL.
699
+ get_demo_link: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
685
700
  // Embedding — frontend
686
- generate_guest_token: { category: "embedding", workflowIntent: "embed_dashboard" },
687
- generate_embed_code: { category: "embedding", workflowIntent: "embed_dashboard" },
701
+ generate_guest_token: { category: "embedding", workflowIntent: "embed_dashboard", effect: "commit" },
702
+ generate_embed_code: { category: "embedding", workflowIntent: "embed_dashboard", effect: "read" },
688
703
  // Embedding — customer dashboards & widgets
689
- list_dashboards: { category: "embedding", workflowIntent: "embedded_widget" },
690
- create_dashboard: { category: "embedding", workflowIntent: "author_dashboard" },
691
- get_dashboard: { category: "embedding", workflowIntent: "author_dashboard" },
692
- generate_dashboard_tiles: { category: "embedding", workflowIntent: "author_dashboard" },
693
- list_widgets: { category: "embedding", workflowIntent: "embedded_widget" },
694
- add_widget: { category: "embedding", workflowIntent: "embedded_widget" },
695
- update_widget: { category: "embedding", workflowIntent: "embedded_widget" },
696
- remove_widget: { category: "embedding", workflowIntent: "embedded_widget" },
697
- generate_widget: { category: "embedding", workflowIntent: "embedded_widget" },
698
- validate_metric_spec: { category: "embedding", workflowIntent: "sql_to_embedded_metric" },
704
+ list_dashboards: { category: "embedding", workflowIntent: "embedded_widget", effect: "read" },
705
+ create_dashboard: { category: "embedding", workflowIntent: "author_dashboard", effect: "commit" },
706
+ get_dashboard: { category: "embedding", workflowIntent: "author_dashboard", effect: "read" },
707
+ // Does not persist a dashboard, but mints an internal guest token to render tile previews.
708
+ generate_dashboard_tiles: { category: "embedding", workflowIntent: "author_dashboard", effect: "commit" },
709
+ list_widgets: { category: "embedding", workflowIntent: "embedded_widget", effect: "read" },
710
+ add_widget: { category: "embedding", workflowIntent: "embedded_widget", effect: "commit" },
711
+ update_widget: { category: "embedding", workflowIntent: "embedded_widget", effect: "commit" },
712
+ remove_widget: { category: "embedding", workflowIntent: "embedded_widget", effect: "commit" },
713
+ // Returns an unsaved draft, but mints an internal write-capable guest token to generate it.
714
+ generate_widget: { category: "embedding", workflowIntent: "embedded_widget", effect: "commit" },
715
+ // Dry-run validation only, but mints an internal write-capable guest token to check conflicts.
716
+ validate_metric_spec: { category: "embedding", workflowIntent: "sql_to_embedded_metric", effect: "commit" },
699
717
  create_or_update_metric_from_query: {
700
718
  category: "embedding",
701
- workflowIntent: "sql_to_embedded_metric"
719
+ workflowIntent: "sql_to_embedded_metric",
720
+ effect: "commit"
702
721
  },
703
722
  // Internal analytics
704
723
  create_workspace_metric: {
705
724
  category: "internal_analytics",
706
- workflowIntent: "sql_to_workspace_metric"
725
+ workflowIntent: "sql_to_workspace_metric",
726
+ effect: "commit"
707
727
  },
708
- ask_question: { category: "internal_analytics", workflowIntent: "query_data" },
728
+ // Runs a query and returns rows; no dashboard/widget/row is persisted.
729
+ ask_question: { category: "internal_analytics", workflowIntent: "query_data", effect: "read" },
730
+ preview_chart: { category: "internal_analytics", workflowIntent: "query_data", effect: "view" },
731
+ save_chart_as_dashboard: { category: "internal_analytics", workflowIntent: "author_dashboard", effect: "commit" },
709
732
  // Semantic layer
710
- get_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data" },
711
- update_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data" },
712
- start_semantic_layer_generation: { category: "semantic_layer", workflowIntent: "query_data" },
733
+ get_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data", effect: "read" },
734
+ update_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data", effect: "commit" },
735
+ start_semantic_layer_generation: { category: "semantic_layer", workflowIntent: "query_data", effect: "commit" },
713
736
  get_semantic_layer_generation_status: {
714
737
  category: "semantic_layer",
715
- workflowIntent: "query_data"
738
+ workflowIntent: "query_data",
739
+ effect: "read"
716
740
  },
717
741
  // Reports
718
- list_scheduled_reports: { category: "reports", workflowIntent: "reports" }
742
+ list_scheduled_reports: { category: "reports", workflowIntent: "reports", effect: "read" }
719
743
  };
720
744
 
721
745
  // src/tools/data-app/list-data-apps.ts
@@ -5315,8 +5339,157 @@ function registerGetDashboard(server, client) {
5315
5339
  );
5316
5340
  }
5317
5341
 
5318
- // src/tools/query/ask-question.ts
5342
+ // src/apps/preview.ts
5343
+ import { createHash } from "crypto";
5319
5344
  import { z as z25 } from "zod";
5345
+ var draftSchema = z25.object({
5346
+ question: z25.string().min(1).max(2e3),
5347
+ sql: z25.string().min(1).max(2e4),
5348
+ datamartName: z25.string().min(1).max(256),
5349
+ dimensions: z25.array(z25.string().max(128)).max(20).default([]),
5350
+ measures: z25.array(z25.string().max(128)).max(20).default([]),
5351
+ chartType: z25.string().min(1).max(80),
5352
+ title: z25.string().min(1).max(200),
5353
+ sessionId: z25.string().max(256).optional(),
5354
+ /** Workspaces built on this datamart. One means Save needs no choice. */
5355
+ workspaces: z25.array(z25.string().max(256)).max(50).default([])
5356
+ }).strict();
5357
+ var PREVIEW_PATH = "/api/v2/data-app/chart-preview";
5358
+ var METRIC_PATH = "/api/mcp/metrics/create";
5359
+ var DASHBOARD_PATH = "/api/v2/workspace/dashboard";
5360
+ var PREVIEW_TYPES = ["bar", "row", "line", "area", "pie", "doughnut", "table"];
5361
+ var RENDER_TYPES = [...PREVIEW_TYPES, "single value"];
5362
+ async function previewPage(client, draft, rows, chartType) {
5363
+ const page = await client.request({
5364
+ method: "POST",
5365
+ path: PREVIEW_PATH,
5366
+ auth: "service",
5367
+ skipDataUnwrap: true,
5368
+ body: {
5369
+ rows: firstRows(rows),
5370
+ chartType,
5371
+ title: draft.title,
5372
+ dimensions: draft.dimensions,
5373
+ measures: draft.measures,
5374
+ width: 600,
5375
+ height: 320
5376
+ }
5377
+ });
5378
+ return pageSchema.parse(page);
5379
+ }
5380
+ function tablePage(draft, rows) {
5381
+ const page = firstRows(rows);
5382
+ return {
5383
+ kind: "table",
5384
+ title: draft.title,
5385
+ chartSpec: { type: "table" },
5386
+ rows: page,
5387
+ columns: Object.keys(page[0] ?? {})
5388
+ };
5389
+ }
5390
+ async function draftPage(client, draft, rows, chartType) {
5391
+ const data = rowsSchema.parse(firstRows(rows));
5392
+ const carry = { draft: { ...draft, chartType }, previewTypes: PREVIEW_TYPES };
5393
+ if (chartType === "table" || !data.length) return { ...tablePage(draft, data), ...carry };
5394
+ try {
5395
+ return { ...await previewPage(client, draft, data, chartType), ...carry };
5396
+ } catch (error) {
5397
+ const previewError = error instanceof DatabrainApiError ? error.code : "PREVIEW_UNAVAILABLE";
5398
+ return { ...tablePage(draft, data), ...carry, draft: { ...draft, chartType: "table" }, previewError };
5399
+ }
5400
+ }
5401
+ var sameName = (a, b) => typeof a === "string" && a.trim().toLowerCase() === b.trim().toLowerCase();
5402
+ async function workspacesForDatamart(client, datamartName, mode = "hint") {
5403
+ const cached = (key) => mode === "hint" ? { cacheKey: key, cacheTtlMs: 5 * 60 * 1e3 } : {};
5404
+ try {
5405
+ const [workspaces, datamarts] = await Promise.all([
5406
+ client.request({ method: "GET", path: "/api/v2/workspace", auth: "service", ...cached("list_workspaces") }),
5407
+ client.request({ method: "GET", path: "/api/v2/data-app/datamarts", auth: "service", ...cached("list_datamarts") })
5408
+ ]);
5409
+ const datasource = (Array.isArray(datamarts) ? datamarts : []).find((d) => sameName(d?.name ?? d?.datamartName, datamartName))?.companyIntegration?.id;
5410
+ const all = (Array.isArray(workspaces) ? workspaces : []).filter((w) => typeof w?.name === "string");
5411
+ const onDatamart = all.filter((w) => sameName(w.datamart?.name ?? w.datamartName, datamartName));
5412
+ const onDatasource = datasource ? all.filter((w) => !w.datamart && w.companyIntegration?.id === datasource) : [];
5413
+ return [...new Set([...onDatamart, ...onDatasource].map((w) => w.name))];
5414
+ } catch {
5415
+ return [];
5416
+ }
5417
+ }
5418
+ function saveKey(draft, input) {
5419
+ const h = createHash("sha256").update(JSON.stringify({
5420
+ sql: draft.sql,
5421
+ datamartName: draft.datamartName,
5422
+ workspaceName: input.workspaceName,
5423
+ dashboardTitle: input.dashboardTitle,
5424
+ chartType: input.chartType,
5425
+ // One attempt, many retries: the tile mints an id when the form opens and re-sends it on
5426
+ // retry, so a retry replays and a fresh Save is a fresh key. Without one, content is the key.
5427
+ attemptId: input.attemptId ?? null
5428
+ })).digest();
5429
+ h[6] = h[6] & 15 | 64;
5430
+ h[8] = h[8] & 63 | 128;
5431
+ const x = h.subarray(0, 16).toString("hex");
5432
+ return `${x.slice(0, 8)}-${x.slice(8, 12)}-${x.slice(12, 16)}-${x.slice(16, 20)}-${x.slice(20, 32)}`;
5433
+ }
5434
+ async function saveDraftAsDashboard(client, draft, input) {
5435
+ const metric = await client.request({
5436
+ method: "POST",
5437
+ path: METRIC_PATH,
5438
+ auth: "service",
5439
+ body: {
5440
+ workspaceName: input.workspaceName,
5441
+ name: input.dashboardTitle,
5442
+ query: draft.sql,
5443
+ description: draft.question,
5444
+ isPublished: false,
5445
+ validateOnly: false
5446
+ }
5447
+ });
5448
+ const metricId = metric?.metricId || metric?.id;
5449
+ if (!metricId) throw new DatabrainApiError(502, "METRIC_ID_MISSING", "The metric was created but returned no id.");
5450
+ const slug = input.dashboardTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63) || "chart";
5451
+ const body = {
5452
+ schemaVersion: 1,
5453
+ title: input.dashboardTitle,
5454
+ description: draft.question,
5455
+ layout: { columns: 24 },
5456
+ tiles: [{
5457
+ id: slug,
5458
+ kind: "databrain-chart",
5459
+ title: input.dashboardTitle,
5460
+ position: { x: 0, y: 0, w: 12, h: 8 },
5461
+ chart: { type: input.chartType, metricRef: metricId }
5462
+ }]
5463
+ };
5464
+ const dashboard = await client.request({
5465
+ method: "POST",
5466
+ path: DASHBOARD_PATH,
5467
+ auth: "service",
5468
+ query: { workspaceName: input.workspaceName },
5469
+ headers: { "Idempotency-Key": saveKey(draft, input) },
5470
+ body,
5471
+ invalidateCache: ["list_dashboards"],
5472
+ // A metadata insert: 15s keeps the attempt and its retries inside the host's 60s window.
5473
+ timeoutMs: 15e3
5474
+ });
5475
+ if (!dashboard?.dashboardId) {
5476
+ throw new DatabrainApiError(502, "DASHBOARD_ID_MISSING", `Metric ${metricId} was saved but the dashboard returned no id.`);
5477
+ }
5478
+ return { dashboardId: dashboard.dashboardId, metricId, workspaceName: input.workspaceName, title: input.dashboardTitle };
5479
+ }
5480
+
5481
+ // src/tools/query/ask-question.ts
5482
+ import { z as z26 } from "zod";
5483
+ function normalizePreviewType(type) {
5484
+ const t = (type || "").toLowerCase().trim();
5485
+ if (RENDER_TYPES.includes(t)) return t;
5486
+ if (t === "single value" || t === "kpi" || t === "number") return "single value";
5487
+ if (t === "time series" || t === "stepped") return "line";
5488
+ if (t === "stack" || t === "column") return "bar";
5489
+ if (t === "horizontal stack" || t === "horizontal bar") return "row";
5490
+ if (t === "stacked area") return "area";
5491
+ return "table";
5492
+ }
5320
5493
  var MAX_DISPLAY_ROWS = 50;
5321
5494
  function formatDataTable(data, columns) {
5322
5495
  if (!Array.isArray(data) || data.length === 0) return "_No data returned._";
@@ -5346,16 +5519,16 @@ function registerAskQuestion(server, client) {
5346
5519
  "ask_question",
5347
5520
  "Ask a natural language question \u2014 converts to SQL, returns data + chart suggestion. Requires datamartName with a populated semantic layer.",
5348
5521
  {
5349
- question: z25.string().describe(
5522
+ question: z26.string().describe(
5350
5523
  'The natural language question to ask (e.g. "What was total revenue last month?")'
5351
5524
  ),
5352
- datamartName: z25.string().optional().describe(
5525
+ datamartName: z26.string().optional().describe(
5353
5526
  "Name of the datamart to query. Use `list_datamarts` to find available names. REQUIRED unless exactly one datamart exists (auto-resolved). Do NOT pass a workspace name here."
5354
5527
  ),
5355
- sessionId: z25.string().optional().describe(
5528
+ sessionId: z26.string().optional().describe(
5356
5529
  "Session ID from a previous ask_question response, for follow-up questions."
5357
5530
  ),
5358
- timezone: z25.string().optional().describe('IANA timezone (e.g. "America/New_York"). Defaults to UTC.')
5531
+ timezone: z26.string().optional().describe('IANA timezone (e.g. "America/New_York"). Defaults to UTC.')
5359
5532
  },
5360
5533
  WRITE_CREATE,
5361
5534
  async (params) => {
@@ -5460,15 +5633,22 @@ You can verify with \`get_semantic_layer\` using datamartName "${datamartName}".
5460
5633
  });
5461
5634
  const data = Array.isArray(result.data) ? result.data : [];
5462
5635
  if (hasChartApps(server)) {
5636
+ const chartType = normalizePreviewType(result.suggestedChartType);
5637
+ const draft = {
5638
+ question: params.question,
5639
+ sql: result.query || "",
5640
+ datamartName,
5641
+ dimensions: result.columns?.dimensions || [],
5642
+ measures: result.columns?.measures || [],
5643
+ chartType,
5644
+ title: params.question.slice(0, 200),
5645
+ sessionId: result.sessionId || void 0,
5646
+ workspaces: await workspacesForDatamart(client, datamartName)
5647
+ };
5463
5648
  const rows = firstRows(data);
5464
- return chartResult(`Query Results: ${data.length} rows returned; showing the first ${rows.length}.`, {
5465
- kind: "table",
5466
- title: "Query results",
5467
- chartSpec: { type: result.suggestedChartType || "table" },
5468
- rows,
5469
- columns: Object.keys(rows[0] ?? {}),
5470
- description: "Showing the first page. Interactive chart preview is not available for this query yet."
5471
- });
5649
+ const page = draft.sql ? await draftPage(client, draft, rows, chartType) : { ...tablePage(draft, rows), previewTypes: [] };
5650
+ const shown = rows.length === data.length ? `${data.length} rows` : `first ${rows.length} of ${data.length} rows`;
5651
+ return chartResult(`${page.kind === "table" ? "Table" : "Chart"} ready (${page.chartSpec && page.chartSpec.type}): ${shown}.` + (result.summary ? ` ${result.summary}` : ""), { ...page, rowsTotal: data.length });
5472
5652
  }
5473
5653
  const table = formatDataTable(data, result.columns);
5474
5654
  const parts = [];
@@ -5543,14 +5723,14 @@ To fix this:
5543
5723
  }
5544
5724
 
5545
5725
  // src/tools/query/get-semantic-layer.ts
5546
- import { z as z26 } from "zod";
5726
+ import { z as z27 } from "zod";
5547
5727
  function registerGetSemanticLayer(server, client) {
5548
5728
  const services = createServiceBundle(client);
5549
5729
  server.tool(
5550
5730
  "get_semantic_layer",
5551
5731
  "Get semantic layer metadata for a datamart: table/column descriptions, synonyms, completion score. Omit datamartName to auto-resolve.",
5552
5732
  {
5553
- datamartName: z26.string().optional().describe(
5733
+ datamartName: z27.string().optional().describe(
5554
5734
  "Name of the datamart to inspect. Omit to list available datamarts."
5555
5735
  )
5556
5736
  },
@@ -5660,15 +5840,15 @@ ${result.feedback}`);
5660
5840
  }
5661
5841
 
5662
5842
  // src/tools/query/update-semantic-layer.ts
5663
- import { z as z27 } from "zod";
5664
- var columnSchema2 = z27.object({
5665
- name: z27.string().describe("Column name (must exist in the datamart)"),
5666
- description: z27.string().optional().describe("Business-friendly description of what this column represents"),
5667
- synonyms: z27.array(z27.string()).optional().describe(
5843
+ import { z as z28 } from "zod";
5844
+ var columnSchema2 = z28.object({
5845
+ name: z28.string().describe("Column name (must exist in the datamart)"),
5846
+ description: z28.string().optional().describe("Business-friendly description of what this column represents"),
5847
+ synonyms: z28.array(z28.string()).optional().describe(
5668
5848
  'Alternative names users might use for this column (e.g. ["revenue", "sales amount"])'
5669
5849
  ),
5670
- miscellaneousInfo: z27.string().optional().describe("Additional context such as valid values, units, or caveats"),
5671
- columnType: z27.enum([
5850
+ miscellaneousInfo: z28.string().optional().describe("Additional context such as valid values, units, or caveats"),
5851
+ columnType: z28.enum([
5672
5852
  "String",
5673
5853
  "Long String",
5674
5854
  "String (Custom)",
@@ -5681,16 +5861,16 @@ var columnSchema2 = z27.object({
5681
5861
  "JSON"
5682
5862
  ]).nullable().optional().describe('Semantic column type. Use "Identifier" for IDs/foreign keys, "Number" for numeric values, "String" for text. Omit for date and boolean columns.')
5683
5863
  });
5684
- var tableSchema2 = z27.object({
5685
- name: z27.string().describe("Table name (must exist in the datamart)"),
5686
- description: z27.string().optional().describe(
5864
+ var tableSchema2 = z28.object({
5865
+ name: z28.string().describe("Table name (must exist in the datamart)"),
5866
+ description: z28.string().optional().describe(
5687
5867
  "Business-friendly description of what this table represents"
5688
5868
  ),
5689
- synonyms: z27.array(z27.string()).optional().describe("Alternative names for this table"),
5690
- miscellaneousInfo: z27.string().optional().describe(
5869
+ synonyms: z28.array(z28.string()).optional().describe("Alternative names for this table"),
5870
+ miscellaneousInfo: z28.string().optional().describe(
5691
5871
  "Additional context such as how the table relates to other tables"
5692
5872
  ),
5693
- columns: z27.array(columnSchema2).optional().describe("Column-level semantic definitions to update")
5873
+ columns: z28.array(columnSchema2).optional().describe("Column-level semantic definitions to update")
5694
5874
  });
5695
5875
  function columnKey(tableName, columnName) {
5696
5876
  return `${tableName.toLowerCase()}\0${columnName.toLowerCase()}`;
@@ -5757,13 +5937,13 @@ function registerUpdateSemanticLayer(server, client) {
5757
5937
  "update_semantic_layer",
5758
5938
  "Populate or update the semantic layer for a datamart. Add table/column descriptions, synonyms, context. Required before ask_question works. Auto-generate descriptions from column names when empty.",
5759
5939
  {
5760
- datamartName: z27.string().optional().describe(
5940
+ datamartName: z28.string().optional().describe(
5761
5941
  "Name of the datamart to update. Omit to list available datamarts."
5762
5942
  ),
5763
- tables: z27.array(tableSchema2).optional().describe(
5943
+ tables: z28.array(tableSchema2).optional().describe(
5764
5944
  "Table and column definitions to update. Only include tables/columns you want to change."
5765
5945
  ),
5766
- feedback: z27.string().optional().describe(
5946
+ feedback: z28.string().optional().describe(
5767
5947
  'General feedback or context about the datamart (e.g. "This datamart contains e-commerce data for the US market").'
5768
5948
  )
5769
5949
  },
@@ -5825,7 +6005,7 @@ You can now:
5825
6005
  }
5826
6006
 
5827
6007
  // src/tools/query/semantic-generation.ts
5828
- import { z as z28 } from "zod";
6008
+ import { z as z29 } from "zod";
5829
6009
  function nonEmptyString(value) {
5830
6010
  return typeof value === "string" && value.trim().length > 0 ? value : null;
5831
6011
  }
@@ -5980,9 +6160,9 @@ function registerStartSemanticLayerGeneration(server, client) {
5980
6160
  "start_semantic_layer_generation",
5981
6161
  "Start backend semantic-layer auto-generation for a datamart. Returns an async job id to poll.",
5982
6162
  {
5983
- datamartName: z28.string().optional().describe("Datamart name. Omit to list available datamarts"),
5984
- workspaceName: z28.string().optional().describe("Workspace linked to the datamart. Use when datamartName resolution needs a dataMartId bridge."),
5985
- datamartId: z28.string().optional().describe("Datamart UUID. Use only when already known.")
6163
+ datamartName: z29.string().optional().describe("Datamart name. Omit to list available datamarts"),
6164
+ workspaceName: z29.string().optional().describe("Workspace linked to the datamart. Use when datamartName resolution needs a dataMartId bridge."),
6165
+ datamartId: z29.string().optional().describe("Datamart UUID. Use only when already known.")
5986
6166
  },
5987
6167
  WRITE_CREATE,
5988
6168
  async (params) => {
@@ -6024,9 +6204,9 @@ function registerGetSemanticLayerGenerationStatus(server, client) {
6024
6204
  "get_semantic_layer_generation_status",
6025
6205
  "Get semantic-layer auto-generation job status for a datamart.",
6026
6206
  {
6027
- datamartName: z28.string().optional().describe("Datamart name. Omit to list available datamarts"),
6028
- workspaceName: z28.string().optional().describe("Workspace linked to the datamart. Use when datamartName resolution needs a dataMartId bridge."),
6029
- datamartId: z28.string().optional().describe("Datamart UUID. Use only when already known.")
6207
+ datamartName: z29.string().optional().describe("Datamart name. Omit to list available datamarts"),
6208
+ workspaceName: z29.string().optional().describe("Workspace linked to the datamart. Use when datamartName resolution needs a dataMartId bridge."),
6209
+ datamartId: z29.string().optional().describe("Datamart UUID. Use only when already known.")
6030
6210
  },
6031
6211
  READ_ONLY,
6032
6212
  async (params) => {
@@ -6063,7 +6243,7 @@ function registerGetSemanticLayerGenerationStatus(server, client) {
6063
6243
  }
6064
6244
 
6065
6245
  // src/tools/widgets/list-widgets.ts
6066
- import { z as z29 } from "zod";
6246
+ import { z as z30 } from "zod";
6067
6247
  function widgetReferenceId(widget) {
6068
6248
  for (const candidate of [widget.externalMetricId, widget.id, widget._id, widget.metricId]) {
6069
6249
  if (typeof candidate === "string" && candidate.trim().length > 0) return candidate.trim();
@@ -6076,10 +6256,10 @@ function registerListWidgets(server, client) {
6076
6256
  "list_widgets",
6077
6257
  "List widgets on a customer dashboard. Non-technical flow: pass `clientId` + `dashboardName` (+ optional `workspaceName` if ambiguous). Returns each widget's externalMetricId (uuid, used for update/remove), metricId (slug), name, published state, and creator identifier.",
6078
6258
  {
6079
- clientId: z29.string().describe("Client/tenant identifier for this dashboard"),
6080
- dashboardName: z29.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6081
- workspaceName: z29.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6082
- embedId: z29.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier.")
6259
+ clientId: z30.string().describe("Client/tenant identifier for this dashboard"),
6260
+ dashboardName: z30.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6261
+ workspaceName: z30.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6262
+ embedId: z30.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier.")
6083
6263
  },
6084
6264
  READ_ONLY,
6085
6265
  async (params) => {
@@ -6143,29 +6323,29 @@ function registerListWidgets(server, client) {
6143
6323
  }
6144
6324
 
6145
6325
  // src/tools/widgets/add-widget.ts
6146
- import { z as z30 } from "zod";
6326
+ import { z as z31 } from "zod";
6147
6327
  function registerAddWidget(server, client) {
6148
6328
  const services = createServiceBundle(client);
6149
6329
  server.tool(
6150
6330
  "add_widget",
6151
6331
  "Add a widget to a customer dashboard. Non-technical flow: pass `clientId` + `dashboardName` (+ optional `workspaceName` if ambiguous). Cloning via `templateMetricId` is the recommended path \u2014 query, chart config, and datasource are all inherited. Data app and datasource auto-resolve; never ask the user for them.",
6152
6332
  {
6153
- clientId: z30.string().describe("Client/tenant identifier (widget is created in their scope)"),
6154
- dashboardName: z30.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6155
- workspaceName: z30.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6156
- embedId: z30.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6157
- dataAppName: z30.string().optional().describe("Technical override. Auto-resolved from the embed; non-technical callers should leave this blank."),
6158
- templateMetricId: z30.string().optional().describe("Source widget metricId to clone from. Copies query, chartOptions, and datasource fields; caller can override via other params."),
6159
- name: z30.string().optional().describe("Widget name (overrides template)"),
6160
- metricId: z30.string().optional().describe("Unique slug for the new widget (auto-generated if omitted)"),
6161
- query: z30.string().optional().describe("SQL query body (overrides template)"),
6162
- chartOptions: z30.record(z30.unknown()).optional().describe("Chart config JSON (chart type, colors, legend, axes). Overrides template."),
6163
- description: z30.string().optional(),
6164
- companyIntegrationId: z30.string().optional().describe("Datasource UUID override. Auto-resolved from `embedId` or sole active datasource; leave blank unless the user explicitly picked one by ID."),
6165
- integrationName: z30.string().optional().describe('Datasource display name (e.g. "Snowflake"). Use this when the user picks a datasource by name \u2014 the id is looked up automatically.'),
6166
- isPublished: z30.boolean().optional().describe("Publish immediately (default true)"),
6167
- body: z30.record(z30.unknown()).optional().describe("Raw createMetric body passthrough. If provided, used as-is (after defaults). Overrides all other params."),
6168
- widgets: z30.array(z30.record(z30.unknown())).min(1).max(50).optional().describe("Batch of raw createMetric bodies. Dashboard attachment is added to each body.")
6333
+ clientId: z31.string().describe("Client/tenant identifier (widget is created in their scope)"),
6334
+ dashboardName: z31.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6335
+ workspaceName: z31.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6336
+ embedId: z31.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6337
+ dataAppName: z31.string().optional().describe("Technical override. Auto-resolved from the embed; non-technical callers should leave this blank."),
6338
+ templateMetricId: z31.string().optional().describe("Source widget metricId to clone from. Copies query, chartOptions, and datasource fields; caller can override via other params."),
6339
+ name: z31.string().optional().describe("Widget name (overrides template)"),
6340
+ metricId: z31.string().optional().describe("Unique slug for the new widget (auto-generated if omitted)"),
6341
+ query: z31.string().optional().describe("SQL query body (overrides template)"),
6342
+ chartOptions: z31.record(z31.unknown()).optional().describe("Chart config JSON (chart type, colors, legend, axes). Overrides template."),
6343
+ description: z31.string().optional(),
6344
+ companyIntegrationId: z31.string().optional().describe("Datasource UUID override. Auto-resolved from `embedId` or sole active datasource; leave blank unless the user explicitly picked one by ID."),
6345
+ integrationName: z31.string().optional().describe('Datasource display name (e.g. "Snowflake"). Use this when the user picks a datasource by name \u2014 the id is looked up automatically.'),
6346
+ isPublished: z31.boolean().optional().describe("Publish immediately (default true)"),
6347
+ body: z31.record(z31.unknown()).optional().describe("Raw createMetric body passthrough. If provided, used as-is (after defaults). Overrides all other params."),
6348
+ widgets: z31.array(z31.record(z31.unknown())).min(1).max(50).optional().describe("Batch of raw createMetric bodies. Dashboard attachment is added to each body.")
6169
6349
  },
6170
6350
  WRITE_CREATE,
6171
6351
  async (params) => {
@@ -6313,20 +6493,20 @@ Use \`list_widgets\` to verify, or \`update_widget\`/\`remove_widget\` to adjust
6313
6493
  }
6314
6494
 
6315
6495
  // src/tools/widgets/update-widget.ts
6316
- import { z as z31 } from "zod";
6496
+ import { z as z32 } from "zod";
6317
6497
  function registerUpdateWidget(server, client) {
6318
6498
  const services = createServiceBundle(client);
6319
6499
  server.tool(
6320
6500
  "update_widget",
6321
6501
  "Update a widget on a customer dashboard. Non-technical flow: pass `clientId` + `dashboardName` (+ optional `workspaceName` if ambiguous) + `externalMetricId` + `set`. Data app auto-resolves from the dashboard.",
6322
6502
  {
6323
- externalMetricId: z31.string().describe("Internal uuid of the widget (externalMetrics.id). Not the user-facing metricId slug."),
6324
- clientId: z31.string().describe("Client/tenant identifier"),
6325
- dashboardName: z31.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6326
- workspaceName: z31.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6327
- embedId: z31.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6328
- dataAppName: z31.string().optional().describe("Technical override. Auto-resolved from the dashboard; non-technical callers should leave this blank."),
6329
- set: z31.record(z31.unknown()).describe("Partial patch. Keys can include: name, query, chartOptions, description, isPublished, isLive, selectedGroupBy, drillDownSettings, limit, etc.")
6503
+ externalMetricId: z32.string().describe("Internal uuid of the widget (externalMetrics.id). Not the user-facing metricId slug."),
6504
+ clientId: z32.string().describe("Client/tenant identifier"),
6505
+ dashboardName: z32.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6506
+ workspaceName: z32.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6507
+ embedId: z32.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6508
+ dataAppName: z32.string().optional().describe("Technical override. Auto-resolved from the dashboard; non-technical callers should leave this blank."),
6509
+ set: z32.record(z32.unknown()).describe("Partial patch. Keys can include: name, query, chartOptions, description, isPublished, isLive, selectedGroupBy, drillDownSettings, limit, etc.")
6330
6510
  },
6331
6511
  WRITE_IDEMPOTENT,
6332
6512
  async (params) => {
@@ -6389,19 +6569,19 @@ Use \`list_widgets\` to verify.`
6389
6569
  }
6390
6570
 
6391
6571
  // src/tools/widgets/remove-widget.ts
6392
- import { z as z32 } from "zod";
6572
+ import { z as z33 } from "zod";
6393
6573
  function registerRemoveWidget(server, client) {
6394
6574
  const services = createServiceBundle(client);
6395
6575
  server.tool(
6396
6576
  "remove_widget",
6397
6577
  "Remove a widget from a customer dashboard. Non-technical flow: pass `clientId` + `dashboardName` (+ optional `workspaceName` if ambiguous) + `externalMetricId`. Per-client soft delete \u2014 the widget stays on the template dashboard and on other customers' dashboards.",
6398
6578
  {
6399
- externalMetricId: z32.string().describe("Internal uuid of the widget (externalMetrics.id)"),
6400
- clientId: z32.string().describe("Client/tenant identifier \u2014 the widget will be hidden for this client only"),
6401
- dashboardName: z32.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6402
- workspaceName: z32.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6403
- embedId: z32.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6404
- dataAppName: z32.string().optional().describe("Technical override. Auto-resolved from the dashboard; non-technical callers should leave this blank.")
6579
+ externalMetricId: z33.string().describe("Internal uuid of the widget (externalMetrics.id)"),
6580
+ clientId: z33.string().describe("Client/tenant identifier \u2014 the widget will be hidden for this client only"),
6581
+ dashboardName: z33.string().optional().describe("Dashboard name (non-technical). Preferred input \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6582
+ workspaceName: z33.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6583
+ embedId: z33.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6584
+ dataAppName: z33.string().optional().describe("Technical override. Auto-resolved from the dashboard; non-technical callers should leave this blank.")
6405
6585
  },
6406
6586
  DESTRUCTIVE,
6407
6587
  async (params) => {
@@ -6457,21 +6637,21 @@ Note: this is a per-client soft delete. The widget remains available for other c
6457
6637
  }
6458
6638
 
6459
6639
  // src/tools/widgets/generate-widget.ts
6460
- import { z as z33 } from "zod";
6640
+ import { z as z34 } from "zod";
6461
6641
  function registerGenerateWidget(server, client) {
6462
6642
  const services = createServiceBundle(client);
6463
6643
  const tool = server.tool(
6464
6644
  "generate_widget",
6465
6645
  "AI-generate a widget draft from a natural-language prompt. Does NOT persist \u2014 returns a draft to pass to `add_widget`. Non-technical flow: `clientId` + `dashboardName` (+ `workspaceName` if ambiguous); data app and datasource auto-resolve. Never ask the user for data app, datasource, or integration.",
6466
6646
  {
6467
- clientId: z33.string().describe("Client/tenant identifier"),
6468
- userInputs: z33.record(z33.unknown()).describe('Prompt + context object. Typical shape: { prompt: "calls per day over last 30 days", schema: {...}, examples: [...] }. Backend decides which keys it honors.'),
6469
- dashboardName: z33.string().optional().describe("Dashboard name (non-technical). Preferred input for CS/CX flows \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6470
- workspaceName: z33.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6471
- embedId: z33.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6472
- dataAppName: z33.string().optional().describe("Technical override. Auto-resolved from the embed; non-technical callers should leave this blank."),
6473
- integrationId: z33.string().optional().describe("Technical override \u2014 the datasource UUID. Non-technical callers must leave this blank; the datasource is inherited from the dashboard's existing widgets."),
6474
- integrationName: z33.string().optional().describe("Technical override \u2014 datasource display name. Non-technical callers must leave this blank; the datasource is inherited from the dashboard's existing widgets.")
6647
+ clientId: z34.string().describe("Client/tenant identifier"),
6648
+ userInputs: z34.record(z34.unknown()).describe('Prompt + context object. Typical shape: { prompt: "calls per day over last 30 days", schema: {...}, examples: [...] }. Backend decides which keys it honors.'),
6649
+ dashboardName: z34.string().optional().describe("Dashboard name (non-technical). Preferred input for CS/CX flows \u2014 pass this with optional `workspaceName` instead of `embedId`."),
6650
+ workspaceName: z34.string().optional().describe("Workspace name (non-technical). Only needed if `dashboardName` is ambiguous across workspaces."),
6651
+ embedId: z34.string().optional().describe("Technical alternative to `dashboardName`. Pass only if you already have the embed identifier."),
6652
+ dataAppName: z34.string().optional().describe("Technical override. Auto-resolved from the embed; non-technical callers should leave this blank."),
6653
+ integrationId: z34.string().optional().describe("Technical override \u2014 the datasource UUID. Non-technical callers must leave this blank; the datasource is inherited from the dashboard's existing widgets."),
6654
+ integrationName: z34.string().optional().describe("Technical override \u2014 datasource display name. Non-technical callers must leave this blank; the datasource is inherited from the dashboard's existing widgets.")
6475
6655
  },
6476
6656
  READ_ONLY,
6477
6657
  async (params) => {
@@ -6556,9 +6736,9 @@ function registerGenerateWidget(server, client) {
6556
6736
  }
6557
6737
 
6558
6738
  // src/tools/widgets/create-or-update-metric-from-query.ts
6559
- import { z as z34 } from "zod";
6560
- var modeSchema = z34.enum(["dry_run", "apply"]).default("dry_run");
6561
- var conflictStrategySchema = z34.enum(["fail", "update", "create_new"]).default("fail");
6739
+ import { z as z35 } from "zod";
6740
+ var modeSchema = z35.enum(["dry_run", "apply"]).default("dry_run");
6741
+ var conflictStrategySchema = z35.enum(["fail", "update", "create_new"]).default("fail");
6562
6742
  function makePlanText(plan) {
6563
6743
  return JSON.stringify(plan, null, 2);
6564
6744
  }
@@ -6575,22 +6755,22 @@ function registerCreateOrUpdateMetricFromQuery(server, client) {
6575
6755
  "[EMBEDDING] Create or update a production metric/widget on a customer dashboard from validated SQL. Requires clientId (multi-tenant embed). Defaults to dry-run; apply requires explicit confirmation.",
6576
6756
  {
6577
6757
  mode: modeSchema.describe("dry_run returns the plan only; apply executes after confirmation"),
6578
- confirm: z34.string().optional().describe(`Required for apply: ${APPLY_TO_PRODUCTION_CONFIRMATION}`),
6758
+ confirm: z35.string().optional().describe(`Required for apply: ${APPLY_TO_PRODUCTION_CONFIRMATION}`),
6579
6759
  conflictStrategy: conflictStrategySchema.describe("What to do if metricId already exists on the target dashboard"),
6580
- clientId: z34.string().describe("Client/tenant identifier for the dashboard widget scope"),
6581
- workspaceName: z34.string().describe("Target workspace name"),
6582
- dashboardName: z34.string().optional().describe("Dashboard name to attach to"),
6583
- embedId: z34.string().optional().describe("Technical embed id alternative to dashboardName"),
6584
- dataAppName: z34.string().optional().describe("Optional data app override"),
6585
- name: z34.string().describe("Metric/widget display name"),
6586
- metricId: z34.string().describe("Stable metric slug to create or update"),
6587
- query: z34.string().describe("SQL query already validated against the warehouse"),
6588
- description: z34.string().optional().describe("Metric description"),
6589
- chartOptions: z34.record(z34.unknown()).optional().describe("Chart configuration JSON"),
6590
- companyIntegrationId: z34.string().optional().describe("Datasource UUID override"),
6591
- integrationName: z34.string().optional().describe("Datasource display name override"),
6592
- isPublished: z34.boolean().optional().describe("Publish after apply. Defaults to false for production safety"),
6593
- requestedBy: z34.string().optional().describe("Human operator/request context to store on the metric when supported")
6760
+ clientId: z35.string().describe("Client/tenant identifier for the dashboard widget scope"),
6761
+ workspaceName: z35.string().describe("Target workspace name"),
6762
+ dashboardName: z35.string().optional().describe("Dashboard name to attach to"),
6763
+ embedId: z35.string().optional().describe("Technical embed id alternative to dashboardName"),
6764
+ dataAppName: z35.string().optional().describe("Optional data app override"),
6765
+ name: z35.string().describe("Metric/widget display name"),
6766
+ metricId: z35.string().describe("Stable metric slug to create or update"),
6767
+ query: z35.string().describe("SQL query already validated against the warehouse"),
6768
+ description: z35.string().optional().describe("Metric description"),
6769
+ chartOptions: z35.record(z35.unknown()).optional().describe("Chart configuration JSON"),
6770
+ companyIntegrationId: z35.string().optional().describe("Datasource UUID override"),
6771
+ integrationName: z35.string().optional().describe("Datasource display name override"),
6772
+ isPublished: z35.boolean().optional().describe("Publish after apply. Defaults to false for production safety"),
6773
+ requestedBy: z35.string().optional().describe("Human operator/request context to store on the metric when supported")
6594
6774
  },
6595
6775
  WRITE_IDEMPOTENT,
6596
6776
  async (params) => {
@@ -6750,8 +6930,8 @@ function registerCreateOrUpdateMetricFromQuery(server, client) {
6750
6930
  }
6751
6931
 
6752
6932
  // src/tools/widgets/create-workspace-metric.ts
6753
- import { z as z35 } from "zod";
6754
- var modeSchema2 = z35.enum(["dry_run", "apply"]).default("dry_run");
6933
+ import { z as z36 } from "zod";
6934
+ var modeSchema2 = z36.enum(["dry_run", "apply"]).default("dry_run");
6755
6935
  function registerCreateWorkspaceMetric(server, client) {
6756
6936
  server.tool(
6757
6937
  "create_workspace_metric",
@@ -6760,16 +6940,16 @@ function registerCreateWorkspaceMetric(server, client) {
6760
6940
  mode: modeSchema2.describe(
6761
6941
  "dry_run validates the SQL only (no write); apply creates or updates the metric after confirmation"
6762
6942
  ),
6763
- confirm: z35.string().optional().describe(`Required for apply: ${APPLY_TO_PRODUCTION_CONFIRMATION}`),
6764
- workspaceName: z35.string().describe("Target workspace name"),
6765
- name: z35.string().describe("Metric display name"),
6766
- query: z35.string().describe("SQL query to validate and store"),
6767
- metricId: z35.string().optional().describe(
6943
+ confirm: z36.string().optional().describe(`Required for apply: ${APPLY_TO_PRODUCTION_CONFIRMATION}`),
6944
+ workspaceName: z36.string().describe("Target workspace name"),
6945
+ name: z36.string().describe("Metric display name"),
6946
+ query: z36.string().describe("SQL query to validate and store"),
6947
+ metricId: z36.string().optional().describe(
6768
6948
  "Stable metric slug. Pass an existing slug to UPDATE that metric in place. Omit to create \u2014 the slug is derived deterministically from the name (no random/uniqueness suffix), so re-running with the same name upserts the same metric rather than creating a duplicate."
6769
6949
  ),
6770
- description: z35.string().optional().describe("Metric description"),
6771
- datasourceId: z35.string().optional().describe("Datasource UUID override; defaults to the workspace datasource"),
6772
- isPublished: z35.boolean().optional().describe(
6950
+ description: z36.string().optional().describe("Metric description"),
6951
+ datasourceId: z36.string().optional().describe("Datasource UUID override; defaults to the workspace datasource"),
6952
+ isPublished: z36.boolean().optional().describe(
6773
6953
  "Publish after apply. Defaults to false. Applies to creates; on updates the existing publish state is preserved."
6774
6954
  )
6775
6955
  },
@@ -6825,25 +7005,25 @@ function registerCreateWorkspaceMetric(server, client) {
6825
7005
  }
6826
7006
 
6827
7007
  // src/tools/widgets/validate-metric-spec.ts
6828
- import { z as z36 } from "zod";
7008
+ import { z as z37 } from "zod";
6829
7009
  function registerValidateMetricSpec(server, client) {
6830
7010
  const services = createServiceBundle(client);
6831
7011
  server.tool(
6832
7012
  "validate_metric_spec",
6833
7013
  "Validate a production metric spec from SQL without saving it. Resolves dashboard, data app, datasource, conflicts, and required fields.",
6834
7014
  {
6835
- clientId: z36.string().describe("Client/tenant identifier used to validate dashboard widget scope"),
6836
- workspaceName: z36.string().describe("Target production-backed workspace name"),
6837
- dashboardName: z36.string().optional().describe("Dashboard name to attach to"),
6838
- embedId: z36.string().optional().describe("Technical embed id alternative to dashboardName"),
6839
- dataAppName: z36.string().optional().describe("Optional data app override"),
6840
- name: z36.string().describe("Metric/widget display name"),
6841
- metricId: z36.string().describe("Stable metric slug to create or update"),
6842
- query: z36.string().describe("SQL query already validated against the warehouse"),
6843
- description: z36.string().optional().describe("Metric description"),
6844
- chartOptions: z36.record(z36.unknown()).optional().describe("Chart configuration JSON"),
6845
- companyIntegrationId: z36.string().optional().describe("Datasource UUID override"),
6846
- integrationName: z36.string().optional().describe("Datasource display name override")
7015
+ clientId: z37.string().describe("Client/tenant identifier used to validate dashboard widget scope"),
7016
+ workspaceName: z37.string().describe("Target production-backed workspace name"),
7017
+ dashboardName: z37.string().optional().describe("Dashboard name to attach to"),
7018
+ embedId: z37.string().optional().describe("Technical embed id alternative to dashboardName"),
7019
+ dataAppName: z37.string().optional().describe("Optional data app override"),
7020
+ name: z37.string().describe("Metric/widget display name"),
7021
+ metricId: z37.string().describe("Stable metric slug to create or update"),
7022
+ query: z37.string().describe("SQL query already validated against the warehouse"),
7023
+ description: z37.string().optional().describe("Metric description"),
7024
+ chartOptions: z37.record(z37.unknown()).optional().describe("Chart configuration JSON"),
7025
+ companyIntegrationId: z37.string().optional().describe("Datasource UUID override"),
7026
+ integrationName: z37.string().optional().describe("Datasource display name override")
6847
7027
  },
6848
7028
  READ_ONLY,
6849
7029
  async (params) => {
@@ -6934,20 +7114,20 @@ function registerValidateMetricSpec(server, client) {
6934
7114
  }
6935
7115
 
6936
7116
  // src/tools/reports/list-scheduled-reports.ts
6937
- import { z as z37 } from "zod";
7117
+ import { z as z38 } from "zod";
6938
7118
  function registerListScheduledReports(server, client) {
6939
7119
  const services = createServiceBundle(client);
6940
7120
  server.tool(
6941
7121
  "list_scheduled_reports",
6942
7122
  "List configured scheduled reports for a specific client/dashboard embed. Shows schedule metadata, not delivery success history.",
6943
7123
  {
6944
- clientId: z37.string().describe("Client/tenant identifier. Required by the current backend API for non-empty results"),
6945
- dashboardName: z37.string().optional().describe("Dashboard name to inspect"),
6946
- workspaceName: z37.string().optional().describe("Workspace name if dashboardName is ambiguous"),
6947
- embedId: z37.string().optional().describe("Technical embed id alternative to dashboardName"),
6948
- userIdentifier: z37.string().optional().describe("Optional creator/user filter"),
6949
- pageNumber: z37.number().int().positive().optional().describe("Page number when pagination is enabled"),
6950
- isPagination: z37.boolean().optional().describe("Enable backend pagination")
7124
+ clientId: z38.string().describe("Client/tenant identifier. Required by the current backend API for non-empty results"),
7125
+ dashboardName: z38.string().optional().describe("Dashboard name to inspect"),
7126
+ workspaceName: z38.string().optional().describe("Workspace name if dashboardName is ambiguous"),
7127
+ embedId: z38.string().optional().describe("Technical embed id alternative to dashboardName"),
7128
+ userIdentifier: z38.string().optional().describe("Optional creator/user filter"),
7129
+ pageNumber: z38.number().int().positive().optional().describe("Page number when pagination is enabled"),
7130
+ isPagination: z38.boolean().optional().describe("Enable backend pagination")
6951
7131
  },
6952
7132
  READ_ONLY,
6953
7133
  async (params) => {
@@ -10439,16 +10619,25 @@ export {
10439
10619
  DatabrainClient,
10440
10620
  createServiceBundle,
10441
10621
  READ_ONLY,
10622
+ WRITE_CREATE,
10623
+ APPLY_TO_PRODUCTION_CONFIRMATION,
10442
10624
  CHART_URI,
10443
10625
  KPI_URI,
10444
10626
  APP_MIME,
10627
+ rowsSchema,
10445
10628
  referenceSchema,
10446
10629
  viewSchema,
10447
10630
  pageSchema,
10631
+ appMeta,
10448
10632
  enableChartApps,
10449
10633
  chartResult,
10634
+ draftSchema,
10635
+ RENDER_TYPES,
10636
+ draftPage,
10637
+ workspacesForDatamart,
10638
+ saveDraftAsDashboard,
10450
10639
  registerAllTools,
10451
10640
  registerAllResources,
10452
10641
  registerAllPrompts
10453
10642
  };
10454
- //# sourceMappingURL=chunk-3AFT7S6E.js.map
10643
+ //# sourceMappingURL=chunk-I35U2LBX.js.map