@databrainhq/mcp-server 0.2.2 → 0.2.3

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/index.js CHANGED
@@ -218,7 +218,7 @@ var DatabrainClient = class {
218
218
  throw new DatabrainApiError(
219
219
  401,
220
220
  "MISSING_API_TOKEN",
221
- "A per-data-app API token is required for this embedding operation but none is configured. Use `setup_embed_interactive` with step `ensure_api_token` to create or set one, or call `create_api_token` / `set_api_token` directly. Do not ask the user for this token \u2014 create it via the MCP tools."
221
+ "A per-data-app API token is required for this embedding operation but none is configured. Call `create_api_token` to generate one, or `set_api_token` if you already have the value. Do not ask the user for this token \u2014 create it via the MCP tools."
222
222
  );
223
223
  }
224
224
  let url = `${this.config.apiUrl}${options.path}`;
@@ -1690,7 +1690,7 @@ Next: use \`generate_guest_token\` with the clientId and \`generate_embed_code\`
1690
1690
  - workspaceName: \`${body.workspaceName}\`
1691
1691
  - accessSettings.datamartName: \`${datamartName}\`
1692
1692
 
1693
- Next: run \`get_embed_details\` and \`diagnose_embed_health\` to verify update compatibility.`
1693
+ Next: run \`get_embed_details\` to verify the embed configuration.`
1694
1694
  );
1695
1695
  } catch (err) {
1696
1696
  if (err instanceof DatabrainApiError) return err.toToolResponse();
@@ -2377,612 +2377,71 @@ Use \`get_embed_details\` to view the full current theme configuration.` + GUEST
2377
2377
  );
2378
2378
  }
2379
2379
 
