XCubes

Build your first model

This guide walks you through building a simple P&L model from scratch. You will create two dimensions, a cube, enter data, add a formula rollup, and place a chart on a dashboard. Each step shows both the UI action and the equivalent MCP tool call so you can follow along in either context.

The finished model will have:

Step 1 — Create the Accounts dimension

In the UI: Open your project, go to Dimensions, and click New dimension. Name it Accounts, leave the type as Free-form, and save.

MCP:

create_dimension({ "name": "Accounts", "dimensionType": "freeform" })

Save the returned dimensionId — you will need it in the next step.

Step 2 — Add items to Accounts

You need three input items and one formula rollup. In a free-form dimension the rollup is a formula item that sums its siblings explicitly.

In the UI: Open the Accounts dimension and add four items in order:

Code Description Formula
ProductSales Product sales (none)
ServiceSales Service sales (none)
OtherRevenue Other revenue (none)
TotalRevenue Total revenue ProductSales + ServiceSales + OtherRevenue

MCP:

add_dimension_items({
  "dimensionId": "<accounts-id>",
  "items": [
    { "code": "ProductSales", "description": "Product sales" },
    { "code": "ServiceSales", "description": "Service sales" },
    { "code": "OtherRevenue", "description": "Other revenue" },
    {
      "code": "TotalRevenue",
      "description": "Total revenue",
      "formula": "ProductSales + ServiceSales + OtherRevenue",
      "fontStyle": "bold"
    }
  ]
})

Note the explicit + sum rather than SetSum() — for an enumerated list of named items, an explicit sum is clearer and more predictable.

Step 3 — Create the Month dimension

In the UI: Click New dimension, name it Month, tick Time scale, choose Monthly, set the start to January 2026, and create 3 periods.

MCP:

create_dimension({
  "name": "Month",
  "isTimeScale": true,
  "periodType": "month"
})

XCubes generates the month items automatically (2026-01, 2026-02, 2026-03). Save the returned dimensionId.

Step 4 — Create the cube

A cube needs at least one row dimension and one column dimension.

In the UI: Go to Cubes, click New cube, name it Revenue, assign Accounts to rows and Month to columns, and save.

MCP:

create_cube({
  "name": "Revenue",
  "rowDimensions": [{ "dimensionId": "<accounts-id>" }],
  "colDimensions": [{ "dimensionId": "<month-id>" }]
})

Save the returned cubeId.

Step 5 — Enter data

Before writing any cells, call get_cube_structure to learn the exact item codes. Do not guess them — even for auto-generated month codes.

MCP (required first):

get_cube_structure({ "cubeId": "<revenue-id>" })

This returns the Accounts items (ProductSales, ServiceSales, OtherRevenue, TotalRevenue) and the Month items (2026-01, 2026-02, 2026-03). The TotalRevenue row is a formula item — it has no input cells.

In the UI: Click the cube to open the grid. Type values into the leaf rows (Product sales, Service sales, Other revenue) for each month. TotalRevenue computes automatically.

MCP (after get_cube_structure):

set_cube_data({
  "cubeId": "<revenue-id>",
  "cells": [
    { "coordinates": { "Accounts": "ProductSales", "Month": "2026-01" }, "value": 120000 },
    { "coordinates": { "Accounts": "ServiceSales", "Month": "2026-01" }, "value": 45000 },
    { "coordinates": { "Accounts": "OtherRevenue", "Month": "2026-01" }, "value": 8000 },
    { "coordinates": { "Accounts": "ProductSales", "Month": "2026-02" }, "value": 135000 },
    { "coordinates": { "Accounts": "ServiceSales", "Month": "2026-02" }, "value": 48000 },
    { "coordinates": { "Accounts": "OtherRevenue", "Month": "2026-02" }, "value": 9000 },
    { "coordinates": { "Accounts": "ProductSales", "Month": "2026-03" }, "value": 142000 },
    { "coordinates": { "Accounts": "ServiceSales", "Month": "2026-03" }, "value": 52000 },
    { "coordinates": { "Accounts": "OtherRevenue", "Month": "2026-03" }, "value": 7500 }
  ]
})

Coordinates must include every dimension of the cube — here, both Accounts and Month. Omitting either returns a "Missing coordinates" error.

Cells that land on a formula item are skipped, not written — TotalRevenue is computed from its formula, so a set_cube_data call targeting it has no effect (the response reports those cells in its skipped count). Write the input items (ProductSales, ServiceSales, OtherRevenue) and let the rollup compute.

Step 6 — Verify the formula

Read back a few cells to confirm TotalRevenue is computing correctly.

MCP:

get_cube_data({
  "cubeId": "<revenue-id>",
  "rowItems": [{ "dimensionId": "<accounts-id>", "itemCodes": ["TotalRevenue"] }]
})

The returned CSV should show 173000 for January (120000 + 45000 + 8000), 192000 for February, and 201500 for March.

Step 7 — Create a dashboard with a chart

In the UI: Go to Dashboards, click New dashboard, name it Revenue overview. Add a chart widget, select the Revenue cube, set Month as the category axis and Accounts as the series, and choose bar chart type. Pin the Accounts series to the three input items to avoid showing the TotalRevenue bar alongside the detail.

MCP:

First, get item UIDs from get_cube_structure (the localUid field on each item). Then:

create_dashboard({
  "name": "Revenue overview",
  "widgets": [{
    "id": "w1",
    "type": "chart",
    "cubeId": "<revenue-id>",
    "chartType": "bar",
    "chartSelection": {
      "categoryDimensionIds": ["<month-id>"],
      "seriesDimensionIds": ["<accounts-id>"],
      "filters": {
        "<accounts-id>": [<uid-ProductSales>, <uid-ServiceSales>, <uid-OtherRevenue>]
      }
    },
    "chartOptions": { "legendShow": true, "stacking": "stacked" },
    "title": "Revenue by account"
  }]
})

The filters map uses numeric localUid values (from get_cube_structure), not item codes. Filtering to the three leaf items keeps the chart clean — TotalRevenue would otherwise double-count.

What you have built

You now have a complete, minimal model: named dimensions, a cube with live formula computation, and a dashboard chart. From here you can:

See Cube references, Dimensions, and Dashboards to go further.