Saltearse al contenido

Servidor MCP

Saiku Cloud incluye un servidor Model Context Protocol (MCP) integrado que expone sus cubos a los agentes LLM como herramientas tipadas. Los agentes descubren qué cubos están disponibles, piden su estructura y ejecutan consultas — todo a través de una superficie de herramientas pequeña y validada que les impide inventarse nombres de medidas o alucinar referencias a columnas.

El endpoint MCP está en https://api.saiku.bi/rest/saiku/api/mcp. Habla MCP por streamable-HTTP (la versión actual del protocolo) y soporta dos formas de autenticación:

  • Conector OAuth 2.1recomendado para clientes de chat (Claude Desktop, claude.ai, Cursor — cualquier cosa con una opción de “conector personalizado” / “MCP remoto”). Pegue la URL y el cliente inicia sesión al usuario; no hay claves que copiar o crear. Autoservicio, disponible en Team y planes superiores.
  • API key Bearerpara clientes programáticos / SDK. La misma clave sk_... que cualquier otro endpoint de esta superficie.

Consulte Conectar un agente para ambos.

¿Por qué MCP en lugar de SQL plano?

Los LLM son consistentemente malos escribiendo SQL analítico. En Spider 2.0, el benchmark estándar de text-to-SQL del mundo real, los modelos de frontera punteros obtienen alrededor de un 24%. Los fallos no son sutiles — nombres de columna inventados, joins incorrectos, tablas alucinadas, schemas confundidos entre bases de datos.

Un cubo de Saiku previene esa clase de fallo de forma estructural:

  • El agente elige medidas y dimensiones por nombre de un schema autodescriptivo.
  • La validación se ejecuta en el servidor. Si el agente inventa un nombre, devolvemos un 400 estructurado listando las alternativas válidas.
  • La agregación, los joins y los totales son parte de la definición del cubo — el agente no compone joins ni elige agregaciones, solo elige qué medidas y dimensiones quiere.

El resultado es una superficie analítica que los LLMs pueden usar de forma fiable en producción, no solo en demos.

El handshake

MCP es JSON-RPC 2.0 sobre HTTP. El flujo completo:

  1. El cliente envía initialize (no se requiere encabezado de sesión).
  2. El servidor responde con serverInfo y un ID de sesión en el encabezado de respuesta Mcp-Session-Id.
  3. El cliente incluye Mcp-Session-Id en cada petición posterior.
  4. El cliente llama a tools/list para descubrir herramientas, luego a tools/call para invocarlas.

Un initialize mínimo:

Ventana de terminal
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" }
}
}'

La respuesta incluye el encabezado de ID de sesión — extráigalo de Mcp-Session-Id y envíelo en cada llamada posterior.

Si usa un cliente MCP de alto nivel (los SDKs oficiales gestionan el handshake por usted), todo esto es invisible. Configure el cliente con la URL + su clave Bearer y funciona.

Las seis herramientas

El servidor expone seis herramientas, diseñadas para ser el conjunto mínimo útil para trabajo analítico.

IDs de cubo

Cada herramienta que nombra un cubo toma un ID de cubo en el formato connectionName/catalog/schema/cubeName. Obtiene las partes de la respuesta de list_cubes. Ejemplo:

cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales

Use esa cadena completa separada por barras como argumento cube en todos los lugares en los que las herramientas siguientes lo piden.

list_cubes

Lista cada cubo OLAP que el usuario actual puede consultar. Siempre su primera llamada cuando no sabe qué hay disponible.

{
"name": "list_cubes",
"arguments": {}
}

Respuesta:

{
"cubes": [
{
"connectionName": "cloud__62e7bf54__v1__foodmart-globex-demo",
"catalog": "FoodMart",
"schema": "FoodMart",
"cubeName": "Sales",
"cubeCaption": "Sales",
"defaultMeasure": "Unit Sales",
"measureCount": 8
}
]
}

Devuelve hasta unas pocas docenas de entradas. No paginada — los cubos de Saiku se cuentan en decenas por tenant, no en miles.

describe_cube

Obtiene la estructura consultable completa de un cubo. Llame siempre a esta antes de run_query si aún no ha visto la estructura del cubo — le dice exactamente qué nombres son válidos e incluye ejemplos de cuerpos de consulta listos para usar.

{
"name": "describe_cube",
"arguments": {
"cube": "cloud__62e7bf54__v1__foodmart-globex-demo/FoodMart/FoodMart/Sales"
}
}

Devuelve medidas (indexadas por nombre en minúsculas), dimensiones, jerarquías, niveles, miembros de muestra con nombres únicos MDX (estilo [Customer].[Customers].[USA].[CA].[San Diego]), y un bloque requestSchema + examples listo para usar con la herramienta run_query.

search_members

Encuentra los nombres únicos MDX de miembros en un nivel por coincidencia de subcadena. Use cuando el cubo tiene más miembros en un nivel de los que cubrió la muestra de describe_cube (por ejemplo, buscar una ciudad, cliente o marca de producto específicos), o cuando el usuario dice “filtrar por Italia” y necesita confirmar la ortografía.

{
"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 es requerido cuando la dimensión tiene más de una (común — las dimensiones de tiempo suelen tener varias). Para dimensiones de una sola jerarquía puede omitirlo.

Devuelve hasta limit resultados con caption, name y uniqueName.

run_query

La herramienta principal. La mayoría de las preguntas de los usuarios aterrizan aquí. Construya la petición contra la estructura de describe_cube; el servidor valida cada nombre y devuelve un VALIDATION_ERROR estructurado con alternativas válidas si algún nombre es incorrecto, así que no prevalide usted mismo.

{
"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
}
}

Reglas de forma extraídas del requestSchema en vivo:

  • measures — array de objetos. Cada elemento tiene un name que coincide con la leyenda básica del mapa measures de describe_cube (por ejemplo "Unit Sales", no "[Measures].[Unit Sales]").
  • rows / columns / filters — array de selecciones de eje. Cada elemento tiene dimension y level (requeridos), hierarchy (requerido cuando la dimensión tiene más de una), y un array opcional members de nombres únicos MDX al que restringir.
  • cube — la cadena completa del ID del cubo (ver arriba) o un objeto {connectionName, catalog, schema, cubeName}.
  • format"records" (por defecto) o "matrix". Los agentes casi siempre quieren records.
  • limit — tope de filas. Por defecto 100; máximo 10 000 en la ruta de Mondrian.

Respuesta:

{
"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" }
}
}
]
}

El envoltorio de celda ({value, formatted, properties}) lleva tanto el valor numérico parseado como la cadena de visualización formateada por Mondrian. Use value para aritmética, formatted para mostrar.

El queryId de la respuesta puede pasarse a drillthrough para inspeccionar las filas subyacentes detrás de cualquier celda.

preview_query

Compila una consulta a MDX sin ejecutarla. Use cuando quiera mostrar al usuario lo que hará la consulta, auditar una consulta generada o estimar el coste antes de ejecutar una agregación costosa.

{
"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" }]
}
}

Respuesta:

{
"status": "PREVIEW",
"queryId": "f4e2a890-…",
"generatedMdx": "SELECT NON EMPTY {[Measures].[Unit Sales]} ON COLUMNS,\nNON EMPTY [Time].[Time].[Year].Members ON ROWS\nFROM [Sales]"
}

La validación se ejecuta igual que en run_query — preview devuelve la misma forma VALIDATION_ERROR si los nombres no se resuelven.

drillthrough

Obtiene las filas crudas de la tabla de hechos detrás de una consulta específica. Use cuando el usuario pida “muéstrame las transacciones subyacentes” o quiera inspeccionar el detalle de una sola celda.

{
"name": "drillthrough",
"arguments": {
"queryId": "eb623b5f-f32d-4b84-96fa-2bde148556a0",
"maxrows": 100
}
}

Pase el queryId devuelto por una llamada run_query anterior (es el campo queryId en la respuesta, no el id del envoltorio JSON-RPC). Las celdas en la respuesta usan el mismo envoltorio tipado que run_query.

Errores de validación

Cada herramienta que acepta nombres de cubo / medida / dimensión ejecuta una validación en el servidor. Cuando algo no se resuelve, obtiene un error estructurado en lugar de un 500 genérico:

{
"isError": true,
"structuredContent": {
"code": "VALIDATION_ERROR",
"message": "Unknown measure: [Measures].[Reveue]",
"field": "measures[0]",
"alternatives": [
"[Measures].[Revenue]",
"[Measures].[Repeat Revenue]"
]
}
}

El campo alternatives es la funcionalidad estrella para agentes LLM — cuando el modelo confunde un nombre, el servidor le dice las opciones válidas más cercanas, y el agente puede autocorregirse en un solo reintento en lugar de adivinar.

Conectar un agente

Clientes de chat — Conector OAuth (recomendado)

Los clientes que soportan conectores MCP personalizados / remotos (Claude Desktop, claude.ai, Cursor y otros) se conectan sin API key — autentican al usuario mediante OAuth en su lugar. Añada la URL MCP como un conector personalizado y el cliente hace el resto:

  1. En la configuración de conectores del cliente, añada un servidor MCP personalizado/remoto con la URL https://api.saiku.bi/rest/saiku/api/mcp. Deje en blanco cualquier campo opcional de “client ID / secret”.
  2. El cliente descubre automáticamente los endpoints OAuth de Saiku Cloud y se registra a sí mismo — no hay client ID o secreto que crear (Dynamic Client Registration).
  3. Se abre un navegador para iniciar sesión en Saiku Cloud (su login habitual del workspace), luego muestra una pantalla de consentimiento nombrando al cliente y el acceso que pide (consulta de cubo de solo lectura). Apruébelo.
  4. El conector está activo — el agente puede llamar a list_cubes y las demás herramientas inmediatamente.

Autorizar un conector requiere un workspace Team, Business o Enterprise. La credencial que recibe el cliente está limitada a MCP de solo lectura para su workspace y nada más; nunca ve las credenciales de su data warehouse, otros tenants ni ninguna superficie de escritura.

Gestión de conectores. Cada cliente autorizado aparece en Conexiones → Agentes conectados en el dashboard, donde puede revocar cualquiera de ellos con un clic. Los tokens de acceso son de corta duración (1 hora) y se refrescan silenciosamente; una revocación invalida el token de refresco inmediatamente, así que el acceso se detiene en la hora siguiente como máximo — normalmente al instante.

Programático — API key Bearer

Para su propio código, frameworks de agente o cualquier cliente que inyecte un encabezado estático, genere una API key en el dashboard (API keys, limítela a MCP) y pásela como token Bearer:

{
"mcpServers": {
"saiku": {
"url": "https://api.saiku.bi/rest/saiku/api/mcp",
"headers": {
"Authorization": "Bearer sk_..."
}
}
}
}

A través de los SDKs MCP oficiales: instancie un StreamableHttpClientTransport contra la URL con el encabezado Bearer, luego llame a la API estándar del cliente MCP.

Tras conectar (de cualquiera de las dos formas), el prompt de su agente normalmente necesita una línea — “Tienes acceso a un servidor MCP saiku con herramientas para consultar cubos analíticos. Usa list_cubes para empezar”. Todo lo demás es el agente descubriendo y usando las herramientas tal como se describen en el schema.

Límites de velocidad

El tráfico MCP cuenta para el presupuesto estándar de límite de velocidad de su tenant (consulte Autenticación). Los agentes intensivos en el nivel Starter pueden alcanzar el límite; considere Team o Business para cargas de trabajo de agentes en producción.

Lo que MCP no expone

La superficie MCP es de solo lectura. Las herramientas que modifican el estado — guardar workbooks, crear schemas, añadir conexiones, mutar definiciones de cubo — no se exponen mediante MCP. Esas viven en el dashboard o en la API REST, donde hay una persona en el bucle.

Esto es deliberado: un agente que puede leer sus datos pero no puede modificar sus schemas nunca puede romper accidentalmente su configuración analítica. Si quiere un agente que cree cubos, use la API de inferencia de IA y ponga un paso de revisión humana en medio.

Próximos pasos