2380
- // src/tools/embed/configure-embed.ts
2381
- import { z as z15 } from "zod";
2382
- var stringFilterSchema = z15.object({
2383
- filterName: z15.string().describe("Name of the filter as it appears in the dashboard"),
2384
- options: z15.array(z15.object({
2385
- value: z15.string(),
2386
- label: z15.string()
2387
- })).describe("Dropdown options"),
2388
- defaultOption: z15.union([z15.string(), z15.array(z15.string())]).optional().describe("Default selected value (string or array for multi-select)")
2389
- });
2390
- var numberFilterSchema = z15.object({
2391
- filterName: z15.string().describe("Name of the filter"),
2392
- min: z15.number().describe("Minimum value"),
2393
- max: z15.number().describe("Maximum value")
2394
- });
2395
- var datePresetSchema = z15.object({
2396
- type: z15.string().optional().describe('Preset type (e.g. "Last", "This")'),
2397
- interval: z15.string().optional().describe('Interval (e.g. "Days", "Months", "Years")'),
2398
- timeGrain: z15.string().optional().describe("Time grain"),
2399
- label: z15.string().describe('Display label (e.g. "Last 30 Days")'),
2400
- startDate: z15.string().optional().describe("Start date (YYYY-MM-DD)"),
2401
- endDate: z15.string().optional().describe("End date (YYYY-MM-DD)")
2402
- });
2403
- var dateFilterSchema = z15.object({
2404
- filterName: z15.string().describe("Name of the filter"),
2405
- startDate: z15.string().optional().describe("Default start date (YYYY-MM-DD)"),
2406
- endDate: z15.string().optional().describe("Default end date (YYYY-MM-DD)"),
2407
- datePresetOptions: z15.array(datePresetSchema).optional().describe("Custom date presets to show in the date picker")
2408
- });
2409
- var sqlFilterSchema = z15.object({
2410
- filterName: z15.string().describe("Name of the filter"),
2411
- sql: z15.string().describe("SQL query to fetch filter options"),
2412
- columnName: z15.string().describe("Column from the SQL result to use as option values")
2413
- });
2414
- var SUPPORTED_LANGUAGES = [
2415
- "en",
2416
- "fr",
2417
- "es",
2418
- "de",
2419
- "it",
2420
- "pt",
2421
- "zh",
2422
- "ja",
2423
- "ko",
2424
- "hi",
2425
- "ar",
2426
- "ru"
2427
- ];
2428
- function registerConfigureEmbed(server, client) {
2429
- const services = createServiceBundle(client);
2430
- server.tool(
2431
- "configure_embed",
2432
- "Configure embed options (UI toggles, downloads, layout), filters (string/date/number/SQL), and i18n (language, translations).",
2433
- {
2434
- embedId: z15.string().describe("ID of the embed to configure"),
2435
- body: z15.record(z15.unknown()).optional().describe(
2436
- "Raw API body for PUT /api/v2/data-app/embeds. If provided, sent directly and convenience fields are ignored."
2437
- ),
2438
- // ===== OPTIONS (from configure_embed_options) =====
2439
- // Metric Operations
2440
- disableMetricCreation: z15.boolean().optional().describe("Disable creating new metrics"),
2441
- disableMetricUpdation: z15.boolean().optional().describe("Disable updating existing metrics"),
2442
- disableMetricDeletion: z15.boolean().optional().describe("Disable deleting metrics"),
2443
- disableManageMetrics: z15.boolean().optional().describe("Hide the manage metrics interface"),
2444
- // Layout
2445
- disableLayoutCustomization: z15.boolean().optional().describe("Prevent layout changes"),
2446
- disableSaveLayout: z15.boolean().optional().describe("Prevent saving layout changes"),
2447
- // Downloads & Export
2448
- enableDownloadCsv: z15.boolean().optional().describe("Enable CSV download for individual metrics"),
2449
- enableEmailCsv: z15.boolean().optional().describe("Enable emailing metric data as CSV"),
2450
- disableDownloadPng: z15.boolean().optional().describe("Disable PNG download in fullscreen"),
2451
- enableDownloadAllMetrics: z15.boolean().optional().describe("Enable bulk download of all metrics as CSV"),
2452
- enableDownloadAllPdf: z15.boolean().optional().describe("Enable downloading entire dashboard as PDF"),
2453
- disableDownloadDataNoFilters: z15.boolean().optional().describe("Prevent data download when no filters"),
2454
- disableDownloadUnderlyingDataNoFilters: z15.boolean().optional().describe("Prevent underlying data download without filters"),
2455
- // UI Visibility
2456
- hideDashboardName: z15.boolean().optional().describe("Hide the dashboard title"),
2457
- hideMetricCardShadow: z15.boolean().optional().describe("Remove card shadow effects"),
2458
- disableMetricCardBorder: z15.boolean().optional().describe("Remove metric card borders"),
2459
- showDashboardActions: z15.boolean().optional().describe("Show/hide dashboard action buttons"),
2460
- disableFullscreen: z15.boolean().optional().describe("Disable fullscreen mode"),
2461
- isHideTablePreview: z15.boolean().optional().describe("Hide table preview in fullscreen"),
2462
- isHideChartSettings: z15.boolean().optional().describe("Hide chart settings in fullscreen"),
2463
- shouldFitFullScreen: z15.boolean().optional().describe("Make fullscreen modal fit the component space"),
2464
- // Loaders
2465
- disableMainLoader: z15.boolean().optional().describe("Hide the main loading indicator"),
2466
- disableMetricLoader: z15.boolean().optional().describe("Hide metric-level loading indicators"),
2467
- // Data Access
2468
- disableUnderlyingData: z15.boolean().optional().describe("Disable access to underlying data"),
2469
- isShowNoDataFoundScreen: z15.boolean().optional().describe('Show a "no data" screen when data unavailable'),
2470
- // Scheduling
2471
- disableScheduleEmailReports: z15.boolean().optional().describe("Disable email report scheduling"),
2472
- // Interactions
2473
- isStickyDashboardFilters: z15.boolean().optional().describe("Make filters sticky when scrolling"),
2474
- enableMultiMetricFilters: z15.boolean().optional().describe("Enable cross-metric filter interactions"),
2475
- optionsIcon: z15.enum(["kebab-menu-vertical", "download"]).optional().describe("Menu icon style"),
2476
- enableTitleClickFullscreen: z15.boolean().optional().describe("Click metric title to enter fullscreen"),
2477
- // Export
2478
- exportMsgPosition: z15.enum([
2479
- "bottom",
2480
- "bottom-left",
2481
- "bottom-right",
2482
- "center",
2483
- "top",
2484
- "top-left",
2485
- "top-right"
2486
- ]).optional().describe('Position of "exporting" notification message'),
2487
- isModifyUrl: z15.boolean().optional().describe("Whether navigating metrics modifies the browser URL"),
2488
- // No-data visuals
2489
- noDataImg: z15.string().optional().describe("URL to custom image when no data found"),
2490
- noDataFoundSvg: z15.string().optional().describe("Inline SVG when no data found"),
2491
- // Metric description
2492
- longDescriptionWidth: z15.string().optional().describe('Width of long-description tooltip (e.g. "300px")'),
2493
- longDescriptionFontColor: z15.string().optional().describe("Font color for long-description tooltip (hex)"),
2494
- // Settings icon
2495
- settingsIconName: z15.string().optional().describe("Custom name/label for the settings icon"),
2496
- settingsIconSvg: z15.string().optional().describe("Inline SVG for a custom settings icon"),
2497
- // Advanced: per-chart settings
2498
- customChartSettings: z15.record(z15.unknown()).optional().describe("Per-chart override settings (JSON)"),
2499
- // Custom Messages
2500
- tokenExpiryMessage: z15.string().optional().describe("Custom message when token expires"),
2501
- tokenAbsentMessage: z15.string().optional().describe("Custom message when token is missing"),
2502
- // ===== FILTERS (from configure_filters) =====
2503
- stringFilters: z15.array(stringFilterSchema).optional().describe("String filter configurations with dropdown options and defaults"),
2504
- numberFilters: z15.array(numberFilterSchema).optional().describe("Number filter configurations with min/max defaults"),
2505
- dateFilters: z15.array(dateFilterSchema).optional().describe("Date filter configurations with default ranges and presets"),
2506
- sqlFilters: z15.array(sqlFilterSchema).optional().describe("SQL-based filter options for large option sets"),
2507
- hideDashboardFilters: z15.array(z15.string()).optional().describe("Filter names to hide from the dashboard UI"),
2508
- hideDatePickerOptions: z15.array(z15.string()).optional().describe('Date picker options to hide (e.g. ["this month", "yesterday"])'),
2509
- metricFilterPosition: z15.enum(["inside", "outside"]).optional().describe("Where to display metric-level filters"),
2510
- // ===== INTERNATIONALIZATION (from configure_internationalization) =====
2511
- language: z15.enum(SUPPORTED_LANGUAGES).optional().describe('Primary language code (e.g. "fr", "es", "ja")'),
2512
- calendarType: z15.enum(["default", "ind"]).optional().describe('Calendar system: "default" or "ind" (Indian)'),
2513
- translations: z15.array(z15.object({
2514
- key: z15.string().describe("Original text to translate (must match exactly)"),
2515
- translations: z15.record(z15.string()).describe("Language code \u2192 translation mapping")
2516
- })).optional().describe("Translation dictionary entries")
2517
- },
2518
- WRITE_IDEMPOTENT,
2519
- async (params) => {
2520
- const { embedId, body, ...opts } = params;
2521
- if (body) {
2522
- try {
2523
- const rawBody = { ...body };
2524
- if (!rawBody.embedId) rawBody.embedId = embedId;
2525
- const result = await services.embedsApi.updateEmbed(rawBody);
2526
- if (result.error) {
2527
- return toolError(`Embed configuration failed: ${stringify(result.error)}`);
2528
- }
2529
- return toolSuccess(
2530
- `Embed configured for "${embedId}" (raw passthrough mode).` + GUEST_TOKEN_REMINDER
2531
- );
2532
- } catch (err) {
2533
- const guardrail = await maybeBuildCorruptedEmbedGuardrail(client, embedId, "configure embed", err);
2534
- if (guardrail) return guardrail;
2535
- if (err instanceof DatabrainApiError) return err.toToolResponse();
2536
- return toolError(`Unexpected error: ${err.message}`);
2537
- }
2538
- }
2539
- const options = {};
2540
- const attrs = {};
2541
- const configured = [];
2542
- if (opts.disableMetricCreation !== void 0) options.disableMetricCreation = opts.disableMetricCreation;
2543
- if (opts.disableMetricUpdation !== void 0) options.disableMetricUpdation = opts.disableMetricUpdation;
2544
- if (opts.disableMetricDeletion !== void 0) options.disableMetricDeletion = opts.disableMetricDeletion;
2545
- if (opts.disableManageMetrics !== void 0) options.disableManageMetrics = opts.disableManageMetrics;
2546
- if (opts.disableLayoutCustomization !== void 0) options.disableLayoutCustomization = opts.disableLayoutCustomization;
2547
- if (opts.disableSaveLayout !== void 0) options.disableSaveLayout = opts.disableSaveLayout;
2548
- if (opts.disableDownloadDataNoFilters !== void 0) options.disableDownloadDataNoFilters = opts.disableDownloadDataNoFilters;
2549
- if (opts.disableDownloadUnderlyingDataNoFilters !== void 0) options.disableDownloadUnderlyingDataNoFilters = opts.disableDownloadUnderlyingDataNoFilters;
2550
- if (opts.hideDashboardName !== void 0) options.hideDashboardName = opts.hideDashboardName;
2551
- if (opts.hideMetricCardShadow !== void 0) options.hideMetricCardShadow = opts.hideMetricCardShadow;
2552
- if (opts.disableMetricCardBorder !== void 0) options.disableMetricCardBorder = opts.disableMetricCardBorder;
2553
- if (opts.showDashboardActions !== void 0) options.showDashboardActions = opts.showDashboardActions;
2554
- if (opts.shouldFitFullScreen !== void 0) options.shouldFitFullScreen = opts.shouldFitFullScreen;
2555
- if (opts.isShowNoDataFoundScreen !== void 0) options.isShowNoDataFoundScreen = opts.isShowNoDataFoundScreen;
2556
- if (opts.disableMainLoader !== void 0) options.disableMainLoader = opts.disableMainLoader;
2557
- if (opts.disableMetricLoader !== void 0) options.disableMetricLoader = opts.disableMetricLoader;
2558
- if (opts.disableUnderlyingData !== void 0) options.disableUnderlyingData = opts.disableUnderlyingData;
2559
- if (opts.disableScheduleEmailReports !== void 0) options.disableScheduleEmailReports = opts.disableScheduleEmailReports;
2560
- if (opts.exportMsgPosition) options.exportMsgPosition = opts.exportMsgPosition;
2561
- if (opts.isModifyUrl !== void 0) options.isModifyUrl = opts.isModifyUrl;
2562
- if (opts.enableDownloadCsv !== void 0) attrs.enableDownloadCsv = opts.enableDownloadCsv;
2563
- if (opts.enableEmailCsv !== void 0) attrs.enableEmailCsv = opts.enableEmailCsv;
2564
- if (opts.disableDownloadPng !== void 0) attrs.disableDownloadPng = opts.disableDownloadPng;
2565
- if (opts.enableDownloadAllMetrics !== void 0) attrs.enableDownloadAllMetrics = opts.enableDownloadAllMetrics;
2566
- if (opts.enableDownloadAllPdf !== void 0) attrs.enableDownloadAllPdf = opts.enableDownloadAllPdf;
2567
- if (opts.disableFullscreen !== void 0) attrs.disableFullscreen = opts.disableFullscreen;
2568
- if (opts.isHideTablePreview !== void 0) attrs.isHideTablePreview = opts.isHideTablePreview;
2569
- if (opts.isHideChartSettings !== void 0) attrs.isHideChartSettings = opts.isHideChartSettings;
2570
- if (opts.isStickyDashboardFilters !== void 0) attrs.isStickyDashboardFilters = opts.isStickyDashboardFilters;
2571
- if (opts.enableMultiMetricFilters !== void 0) attrs.enableMultiMetricFilters = opts.enableMultiMetricFilters;
2572
- if (opts.optionsIcon) attrs.optionsIcon = opts.optionsIcon;
2573
- if (opts.enableTitleClickFullscreen !== void 0) attrs.enableTitleClickFullscreen = opts.enableTitleClickFullscreen;
2574
- if (opts.noDataImg) attrs.noDataImg = opts.noDataImg;
2575
- if (opts.noDataFoundSvg) attrs.noDataFoundSvg = opts.noDataFoundSvg;
2576
- if (opts.customChartSettings) attrs.customChartSettings = opts.customChartSettings;
2577
- if (opts.longDescriptionWidth || opts.longDescriptionFontColor) {
2578
- attrs.longDescriptionConfig = {
2579
- ...opts.longDescriptionWidth && { width: opts.longDescriptionWidth },
2580
- ...opts.longDescriptionFontColor && { fontColor: opts.longDescriptionFontColor }
2581
- };
2582
- }
2583
- if (opts.settingsIconName || opts.settingsIconSvg) {
2584
- attrs.settingsIcon = {
2585
- ...opts.settingsIconName && { name: opts.settingsIconName },
2586
- ...opts.settingsIconSvg && { iconSvg: opts.settingsIconSvg }
2587
- };
2588
- }
2589
- const customMessages = {};
2590
- if (opts.tokenExpiryMessage) customMessages.tokenExpiry = opts.tokenExpiryMessage;
2591
- if (opts.tokenAbsentMessage) customMessages.tokenAbsent = opts.tokenAbsentMessage;
2592
- if (Object.keys(customMessages).length) options.customMessages = customMessages;
2593
- const globalFilterOptions = {};
2594
- if (opts.stringFilters) {
2595
- for (const f of opts.stringFilters) {
2596
- globalFilterOptions[f.filterName] = {
2597
- options: f.options,
2598
- ...f.defaultOption !== void 0 && { defaultOption: f.defaultOption }
2599
- };
2600
- }
2601
- configured.push(`${opts.stringFilters.length} string filter(s)`);
2602
- }
2603
- if (opts.numberFilters) {
2604
- for (const f of opts.numberFilters) {
2605
- globalFilterOptions[f.filterName] = {
2606
- defaultOption: { min: f.min, max: f.max }
2607
- };
2608
- }
2609
- configured.push(`${opts.numberFilters.length} number filter(s)`);
2610
- }
2611
- if (opts.dateFilters) {
2612
- for (const f of opts.dateFilters) {
2613
- const config = {};
2614
- if (f.startDate || f.endDate) {
2615
- config.defaultOption = {
2616
- ...f.startDate && { startDate: f.startDate },
2617
- ...f.endDate && { endDate: f.endDate }
2618
- };
2619
- }
2620
- if (f.datePresetOptions) config.datePresetOptions = f.datePresetOptions;
2621
- globalFilterOptions[f.filterName] = config;
2622
- }
2623
- configured.push(`${opts.dateFilters.length} date filter(s)`);
2624
- }
2625
- if (opts.sqlFilters) {
2626
- for (const f of opts.sqlFilters) {
2627
- globalFilterOptions[f.filterName] = {
2628
- sql: f.sql,
2629
- columnName: f.columnName
2630
- };
2631
- }
2632
- configured.push(`${opts.sqlFilters.length} SQL filter(s)`);
2633
- }
2634
- if (Object.keys(globalFilterOptions).length) options.globalFilterOptions = globalFilterOptions;
2635
- if (opts.hideDashboardFilters) {
2636
- attrs.hideDashboardFilters = opts.hideDashboardFilters;
2637
- configured.push(`hiding ${opts.hideDashboardFilters.length} filter(s)`);
2638
- }
2639
- if (opts.hideDatePickerOptions) {
2640
- options.hideDatePickerOptions = opts.hideDatePickerOptions;
2641
- configured.push(`hiding ${opts.hideDatePickerOptions.length} date picker option(s)`);
2642
- }
2643
- if (opts.metricFilterPosition) {
2644
- attrs.metricFilterPosition = opts.metricFilterPosition;
2645
- configured.push(`metric filter position: ${opts.metricFilterPosition}`);
2646
- }
2647
- if (opts.language) {
2648
- attrs.language = opts.language;
2649
- configured.push(`language: ${opts.language}`);
2650
- }
2651
- if (opts.calendarType) {
2652
- attrs.calendarType = opts.calendarType;
2653
- configured.push(`calendar: ${opts.calendarType}`);
2654
- }
2655
- if (opts.translations?.length) {
2656
- const dict = {};
2657
- for (const entry of opts.translations) {
2658
- dict[entry.key] = entry.translations;
2659
- }
2660
- attrs.translationDictionary = dict;
2661
- configured.push(`${opts.translations.length} translation(s)`);
2662
- }
2663
- const optionKeys = Object.keys(options).filter((k) => k !== "globalFilterOptions" && k !== "customMessages" && k !== "hideDatePickerOptions");
2664
- const attrKeys = Object.keys(attrs).filter(
2665
- (k) => k !== "hideDashboardFilters" && k !== "metricFilterPosition" && k !== "language" && k !== "calendarType" && k !== "translationDictionary"
2666
- );
2667
- if (optionKeys.length || attrKeys.length) {
2668
- configured.push(`${optionKeys.length + attrKeys.length} display option(s)`);
2669
- }
2670
- if (Object.keys(options).length === 0 && Object.keys(attrs).length === 0) {
2671
- return toolError("No configuration provided. Specify at least one option, filter, or i18n setting.");
2672
- }
2673
- try {
2674
- const patch = {};
2675
- if (Object.keys(options).length) patch.options = options;
2676
- if (Object.keys(attrs).length) patch.componentAttributes = attrs;
2677
- const result = await services.embedService.updateEmbed(embedId, patch);
2678
- if (result.error) {
2679
- return toolError(`Embed configuration failed: ${stringify(result.error)}`);
2680
- }
2681
- return toolSuccess(
2682
- `Embed configured for "${embedId}".
2683
-
2684
- **Configured:** ${configured.join(", ")}
2685
-
2686
- Use \`get_embed_details\` to view the full configuration.` + GUEST_TOKEN_REMINDER
2687
- );
2688
- } catch (err) {
2689
- const guardrail = await maybeBuildCorruptedEmbedGuardrail(client, embedId, "configure embed", err);
2690
- if (guardrail) return guardrail;
2691
- if (err instanceof DatabrainApiError) return err.toToolResponse();
2692
- return toolError(`Unexpected error: ${err.message}`);
2693
- }
2694
- }
2695
- );
2696
- }
2697
-
2698
- // src/tools/embed/diagnose-embed-health.ts
2699
- import { z as z16 } from "zod";
2700
- function asRecord2(value) {
2701
- return value && typeof value === "object" ? value : null;
2702
- }
2703
- function firstString(...values) {
2704
- for (const v of values) {
2705
- if (typeof v === "string" && v.trim().length > 0) return v;
2706
- }
2707
- return null;
2708
- }
2709
- function runRuntimeReadinessChecks(params) {
2710
- const payload = params.guestTokenBody ?? {
2711
- clientId: params.clientId,
2712
- dataAppName: params.dataAppName,
2713
- permissions: params.permissions
2714
- };
2715
- const checks = [];
2716
- const topLevelPermissions = payload.permissions;
2717
- const paramsObj = payload.params;
2718
- const nestedPermissions = paramsObj?.permissions;
2719
- checks.push({
2720
- check: "Top-level dataAppName",
2721
- status: typeof payload.dataAppName === "string" && payload.dataAppName.length > 0 ? "pass" : "fail",
2722
- details: typeof payload.dataAppName === "string" && payload.dataAppName.length > 0 ? "dataAppName is present at top level." : "Missing top-level dataAppName in guest token body."
2723
- });
2724
- checks.push({
2725
- check: "Top-level permissions object",
2726
- status: typeof topLevelPermissions === "object" && topLevelPermissions !== null ? "pass" : "fail",
2727
- details: typeof topLevelPermissions === "object" && topLevelPermissions !== null ? "permissions is present at top level." : "Missing top-level permissions object."
2728
- });
2729
- checks.push({
2730
- check: "No nested permissions in params",
2731
- status: nestedPermissions ? "fail" : "pass",
2732
- details: nestedPermissions ? "Found params.permissions. Move permissions to top level." : "No nested permissions found."
2733
- });
2734
- const disableMetricCreationFromToken = typeof topLevelPermissions === "object" && topLevelPermissions !== null ? topLevelPermissions.isDisableMetricCreation : void 0;
2735
- checks.push({
2736
- check: "Guest token metric creation gate",
2737
- status: disableMetricCreationFromToken === true ? "fail" : "pass",
2738
- details: disableMetricCreationFromToken === true ? "permissions.isDisableMetricCreation=true blocks + Create Metric." : "permissions.isDisableMetricCreation is not forcing metric creation off."
2739
- });
2740
- if (params.embedOptions) {
2741
- checks.push({
2742
- check: "Embed option metric creation gate",
2743
- status: params.embedOptions.disableMetricCreation === true ? "fail" : "pass",
2744
- details: params.embedOptions.disableMetricCreation === true ? "embed option disableMetricCreation=true blocks + Create Metric." : "Embed options are not forcing metric creation off."
2745
- });
2746
- }
2747
- if (params.dashboardRuntime) {
2748
- checks.push({
2749
- check: "Dashboard runtime: isAllowedToCreateMetrics",
2750
- status: params.dashboardRuntime.isAllowedToCreateMetrics === true ? "pass" : "fail",
2751
- details: params.dashboardRuntime.isAllowedToCreateMetrics === true ? "Dashboard runtime allows metric creation." : "Dashboard runtime says metric creation is not allowed."
2752
- });
2753
- checks.push({
2754
- check: "Dashboard runtime: metricCreationMode",
2755
- status: params.dashboardRuntime.metricCreationMode === "DRAG_DROP" ? "pass" : "warn",
2756
- details: `metricCreationMode is "${params.dashboardRuntime.metricCreationMode ?? "unknown"}".`
2757
- });
2758
- }
2759
- return checks;
2760
- }
2761
- function registerDiagnoseEmbedHealth(server, client) {
2762
- server.tool(
2763
- "diagnose_embed_health",
2764
- "Diagnose embed shape and required fields. Optionally validates runtime readiness if guestTokenBody or permissions are provided.",
2765
- {
2766
- embedId: z16.string().describe("Embed ID to diagnose"),
2767
- dataAppName: z16.string().optional().describe("Optional data app name to scope dashboard checks"),
2768
- // Runtime readiness params (absorbed from check_runtime_readiness)
2769
- guestTokenBody: z16.record(z16.unknown()).optional().describe(
2770
- "Exact request body sent to POST /api/v2/guest-token/create (for runtime validation)."
2771
- ),
2772
- permissions: z16.record(z16.unknown()).optional().describe(
2773
- "Guest token permissions (used when guestTokenBody is not provided)."
2774
- ),
2775
- embedOptions: z16.object({
2776
- disableMetricCreation: z16.boolean().optional()
2777
- }).optional().describe("Embed web component options (if known)."),
2778
- dashboardRuntime: z16.object({
2779
- isAllowedToCreateMetrics: z16.boolean().optional(),
2780
- metricCreationMode: z16.string().optional()
2781
- }).optional().describe("Runtime flags from dashboard response payload.")
2782
- },
2783
- READ_ONLY,
2784
- async (params) => {
2785
- try {
2786
- const raw = await client.request({
2787
- method: "GET",
2788
- path: "/api/v2/data-app/embeds",
2789
- auth: "api",
2790
- query: { embedId: params.embedId }
2791
- });
2792
- const embedList = Array.isArray(raw) ? raw : [raw];
2793
- const embed = embedList.find((e) => (e?.embedId || e?._id || e?.id) === params.embedId) || embedList[0];
2794
- const embedObj = asRecord2(embed);
2795
- if (!embedObj) {
2796
- return toolError(
2797
- `Embed "${params.embedId}" is not returned as an object by GET /embeds. This indicates malformed API data for this record.`
2798
- );
2799
- }
2800
- const embedMetadata = asRecord2(embedObj.embedMetadata);
2801
- const accessSettings = asRecord2(embedObj.accessSettings) || (embedMetadata ? asRecord2(embedMetadata.accessSettings) : null);
2802
- const dashboardIdCandidates = [
2803
- firstString(embedObj.dashboardId),
2804
- firstString(embedObj.externalDashboardId),
2805
- embedMetadata ? firstString(embedMetadata.dashboardId) : null
2806
- ].filter(Boolean);
2807
- const workspaceCandidates = [
2808
- firstString(embedObj.workspaceName),
2809
- firstString(embedObj.workspace),
2810
- firstString(embedObj.workspaceId),
2811
- embedMetadata ? firstString(embedMetadata.workspaceName) : null,
2812
- embedMetadata ? firstString(embedMetadata.workspaceId) : null
2813
- ].filter(Boolean);
2814
- const datamartName = firstString(
2815
- accessSettings?.datamartName,
2816
- embedObj.datamartName,
2817
- embedMetadata?.datamartName
2818
- );
2819
- let datamartsCount = 0;
2820
- let datamartNames = [];
2821
- try {
2822
- const datamarts = await client.request({
2823
- method: "GET",
2824
- path: "/api/v2/data-app/datamarts",
2825
- auth: "service",
2826
- cacheKey: "list_datamarts",
2827
- cacheTtlMs: 5 * 60 * 1e3
2828
- });
2829
- if (Array.isArray(datamarts)) {
2830
- datamartsCount = datamarts.length;
2831
- datamartNames = datamarts.map((d) => firstString(d?.name, d?.datamartName)).filter(Boolean).slice(0, 10);
2832
- }
2833
- } catch {
2834
- }
2835
- let dashboardsCount = 0;
2836
- let dashboardIdSample = [];
2837
- try {
2838
- const dashboardQuery = params.dataAppName && params.dataAppName.trim().length > 0 ? { dataAppName: params.dataAppName } : void 0;
2839
- const dashboards = await client.request({
2840
- method: "GET",
2841
- path: "/api/v2/data-app/dashboards",
2842
- auth: "api",
2843
- query: dashboardQuery,
2844
- cacheKey: "list_dashboards",
2845
- cacheTtlMs: 5 * 60 * 1e3
2846
- });
2847
- if (Array.isArray(dashboards)) {
2848
- dashboardsCount = dashboards.length;
2849
- dashboardIdSample = dashboards.map(
2850
- (d) => firstString(
2851
- d?.dashboardId,
2852
- d?.externalDashboardId,
2853
- d?._id,
2854
- d?.id,
2855
- d?.uid
2856
- )
2857
- ).filter(Boolean).slice(0, 10);
2858
- }
2859
- } catch {
2860
- }
2861
- const issues = [];
2862
- if (!firstString(embedObj.embedId, embedObj.id, embedObj._id)) {
2863
- issues.push("No stable embed identifier found in record");
2864
- }
2865
- if (!accessSettings) {
2866
- issues.push("Missing accessSettings");
2867
- }
2868
- if (!datamartName) {
2869
- issues.push("Missing datamartName (in accessSettings or embed metadata)");
2870
- }
2871
- if (dashboardIdCandidates.length === 0) {
2872
- issues.push("No dashboard identifier found on embed");
2873
- }
2874
- if (workspaceCandidates.length === 0) {
2875
- issues.push("No workspace identifier/name found on embed");
2876
- }
2877
- const health = issues.length === 0 ? "healthy-shape" : "inconsistent-shape";
2878
- let report = `Embed Health Report: \`${params.embedId}\`
2879
-
2880
- - **Status:** ${health}
2881
- - **Issues:** ${issues.length ? issues.join("; ") : "none detected in shape checks"}
2882
- - **Dashboard ID candidates:** ${dashboardIdCandidates.length ? dashboardIdCandidates.map((id) => `\`${id}\``).join(", ") : "none"}
2883
- - **Workspace candidates:** ${workspaceCandidates.length ? workspaceCandidates.map((id) => `\`${id}\``).join(", ") : "none"}
2884
- - **Resolved datamartName:** ${datamartName ? `\`${datamartName}\`` : "none"}
2885
- - **Datamarts visible:** ${datamartsCount}${datamartNames.length ? ` (sample: ${datamartNames.join(", ")})` : ""}
2886
- - **Dashboards visible:** ${dashboardsCount}${dashboardIdSample.length ? ` (ID sample: ${dashboardIdSample.map((id) => `\`${id}\``).join(", ")})` : ""}
2887
- `;
2888
- if (params.guestTokenBody || params.permissions || params.embedOptions || params.dashboardRuntime) {
2889
- const runtimeChecks = runRuntimeReadinessChecks({
2890
- guestTokenBody: params.guestTokenBody,
2891
- clientId: void 0,
2892
- dataAppName: params.dataAppName,
2893
- permissions: params.permissions,
2894
- embedOptions: params.embedOptions,
2895
- dashboardRuntime: params.dashboardRuntime
2896
- });
2897
- const hasFail = runtimeChecks.some((c) => c.status === "fail");
2898
- report += `
2899
- ### Runtime Readiness: ${hasFail ? "NOT_READY" : "READY"}
2900
-
2901
- `;
2902
- for (const c of runtimeChecks) {
2903
- const icon = c.status === "pass" ? "PASS" : c.status === "fail" ? "FAIL" : "WARN";
2904
- report += `- **[${icon}]** ${c.check}: ${c.details}
2905
- `;
2906
- }
2907
- }
2908
- report += `
2909
- Raw embed payload:
2910
- \`\`\`json
2911
- ` + JSON.stringify(embedObj, null, 2) + "\n```";
2912
- return toolSuccess(report);
2913
- } catch (err) {
2914
- if (err instanceof DatabrainApiError) return err.toToolResponse();
2915
- return toolError(`Unexpected error: ${err.message}`);
2916
- }
2917
- }
2918
- );
2919
- }
2920
-
2921
2380
  // src/tools/frontend/generate-guest-token.ts
