Skip to main content
Glama
bintocher

Qlik Sense MCP Server

by bintocher

engine_create_hypercube

Create multi-dimensional data cubes for analysis with customizable sorting, including top-N results via expression-based dimension sorting.

Instructions

Create hypercube for data analysis with custom sorting options. IMPORTANT: To get top-N records, use qSortByExpression: 1 in dimension sorting with qExpression containing the measure formula (e.g., 'Count(field)' for ascending, '-Count(field)' for descending). Measure sorting is ignored by Qlik Engine.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
app_idYesApplication ID
dimensionsNoList of dimension definitions with optional sorting
measuresNoList of measure definitions with optional sorting
max_rowsNoMaximum rows to return

Implementation Reference

  • Core handler function implementing hypercube creation via Qlik Engine API CreateSessionObject and GetLayout calls. Handles dimension/measure conversion, sorting, and returns hypercube data.
    def create_hypercube(
        self,
        app_handle: int,
        dimensions: List[Dict[str, Any]] = None,
        measures: List[Dict[str, Any]] = None,
        max_rows: int = 1000,
    ) -> Dict[str, Any]:
        """Create hypercube for data extraction with proper structure."""
        try:
            # Handle empty dimensions/measures
            if dimensions is None:
                dimensions = []
            if measures is None:
                measures = []
    
            # Convert old format (list of strings) to new format (list of dicts) for backward compatibility
            converted_dimensions = []
            for dim in dimensions:
                if isinstance(dim, str):
                    # Old format - just field name
                    converted_dimensions.append({
                        "field": dim,
                        "sort_by": {
                            "qSortByNumeric": 0,
                            "qSortByAscii": 1,  # Default: ASCII ascending
                            "qSortByExpression": 0,
                            "qExpression": ""
                        }
                    })
                else:
                    # New format - dict with field and sort options
                    # Set defaults if not specified
                    if "sort_by" not in dim:
                        dim["sort_by"] = {
                            "qSortByNumeric": 0,
                            "qSortByAscii": 1,  # Default: ASCII ascending
                            "qSortByExpression": 0,
                            "qExpression": ""
                        }
                    converted_dimensions.append(dim)
    
            converted_measures = []
            for measure in measures:
                if isinstance(measure, str):
                    # Old format - just expression
                    converted_measures.append({
                        "expression": measure,
                        "sort_by": {
                            "qSortByNumeric": -1  # Default: numeric descending
                        }
                    })
                else:
                    # New format - dict with expression and sort options
                    # Set defaults if not specified
                    if "sort_by" not in measure:
                        measure["sort_by"] = {
                            "qSortByNumeric": -1  # Default: numeric descending
                        }
                    converted_measures.append(measure)
    
            # Create correct hypercube structure
            hypercube_def = {
                "qDimensions": [
                    {
                        "qDef": {
                            "qFieldDefs": [dim["field"]],
                            "qSortCriterias": [
                                {
                                    "qSortByState": 0,
                                    "qSortByFrequency": 0,
                                    "qSortByNumeric": dim["sort_by"].get("qSortByNumeric", 0),
                                    "qSortByAscii": dim["sort_by"].get("qSortByAscii", 1),
                                    "qSortByLoadOrder": 0,
                                    "qSortByExpression": dim["sort_by"].get("qSortByExpression", 0),
                                    "qExpression": {"qv": dim["sort_by"].get("qExpression", "")},
                                }
                            ],
                        },
                        "qNullSuppression": False,
                        "qIncludeElemValue": True,
                    }
                    for dim in converted_dimensions
                ],
                "qMeasures": [
                    {
                        "qDef": {"qDef": measure["expression"], "qLabel": measure.get("label", f"Measure_{i}")},
                        "qSortBy": measure["sort_by"],
                    }
                    for i, measure in enumerate(converted_measures)
                ],
                "qInitialDataFetch": [
                    {
                        "qTop": 0,
                        "qLeft": 0,
                        "qHeight": max_rows,
                        "qWidth": len(converted_dimensions) + len(converted_measures),
                    }
                ],
                "qSuppressZero": False,
                "qSuppressMissing": False,
                "qMode": "S",
                "qInterColumnSortOrder": list(range(len(converted_dimensions) + len(converted_measures))),
            }
    
            obj_def = {
                "qInfo": {
                    "qId": f"hypercube-{len(converted_dimensions)}d-{len(converted_measures)}m",
                    "qType": "HyperCube",
                },
                "qHyperCubeDef": hypercube_def,
            }
    
            result = self.send_request(
                "CreateSessionObject", [obj_def], handle=app_handle
            )
    
            if "qReturn" not in result or "qHandle" not in result["qReturn"]:
                return {"error": "Failed to create hypercube", "response": result}
    
            cube_handle = result["qReturn"]["qHandle"]
    
            # Получаем layout с данными
            layout = self.send_request("GetLayout", [], handle=cube_handle)
    
            if "qLayout" not in layout or "qHyperCube" not in layout["qLayout"]:
                return {"error": "No hypercube in layout", "layout": layout}
    
            hypercube = layout["qLayout"]["qHyperCube"]
    
            return {
                "hypercube_handle": cube_handle,
                "hypercube_data": hypercube,
                "dimensions": converted_dimensions,
                "measures": converted_measures,
                "total_rows": hypercube.get("qSize", {}).get("qcy", 0),
                "total_columns": hypercube.get("qSize", {}).get("qcx", 0),
            }
    
        except Exception as e:
            return {"error": str(e), "details": "Error in create_hypercube method"}
  • MCP server handler for the tool that connects to engine, opens the app, calls engine_api.create_hypercube, and returns JSON response.
    elif name == "engine_create_hypercube":
        app_id = arguments["app_id"]
        dimensions = arguments.get("dimensions", [])
        measures = arguments.get("measures", [])
        max_rows = arguments.get("max_rows", 1000)
    
        def _create_hypercube():
            try:
                self.engine_api.connect()
                app_result = self.engine_api.open_doc(app_id, no_data=False)
                app_handle = app_result.get("qReturn", {}).get("qHandle", -1)
                if app_handle != -1:
                    return self.engine_api.create_hypercube(app_handle, dimensions, measures, max_rows)
                else:
                    raise Exception("Failed to open app")
            except Exception as e:
                return {"error": str(e)}
            finally:
                self.engine_api.disconnect()
    
        result = await asyncio.to_thread(_create_hypercube)
        return [
            TextContent(
                type="text",
                text=json.dumps(result, indent=2, ensure_ascii=False)
            )
        ]
  • MCP tool registration including name, description, and detailed input schema for dimensions, measures with sorting options.
    Tool(name="engine_create_hypercube", description="Create hypercube for data analysis with custom sorting options. IMPORTANT: To get top-N records, use qSortByExpression: 1 in dimension sorting with qExpression containing the measure formula (e.g., 'Count(field)' for ascending, '-Count(field)' for descending). Measure sorting is ignored by Qlik Engine.", inputSchema={
        "type": "object",
        "properties": {
            "app_id": {"type": "string", "description": "Application ID"},
            "dimensions": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "field": {"type": "string", "description": "Field name for dimension"},
                        "label": {"type": "string", "description": "Optional label for dimension"},
                        "sort_by": {
                            "type": "object",
                            "properties": {
                                "qSortByNumeric": {"type": "integer", "description": "Sort by numeric value (-1 desc, 0 none, 1 asc)", "default": 0},
                                "qSortByAscii": {"type": "integer", "description": "Sort by ASCII value (-1 desc, 0 none, 1 asc)", "default": 1},
                                "qSortByExpression": {"type": "integer", "description": "Use expression for sorting (0/1). For top-N results, set to 1 and use qExpression with measure formula", "default": 0},
                                "qExpression": {"type": "string", "description": "Expression for custom sorting. For top-N: 'Count(field)' for ascending, '-Count(field)' for descending", "default": ""}
                            },
                            "additionalProperties": False
                        }
                    },
                    "additionalProperties": False
                },
                "description": "List of dimension definitions with optional sorting"
            },
            "measures": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "expression": {"type": "string", "description": "Measure expression"},
                        "label": {"type": "string", "description": "Optional label for measure"},
                        "sort_by": {
                            "type": "object",
                            "properties": {
                                "qSortByNumeric": {"type": "integer", "description": "Sort by numeric value (-1 desc, 0 none, 1 asc). NOTE: Measure sorting is ignored by Qlik Engine - use dimension sorting with qSortByExpression for top-N results", "default": -1}
                            },
                            "additionalProperties": False
                        }
                    },
                    "additionalProperties": False
                },
                "description": "List of measure definitions with optional sorting"
            },
            "max_rows": {"type": "integer", "description": "Maximum rows to return", "default": 1000}
        },
        "required": ["app_id"]
    })
  • Detailed input schema defining parameters for app_id, dimensions (with field, label, sort_by options), measures (with expression, label, sort_by), and max_rows.
        "type": "object",
        "properties": {
            "app_id": {"type": "string", "description": "Application ID"},
            "dimensions": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "field": {"type": "string", "description": "Field name for dimension"},
                        "label": {"type": "string", "description": "Optional label for dimension"},
                        "sort_by": {
                            "type": "object",
                            "properties": {
                                "qSortByNumeric": {"type": "integer", "description": "Sort by numeric value (-1 desc, 0 none, 1 asc)", "default": 0},
                                "qSortByAscii": {"type": "integer", "description": "Sort by ASCII value (-1 desc, 0 none, 1 asc)", "default": 1},
                                "qSortByExpression": {"type": "integer", "description": "Use expression for sorting (0/1). For top-N results, set to 1 and use qExpression with measure formula", "default": 0},
                                "qExpression": {"type": "string", "description": "Expression for custom sorting. For top-N: 'Count(field)' for ascending, '-Count(field)' for descending", "default": ""}
                            },
                            "additionalProperties": False
                        }
                    },
                    "additionalProperties": False
                },
                "description": "List of dimension definitions with optional sorting"
            },
            "measures": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "expression": {"type": "string", "description": "Measure expression"},
                        "label": {"type": "string", "description": "Optional label for measure"},
                        "sort_by": {
                            "type": "object",
                            "properties": {
                                "qSortByNumeric": {"type": "integer", "description": "Sort by numeric value (-1 desc, 0 none, 1 asc). NOTE: Measure sorting is ignored by Qlik Engine - use dimension sorting with qSortByExpression for top-N results", "default": -1}
                            },
                            "additionalProperties": False
                        }
                    },
                    "additionalProperties": False
                },
                "description": "List of measure definitions with optional sorting"
            },
            "max_rows": {"type": "integer", "description": "Maximum rows to return", "default": 1000}
        },
        "required": ["app_id"]
    })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bintocher/qlik-sense-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server