MCP Server
Saiku Cloud liefert einen eingebauten Model Context Protocol (MCP) Server, der Ihre Cubes als typisierte Tools an LLM-Agenten freigibt. Agenten entdecken, welche Cubes verfügbar sind, fragen ihre Struktur ab und führen Abfragen aus — alles über eine kleine, validierte Tool-Oberfläche, die sie davon abhält, Measure-Namen zu erfinden oder Spaltenverweise zu halluzinieren.
Der MCP-Endpunkt sitzt unter
https://api.saiku.bi/rest/saiku/api/mcp. Er spricht
Streamable-HTTP MCP (die aktuelle Protokollversion) und unterstützt
zwei Authentifizierungsmethoden:
- OAuth-2.1-Connector — empfohlen für Chat-Clients (Claude Desktop, claude.ai, Cursor — alles mit einer „Custom Connector” / „Remote MCP”-Option). Fügen Sie die URL ein, und der Client meldet den Benutzer an; es gibt keine Schlüssel zu kopieren oder zu erstellen. Self-Service, verfügbar ab Team-Plan.
- Bearer-API-Key — für programmatische / SDK-Clients. Der
gleiche
sk_...-Schlüssel wie für jeden anderen Endpunkt auf dieser Oberfläche.
Siehe Einen Agenten verbinden für beide Methoden.
Warum MCP statt einfachem SQL?
LLMs sind zuverlässig schlecht darin, analytisches SQL zu schreiben. Auf Spider 2.0, dem Standard-Real-World-Text-to-SQL-Benchmark, erreichen die besten Frontier-Modelle etwa 24%. Die Fehler sind nicht subtil — erfundene Spaltennamen, falsche Joins, halluzinierte Tabellen, über Datenbanken hinweg verwechselte Schemas.
Ein Saiku-Cube verhindert diese Fehlerklasse strukturell:
- Der Agent wählt Measures und Dimensionen nach Namen aus einem selbstbeschreibenden Schema.
- Die Validierung läuft serverseitig. Wenn der Agent einen Namen erfindet, geben wir einen strukturierten 400-Code zurück, der die gültigen Alternativen auflistet.
- Aggregation, Joins und Totalisierung sind Teil der Cube-Definition — der Agent komponiert keine Joins und wählt keine Aggregationen, er wählt nur, welche Measures und Dimensionen er möchte.
Das Ergebnis ist eine analytische Oberfläche, die LLMs zuverlässig in Produktion verwenden können, nicht nur in Demos.
Der Handshake
MCP ist JSON-RPC 2.0 über HTTP. Der vollständige Flow:
- Der Client sendet
initialize(kein Session-Header erforderlich). - Der Server antwortet mit
serverInfound einer Session-ID im Response-HeaderMcp-Session-Id. - Der Client schließt
Mcp-Session-Idin jeder weiteren Anfrage ein. - Der Client ruft
tools/listauf, um Tools zu entdecken, danntools/call, um sie aufzurufen.
Ein minimales Initialize:
curl -X POST https://api.saiku.bi/rest/saiku/api/mcp \ -H "Authorization: Bearer $SAIKU_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "my-agent", "version": "1.0" } } }'Die Antwort enthält den Session-ID-Header — extrahieren Sie ihn aus
Mcp-Session-Id und senden Sie ihn bei jedem weiteren Aufruf.
Wenn Sie einen High-Level-MCP-Client verwenden (die offiziellen SDKs übernehmen den Handshake für Sie), ist das alles unsichtbar. Konfigurieren Sie den Client mit der URL + Ihrem Bearer-Key, und er funktioniert.
Die sechs Tools
Der Server stellt sechs Tools zur Verfügung, die als die minimale nützliche Menge für analytische Arbeit konzipiert sind.
Cube-IDs
Jedes Tool, das einen Cube benennt, nimmt eine Cube-ID im Format
connectionName/catalog/schema/cubeName. Sie erhalten die Teile aus
der list_cubes-Antwort. Beispiel:
cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/SalesVerwenden Sie diesen gesamten Slash-separierten String als
cube-Argument überall dort, wo die unten beschriebenen Tools einen
wünschen.
list_cubes
Listet jeden OLAP-Cube auf, den der aktuelle Benutzer abfragen kann. Immer Ihr erster Aufruf, wenn Sie nicht wissen, was verfügbar ist.
{ "name": "list_cubes", "arguments": {}}Antwort:
{ "cubes": [ { "connectionName": "cloud__62e7bf54__v1__foodmart-globex-demo", "catalog": "FoodMart", "schema": "FoodMart", "cubeName": "Sales", "cubeCaption": "Sales", "defaultMeasure": "Unit Sales", "measureCount": 8 } ]}Liefert bis zu einigen Dutzend Einträgen zurück. Nicht paginiert — Saiku-Cubes werden pro Tenant in Zehnern gezählt, nicht in Tausenden.
describe_cube
Erhalten Sie die vollständige abfragbare Struktur eines Cubes. Rufen
Sie dies immer vor run_query auf, wenn Sie die Cube-Struktur noch
nicht gesehen haben — es sagt Ihnen genau, welche Namen gültig sind,
und enthält fertige Beispiel-Abfrage-Bodies.
{ "name": "describe_cube", "arguments": { "cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales" }}Liefert Measures zurück (per Kleinschreibung-Namen verschlüsselt),
Dimensionen, Hierarchien, Levels, Sample-Member mit eindeutigen
MDX-Namen (Stil [Customer].[Customers].[USA].[CA].[San Diego]) und
einen einsatzbereiten requestSchema + examples-Block für das
run_query-Tool.
search_members
Finden Sie die eindeutigen MDX-Namen von Membern auf einem Level per
Substring-Match. Verwenden Sie dies, wenn der Cube mehr Member auf
einem Level hat, als das Sample von describe_cube abdeckt (z. B.
Suche nach einer bestimmten Stadt, einem Kunden oder einer
Produktmarke), oder wenn der Benutzer „nach Italien filtern” sagt
und Sie die Schreibweise bestätigen müssen.
{ "name": "search_members", "arguments": { "cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales", "dimension": "Customers", "hierarchy": "Customers", "level": "City", "q": "San", "limit": 25 }}hierarchy ist erforderlich, wenn die Dimension mehr als eine hat
(häufig — Time-Dimensionen haben typischerweise mehrere). Bei
Dimensionen mit einer einzigen Hierarchie können Sie es weglassen.
Liefert bis zu limit Treffer mit caption, name und uniqueName
zurück.
run_query
Das primäre Tool. Die meisten Benutzerfragen landen hier. Bauen Sie
die Anfrage gegen die Struktur aus describe_cube; der Server
validiert jeden Namen und gibt einen strukturierten
VALIDATION_ERROR mit gültigen Alternativen zurück, wenn ein Name
falsch ist, also vorvalidieren Sie nicht selbst.
{ "name": "run_query", "arguments": { "cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales", "measures": [ { "name": "Unit Sales" }, { "name": "Store Sales" } ], "rows": [ { "dimension": "Time", "hierarchy": "Time", "level": "Year" } ], "columns": [ { "dimension": "Customers", "hierarchy": "Customers", "level": "Country", "members": ["[Customer].[Customers].[USA]"] } ], "filters": [ { "dimension": "Promotions", "hierarchy": "Promotions", "level": "Promotion Name", "members": ["[Promotion].[Promotions].[No Promotion]"] } ], "limit": 100 }}Form-Regeln aus dem Live-requestSchema:
measures— Array von Objekten. Jeder Eintrag hat einenname, der der bloßen Beschriftung aus dermeasures-Map vondescribe_cubeentspricht (z. B."Unit Sales", nicht"[Measures].[Unit Sales]").rows/columns/filters— Array von Achsenauswahlen. Jeder Eintrag hatdimensionundlevel(erforderlich),hierarchy(erforderlich, wenn die Dimension mehr als eine hat) und ein optionalesmembers-Array von eindeutigen MDX-Namen zur Einschränkung.cube— der vollständige Cube-ID-String (siehe oben) oder ein Objekt{connectionName, catalog, schema, cubeName}.format—"records"(Standard) oder"matrix". Agenten wollen fast immer Records.limit— Zeilenobergrenze. Standard 100; Max. 10 000 auf dem Mondrian-Pfad.
Antwort:
{ "status": "SUCCESS", "queryId": "eb623b5f-f32d-4b84-96fa-2bde148556a0", "runtimeMs": 196, "totalRows": 1, "data": [ { "Year": "1997", "Unit Sales": { "value": 266773.0, "formatted": "266,773", "properties": { "formatString": "Standard", "datatype": "Numeric" } }, "Store Sales": { "value": 565238.13, "formatted": "565,238.13", "properties": { "formatString": "#,###.00", "datatype": "Numeric" } } } ]}Der Zell-Envelope ({value, formatted, properties}) trägt sowohl
den geparsten numerischen Wert als auch den formatierten
Anzeigestring von Mondrian. Verwenden Sie value für Arithmetik,
formatted für die Anzeige.
Die queryId in der Antwort kann an drillthrough übergeben werden,
um die zugrundeliegenden Zeilen hinter einer beliebigen Zelle zu
inspizieren.
preview_query
Kompilieren Sie eine Abfrage zu MDX, ohne sie auszuführen. Verwenden Sie dies, wenn Sie dem Benutzer zeigen möchten, was die Abfrage tun wird, eine generierte Abfrage auditieren oder die Kosten vor dem Ausführen einer teuren Aggregation schätzen möchten.
{ "name": "preview_query", "arguments": { "cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales", "measures": [{ "name": "Unit Sales" }], "rows": [{ "dimension": "Time", "hierarchy": "Time", "level": "Year" }] }}Antwort:
{ "status": "PREVIEW", "queryId": "f4e2a890-…", "generatedMdx": "SELECT NON EMPTY {[Measures].[Unit Sales]} ON COLUMNS,\nNON EMPTY [Time].[Time].[Year].Members ON ROWS\nFROM [Sales]"}Die Validierung läuft genauso wie bei run_query — Preview liefert
die gleiche VALIDATION_ERROR-Form, wenn sich Namen nicht auflösen
lassen.
drillthrough
Holen Sie die rohen Faktentabellenzeilen hinter einer bestimmten Abfrage. Verwenden Sie dies, wenn der Benutzer fragt: „zeige mir die zugrundeliegenden Transaktionen” oder Details zu einer einzelnen Zelle inspizieren möchte.
{ "name": "drillthrough", "arguments": { "queryId": "eb623b5f-f32d-4b84-96fa-2bde148556a0", "maxrows": 100 }}Übergeben Sie die queryId, die ein früherer run_query-Aufruf
zurückgegeben hat (es ist das queryId-Feld in der Antwort, nicht
die id des JSON-RPC-Envelopes). Zellen in der Antwort verwenden
denselben typisierten Envelope wie run_query.
Validierungsfehler
Jedes Tool, das Cube- / Measure- / Dimension-Namen akzeptiert, führt serverseitige Validierung durch. Wenn etwas nicht aufgelöst werden kann, erhalten Sie einen strukturierten Fehler statt eines generischen 500:
{ "isError": true, "structuredContent": { "code": "VALIDATION_ERROR", "message": "Unknown measure: [Measures].[Reveue]", "field": "measures[0]", "alternatives": [ "[Measures].[Revenue]", "[Measures].[Repeat Revenue]" ] }}Das alternatives-Feld ist das Killer-Feature für LLM-Agenten — wenn
sich das Modell einen Namen falsch merkt, teilt der Server ihm die
nächstgelegenen gültigen Optionen mit, und der Agent kann sich in
einem einzigen Retry selbst korrigieren, statt zu raten.
Einen Agenten verbinden
Chat-Clients — OAuth-Connector (empfohlen)
Clients, die Custom- / Remote-MCP-Connectors unterstützen (Claude Desktop, claude.ai, Cursor und andere), verbinden sich ohne API-Key — sie authentifizieren den Benutzer stattdessen über OAuth. Fügen Sie die MCP-URL als Custom Connector hinzu, und der Client erledigt den Rest:
- Fügen Sie in den Connector-Einstellungen des Clients einen
Custom- / Remote-MCP-Server mit der URL
https://api.saiku.bi/rest/saiku/api/mcphinzu. Lassen Sie etwaige optionale „Client-ID / Secret”-Felder leer. - Der Client entdeckt die OAuth-Endpunkte von Saiku Cloud automatisch und registriert sich selbst — keine Client-ID oder Secret zu erstellen (Dynamic Client Registration).
- Ein Browser öffnet sich, um sich bei Saiku Cloud anzumelden (Ihr normaler Workspace-Login), und zeigt dann einen Consent-Screen, der den Client und den angeforderten Zugriff benennt (Lesezugriff auf Cube-Abfragen). Genehmigen Sie ihn.
- Der Connector ist live — der Agent kann
list_cubesund die anderen Tools sofort aufrufen.
Das Autorisieren eines Connectors erfordert einen Workspace mit Team-, Business- oder Enterprise-Plan. Das Credential, das der Client erhält, ist auf Read-only-MCP für Ihren Workspace gescopt und auf nichts anderes; es sieht niemals Ihre Warehouse-Anmeldedaten, andere Tenants oder eine Schreib-Oberfläche.
Connectors verwalten. Jeder autorisierte Client erscheint unter Verbindungen → Verbundene Agenten im Dashboard, wo Sie jeden mit einem Klick widerrufen können. Access-Tokens sind kurzlebig (1 Stunde) und aktualisieren sich still; ein Widerruf invalidiert das Refresh-Token sofort, sodass der Zugriff höchstens innerhalb der Stunde stoppt — meist sofort.
Programmatisch — Bearer-API-Key
Für Ihren eigenen Code, Agenten-Frameworks oder jeden Client, der einen statischen Header injiziert, erzeugen Sie einen API-Key im Dashboard (API-Keys, scopen Sie ihn auf MCP) und übergeben Sie ihn als Bearer-Token:
{ "mcpServers": { "saiku": { "url": "https://api.saiku.bi/rest/saiku/api/mcp", "headers": { "Authorization": "Bearer sk_..." } } }}Über die offiziellen MCP-SDKs: Instantiieren Sie ein
StreamableHttpClientTransport gegen die URL mit dem Bearer-Header
und rufen Sie dann die Standard-MCP-Client-API auf.
Nach dem Verbinden (auf beide Arten) braucht der Prompt Ihres
Agenten typischerweise eine Zeile — „Sie haben Zugriff auf einen
saiku-MCP-Server mit Tools zum Abfragen von Analyse-Cubes.
Verwenden Sie list_cubes, um zu beginnen.” Alles andere ist der
Agent, der die Tools so entdeckt und verwendet, wie sie im Schema
beschrieben sind.
Rate-Limits
MCP-Traffic zählt zum Standard-Rate-Limit-Budget Ihres Tenants (siehe Authentifizierung). Schwere Agenten im Starter-Plan können das Limit erreichen; ziehen Sie Team oder Business für produktive Agenten-Workloads in Betracht.
Was MCP nicht freigibt
Die MCP-Oberfläche ist read-only. Tools, die Status modifizieren — Workbooks speichern, Schemas erstellen, Verbindungen hinzufügen, Cube-Definitionen mutieren — werden nicht über MCP freigegeben. Diese leben auf dem Dashboard oder der REST-API, wo ein Mensch in der Schleife ist.
Das ist beabsichtigt: Ein Agent, der Ihre Daten lesen, aber Ihre Schemas nicht modifizieren kann, kann Ihr Analyse-Setup niemals versehentlich kaputt machen. Wenn Sie einen Agenten möchten, der Cubes erstellt, verwenden Sie die AI Inference API und setzen Sie einen menschlichen Review-Schritt dazwischen.
Wie geht es weiter?
- AI Inference API — zum Erstellen von Cubes statt sie abzufragen.
- Authentifizierung — Bearer-Tokens, Rate-Limits, Fehlerformate.
- Tenant-Isolation — wie MCP Ihre Daten für die Agenten anderer Tenants unsichtbar hält.