2922
- import { z as z17 } from "zod";
2381
+ import { z as z15 } from "zod";
2923
2382
  function registerGenerateGuestToken(server, client) {
2924
2383
  const services = createServiceBundle(client);
2925
2384
  server.tool(
2926
2385
  "generate_guest_token",
2927
2386
  "Generate a guest token for frontend embedding. Requires clientId. Omit dataAppName to auto-resolve.",
2928
2387
  {
2929
- clientId: z17.string().describe('Unique end-user identifier for multi-tenant filtering. Use "None" if no tenancy.'),
2930
- dataAppName: z17.string().optional().describe("Name of the data app. Omit to list available data apps."),
2931
- body: z17.record(z17.unknown()).optional().describe(
2388
+ clientId: z15.string().describe('Unique end-user identifier for multi-tenant filtering. Use "None" if no tenancy.'),
2389
+ dataAppName: z15.string().optional().describe("Name of the data app. Omit to list available data apps."),
2390
+ body: z15.record(z15.unknown()).optional().describe(
2932
2391
  "Raw API body for POST /api/v2/guest-token/create. If provided, sent directly and convenience fields are ignored."
2933
2392
  ),
2934
- params: z17.object({
2935
- allowedEmbeds: z17.array(z17.string()).optional().describe("Restrict token to specific embed IDs"),
2936
- rlsSettings: z17.array(z17.object({
2937
- metricId: z17.string().describe("Metric ID"),
2938
- values: z17.record(z17.unknown()).describe("RLS values by column name")
2393
+ params: z15.object({
2394
+ allowedEmbeds: z15.array(z15.string()).optional().describe("Restrict token to specific embed IDs"),
2395
+ rlsSettings: z15.array(z15.object({
2396
+ metricId: z15.string().describe("Metric ID"),
2397
+ values: z15.record(z15.unknown()).describe("RLS values by column name")
2939
2398
  })).optional().describe("Legacy alias used in docs/examples; forwarded as params.rlsSettings"),
2940
- appFilters: z17.array(z17.object({
2941
- metricId: z17.string().describe("Metric ID"),
2942
- values: z17.record(z17.unknown()).describe("Filter values by column name")
2399
+ appFilters: z15.array(z15.object({
2400
+ metricId: z15.string().describe("Metric ID"),
2401
+ values: z15.record(z15.unknown()).describe("Filter values by column name")
2943
2402
  })).optional().describe("Metric-level app filters"),
2944
- dashboardAppFilters: z17.array(z17.object({
2945
- dashboardId: z17.string().describe("Dashboard ID"),
2946
- values: z17.record(z17.unknown()).describe("Filter values by dashboard filter name"),
2947
- isShowOnUrl: z17.boolean().optional().describe("Whether filters are shown in URL params")
2403
+ dashboardAppFilters: z15.array(z15.object({
2404
+ dashboardId: z15.string().describe("Dashboard ID"),
2405
+ values: z15.record(z15.unknown()).describe("Filter values by dashboard filter name"),
2406
+ isShowOnUrl: z15.boolean().optional().describe("Whether filters are shown in URL params")
2948
2407
  })).optional().describe("Dashboard-level app filters"),
2949
- hideDashboardFilters: z17.array(z17.string()).optional().describe("Dashboard filter names to hide"),
2950
- userIdentifier: z17.string().optional().describe("End-user identifier for private metrics support"),
2951
- timezone: z17.string().optional().describe('IANA timezone, e.g. "America/New_York"')
2408
+ hideDashboardFilters: z15.array(z15.string()).optional().describe("Dashboard filter names to hide"),
2409
+ userIdentifier: z15.string().optional().describe("End-user identifier for private metrics support"),
2410
+ timezone: z15.string().optional().describe('IANA timezone, e.g. "America/New_York"')
2952
2411
  }).optional().describe("Advanced token params"),
2953
2412
  // Legacy convenience fields (auto-mapped into params for backward compatibility)
2954
- timezone: z17.string().optional().describe("Legacy: moved under params.timezone"),
2955
- allowedEmbeds: z17.array(z17.string()).optional().describe("Legacy: moved under params.allowedEmbeds"),
2956
- rlsSettings: z17.array(z17.object({
2957
- metricId: z17.string().describe("Metric ID"),
2958
- values: z17.record(z17.unknown()).describe("RLS values by column name")
2413
+ timezone: z15.string().optional().describe("Legacy: moved under params.timezone"),
2414
+ allowedEmbeds: z15.array(z15.string()).optional().describe("Legacy: moved under params.allowedEmbeds"),
2415
+ rlsSettings: z15.array(z15.object({
2416
+ metricId: z15.string().describe("Metric ID"),
2417
+ values: z15.record(z15.unknown()).describe("RLS values by column name")
2959
2418
  })).optional().describe("Legacy: moved under params.rlsSettings"),
2960
- appFilters: z17.array(z17.object({
2961
- metricId: z17.string().describe("Metric ID"),
2962
- values: z17.record(z17.unknown()).describe("Filter values by column name")
2419
+ appFilters: z15.array(z15.object({
2420
+ metricId: z15.string().describe("Metric ID"),
2421
+ values: z15.record(z15.unknown()).describe("Filter values by column name")
2963
2422
  })).optional().describe("Legacy: moved under params.appFilters"),
2964
- dashboardAppFilters: z17.array(z17.object({
2965
- dashboardId: z17.string().describe("Dashboard ID to apply filters to"),
2966
- values: z17.record(z17.unknown()).describe("Filter values for this dashboard"),
2967
- isShowOnUrl: z17.boolean().optional().describe("Whether filters are shown in URL params")
2423
+ dashboardAppFilters: z15.array(z15.object({
2424
+ dashboardId: z15.string().describe("Dashboard ID to apply filters to"),
2425
+ values: z15.record(z15.unknown()).describe("Filter values for this dashboard"),
2426
+ isShowOnUrl: z15.boolean().optional().describe("Whether filters are shown in URL params")
2968
2427
  })).optional().describe("Legacy: moved under params.dashboardAppFilters"),
2969
- permissions: z17.object({
2970
- isEnableArchiveMetrics: z17.boolean().optional(),
2971
- isEnableManageMetrics: z17.boolean().optional(),
2972
- isEnableCreateDashboardView: z17.boolean().optional(),
2973
- isEnableMetricUpdation: z17.boolean().optional(),
2974
- isEnableCustomizeLayout: z17.boolean().optional(),
2975
- isEnableUnderlyingData: z17.boolean().optional(),
2976
- isEnableDownloadMetrics: z17.boolean().optional(),
2977
- isShowSideBar: z17.boolean().optional(),
2978
- isShowDashboardName: z17.boolean().optional(),
2979
- isDisableMetricCreation: z17.boolean().optional()
2428
+ permissions: z15.object({
2429
+ isEnableArchiveMetrics: z15.boolean().optional(),
2430
+ isEnableManageMetrics: z15.boolean().optional(),
2431
+ isEnableCreateDashboardView: z15.boolean().optional(),
2432
+ isEnableMetricUpdation: z15.boolean().optional(),
2433
+ isEnableCustomizeLayout: z15.boolean().optional(),
2434
+ isEnableUnderlyingData: z15.boolean().optional(),
2435
+ isEnableDownloadMetrics: z15.boolean().optional(),
2436
+ isShowSideBar: z15.boolean().optional(),
2437
+ isShowDashboardName: z15.boolean().optional(),
2438
+ isDisableMetricCreation: z15.boolean().optional()
2980
2439
  }).optional().describe("Runtime permission overrides (merge with and override embed-level settings)"),
2981
- theme: z17.record(z17.unknown()).optional().describe("Runtime theme overrides (overrides embed-level theme)"),
2982
- hideDashboardFilters: z17.array(z17.string()).optional().describe("Legacy: moved under params.hideDashboardFilters"),
2983
- userIdentifier: z17.string().optional().describe("Legacy: moved under params.userIdentifier"),
2984
- expiryTime: z17.number().optional().describe("Token TTL in milliseconds"),
2985
- datasourceName: z17.string().optional().describe("Datasource name for multi-datasource routing")
2440
+ theme: z15.record(z15.unknown()).optional().describe("Runtime theme overrides (overrides embed-level theme)"),
2441
+ hideDashboardFilters: z15.array(z15.string()).optional().describe("Legacy: moved under params.hideDashboardFilters"),
2442
+ userIdentifier: z15.string().optional().describe("Legacy: moved under params.userIdentifier"),
2443
+ expiryTime: z15.number().optional().describe("Token TTL in milliseconds"),
2444
+ datasourceName: z15.string().optional().describe("Datasource name for multi-datasource routing")
2986
2445
  },
2987
2446
  WRITE_CREATE,
2988
2447
  async (params) => {
@@ -3035,7 +2494,7 @@ Next step: Use \`generate_embed_code\` to get copy-paste-ready frontend code.`
3035
2494
  }
3036
2495
 
3037
2496
  // src/tools/frontend/generate-embed-code.ts
3038
- import { z as z18 } from "zod";
2497
+ import { z as z16 } from "zod";
3039
2498
 
3040
2499
  // src/templates/react.ts
3041
2500
  function kebabCase(str) {
@@ -4031,22 +3490,22 @@ function registerGenerateEmbedCode(server, _client) {
4031
3490
  "generate_embed_code",
4032
3491
  "Generate framework-specific embed code (React, Next.js, Vue, Angular, Svelte, SolidJS, vanilla HTML).",
4033
3492
  {
4034
- embedId: z18.string().describe("The embed ID to generate code for"),
4035
- framework: z18.enum(FRAMEWORKS).describe("Frontend framework"),
4036
- embedType: z18.enum(["dashboard", "metric"]).optional().default("dashboard"),
4037
- options: z18.object({
4038
- enableDownloadCsv: z18.boolean().optional(),
4039
- enableEmailCsv: z18.boolean().optional(),
4040
- enableDownloadAllMetrics: z18.boolean().optional(),
4041
- enableDownloadAllPdf: z18.boolean().optional(),
4042
- disableFullscreen: z18.boolean().optional(),
4043
- isHideTablePreview: z18.boolean().optional(),
4044
- isHideChartSettings: z18.boolean().optional(),
4045
- isStickyDashboardFilters: z18.boolean().optional(),
4046
- enableMultiMetricFilters: z18.boolean().optional(),
4047
- themeName: z18.string().optional(),
4048
- customTheme: z18.record(z18.unknown()).optional(),
4049
- optionsIcon: z18.enum(["kebab-menu-vertical", "download"]).optional()
3493
+ embedId: z16.string().describe("The embed ID to generate code for"),
3494
+ framework: z16.enum(FRAMEWORKS).describe("Frontend framework"),
3495
+ embedType: z16.enum(["dashboard", "metric"]).optional().default("dashboard"),
3496
+ options: z16.object({
3497
+ enableDownloadCsv: z16.boolean().optional(),
3498
+ enableEmailCsv: z16.boolean().optional(),
3499
+ enableDownloadAllMetrics: z16.boolean().optional(),
3500
+ enableDownloadAllPdf: z16.boolean().optional(),
3501
+ disableFullscreen: z16.boolean().optional(),
3502
+ isHideTablePreview: z16.boolean().optional(),
3503
+ isHideChartSettings: z16.boolean().optional(),
3504
+ isStickyDashboardFilters: z16.boolean().optional(),
3505
+ enableMultiMetricFilters: z16.boolean().optional(),
3506
+ themeName: z16.string().optional(),
3507
+ customTheme: z16.record(z16.unknown()).optional(),
3508
+ optionsIcon: z16.enum(["kebab-menu-vertical", "download"]).optional()
4050
3509
  }).optional()
4051
3510
  },
4052
3511
  READ_ONLY,
@@ -4086,17 +3545,17 @@ ${generated.instructions}`;
4086
3545
  }
4087
3546
 
4088
3547
  // src/tools/analytics/list-dashboards.ts
4089
- import { z as z19 } from "zod";
3548
+ import { z as z17 } from "zod";
4090
3549
  function registerListDashboards(server, client) {
4091
3550
  const services = createServiceBundle(client);
4092
3551
  server.tool(
4093
3552
  "list_dashboards",
4094
3553
  "List dashboards globally or for a specific data app.",
4095
3554
  {
4096
- scope: z19.enum(["auto", "global", "data_app"]).optional().describe(
3555
+ scope: z17.enum(["auto", "global", "data_app"]).optional().describe(
4097
3556
  "Dashboard listing scope. auto: use data_app when dataAppName + API token are available, otherwise global."
4098
3557
  ),
4099
- dataAppName: z19.string().optional().describe("Data app name for data_app scope. Ignored for global scope.")
3558
+ dataAppName: z17.string().optional().describe("Data app name for data_app scope. Ignored for global scope.")
4100
3559
  },
4101
3560
  READ_ONLY,
4102
3561
  async (params) => {
@@ -4130,617 +3589,8 @@ function registerListDashboards(server, client) {
4130
3589
  );
4131
3590
  }
4132
3591
 
4133
- // src/tools/orchestration/setup-embed-interactive.ts
4134
- import { z as z20 } from "zod";
4135
- var STEPS = [
4136
- "discover_data_apps",
4137
- "choose_data_app",
4138
- "create_data_app",
4139
- "ensure_api_token",
4140
- "discover_workspaces",
4141
- "choose_workspace",
4142
- "list_dashboards",
4143
- "choose_dashboard",
4144
- "create_embed",
4145
- "runtime_readiness",
4146
- "complete"
4147
- ];
4148
- var stateSchema = z20.object({
4149
- dataAppName: z20.string().optional(),
4150
- dataAppId: z20.string().optional(),
4151
- workspaceName: z20.string().optional(),
4152
- embedType: z20.enum(["dashboard", "metric"]).optional(),
4153
- dashboardId: z20.string().optional(),
4154
- metricId: z20.string().optional(),
4155
- datamartName: z20.string().optional(),
4156
- embedId: z20.string().optional(),
4157
- embedName: z20.string().optional(),
4158
- clientId: z20.string().optional(),
4159
- runtimeValidated: z20.boolean().optional()
4160
- });
4161
- function emit(status, step, state, message, options, nextStep) {
4162
- const payload = {
4163
- status,
4164
- step,
4165
- message,
4166
- state
4167
- };
4168
- if (options) payload.options = options;
4169
- if (nextStep) payload.nextStep = nextStep;
4170
- return toolSuccess(JSON.stringify(payload, null, 2));
4171
- }
4172
- function parseUserChoiceObject(userChoice) {
4173
- if (!userChoice) return null;
4174
- try {
4175
- const parsed = JSON.parse(userChoice);
4176
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
4177
- return parsed;
4178
- }
4179
- return null;
4180
- } catch {
4181
- return null;
4182
- }
4183
- }
4184
- function parseNameFromUserChoice(userChoice) {
4185
- if (!userChoice) return null;
4186
- const choiceObj = parseUserChoiceObject(userChoice);
4187
- if (choiceObj) {
4188
- const rawName = choiceObj.name;
4189
- if (typeof rawName === "string" && rawName.trim().length > 0) return rawName.trim();
4190
- return null;
4191
- }
4192
- const trimmed = userChoice.trim();
4193
- return trimmed.length > 0 ? trimmed : null;
4194
- }
4195
- function registerSetupEmbedInteractive(server, client) {
4196
- const services = createServiceBundle(client);
4197
- const listDashboardsForContext = async (currentState) => {
4198
- const dataAppName = currentState.dataAppName;
4199
- const workspaceName = currentState.workspaceName;
4200
- if (dataAppName && dataAppName.trim().length > 0 && client.hasApiToken()) {
4201
- const dashboards2 = await services.dashboardsApi.listDashboards(dataAppName);
4202
- if (Array.isArray(dashboards2) && dashboards2.length > 0) {
4203
- return { dashboards: dashboards2, scope: "data_app" };
4204
- }
4205
- }
4206
- if (workspaceName && workspaceName.trim().length > 0) {
4207
- const dashboards2 = await services.dashboardsApi.listDashboardsForWorkspace(workspaceName);
4208
- return { dashboards: dashboards2, scope: "workspace" };
4209
- }
4210
- const dashboards = await services.dashboardsApi.listDashboardsAcrossWorkspaces();
4211
- return { dashboards, scope: "global" };
4212
- };
4213
- server.tool(
4214
- "setup_embed_interactive",
4215
- "Step-by-step embed setup wizard. Pass step and state from previous call.",
4216
- {
4217
- step: z20.enum(STEPS).describe("Current orchestration step"),
4218
- state: stateSchema.optional().describe("State from previous step \u2014 pass forward unchanged"),
4219
- userChoice: z20.string().optional().describe("User response for CHOICE_REQUIRED or CONFIRM_REQUIRED")
4220
- },
4221
- WRITE_CREATE,
4222
- async (params) => {
4223
- const state = params.state ?? {};
4224
- const step = params.step;
4225
- try {
4226
- if (step === "discover_data_apps") {
4227
- const apps = await services.dataAppsApi.listDataApps();
4228
- if (!Array.isArray(apps) || apps.length === 0) {
4229
- return emit(
4230
- "CHOICE_REQUIRED",
4231
- step,
4232
- state,
4233
- "No data apps found. Ask user for a data app name to create one.",
4234
- [
4235
- { id: "create", label: "Create a new data app" },
4236
- { id: "stop", label: "Stop setup" }
4237
- ],
4238
- "create_data_app"
4239
- );
4240
- }
4241
- if (apps.length === 1) {
4242
- const app = services.discoveryService.normalizeDataApp(apps[0]);
4243
- return emit(
4244
- "CONFIRM_REQUIRED",
4245
- step,
4246
- {
4247
- ...state,
4248
- dataAppName: app.name,
4249
- dataAppId: app.dataAppId || void 0
4250
- },
4251
- `Found one data app: "${app.name}". Confirm to continue.`,
4252
- [{ id: app.name, label: `${app.name} (${app.dataAppId || "no-id"})` }],
4253
- "ensure_api_token"
4254
- );
4255
- }
4256
- const options = apps.map((a) => {
4257
- const n = services.discoveryService.normalizeDataApp(a);
4258
- return {
4259
- id: n.dataAppId || n.name,
4260
- label: `${n.name} (${n.dataAppId || "no-id"})`,
4261
- dataAppName: n.name,
4262
- dataAppId: n.dataAppId
4263
- };
4264
- });
4265
- return emit(
4266
- "CHOICE_REQUIRED",
4267
- step,
4268
- state,
4269
- `Found ${apps.length} data app(s). Ask the user which one to embed from.`,
4270
- options,
4271
- "choose_data_app"
4272
- );
4273
- }
4274
- if (step === "choose_data_app") {
4275
- if (!params.userChoice) {
4276
- return toolError("userChoice is required for choose_data_app.");
4277
- }
4278
- const apps = await services.dataAppsApi.listDataApps();
4279
- const q = params.userChoice.toLowerCase();
4280
- const match = apps.find((a) => {
4281
- const n2 = services.discoveryService.normalizeDataApp(a);
4282
- return n2.name.toLowerCase() === q || (n2.dataAppId || "").toLowerCase() === q || n2.name.toLowerCase().includes(q);
4283
- });
4284
- if (!match) {
4285
- return toolError(
4286
- `No data app matched "${params.userChoice}". Re-run discover_data_apps.`
4287
- );
4288
- }
4289
- const n = services.discoveryService.normalizeDataApp(match);
4290
- return emit(
4291
- "READY",
4292
- step,
4293
- {
4294
- ...state,
4295
- dataAppName: n.name,
4296
- dataAppId: n.dataAppId || void 0
4297
- },
4298
- `Selected data app: "${n.name}".`,
4299
- void 0,
4300
- "ensure_api_token"
4301
- );
4302
- }
4303
- if (step === "create_data_app") {
4304
- const name = parseNameFromUserChoice(params.userChoice);
4305
- if (!name) {
4306
- return toolError(
4307
- 'Provide data app name in userChoice. Accepts plain string or JSON: {"name":"my-data-app"}.'
4308
- );
4309
- }
4310
- const created = await client.request({
4311
- method: "POST",
4312
- path: "/api/v2/data-app/",
4313
- auth: "service",
4314
- body: { name },
4315
- invalidateCache: ["list_data_apps"]
4316
- });
4317
- return emit(
4318
- "READY",
4319
- step,
4320
- {
4321
- ...state,
4322
- dataAppName: name,
4323
- dataAppId: created.id || void 0
4324
- },
4325
- `Created data app "${name}".`,
4326
- void 0,
4327
- "ensure_api_token"
4328
- );
4329
- }
4330
- if (step === "ensure_api_token") {
4331
- const appName = state.dataAppName;
4332
- if (!appName) {
4333
- return toolError("state.dataAppName is required. Run discover_data_apps first.");
4334
- }
4335
- const tokens = await client.request({
4336
- method: "GET",
4337
- path: "/api/v2/data-app/api-tokens",
4338
- auth: "service",
4339
- query: { dataAppName: appName }
4340
- });
4341
- if (Array.isArray(tokens) && tokens.length > 0) {
4342
- const tokenValue = tokens[0].token || tokens[0].apiToken || tokens[0].key;
4343
- if (tokenValue) {
4344
- client.setRuntimeApiToken(tokenValue);
4345
- return emit(
4346
- "READY",
4347
- step,
4348
- { ...state, dataAppName: appName },
4349
- `API token found and activated for "${appName}".`,
4350
- void 0,
4351
- "discover_workspaces"
4352
- );
4353
- }
4354
- return emit(
4355
- "CHOICE_REQUIRED",
4356
- step,
4357
- { ...state, dataAppName: appName },
4358
- `"${appName}" has API token(s) but the value was not returned. Call \`create_api_token\` to generate a new one, or \`set_api_token\` if you have the value. Then re-run discover_workspaces.`,
4359
- [
4360
- { id: "create", label: "Create new API token (call create_api_token)" },
4361
- { id: "set", label: "Set existing token (call set_api_token)" }
4362
- ],
4363
- "discover_workspaces"
4364
- );
4365
- }
4366
- return emit(
4367
- "CHOICE_REQUIRED",
4368
- step,
4369
- { ...state, dataAppName: appName },
4370
- `No API token for "${appName}". Call \`create_api_token\` to generate one. Then proceed to discover_workspaces.`,
4371
- [
4372
- { id: "create", label: "Create API token now (call create_api_token)" }
4373
- ],
4374
- "discover_workspaces"
4375
- );
4376
- }
4377
- if (step === "discover_workspaces") {
4378
- const workspaces = await services.workspacesApi.listWorkspaces();
4379
- if (!Array.isArray(workspaces) || workspaces.length === 0) {
4380
- return emit(
4381
- "READY",
4382
- step,
4383
- state,
4384
- "No workspaces found. Create a workspace in Databrain UI first, then re-run this step."
4385
- );
4386
- }
4387
- if (workspaces.length === 1) {
4388
- const ws = workspaces[0];
4389
- const wsName = (typeof ws.name === "string" ? ws.name.trim() : "") || "Unnamed";
4390
- return emit(
4391
- "READY",
4392
- step,
4393
- { ...state, workspaceName: wsName },
4394
- `Found one workspace: "${wsName}". Auto-selected.`,
4395
- void 0,
4396
- "list_dashboards"
4397
- );
4398
- }
4399
- const options = workspaces.filter((ws) => typeof ws.name === "string" && ws.name.trim().length > 0).map((ws) => ({
4400
- id: ws.name,
4401
- label: `${ws.name} (${ws._id || ws.id || "no-id"})`,
4402
- workspaceName: ws.name
4403
- }));
4404
- return emit(
4405
- "CHOICE_REQUIRED",
4406
- step,
4407
- state,
4408
- `Found ${workspaces.length} workspace(s). Ask the user which workspace to use.`,
4409
- options,
4410
- "choose_workspace"
4411
- );
4412
- }
4413
- if (step === "choose_workspace") {
4414
- if (!params.userChoice) {
4415
- return toolError("userChoice is required for choose_workspace.");
4416
- }
4417
- const workspaces = await services.workspacesApi.listWorkspaces();
4418
- const q = params.userChoice.toLowerCase();
4419
- const match = workspaces.find((ws) => {
4420
- const name = (typeof ws.name === "string" ? ws.name.trim() : "").toLowerCase();
4421
- const wsId = (ws._id || ws.id || "").toLowerCase();
4422
- return name === q || wsId === q || name.includes(q);
4423
- });
4424
- if (!match) {
4425
- return toolError(
4426
- `No workspace matched "${params.userChoice}". Re-run discover_workspaces.`
4427
- );
4428
- }
4429
- const wsName = (typeof match.name === "string" ? match.name.trim() : "") || "Unnamed";
4430
- return emit(
4431
- "READY",
4432
- step,
4433
- { ...state, workspaceName: wsName },
4434
- `Selected workspace: "${wsName}".`,
4435
- void 0,
4436
- "list_dashboards"
4437
- );
4438
- }
4439
- if (step === "list_dashboards") {
4440
- const { dashboards, scope } = await listDashboardsForContext(state);
4441
- if (!Array.isArray(dashboards) || dashboards.length === 0) {
4442
- const scopeMsg = scope === "data_app" ? `No dashboards found for data app "${state.dataAppName || "unknown"}".` : scope === "workspace" ? `No dashboards found in workspace "${state.workspaceName || "unknown"}". Create a dashboard in Databrain UI first, then re-run this step.` : "No dashboards found in available workspaces. Create a dashboard in Databrain UI first, then re-run this step.";
4443
- return emit("READY", step, state, scopeMsg);
4444
- }
4445
- const options = dashboards.map((d) => {
4446
- const n = services.discoveryService.normalizeDashboard(d);
4447
- return {
4448
- id: n.dashboardId || n.name,
4449
- label: `${n.name} (${n.dashboardId || "no-id"})${n.workspaceName ? ` \u2014 workspace: ${n.workspaceName}` : ""}`,
4450
- dashboardId: n.dashboardId,
4451
- workspaceName: n.workspaceName
4452
- };
4453
- });
4454
- const foundMsg = scope === "data_app" ? `Found ${dashboards.length} dashboard(s) for data app "${state.dataAppName || "unknown"}". Ask the user which dashboard to embed.` : scope === "workspace" ? `Found ${dashboards.length} dashboard(s) in workspace "${state.workspaceName || "unknown"}". Ask the user which dashboard to embed.` : `Found ${dashboards.length} dashboard(s) across workspaces. Ask the user which dashboard to embed.`;
4455
- return emit(
4456
- "CHOICE_REQUIRED",
4457
- step,
4458
- state,
4459
- foundMsg,
4460
- options,
4461
- "choose_dashboard"
4462
- );
4463
- }
4464
- if (step === "choose_dashboard") {
4465
- if (!params.userChoice) {
4466
- return toolError("userChoice is required for choose_dashboard. Pass dashboardId or name.");
4467
- }
4468
- const { dashboards } = await listDashboardsForContext(state);
4469
- const q = params.userChoice.toLowerCase();
4470
- const match = dashboards.find((d) => {
4471
- const n2 = services.discoveryService.normalizeDashboard(d);
4472
- return (n2.dashboardId || "").toLowerCase() === q || (n2.name || "").toLowerCase() === q || (n2.name || "").toLowerCase().includes(q);
4473
- });
4474
- if (!match) {
4475
- return toolError(
4476
- `No dashboard matched "${params.userChoice}". Re-run list_dashboards.`
4477
- );
4478
- }
4479
- const n = services.discoveryService.normalizeDashboard(match);
4480
- let resolvedDatamartName = state.datamartName;
4481
- const resolveAppId = state.dataAppId || n.workspaceName;
4482
- if (!resolvedDatamartName && resolveAppId) {
4483
- try {
4484
- const datamarts = await services.datamartsApi.listDatamartsByDataAppId(resolveAppId);
4485
- const names = Array.from(
4486
- new Set(
4487
- datamarts.map((dm) => dm.name || dm.datamartName).filter((v) => typeof v === "string" && v.trim().length > 0)
4488
- )
4489
- );
4490
- if (names.length === 1) resolvedDatamartName = names[0];
4491
- } catch {
4492
- }
4493
- }
4494
- return emit(
4495
- "READY",
4496
- step,
4497
- {
4498
- ...state,
4499
- dashboardId: n.dashboardId,
4500
- embedType: "dashboard",
4501
- ...n.workspaceName ? { workspaceName: n.workspaceName } : {},
4502
- ...resolvedDatamartName ? { datamartName: resolvedDatamartName } : {}
4503
- },
4504
- `Selected dashboard: "${n.name}" (${n.dashboardId}).${n.workspaceName ? ` workspaceName=${n.workspaceName}.` : ""}${resolvedDatamartName ? ` datamartName=${resolvedDatamartName}.` : ""} Proceeding to create embed.`,
4505
- void 0,
4506
- "create_embed"
4507
- );
4508
- }
4509
- if (step === "create_embed") {
4510
- const choiceObj = parseUserChoiceObject(params.userChoice);
4511
- const merged = {
4512
- ...state,
4513
- ...choiceObj || {}
4514
- };
4515
- const dashboardId = merged.dashboardId;
4516
- const metricId = merged.metricId;
4517
- let resolvedWorkspaceName = merged.workspaceName;
4518
- const embedType = merged.embedType?.toLowerCase() === "metric" ? "metric" : "dashboard";
4519
- const datamartName = merged.datamartName;
4520
- const embedName = merged.embedName || (embedType === "dashboard" && dashboardId ? `embed-${dashboardId}` : embedType === "metric" && metricId ? `embed-metric-${metricId}` : void 0);
4521
- let resolvedDatamartName = datamartName;
4522
- let resolveAppId = merged.dataAppId;
4523
- let availableDatamartNames = [];
4524
- if (!resolveAppId) {
4525
- const appName = merged.dataAppName;
4526
- if (appName) {
4527
- try {
4528
- const apps = await services.dataAppsApi.listDataApps();
4529
- const app = apps.find((a) => {
4530
- const n = services.discoveryService.normalizeDataApp(a);
4531
- return n.name.toLowerCase() === appName.toLowerCase() || (n.dataAppId || "").toLowerCase() === appName.toLowerCase();
4532
- });
4533
- if (app) {
4534
- resolveAppId = services.discoveryService.normalizeDataApp(app).dataAppId || void 0;
4535
- }
4536
- } catch {
4537
- }
4538
- }
4539
- }
4540
- if (embedType === "dashboard" && dashboardId && merged.dataAppName && client.hasApiToken()) {
4541
- try {
4542
- const scopedDashboards = await services.dashboardsApi.listDashboards(
4543
- merged.dataAppName
4544
- );
4545
- const dashboardMatch = scopedDashboards.find((d) => {
4546
- const n = services.discoveryService.normalizeDashboard(d);
4547
- return (n.dashboardId || "").toLowerCase() === dashboardId.toLowerCase();
4548
- });
4549
- if (!dashboardMatch) {
4550
- return emit(
4551
- "CHOICE_REQUIRED",
4552
- step,
4553
- merged,
4554
- `dashboardId "${dashboardId}" is not available under data app "${merged.dataAppName || "unknown"}". Re-run list_dashboards and choose from the current data app scope.`,
4555
- [],
4556
- "list_dashboards"
4557
- );
4558
- }
4559
- const dashboardNormalized = services.discoveryService.normalizeDashboard(dashboardMatch);
4560
- if (dashboardNormalized.workspaceName) {
4561
- if (resolvedWorkspaceName && resolvedWorkspaceName !== dashboardNormalized.workspaceName) {
4562
- return emit(
4563
- "CHOICE_REQUIRED",
4564
- step,
4565
- merged,
4566
- `workspaceName "${resolvedWorkspaceName}" does not match dashboard workspace "${dashboardNormalized.workspaceName}". Use the dashboard workspace.`,
4567
- [
4568
- {
4569
- id: "use_dashboard_workspace",
4570
- label: dashboardNormalized.workspaceName,
4571
- workspaceName: dashboardNormalized.workspaceName
4572
- }
4573
- ],
4574
- "create_embed"
4575
- );
4576
- }
4577
- resolvedWorkspaceName = dashboardNormalized.workspaceName;
4578
- }
4579
- } catch {
4580
- }
4581
- }
4582
- if (embedType === "dashboard" && !resolvedDatamartName) {
4583
- if (resolveAppId) {
4584
- try {
4585
- const datamarts = await services.datamartsApi.listDatamartsByDataAppId(
4586
- resolveAppId
4587
- );
4588
- const names = Array.from(
4589
- new Set(
4590
- datamarts.map((dm) => dm.name || dm.datamartName).filter(
4591
- (v) => typeof v === "string" && v.trim().length > 0
4592
- )
4593
- )
4594
- );
4595
- availableDatamartNames = names;
4596
- if (names.length === 1) {
4597
- resolvedDatamartName = names[0];
4598
- } else if (names.length > 1) {
4599
- return emit(
4600
- "CHOICE_REQUIRED",
4601
- step,
4602
- merged,
4603
- "Multiple datamarts are available for this data app. Ask the user to select one for accessSettings.datamartName.",
4604
- names.map((name) => ({
4605
- id: name,
4606
- label: name,
4607
- datamartName: name
4608
- })),
4609
- "create_embed"
4610
- );
4611
- }
4612
- } catch {
4613
- }
4614
- }
4615
- }
4616
- if (embedType === "dashboard" && resolvedDatamartName && resolveAppId && availableDatamartNames.length === 0) {
4617
- try {
4618
- const datamarts = await services.datamartsApi.listDatamartsByDataAppId(resolveAppId);
4619
- availableDatamartNames = Array.from(
4620
- new Set(
4621
- datamarts.map((dm) => dm.name || dm.datamartName).filter((v) => typeof v === "string" && v.trim().length > 0)
4622
- )
4623
- );
4624
- } catch {
4625
- }
4626
- }
4627
- if (embedType === "dashboard" && resolvedDatamartName && availableDatamartNames.length > 0 && !availableDatamartNames.includes(resolvedDatamartName)) {
4628
- return emit(
4629
- "CHOICE_REQUIRED",
4630
- step,
4631
- merged,
4632
- `datamartName "${resolvedDatamartName}" is invalid for this data app. Choose one of the available datamarts.`,
4633
- availableDatamartNames.map((name) => ({
4634
- id: name,
4635
- label: name,
4636
- datamartName: name
4637
- })),
4638
- "create_embed"
4639
- );
4640
- }
4641
- const missing = [];
4642
- if (!resolvedWorkspaceName) missing.push("workspaceName");
4643
- if (!dashboardId) missing.push("dashboardId");
4644
- if (embedType === "metric" && !metricId) missing.push("metricId");
4645
- if (embedType === "dashboard" && !resolvedDatamartName) missing.push("datamartName");
4646
- if (missing.length > 0) {
4647
- return emit(
4648
- "CHOICE_REQUIRED",
4649
- step,
4650
- {
4651
- ...merged,
4652
- ...resolvedDatamartName ? { datamartName: resolvedDatamartName } : {}
4653
- },
4654
- `Missing required fields for embed creation: ${missing.join(", ")}. Provide via userChoice JSON.`,
4655
- [
4656
- {
4657
- id: "provide_fields",
4658
- label: 'Provide JSON: {"dashboardId":"...","workspaceName":"...","datamartName":"..."}'
4659
- }
4660
- ],
4661
- "create_embed"
4662
- );
4663
- }
4664
- const created = await services.embedService.createEmbedStrict({
4665
- dashboardId,
4666
- metricId,
4667
- workspaceName: resolvedWorkspaceName,
4668
- embedType,
4669
- name: embedName,
4670
- accessSettings: {
4671
- datamartName: resolvedDatamartName,
4672
- isAllowMetricCreation: false,
4673
- isAllowMetricDeletion: false,
4674
- isAllowMetricUpdate: false,
4675
- isAllowMetricLayoutChange: false,
4676
- isAllowManageMetrics: false,
4677
- isAllowUnderlyingData: false,
4678
- isAllowAiPilot: false,
4679
- isAllowEmailReports: false,
4680
- isAllowCreateDashboardView: false,
4681
- metricCreationMode: "DRAG_DROP"
4682
- }
4683
- });
4684
- const embedId = created.embedId || created.id || created._id || void 0;
4685
- return emit(
4686
- "READY",
4687
- step,
4688
- { ...merged, embedType, embedId },
4689
- `Embed created successfully${embedId ? ` (embedId: ${embedId})` : ""}. Next: run runtime readiness validation before finishing setup.`,
4690
- void 0,
4691
- "runtime_readiness"
4692
- );
4693
- }
4694
- if (step === "runtime_readiness") {
4695
- const appName = state.dataAppName;
4696
- if (!appName) {
4697
- return toolError("state.dataAppName is required. Run discover_data_apps first.");
4698
- }
4699
- const choiceObj = parseUserChoiceObject(params.userChoice);
4700
- const clientId = choiceObj?.clientId || state.clientId || "None";
4701
- const permissions = {
4702
- isEnableManageMetrics: true,
4703
- isEnableMetricUpdation: true,
4704
- isEnableCustomizeLayout: true,
4705
- isEnableCreateDashboardView: true,
4706
- isDisableMetricCreation: false,
4707
- ...choiceObj?.permissions || {}
4708
- };
4709
- await services.guestTokenService.generateToken({
4710
- clientId,
4711
- dataAppName: appName,
4712
- permissions
4713
- });
4714
- return emit(
4715
- "DONE",
4716
- step,
4717
- {
4718
- ...state,
4719
- clientId,
4720
- runtimeValidated: true
4721
- },
4722
- "Runtime contract validated by generating a guest token with top-level clientId/dataAppName/permissions. Next: run generate_embed_code and then continue with brand-my-embed or secure-my-embed as needed."
4723
- );
4724
- }
4725
- if (step === "complete") {
4726
- return emit(
4727
- "DONE",
4728
- step,
4729
- state,
4730
- "Setup complete. Recommended before handoff: run runtime_readiness. Then use brand-my-embed, secure-my-embed, setup-filters, or localize-embed prompts for further customization."
4731
- );
4732
- }
4733
- return toolError(`Unknown step: ${step}`);
4734
- } catch (err) {
4735
- if (err instanceof DatabrainApiError) return err.toToolResponse();
4736
- return toolError(`Unexpected error: ${err.message}`);
4737
- }
4738
- }
4739
- );
4740
- }
4741
-
4742
3592
  // src/tools/query/ask-question.ts
4743
- import { z as z21 } from "zod";
3593
+ import { z as z18 } from "zod";
4744
3594
  var MAX_DISPLAY_ROWS = 50;
4745
3595
  function formatDataTable(data, columns) {
4746
3596
  if (!Array.isArray(data) || data.length === 0) return "_No data returned._";
@@ -4770,16 +3620,16 @@ function registerAskQuestion(server, client) {
4770
3620
  "ask_question",
4771
3621
  "Ask a natural language question \u2014 converts to SQL, returns data + chart suggestion. Requires datamartName with a populated semantic layer.",
4772
3622
  {
4773
- question: z21.string().describe(
3623
+ question: z18.string().describe(
4774
3624
  'The natural language question to ask (e.g. "What was total revenue last month?")'
4775
3625
  ),
4776
- datamartName: z21.string().optional().describe(
3626
+ datamartName: z18.string().optional().describe(
4777
3627
  "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."
4778
3628
  ),
4779
- sessionId: z21.string().optional().describe(
3629
+ sessionId: z18.string().optional().describe(
4780
3630
  "Session ID from a previous ask_question response, for follow-up questions."
4781
3631
  ),
4782
- timezone: z21.string().optional().describe('IANA timezone (e.g. "America/New_York"). Defaults to UTC.')
3632
+ timezone: z18.string().optional().describe('IANA timezone (e.g. "America/New_York"). Defaults to UTC.')
4783
3633
  },
4784
3634
  WRITE_CREATE,
4785
3635
  async (params) => {
@@ -4944,14 +3794,14 @@ To fix this:
4944
3794
  }
4945
3795
 
4946
3796
  // src/tools/query/get-semantic-layer.ts
4947
- import { z as z22 } from "zod";
3797
+ import { z as z19 } from "zod";
4948
3798
  function registerGetSemanticLayer(server, client) {
4949
3799
  const services = createServiceBundle(client);
4950
3800
  server.tool(
4951
3801
  "get_semantic_layer",
4952
3802
  "Get semantic layer metadata for a datamart: table/column descriptions, synonyms, completion score. Omit datamartName to auto-resolve.",
4953
3803
  {
4954
- datamartName: z22.string().optional().describe(
3804
+ datamartName: z19.string().optional().describe(
4955
3805
  "Name of the datamart to inspect. Omit to list available datamarts."
4956
3806
  )
4957
3807
  },
@@ -5061,15 +3911,15 @@ ${result.feedback}`);
5061
3911
  }
5062
3912
 
5063
3913
  // src/tools/query/update-semantic-layer.ts
5064
- import { z as z23 } from "zod";
5065
- var columnSchema = z23.object({
5066
- name: z23.string().describe("Column name (must exist in the datamart)"),
5067
- description: z23.string().optional().describe("Business-friendly description of what this column represents"),
5068
- synonyms: z23.array(z23.string()).optional().describe(
3914
+ import { z as z20 } from "zod";
3915
+ var columnSchema = z20.object({
3916
+ name: z20.string().describe("Column name (must exist in the datamart)"),
3917
+ description: z20.string().optional().describe("Business-friendly description of what this column represents"),
3918
+ synonyms: z20.array(z20.string()).optional().describe(
5069
3919
  'Alternative names users might use for this column (e.g. ["revenue", "sales amount"])'
5070
3920
  ),
5071
- miscellaneousInfo: z23.string().optional().describe("Additional context such as valid values, units, or caveats"),
5072
- columnType: z23.enum([
3921
+ miscellaneousInfo: z20.string().optional().describe("Additional context such as valid values, units, or caveats"),
3922
+ columnType: z20.enum([
5073
3923
  "String",
5074
3924
  "Long String",
5075
3925
  "String (Custom)",
@@ -5082,16 +3932,16 @@ var columnSchema = z23.object({
5082
3932
  "JSON"
5083
3933
  ]).nullable().optional().describe('Semantic column type. Use "Identifier" for IDs/foreign keys, "Number" for numeric values, "String" for text. Omit for date columns.')
5084
3934
  });
5085
- var tableSchema = z23.object({
5086
- name: z23.string().describe("Table name (must exist in the datamart)"),
5087
- description: z23.string().optional().describe(
3935
+ var tableSchema = z20.object({
3936
+ name: z20.string().describe("Table name (must exist in the datamart)"),
3937
+ description: z20.string().optional().describe(
5088
3938
  "Business-friendly description of what this table represents"
5089
3939
  ),
5090
- synonyms: z23.array(z23.string()).optional().describe("Alternative names for this table"),
5091
- miscellaneousInfo: z23.string().optional().describe(
3940
+ synonyms: z20.array(z20.string()).optional().describe("Alternative names for this table"),
3941
+ miscellaneousInfo: z20.string().optional().describe(
5092
3942
  "Additional context such as how the table relates to other tables"
5093
3943
  ),
5094
- columns: z23.array(columnSchema).optional().describe("Column-level semantic definitions to update")
3944
+ columns: z20.array(columnSchema).optional().describe("Column-level semantic definitions to update")
5095
3945
  });
5096
3946
  function registerUpdateSemanticLayer(server, client) {
5097
3947
  const services = createServiceBundle(client);
@@ -5099,13 +3949,13 @@ function registerUpdateSemanticLayer(server, client) {
5099
3949
  "update_semantic_layer",
5100
3950
  "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.",
5101
3951
  {
5102
- datamartName: z23.string().optional().describe(
3952
+ datamartName: z20.string().optional().describe(
5103
3953
  "Name of the datamart to update. Omit to list available datamarts."
5104
3954
  ),
5105
- tables: z23.array(tableSchema).optional().describe(
3955
+ tables: z20.array(tableSchema).optional().describe(
5106
3956
  "Table and column definitions to update. Only include tables/columns you want to change."
5107
3957
  ),
5108
- feedback: z23.string().optional().describe(
3958
+ feedback: z20.string().optional().describe(
5109
3959
  'General feedback or context about the datamart (e.g. "This datamart contains e-commerce data for the US market").'
5110
3960
  )
5111
3961
  },
@@ -5179,12 +4029,9 @@ function registerAllTools(server, client) {
5179
4029
  registerGetEmbedDetails(server, client);
5180
4030
  registerUpdateEmbed(server, client);
5181
4031
  registerCustomizeTheme(server, client);
5182
- registerConfigureEmbed(server, client);
5183
- registerDiagnoseEmbedHealth(server, client);
5184
4032
  registerGenerateGuestToken(server, client);
5185
4033
  registerGenerateEmbedCode(server, client);
5186
4034
  registerListDashboards(server, client);
5187
- registerSetupEmbedInteractive(server, client);
5188
4035
  registerAskQuestion(server, client);
5189
4036
  registerGetSemanticLayer(server, client);
5190
4037
  registerUpdateSemanticLayer(server, client);
@@ -7660,7 +6507,7 @@ Databrain supports 4 core use cases for embedding analytics. Each maps to a spec
7660
6507
  **Two modes:**
7661
6508
  - **DRAG_DROP:** Visual metric builder \u2014 users drag columns, pick chart types. No AI needed.
7662
6509
  - **CHAT:** AI-powered natural language \u2014 users type questions. Requires LLM connector in Databrain admin.
7663
- **Tool sequence:** \`list_embeds\` \u2192 \`update_embed\` (set accessSettings) \u2192 \`configure_embed\` \u2192 \`generate_guest_token\` (with permissions)
6510
+ **Tool sequence:** \`list_embeds\` \u2192 \`update_embed\` (set accessSettings and options) \u2192 \`generate_guest_token\` (with permissions)
7664
6511
 
7665
6512
  ## Use Case 4: Explore and Query Data
7666
6513
  **When to use:** You want to explore available data and ask questions using natural language.
@@ -7883,7 +6730,7 @@ If creating new: resolve datamartName by calling \`list_datamarts\`, then call \
7883
6730
  - \`accessSettings: { datamartName: "<resolved>" }\` \u2014 only datamartName is needed, the tool fills in all other required defaults automatically. Do NOT add isAllow* fields yourself.
7884
6731
 
7885
6732
  **Step 6 \u2014 Verify Embed**
7886
- Call \`get_embed_details\` and \`diagnose_embed_health\` to verify the embed is properly configured.
6733
+ Call \`get_embed_details\` to verify the embed is properly configured.
7887
6734
  Show the user the embed ID and status.
7888
6735
 
7889
6736
  **Step 7 \u2014 Generate Guest Token**
@@ -8013,7 +6860,7 @@ For CHAT mode:
8013
6860
  \`\`\`
8014
6861
 
8015
6862
  **Step 4 \u2014 Configure Embed Options**
8016
- Call \`configure_embed\` to ensure the UI supports metric creation:
6863
+ Call \`update_embed\` (body passthrough with options) to ensure the UI supports metric creation:
8017
6864
  - \`disableMetricCreation\`: false
8018
6865
  - \`hideCreateMetricButton\`: false
8019
6866
  - \`hideChartSettings\`: false (so users can customize their created metrics)
@@ -8084,7 +6931,7 @@ Use \`customize_embed_theme\` with the chart appearance params to fine-tune char
8084
6931
  Ask if they want to customize tooltip fonts, axis styling, or label positions.
8085
6932
 
8086
6933
  **Step 5 \u2014 Configure Display Options**
8087
- Use \`configure_embed\` to clean up the UI:
6934
+ Use \`update_embed\` (body passthrough) to clean up the UI:
8088
6935
  - Ask if they want to hide the dashboard name (\`hideDashboardName\`)
8089
6936
  - Ask about card shadows and borders
8090
6937
  - Ask about download/export options they want to show
@@ -8126,7 +6973,7 @@ Call \`list_embeds\` and ask the user which embed to localize. Then ask:
8126
6973
  - What is the default/primary language?
8127
6974
 
8128
6975
  **Step 2 \u2014 Set the Primary Language**
8129
- Use \`configure_embed\` with the \`language\` parameter set to their primary language code (e.g. "fr" for French).
6976
+ Use \`update_embed\` (body passthrough with componentAttributes) with the \`language\` parameter set to their primary language code (e.g. "fr" for French).
8130
6977
 
8131
6978
  **Step 3 \u2014 Gather Translations**
8132
6979
  Call \`get_embed_details\` to understand what text is in the dashboard. Then help the user build translations:
@@ -8148,28 +6995,28 @@ For each text element, ask for translations in their target languages. Build tra
8148
6995
  - If a translation is missing for a language, the original key text is shown as fallback
8149
6996
 
8150
6997
  **Step 4 \u2014 Apply Translations**
8151
- Use \`configure_embed\` with the \`translations\` array containing all entries.
6998
+ Use \`update_embed\` (body passthrough with componentAttributes.translationDictionary) with the translations.
8152
6999
 
8153
7000
  **Step 5 \u2014 Configure Calendar (if needed)**
8154
7001
  Ask if they need a different calendar system:
8155
7002
  - \`"default"\` \u2014 standard Gregorian calendar
8156
7003
  - \`"ind"\` \u2014 Indian calendar format
8157
7004
 
8158
- Set via \`calendarType\` in \`configure_embed\` (\`language\` and \`calendarType\` params).
7005
+ Set via \`calendarType\` in \`update_embed\` (body passthrough with componentAttributes).
8159
7006
 
8160
7007
  **Step 6 \u2014 Set Custom Messages**
8161
7008
  Ask if they want to translate system messages:
8162
7009
  - Token expiry message (shown when session expires)
8163
7010
  - Token absent message (shown when no auth token)
8164
7011
 
8165
- Use \`configure_embed\` with \`tokenExpiryMessage\` and \`tokenAbsentMessage\` in their primary language.
7012
+ Use \`update_embed\` (body passthrough with options.customMessages) with \`tokenExpiry\` and \`tokenAbsent\` in their primary language.
8166
7013
 
8167
7014
  **Step 7 \u2014 Test**
8168
7015
  Tell the user to refresh the embed and verify translations appear correctly. If any text isn't translating, double-check that the key matches exactly.
8169
7016
 
8170
7017
  Remind the user: translations can also be applied per-user at the web component level using the \`translation-dictionary\` attribute, which is useful for dynamically switching languages based on user preferences.
8171
7018
 
8172
- **Tip:** The \`language\`, \`calendarType\`, \`hideDashboardFilters\`, and filter settings are all available in the same \`configure_embed\` tool.
7019
+ **Tip:** The \`language\`, \`calendarType\`, \`hideDashboardFilters\`, and filter settings are all configurable via \`update_embed\` body passthrough.
8173
7020
 
8174
7021
  **Important:** After changing language or translation settings, existing guest tokens still carry the old configuration. Remind the user to **regenerate guest tokens** (or reload their app) for changes to take effect.`;
8175
7022
 
@@ -8186,10 +7033,10 @@ Ask the user about their end-user roles. Common patterns:
8186
7033
  Ask: "What roles do your end-users have? What should each role be allowed to do?"
8187
7034
 
8188
7035
  **Step 2 \u2014 Lock Down the Embed Defaults**
8189
- Use \`configure_embed\` to set restrictive defaults (principle of least privilege):
7036
+ Use \`update_embed\` (body passthrough with options) to set restrictive defaults (principle of least privilege):
8190
7037
 
8191
7038
  \`\`\`
8192
- configure_embed(embedId,
7039
+ update_embed(embedId, body: { options: {
8193
7040
  disableMetricCreation: true,
8194
7041
  disableMetricUpdation: true,
8195
7042
  disableMetricDeletion: true,
@@ -8293,7 +7140,7 @@ Ask the user:
8293
7140
  - "Do any filters have very large option lists?" (100+ options \u2014 these benefit from SQL-based filters)
8294
7141
 
8295
7142
  **Step 3 \u2014 Configure String Filters**
8296
- For text/category filters, use \`configure_embed\` with \`stringFilters\`:
7143
+ For text/category filters, use \`update_embed\` (body passthrough with options.globalFilterOptions) for \`stringFilters\`:
8297
7144
 
8298
7145
  \`\`\`
8299
7146
  stringFilters: [{
@@ -8422,15 +7269,15 @@ Ask the user what they want to do:
8422
7269
 
8423
7270
  **Permissions / Access Settings:**
8424
7271
  - What's enabled vs disabled
8425
- - Suggest \`configure_embed\` for changes
7272
+ - Suggest \`update_embed\` for changes
8426
7273
 
8427
7274
  **Filters:**
8428
7275
  - Current filter configuration
8429
- - Suggest \`configure_embed\` with filter params for changes
7276
+ - Suggest \`update_embed\` (body passthrough with options.globalFilterOptions) for changes
8430
7277
 
8431
7278
  **Internationalization:**
8432
7279
  - Current language and translations
8433
- - Suggest \`configure_embed\` with \`language\` and \`translations\` params for changes
7280
+ - Suggest \`update_embed\` (body passthrough with componentAttributes) for changes
8434
7281
 
8435
7282
  3. Ask: "Would you like to modify any of these settings?"
8436
7283
 
@@ -8679,7 +7526,7 @@ function createServer(config) {
8679
7526
  4 core use cases \u2014 match the user's scenario to the right prompt:
8680
7527
  1. Embed existing dashboard \u2192 prompt: embed-existing-dashboard (list_data_apps \u2192 create_api_token \u2192 list_dashboards \u2192 create_embed \u2192 generate_guest_token \u2192 generate_embed_code)
8681
7528
  2. Blank dashboard per client \u2192 prompt: embed-blank-dashboard (list_data_apps \u2192 list_datamarts \u2192 create_embed with clientId per client \u2192 generate_guest_token \u2192 generate_embed_code)
8682
- 3. Enable metric creation \u2192 prompt: enable-metric-creation (list_embeds \u2192 update_embed accessSettings \u2192 configure_embed \u2192 generate_guest_token with permissions)
7529
+ 3. Enable metric creation \u2192 prompt: enable-metric-creation (list_embeds \u2192 update_embed accessSettings \u2192 generate_guest_token with permissions)
8683
7530
  4. Explore & query data \u2192 prompt: query-data (list_datamarts \u2192 get_semantic_layer \u2192 if empty, auto-generate descriptions with update_semantic_layer or use populate-semantic-layer prompt \u2192 ask_question)
8684
7531
 
8685
7532
  Infrastructure CREATION (datasources, datamarts, workspaces) is done in the Databrain UI.
@@ -8687,6 +7534,8 @@ However, the **semantic layer** is populated and maintained entirely via MCP too
8687
7534
 
8688
7535
  After embed setup, customize with: brand-my-embed, setup-filters, localize-embed, secure-my-embed.
8689
7536
  Use generate_guest_token for frontend auth and generate_embed_code for framework snippets.
7537
+ For advanced embed configuration (UI toggles, filters, i18n), use update_embed with a body passthrough.
7538
+ To diagnose embed issues, use get_embed_details and reason about the response.
8690
7539
  Do NOT ask the user for any tokens \u2014 manage them via MCP tools.
8691
7540
 
8692
7541
  IMPORTANT \u2014 accessSettings defaults: