@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.
- package/dist/apps/server.js +2 -2
- package/dist/apps/stdio.js +3 -3
- package/dist/{chunk-4OFVDEFU.js → chunk-3JFMWXRO.js} +2 -2
- package/dist/{chunk-3AFT7S6E.js → chunk-I35U2LBX.js} +366 -177
- package/dist/chunk-I35U2LBX.js.map +1 -0
- package/dist/chunk-NZGQJBJV.js +514 -0
- package/dist/chunk-NZGQJBJV.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/{main-RYW6PTR4.js → main-QHUNQWID.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-3AFT7S6E.js.map +0 -1
- package/dist/chunk-SG7F7PRY.js +0 -314
- package/dist/chunk-SG7F7PRY.js.map +0 -1
- /package/dist/{chunk-4OFVDEFU.js.map → chunk-3JFMWXRO.js.map} +0 -0
- /package/dist/{main-RYW6PTR4.js.map → main-QHUNQWID.js.map} +0 -0
|
@@ -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.
|
|
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:
|
|
654
|
+
if (hasChartApps(server)) tool.update({ _meta: appMeta(["model", "app"]) });
|
|
651
655
|
}
|
|
652
656
|
function chartResult(summary, payload) {
|
|
653
|
-
return bounded({
|
|
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
|
-
|
|
670
|
-
|
|
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
|
-
|
|
684
|
-
|
|
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
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
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
|
-
|
|
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/
|
|
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:
|
|
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:
|
|
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:
|
|
5528
|
+
sessionId: z26.string().optional().describe(
|
|
5356
5529
|
"Session ID from a previous ask_question response, for follow-up questions."
|
|
5357
5530
|
),
|
|
5358
|
-
timezone:
|
|
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
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
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
|
|
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:
|
|
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
|
|
5664
|
-
var columnSchema2 =
|
|
5665
|
-
name:
|
|
5666
|
-
description:
|
|
5667
|
-
synonyms:
|
|
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:
|
|
5671
|
-
columnType:
|
|
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 =
|
|
5685
|
-
name:
|
|
5686
|
-
description:
|
|
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:
|
|
5690
|
-
miscellaneousInfo:
|
|
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:
|
|
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:
|
|
5940
|
+
datamartName: z28.string().optional().describe(
|
|
5761
5941
|
"Name of the datamart to update. Omit to list available datamarts."
|
|
5762
5942
|
),
|
|
5763
|
-
tables:
|
|
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:
|
|
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
|
|
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:
|
|
5984
|
-
workspaceName:
|
|
5985
|
-
datamartId:
|
|
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:
|
|
6028
|
-
workspaceName:
|
|
6029
|
-
datamartId:
|
|
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
|
|
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:
|
|
6080
|
-
dashboardName:
|
|
6081
|
-
workspaceName:
|
|
6082
|
-
embedId:
|
|
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
|
|
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:
|
|
6154
|
-
dashboardName:
|
|
6155
|
-
workspaceName:
|
|
6156
|
-
embedId:
|
|
6157
|
-
dataAppName:
|
|
6158
|
-
templateMetricId:
|
|
6159
|
-
name:
|
|
6160
|
-
metricId:
|
|
6161
|
-
query:
|
|
6162
|
-
chartOptions:
|
|
6163
|
-
description:
|
|
6164
|
-
companyIntegrationId:
|
|
6165
|
-
integrationName:
|
|
6166
|
-
isPublished:
|
|
6167
|
-
body:
|
|
6168
|
-
widgets:
|
|
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
|
|
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:
|
|
6324
|
-
clientId:
|
|
6325
|
-
dashboardName:
|
|
6326
|
-
workspaceName:
|
|
6327
|
-
embedId:
|
|
6328
|
-
dataAppName:
|
|
6329
|
-
set:
|
|
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
|
|
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:
|
|
6400
|
-
clientId:
|
|
6401
|
-
dashboardName:
|
|
6402
|
-
workspaceName:
|
|
6403
|
-
embedId:
|
|
6404
|
-
dataAppName:
|
|
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
|
|
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:
|
|
6468
|
-
userInputs:
|
|
6469
|
-
dashboardName:
|
|
6470
|
-
workspaceName:
|
|
6471
|
-
embedId:
|
|
6472
|
-
dataAppName:
|
|
6473
|
-
integrationId:
|
|
6474
|
-
integrationName:
|
|
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
|
|
6560
|
-
var modeSchema =
|
|
6561
|
-
var conflictStrategySchema =
|
|
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:
|
|
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:
|
|
6581
|
-
workspaceName:
|
|
6582
|
-
dashboardName:
|
|
6583
|
-
embedId:
|
|
6584
|
-
dataAppName:
|
|
6585
|
-
name:
|
|
6586
|
-
metricId:
|
|
6587
|
-
query:
|
|
6588
|
-
description:
|
|
6589
|
-
chartOptions:
|
|
6590
|
-
companyIntegrationId:
|
|
6591
|
-
integrationName:
|
|
6592
|
-
isPublished:
|
|
6593
|
-
requestedBy:
|
|
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
|
|
6754
|
-
var modeSchema2 =
|
|
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:
|
|
6764
|
-
workspaceName:
|
|
6765
|
-
name:
|
|
6766
|
-
query:
|
|
6767
|
-
metricId:
|
|
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:
|
|
6771
|
-
datasourceId:
|
|
6772
|
-
isPublished:
|
|
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
|
|
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:
|
|
6836
|
-
workspaceName:
|
|
6837
|
-
dashboardName:
|
|
6838
|
-
embedId:
|
|
6839
|
-
dataAppName:
|
|
6840
|
-
name:
|
|
6841
|
-
metricId:
|
|
6842
|
-
query:
|
|
6843
|
-
description:
|
|
6844
|
-
chartOptions:
|
|
6845
|
-
companyIntegrationId:
|
|
6846
|
-
integrationName:
|
|
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
|
|
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:
|
|
6945
|
-
dashboardName:
|
|
6946
|
-
workspaceName:
|
|
6947
|
-
embedId:
|
|
6948
|
-
userIdentifier:
|
|
6949
|
-
pageNumber:
|
|
6950
|
-
isPagination:
|
|
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-
|
|
10643
|
+
//# sourceMappingURL=chunk-I35U2LBX.js.map
|