Serwer MCP
Saiku Cloud ma wbudowany serwer Model Context Protocol (MCP), który wystawia Twoje kostki agentom LLM jako typowane narzędzia. Agenci odkrywają, jakie kostki są dostępne, pytają o ich strukturę i uruchamiają zapytania — wszystko przez małą, walidowaną powierzchnię narzędzi, która nie pozwala im wymyślać nazw miar ani halucynować odniesień do kolumn.
Endpoint MCP siedzi pod adresem
https://api.saiku.bi/rest/saiku/api/mcp. Mówi przez
streamable-HTTP MCP (aktualna wersja protokołu) i obsługuje dwa
sposoby uwierzytelniania:
- Konektor OAuth 2.1 — zalecany dla klientów czatu (Claude Desktop, claude.ai, Cursor — wszystko, co ma opcję „konektor niestandardowy” / „zdalne MCP”). Wklej URL i klient loguje użytkownika; nie ma kluczy do kopiowania ani tworzenia. Samoobsługowe, dostępne w planie Team i wyższych.
- Klucz API Bearer — dla klientów programistycznych / SDK.
Ten sam klucz
sk_...co każdy inny endpoint na tej powierzchni.
Zobacz Podłączanie agenta dla obu.
Dlaczego MCP zamiast zwykłego SQL?
LLM-y są niezawodnie słabe w pisaniu analitycznego SQL. Na Spider 2.0, standardowym realistycznym benchmarku text-to-SQL, czołowe modele frontierowe osiągają około 24%. Awarie nie są subtelne — wymyślone nazwy kolumn, złe złączenia, halucynowane tabele, schemy pomylone między bazami.
Kostka Saiku zapobiega tej klasie awarii strukturalnie:
- Agent wybiera miary i wymiary po nazwie z samoopisującej się schemy.
- Walidacja chodzi po stronie serwera. Jeśli agent wymyśli nazwę, zwracamy strukturalne 400 z listą prawidłowych alternatyw.
- Agregacja, złączenia i sumowanie są częścią definicji kostki — agent nie komponuje złączeń ani nie wybiera agregacji, tylko wybiera, jakich miar i wymiarów chce.
Wynikiem jest powierzchnia analityczna, której LLM-y mogą używać niezawodnie w produkcji, nie tylko w demach.
Uścisk dłoni
MCP to JSON-RPC 2.0 nad HTTP. Pełny przepływ:
- Klient wysyła
initialize(nagłówek sesji nie jest wymagany). - Serwer odpowiada z
serverInfoi ID sesji w nagłówku odpowiedziMcp-Session-Id. - Klient dołącza
Mcp-Session-Iddo każdego kolejnego żądania. - Klient wywołuje
tools/listdo odkrycia narzędzi, potemtools/call, by je wywoływać.
Minimalne 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" } } }'Odpowiedź zawiera nagłówek ID sesji — wyciągnij go z Mcp-Session-Id
i wysyłaj przy każdym kolejnym wywołaniu.
Jeśli używasz wysokopoziomowego klienta MCP (oficjalne SDK obsługują uścisk dłoni za Ciebie), to wszystko jest niewidoczne. Skonfiguruj klienta z URL-em + kluczem Bearer i działa.
Sześć narzędzi
Serwer wystawia sześć narzędzi, zaprojektowanych jako minimalny użyteczny zestaw do pracy analitycznej.
ID kostek
Każde narzędzie, które nazywa kostkę, przyjmuje ID kostki w formacie
connectionName/catalog/schema/cubeName. Części dostaniesz z odpowiedzi
list_cubes. Przykład:
cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/SalesUżywaj całego tego ciągu rozdzielonego ukośnikami jako argumentu
cube wszędzie, gdzie poniższe narzędzia go chcą.
list_cubes
Lista wszystkich kostek OLAP, do których bieżący użytkownik może wysyłać zapytania. Zawsze pierwsze wywołanie, gdy nie wiesz, co jest dostępne.
{ "name": "list_cubes", "arguments": {}}Odpowiedź:
{ "cubes": [ { "connectionName": "cloud__62e7bf54__v1__foodmart-globex-demo", "catalog": "FoodMart", "schema": "FoodMart", "cubeName": "Sales", "cubeCaption": "Sales", "defaultMeasure": "Unit Sales", "measureCount": 8 } ]}Zwraca do kilkudziesięciu pozycji. Bez paginacji — kostki Saiku liczy się w dziesiątkach na tenanta, nie w tysiącach.
describe_cube
Dostań kompletną strukturę do odpytywania jednej kostki. Zawsze
wywołuj to przed run_query, jeśli jeszcze nie widziałeś struktury
kostki — mówi dokładnie, jakie nazwy są prawidłowe, i zawiera gotowe
przykładowe ciała zapytań.
{ "name": "describe_cube", "arguments": { "cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales" }}Zwraca miary (kluczowane po lowercase’owej nazwie), wymiary,
hierarchie, poziomy, przykładowych członków z unikalnymi nazwami MDX
(w stylu [Customer].[Customers].[USA].[CA].[San Diego]) i gotowy
do użycia blok requestSchema + examples dla narzędzia run_query.
search_members
Znajdź unikalne nazwy MDX członków na poziomie po dopasowaniu
podciągu. Używaj, gdy kostka ma więcej członków na poziomie niż
pokryła próbka describe_cube (np. wyszukiwanie konkretnego miasta,
klienta lub marki produktu), albo gdy użytkownik mówi „filtruj po
Włochach” i musisz potwierdzić pisownię.
{ "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 jest wymagane, gdy wymiar ma więcej niż jedną (typowe —
wymiary Time mają zwykle kilka). Dla wymiarów z jedną hierarchią
możesz pominąć.
Zwraca do limit trafień z caption, name i uniqueName.
run_query
Główne narzędzie. Większość pytań użytkowników ląduje tutaj. Zbuduj
żądanie względem struktury z describe_cube; serwer waliduje każdą
nazwę i zwraca strukturalny VALIDATION_ERROR z prawidłowymi
alternatywami, jeśli któraś nazwa jest zła, więc nie waliduj
samodzielnie.
{ "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 }}Reguły kształtu wyciągnięte z aktualnego requestSchema:
measures— tablica obiektów. Każda pozycja manamepasujący do gołego podpisu z mapymeasureszdescribe_cube(np."Unit Sales", nie"[Measures].[Unit Sales]").rows/columns/filters— tablica wyborów osi. Każda pozycja madimensionilevel(wymagane),hierarchy(wymagane, gdy wymiar ma więcej niż jedną) i opcjonalną tablicęmembersz unikalnymi nazwami MDX, by ograniczyć zakres.cube— pełny string ID kostki (zobacz wyżej) lub obiekt{connectionName, catalog, schema, cubeName}.format—"records"(domyślnie) lub"matrix". Agenci prawie zawsze chcą records.limit— limit wierszy. Domyślnie 100; max 10 000 na ścieżce Mondrian.
Odpowiedź:
{ "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" } } } ]}Koperta komórki ({value, formatted, properties}) niesie zarówno
sparsowaną wartość liczbową, jak i sformatowany przez Mondriana
napis do wyświetlenia. Używaj value do arytmetyki, formatted do
wyświetlania.
queryId z odpowiedzi można przekazać do drillthrough, by
zinspecować bazowe wiersze za dowolną komórką.
preview_query
Skompiluj zapytanie do MDX bez jego wykonywania. Używaj, gdy chcesz pokazać użytkownikowi, co zapytanie zrobi, zaudytować wygenerowane zapytanie albo oszacować koszt przed uruchomieniem drogiej agregacji.
{ "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" }] }}Odpowiedź:
{ "status": "PREVIEW", "queryId": "f4e2a890-…", "generatedMdx": "SELECT NON EMPTY {[Measures].[Unit Sales]} ON COLUMNS,\nNON EMPTY [Time].[Time].[Year].Members ON ROWS\nFROM [Sales]"}Walidacja chodzi tak samo jak w run_query — preview zwraca ten
sam kształt VALIDATION_ERROR, jeśli nazwy się nie rozwiązują.
drillthrough
Pobierz surowe wiersze tabeli faktów stojące za konkretnym zapytaniem. Używaj, gdy użytkownik pyta „pokaż mi bazowe transakcje” lub chce zinspecować szczegóły jednej komórki.
{ "name": "drillthrough", "arguments": { "queryId": "eb623b5f-f32d-4b84-96fa-2bde148556a0", "maxrows": 100 }}Przekaż queryId zwrócony przez wcześniejsze wywołanie run_query
(to pole queryId w odpowiedzi, nie id koperty JSON-RPC). Komórki
w odpowiedzi używają tej samej typowanej koperty co run_query.
Błędy walidacji
Każde narzędzie, które przyjmuje nazwy kostek / miar / wymiarów, przechodzi walidację po stronie serwera. Gdy coś się nie rozwiązuje, dostajesz strukturalny błąd, a nie generyczne 500:
{ "isError": true, "structuredContent": { "code": "VALIDATION_ERROR", "message": "Unknown measure: [Measures].[Reveue]", "field": "measures[0]", "alternatives": [ "[Measures].[Revenue]", "[Measures].[Repeat Revenue]" ] }}Pole alternatives to zabójcza funkcja dla agentów LLM — gdy model
źle zapamiętał nazwę, serwer mówi mu najbliższe prawidłowe opcje,
a agent może się samodzielnie skorygować w jednej próbie zamiast
zgadywać.
Podłączanie agenta
Klienci czatu — konektor OAuth (zalecane)
Klienci, którzy obsługują niestandardowe / zdalne konektory MCP (Claude Desktop, claude.ai, Cursor i inni), łączą się bez klucza API — uwierzytelniają użytkownika przez OAuth. Dodaj URL MCP jako konektor niestandardowy i klient zrobi resztę:
- W ustawieniach konektorów klienta dodaj niestandardowy/zdalny
serwer MCP z URL-em
https://api.saiku.bi/rest/saiku/api/mcp. Zostaw puste pola opcjonalne „client ID / secret”. - Klient automatycznie odkrywa endpointy OAuth Saiku Cloud i rejestruje się — bez tworzenia client ID ani sekretu (Dynamic Client Registration).
- Przeglądarka otwiera logowanie do Saiku Cloud (Twoje normalne logowanie do workspace), potem pokazuje ekran zgody nazywając klienta i dostęp, o który prosi (odpytywanie kostki tylko do odczytu). Zatwierdź.
- Konektor żyje — agent może natychmiast wywołać
list_cubesi inne narzędzia.
Autoryzacja konektora wymaga workspace w planie Team, Business lub Enterprise. Poświadczenie, które dostaje klient, jest zakresowane do tylko-do-odczytu MCP dla Twojego workspace i niczego więcej; nigdy nie widzi Twoich poświadczeń hurtowni, innych tenantów ani żadnej powierzchni zapisu.
Zarządzanie konektorami. Każdy autoryzowany klient pojawia się w Połączenia → Podłączeni agenci w dashboardzie, gdzie możesz odwołać dowolnego z nich jednym kliknięciem. Tokeny dostępu są krótkożywotne (1 godzina) i odświeżają się po cichu; unieważnienie unieważnia natychmiast refresh token, więc dostęp wygasa najpóźniej w ciągu godziny — zwykle od razu.
Programistyczne — klucz API Bearer
Dla własnego kodu, frameworków agentów lub dowolnego klienta, który wstrzykuje statyczny nagłówek, wygeneruj klucz API w dashboardzie (Klucze API, zakresuj do MCP) i przekaż jako token Bearer:
{ "mcpServers": { "saiku": { "url": "https://api.saiku.bi/rest/saiku/api/mcp", "headers": { "Authorization": "Bearer sk_..." } } }}Przez oficjalne SDK MCP: zinstancjonuj
StreamableHttpClientTransport względem URL-a z nagłówkiem Bearer,
potem wywołuj standardowe API klienta MCP.
Po podłączeniu (na którykolwiek sposób) prompt Twojego agenta
zwykle potrzebuje jednej linijki — „Masz dostęp do serwera MCP
saiku z narzędziami do odpytywania kostek analitycznych. Użyj
list_cubes, by zacząć.” Reszta to agent odkrywający i używający
narzędzi tak, jak są opisane w schemie.
Limity szybkości
Ruch MCP wlicza się w standardowy budżet limitów szybkości Twojego tenanta (zobacz Uwierzytelnianie). Ciężcy agenci na planie Starter mogą uderzyć w limit; rozważ Team lub Business dla produkcyjnych obciążeń agentów.
Czego MCP nie wystawia
Powierzchnia MCP jest tylko do odczytu. Narzędzia, które modyfikują stan — zapisywanie workbooków, tworzenie schem, dodawanie połączeń, mutowanie definicji kostek — nie są wystawione przez MCP. Te żyją w dashboardzie lub w REST API, gdzie człowiek jest w pętli.
To celowe: agent, który może odczytywać Twoje dane, ale nie może modyfikować Twoich schem, nigdy nie zepsuje przypadkowo Twojego ustawienia analitycznego. Jeśli chcesz agenta, który autoruje kostki, użyj API inferencji AI i wstaw między kroki przegląd człowieka.
Co dalej
- API inferencji AI — do autorstwa kostek zamiast ich odpytywania.
- Uwierzytelnianie — tokeny Bearer, limity szybkości, kształty błędów.
- Izolacja tenantów — jak MCP utrzymuje Twoje dane niewidocznymi dla agentów innych tenantów.