@databrainhq/mcp-server 0.3.0-rc.3 → 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-OHTV24NG.js → chunk-3JFMWXRO.js} +2 -2
- package/dist/{chunk-DZOYK5BB.js → chunk-I35U2LBX.js} +355 -175
- package/dist/chunk-I35U2LBX.js.map +1 -0
- package/dist/{chunk-4LIULTLT.js → chunk-NZGQJBJV.js} +199 -64
- package/dist/chunk-NZGQJBJV.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/{main-VPCN2764.js → main-QHUNQWID.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-4LIULTLT.js.map +0 -1
- package/dist/chunk-DZOYK5BB.js.map +0 -1
- /package/dist/{chunk-OHTV24NG.js.map → chunk-3JFMWXRO.js.map} +0 -0
- /package/dist/{main-VPCN2764.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: {
|
|
@@ -664,66 +664,82 @@ function chartResult(summary, payload) {
|
|
|
664
664
|
// src/tools/tool-metadata.ts
|
|
665
665
|
var DEFAULT_TOOL_META = {
|
|
666
666
|
category: "discovery",
|
|
667
|
-
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"
|
|
668
671
|
};
|
|
669
672
|
var TOOL_METADATA = {
|
|
670
673
|
// Identity / discovery
|
|
671
|
-
whoami: { category: "discovery", workflowIntent: "discovery" },
|
|
674
|
+
whoami: { category: "discovery", workflowIntent: "discovery", effect: "read" },
|
|
672
675
|
// Infrastructure / data setup
|
|
673
|
-
list_datasources: { category: "infrastructure", workflowIntent: "setup_data" },
|
|
674
|
-
discover_datasource_schema: { category: "infrastructure", workflowIntent: "setup_data" },
|
|
675
|
-
list_datamarts: { category: "infrastructure", workflowIntent: "setup_data" },
|
|
676
|
-
list_workspaces: { category: "infrastructure", workflowIntent: "setup_data" },
|
|
677
|
-
|
|
678
|
-
|
|
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" },
|
|
679
684
|
// Embedding — data apps & tokens
|
|
680
|
-
list_data_apps: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
681
|
-
list_tenants: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
682
|
-
create_data_app: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
683
|
-
list_api_tokens: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
684
|
-
create_api_token: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
685
|
-
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" },
|
|
686
691
|
// Embedding — embed management
|
|
687
|
-
create_embed: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
688
|
-
list_embeds: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
689
|
-
get_embed_details: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
690
|
-
update_embed: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
691
|
-
|
|
692
|
-
|
|
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" },
|
|
693
700
|
// Embedding — frontend
|
|
694
|
-
generate_guest_token: { category: "embedding", workflowIntent: "embed_dashboard" },
|
|
695
|
-
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" },
|
|
696
703
|
// Embedding — customer dashboards & widgets
|
|
697
|
-
list_dashboards: { category: "embedding", workflowIntent: "embedded_widget" },
|
|
698
|
-
create_dashboard: { category: "embedding", workflowIntent: "author_dashboard" },
|
|
699
|
-
get_dashboard: { category: "embedding", workflowIntent: "author_dashboard" },
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
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" },
|
|
707
717
|
create_or_update_metric_from_query: {
|
|
708
718
|
category: "embedding",
|
|
709
|
-
workflowIntent: "sql_to_embedded_metric"
|
|
719
|
+
workflowIntent: "sql_to_embedded_metric",
|
|
720
|
+
effect: "commit"
|
|
710
721
|
},
|
|
711
722
|
// Internal analytics
|
|
712
723
|
create_workspace_metric: {
|
|
713
724
|
category: "internal_analytics",
|
|
714
|
-
workflowIntent: "sql_to_workspace_metric"
|
|
725
|
+
workflowIntent: "sql_to_workspace_metric",
|
|
726
|
+
effect: "commit"
|
|
715
727
|
},
|
|
716
|
-
|
|
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" },
|
|
717
732
|
// Semantic layer
|
|
718
|
-
get_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data" },
|
|
719
|
-
update_semantic_layer: { category: "semantic_layer", workflowIntent: "query_data" },
|
|
720
|
-
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" },
|
|
721
736
|
get_semantic_layer_generation_status: {
|
|
722
737
|
category: "semantic_layer",
|
|
723
|
-
workflowIntent: "query_data"
|
|
738
|
+
workflowIntent: "query_data",
|
|
739
|
+
effect: "read"
|
|
724
740
|
},
|
|
725
741
|
// Reports
|
|
726
|
-
list_scheduled_reports: { category: "reports", workflowIntent: "reports" }
|
|
742
|
+
list_scheduled_reports: { category: "reports", workflowIntent: "reports", effect: "read" }
|
|
727
743
|
};
|
|
728
744
|
|
|
729
745
|
// src/tools/data-app/list-data-apps.ts
|
|
@@ -5323,8 +5339,157 @@ function registerGetDashboard(server, client) {
|
|
|
5323
5339
|
);
|
|
5324
5340
|
}
|
|
5325
5341
|
|
|
5326
|
-
// src/
|
|
5342
|
+
// src/apps/preview.ts
|
|
5343
|
+
import { createHash } from "crypto";
|
|
5327
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
|
+
}
|
|
5328
5493
|
var MAX_DISPLAY_ROWS = 50;
|
|
5329
5494
|
function formatDataTable(data, columns) {
|
|
5330
5495
|
if (!Array.isArray(data) || data.length === 0) return "_No data returned._";
|
|
@@ -5354,16 +5519,16 @@ function registerAskQuestion(server, client) {
|
|
|
5354
5519
|
"ask_question",
|
|
5355
5520
|
"Ask a natural language question \u2014 converts to SQL, returns data + chart suggestion. Requires datamartName with a populated semantic layer.",
|
|
5356
5521
|
{
|
|
5357
|
-
question:
|
|
5522
|
+
question: z26.string().describe(
|
|
5358
5523
|
'The natural language question to ask (e.g. "What was total revenue last month?")'
|
|
5359
5524
|
),
|
|
5360
|
-
datamartName:
|
|
5525
|
+
datamartName: z26.string().optional().describe(
|
|
5361
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."
|
|
5362
5527
|
),
|
|
5363
|
-
sessionId:
|
|
5528
|
+
sessionId: z26.string().optional().describe(
|
|
5364
5529
|
"Session ID from a previous ask_question response, for follow-up questions."
|
|
5365
5530
|
),
|
|
5366
|
-
timezone:
|
|
5531
|
+
timezone: z26.string().optional().describe('IANA timezone (e.g. "America/New_York"). Defaults to UTC.')
|
|
5367
5532
|
},
|
|
5368
5533
|
WRITE_CREATE,
|
|
5369
5534
|
async (params) => {
|
|
@@ -5468,15 +5633,22 @@ You can verify with \`get_semantic_layer\` using datamartName "${datamartName}".
|
|
|
5468
5633
|
});
|
|
5469
5634
|
const data = Array.isArray(result.data) ? result.data : [];
|
|
5470
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
|
+
};
|
|
5471
5648
|
const rows = firstRows(data);
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
chartSpec: { type: result.suggestedChartType || "table" },
|
|
5476
|
-
rows,
|
|
5477
|
-
columns: Object.keys(rows[0] ?? {}),
|
|
5478
|
-
description: "Showing the first page. Interactive chart preview is not available for this query yet."
|
|
5479
|
-
});
|
|
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 });
|
|
5480
5652
|
}
|
|
5481
5653
|
const table = formatDataTable(data, result.columns);
|
|
5482
5654
|
const parts = [];
|
|
@@ -5551,14 +5723,14 @@ To fix this:
|
|
|
5551
5723
|
}
|
|
5552
5724
|
|
|
5553
5725
|
// src/tools/query/get-semantic-layer.ts
|
|
5554
|
-
import { z as
|
|
5726
|
+
import { z as z27 } from "zod";
|
|
5555
5727
|
function registerGetSemanticLayer(server, client) {
|
|
5556
5728
|
const services = createServiceBundle(client);
|
|
5557
5729
|
server.tool(
|
|
5558
5730
|
"get_semantic_layer",
|
|
5559
5731
|
"Get semantic layer metadata for a datamart: table/column descriptions, synonyms, completion score. Omit datamartName to auto-resolve.",
|
|
5560
5732
|
{
|
|
5561
|
-
datamartName:
|
|
5733
|
+
datamartName: z27.string().optional().describe(
|
|
5562
5734
|
"Name of the datamart to inspect. Omit to list available datamarts."
|
|
5563
5735
|
)
|
|
5564
5736
|
},
|
|
@@ -5668,15 +5840,15 @@ ${result.feedback}`);
|
|
|
5668
5840
|
}
|
|
5669
5841
|
|
|
5670
5842
|
// src/tools/query/update-semantic-layer.ts
|
|
5671
|
-
import { z as
|
|
5672
|
-
var columnSchema2 =
|
|
5673
|
-
name:
|
|
5674
|
-
description:
|
|
5675
|
-
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(
|
|
5676
5848
|
'Alternative names users might use for this column (e.g. ["revenue", "sales amount"])'
|
|
5677
5849
|
),
|
|
5678
|
-
miscellaneousInfo:
|
|
5679
|
-
columnType:
|
|
5850
|
+
miscellaneousInfo: z28.string().optional().describe("Additional context such as valid values, units, or caveats"),
|
|
5851
|
+
columnType: z28.enum([
|
|
5680
5852
|
"String",
|
|
5681
5853
|
"Long String",
|
|
5682
5854
|
"String (Custom)",
|
|
@@ -5689,16 +5861,16 @@ var columnSchema2 = z27.object({
|
|
|
5689
5861
|
"JSON"
|
|
5690
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.')
|
|
5691
5863
|
});
|
|
5692
|
-
var tableSchema2 =
|
|
5693
|
-
name:
|
|
5694
|
-
description:
|
|
5864
|
+
var tableSchema2 = z28.object({
|
|
5865
|
+
name: z28.string().describe("Table name (must exist in the datamart)"),
|
|
5866
|
+
description: z28.string().optional().describe(
|
|
5695
5867
|
"Business-friendly description of what this table represents"
|
|
5696
5868
|
),
|
|
5697
|
-
synonyms:
|
|
5698
|
-
miscellaneousInfo:
|
|
5869
|
+
synonyms: z28.array(z28.string()).optional().describe("Alternative names for this table"),
|
|
5870
|
+
miscellaneousInfo: z28.string().optional().describe(
|
|
5699
5871
|
"Additional context such as how the table relates to other tables"
|
|
5700
5872
|
),
|
|
5701
|
-
columns:
|
|
5873
|
+
columns: z28.array(columnSchema2).optional().describe("Column-level semantic definitions to update")
|
|
5702
5874
|
});
|
|
5703
5875
|
function columnKey(tableName, columnName) {
|
|
5704
5876
|
return `${tableName.toLowerCase()}\0${columnName.toLowerCase()}`;
|
|
@@ -5765,13 +5937,13 @@ function registerUpdateSemanticLayer(server, client) {
|
|
|
5765
5937
|
"update_semantic_layer",
|
|
5766
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.",
|
|
5767
5939
|
{
|
|
5768
|
-
datamartName:
|
|
5940
|
+
datamartName: z28.string().optional().describe(
|
|
5769
5941
|
"Name of the datamart to update. Omit to list available datamarts."
|
|
5770
5942
|
),
|
|
5771
|
-
tables:
|
|
5943
|
+
tables: z28.array(tableSchema2).optional().describe(
|
|
5772
5944
|
"Table and column definitions to update. Only include tables/columns you want to change."
|
|
5773
5945
|
),
|
|
5774
|
-
feedback:
|
|
5946
|
+
feedback: z28.string().optional().describe(
|
|
5775
5947
|
'General feedback or context about the datamart (e.g. "This datamart contains e-commerce data for the US market").'
|
|
5776
5948
|
)
|
|
5777
5949
|
},
|
|
@@ -5833,7 +6005,7 @@ You can now:
|
|
|
5833
6005
|
}
|
|
5834
6006
|
|
|
5835
6007
|
// src/tools/query/semantic-generation.ts
|
|
5836
|
-
import { z as
|
|
6008
|
+
import { z as z29 } from "zod";
|
|
5837
6009
|
function nonEmptyString(value) {
|
|
5838
6010
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
5839
6011
|
}
|
|
@@ -5988,9 +6160,9 @@ function registerStartSemanticLayerGeneration(server, client) {
|
|
|
5988
6160
|
"start_semantic_layer_generation",
|
|
5989
6161
|
"Start backend semantic-layer auto-generation for a datamart. Returns an async job id to poll.",
|
|
5990
6162
|
{
|
|
5991
|
-
datamartName:
|
|
5992
|
-
workspaceName:
|
|
5993
|
-
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.")
|
|
5994
6166
|
},
|
|
5995
6167
|
WRITE_CREATE,
|
|
5996
6168
|
async (params) => {
|
|
@@ -6032,9 +6204,9 @@ function registerGetSemanticLayerGenerationStatus(server, client) {
|
|
|
6032
6204
|
"get_semantic_layer_generation_status",
|
|
6033
6205
|
"Get semantic-layer auto-generation job status for a datamart.",
|
|
6034
6206
|
{
|
|
6035
|
-
datamartName:
|
|
6036
|
-
workspaceName:
|
|
6037
|
-
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.")
|
|
6038
6210
|
},
|
|
6039
6211
|
READ_ONLY,
|
|
6040
6212
|
async (params) => {
|
|
@@ -6071,7 +6243,7 @@ function registerGetSemanticLayerGenerationStatus(server, client) {
|
|
|
6071
6243
|
}
|
|
6072
6244
|
|
|
6073
6245
|
// src/tools/widgets/list-widgets.ts
|
|
6074
|
-
import { z as
|
|
6246
|
+
import { z as z30 } from "zod";
|
|
6075
6247
|
function widgetReferenceId(widget) {
|
|
6076
6248
|
for (const candidate of [widget.externalMetricId, widget.id, widget._id, widget.metricId]) {
|
|
6077
6249
|
if (typeof candidate === "string" && candidate.trim().length > 0) return candidate.trim();
|
|
@@ -6084,10 +6256,10 @@ function registerListWidgets(server, client) {
|
|
|
6084
6256
|
"list_widgets",
|
|
6085
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.",
|
|
6086
6258
|
{
|
|
6087
|
-
clientId:
|
|
6088
|
-
dashboardName:
|
|
6089
|
-
workspaceName:
|
|
6090
|
-
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.")
|
|
6091
6263
|
},
|
|
6092
6264
|
READ_ONLY,
|
|
6093
6265
|
async (params) => {
|
|
@@ -6151,29 +6323,29 @@ function registerListWidgets(server, client) {
|
|
|
6151
6323
|
}
|
|
6152
6324
|
|
|
6153
6325
|
// src/tools/widgets/add-widget.ts
|
|
6154
|
-
import { z as
|
|
6326
|
+
import { z as z31 } from "zod";
|
|
6155
6327
|
function registerAddWidget(server, client) {
|
|
6156
6328
|
const services = createServiceBundle(client);
|
|
6157
6329
|
server.tool(
|
|
6158
6330
|
"add_widget",
|
|
6159
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.",
|
|
6160
6332
|
{
|
|
6161
|
-
clientId:
|
|
6162
|
-
dashboardName:
|
|
6163
|
-
workspaceName:
|
|
6164
|
-
embedId:
|
|
6165
|
-
dataAppName:
|
|
6166
|
-
templateMetricId:
|
|
6167
|
-
name:
|
|
6168
|
-
metricId:
|
|
6169
|
-
query:
|
|
6170
|
-
chartOptions:
|
|
6171
|
-
description:
|
|
6172
|
-
companyIntegrationId:
|
|
6173
|
-
integrationName:
|
|
6174
|
-
isPublished:
|
|
6175
|
-
body:
|
|
6176
|
-
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.")
|
|
6177
6349
|
},
|
|
6178
6350
|
WRITE_CREATE,
|
|
6179
6351
|
async (params) => {
|
|
@@ -6321,20 +6493,20 @@ Use \`list_widgets\` to verify, or \`update_widget\`/\`remove_widget\` to adjust
|
|
|
6321
6493
|
}
|
|
6322
6494
|
|
|
6323
6495
|
// src/tools/widgets/update-widget.ts
|
|
6324
|
-
import { z as
|
|
6496
|
+
import { z as z32 } from "zod";
|
|
6325
6497
|
function registerUpdateWidget(server, client) {
|
|
6326
6498
|
const services = createServiceBundle(client);
|
|
6327
6499
|
server.tool(
|
|
6328
6500
|
"update_widget",
|
|
6329
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.",
|
|
6330
6502
|
{
|
|
6331
|
-
externalMetricId:
|
|
6332
|
-
clientId:
|
|
6333
|
-
dashboardName:
|
|
6334
|
-
workspaceName:
|
|
6335
|
-
embedId:
|
|
6336
|
-
dataAppName:
|
|
6337
|
-
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.")
|
|
6338
6510
|
},
|
|
6339
6511
|
WRITE_IDEMPOTENT,
|
|
6340
6512
|
async (params) => {
|
|
@@ -6397,19 +6569,19 @@ Use \`list_widgets\` to verify.`
|
|
|
6397
6569
|
}
|
|
6398
6570
|
|
|
6399
6571
|
// src/tools/widgets/remove-widget.ts
|
|
6400
|
-
import { z as
|
|
6572
|
+
import { z as z33 } from "zod";
|
|
6401
6573
|
function registerRemoveWidget(server, client) {
|
|
6402
6574
|
const services = createServiceBundle(client);
|
|
6403
6575
|
server.tool(
|
|
6404
6576
|
"remove_widget",
|
|
6405
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.",
|
|
6406
6578
|
{
|
|
6407
|
-
externalMetricId:
|
|
6408
|
-
clientId:
|
|
6409
|
-
dashboardName:
|
|
6410
|
-
workspaceName:
|
|
6411
|
-
embedId:
|
|
6412
|
-
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.")
|
|
6413
6585
|
},
|
|
6414
6586
|
DESTRUCTIVE,
|
|
6415
6587
|
async (params) => {
|
|
@@ -6465,21 +6637,21 @@ Note: this is a per-client soft delete. The widget remains available for other c
|
|
|
6465
6637
|
}
|
|
6466
6638
|
|
|
6467
6639
|
// src/tools/widgets/generate-widget.ts
|
|
6468
|
-
import { z as
|
|
6640
|
+
import { z as z34 } from "zod";
|
|
6469
6641
|
function registerGenerateWidget(server, client) {
|
|
6470
6642
|
const services = createServiceBundle(client);
|
|
6471
6643
|
const tool = server.tool(
|
|
6472
6644
|
"generate_widget",
|
|
6473
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.",
|
|
6474
6646
|
{
|
|
6475
|
-
clientId:
|
|
6476
|
-
userInputs:
|
|
6477
|
-
dashboardName:
|
|
6478
|
-
workspaceName:
|
|
6479
|
-
embedId:
|
|
6480
|
-
dataAppName:
|
|
6481
|
-
integrationId:
|
|
6482
|
-
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.")
|
|
6483
6655
|
},
|
|
6484
6656
|
READ_ONLY,
|
|
6485
6657
|
async (params) => {
|
|
@@ -6564,9 +6736,9 @@ function registerGenerateWidget(server, client) {
|
|
|
6564
6736
|
}
|
|
6565
6737
|
|
|
6566
6738
|
// src/tools/widgets/create-or-update-metric-from-query.ts
|
|
6567
|
-
import { z as
|
|
6568
|
-
var modeSchema =
|
|
6569
|
-
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");
|
|
6570
6742
|
function makePlanText(plan) {
|
|
6571
6743
|
return JSON.stringify(plan, null, 2);
|
|
6572
6744
|
}
|
|
@@ -6583,22 +6755,22 @@ function registerCreateOrUpdateMetricFromQuery(server, client) {
|
|
|
6583
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.",
|
|
6584
6756
|
{
|
|
6585
6757
|
mode: modeSchema.describe("dry_run returns the plan only; apply executes after confirmation"),
|
|
6586
|
-
confirm:
|
|
6758
|
+
confirm: z35.string().optional().describe(`Required for apply: ${APPLY_TO_PRODUCTION_CONFIRMATION}`),
|
|
6587
6759
|
conflictStrategy: conflictStrategySchema.describe("What to do if metricId already exists on the target dashboard"),
|
|
6588
|
-
clientId:
|
|
6589
|
-
workspaceName:
|
|
6590
|
-
dashboardName:
|
|
6591
|
-
embedId:
|
|
6592
|
-
dataAppName:
|
|
6593
|
-
name:
|
|
6594
|
-
metricId:
|
|
6595
|
-
query:
|
|
6596
|
-
description:
|
|
6597
|
-
chartOptions:
|
|
6598
|
-
companyIntegrationId:
|
|
6599
|
-
integrationName:
|
|
6600
|
-
isPublished:
|
|
6601
|
-
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")
|
|
6602
6774
|
},
|
|
6603
6775
|
WRITE_IDEMPOTENT,
|
|
6604
6776
|
async (params) => {
|
|
@@ -6758,8 +6930,8 @@ function registerCreateOrUpdateMetricFromQuery(server, client) {
|
|
|
6758
6930
|
}
|
|
6759
6931
|
|
|
6760
6932
|
// src/tools/widgets/create-workspace-metric.ts
|
|
6761
|
-
import { z as
|
|
6762
|
-
var modeSchema2 =
|
|
6933
|
+
import { z as z36 } from "zod";
|
|
6934
|
+
var modeSchema2 = z36.enum(["dry_run", "apply"]).default("dry_run");
|
|
6763
6935
|
function registerCreateWorkspaceMetric(server, client) {
|
|
6764
6936
|
server.tool(
|
|
6765
6937
|
"create_workspace_metric",
|
|
@@ -6768,16 +6940,16 @@ function registerCreateWorkspaceMetric(server, client) {
|
|
|
6768
6940
|
mode: modeSchema2.describe(
|
|
6769
6941
|
"dry_run validates the SQL only (no write); apply creates or updates the metric after confirmation"
|
|
6770
6942
|
),
|
|
6771
|
-
confirm:
|
|
6772
|
-
workspaceName:
|
|
6773
|
-
name:
|
|
6774
|
-
query:
|
|
6775
|
-
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(
|
|
6776
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."
|
|
6777
6949
|
),
|
|
6778
|
-
description:
|
|
6779
|
-
datasourceId:
|
|
6780
|
-
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(
|
|
6781
6953
|
"Publish after apply. Defaults to false. Applies to creates; on updates the existing publish state is preserved."
|
|
6782
6954
|
)
|
|
6783
6955
|
},
|
|
@@ -6833,25 +7005,25 @@ function registerCreateWorkspaceMetric(server, client) {
|
|
|
6833
7005
|
}
|
|
6834
7006
|
|
|
6835
7007
|
// src/tools/widgets/validate-metric-spec.ts
|
|
6836
|
-
import { z as
|
|
7008
|
+
import { z as z37 } from "zod";
|
|
6837
7009
|
function registerValidateMetricSpec(server, client) {
|
|
6838
7010
|
const services = createServiceBundle(client);
|
|
6839
7011
|
server.tool(
|
|
6840
7012
|
"validate_metric_spec",
|
|
6841
7013
|
"Validate a production metric spec from SQL without saving it. Resolves dashboard, data app, datasource, conflicts, and required fields.",
|
|
6842
7014
|
{
|
|
6843
|
-
clientId:
|
|
6844
|
-
workspaceName:
|
|
6845
|
-
dashboardName:
|
|
6846
|
-
embedId:
|
|
6847
|
-
dataAppName:
|
|
6848
|
-
name:
|
|
6849
|
-
metricId:
|
|
6850
|
-
query:
|
|
6851
|
-
description:
|
|
6852
|
-
chartOptions:
|
|
6853
|
-
companyIntegrationId:
|
|
6854
|
-
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")
|
|
6855
7027
|
},
|
|
6856
7028
|
READ_ONLY,
|
|
6857
7029
|
async (params) => {
|
|
@@ -6942,20 +7114,20 @@ function registerValidateMetricSpec(server, client) {
|
|
|
6942
7114
|
}
|
|
6943
7115
|
|
|
6944
7116
|
// src/tools/reports/list-scheduled-reports.ts
|
|
6945
|
-
import { z as
|
|
7117
|
+
import { z as z38 } from "zod";
|
|
6946
7118
|
function registerListScheduledReports(server, client) {
|
|
6947
7119
|
const services = createServiceBundle(client);
|
|
6948
7120
|
server.tool(
|
|
6949
7121
|
"list_scheduled_reports",
|
|
6950
7122
|
"List configured scheduled reports for a specific client/dashboard embed. Shows schedule metadata, not delivery success history.",
|
|
6951
7123
|
{
|
|
6952
|
-
clientId:
|
|
6953
|
-
dashboardName:
|
|
6954
|
-
workspaceName:
|
|
6955
|
-
embedId:
|
|
6956
|
-
userIdentifier:
|
|
6957
|
-
pageNumber:
|
|
6958
|
-
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")
|
|
6959
7131
|
},
|
|
6960
7132
|
READ_ONLY,
|
|
6961
7133
|
async (params) => {
|
|
@@ -10447,17 +10619,25 @@ export {
|
|
|
10447
10619
|
DatabrainClient,
|
|
10448
10620
|
createServiceBundle,
|
|
10449
10621
|
READ_ONLY,
|
|
10622
|
+
WRITE_CREATE,
|
|
10623
|
+
APPLY_TO_PRODUCTION_CONFIRMATION,
|
|
10450
10624
|
CHART_URI,
|
|
10451
10625
|
KPI_URI,
|
|
10452
10626
|
APP_MIME,
|
|
10627
|
+
rowsSchema,
|
|
10453
10628
|
referenceSchema,
|
|
10454
10629
|
viewSchema,
|
|
10455
10630
|
pageSchema,
|
|
10456
10631
|
appMeta,
|
|
10457
10632
|
enableChartApps,
|
|
10458
10633
|
chartResult,
|
|
10634
|
+
draftSchema,
|
|
10635
|
+
RENDER_TYPES,
|
|
10636
|
+
draftPage,
|
|
10637
|
+
workspacesForDatamart,
|
|
10638
|
+
saveDraftAsDashboard,
|
|
10459
10639
|
registerAllTools,
|
|
10460
10640
|
registerAllResources,
|
|
10461
10641
|
registerAllPrompts
|
|
10462
10642
|
};
|
|
10463
|
-
//# sourceMappingURL=chunk-
|
|
10643
|
+
//# sourceMappingURL=chunk-I35U2LBX.js.map
|