QlikMCP
MCP (Model Context Protocol) server for Qlik Cloud, enabling AI assistants like Claude to interact with your Qlik analytics platform.
Features
- Data Extraction: List apps, sheets, visualizations and extract data from charts
- Expression Evaluation: Calculate Qlik expressions on the fly
- App Management: Trigger reloads, check reload status
- Space & Files: Browse spaces and data files
- Automation: List and trigger Qlik automations
Prerequisites
- Elixir 1.18+
- A Qlik Cloud tenant with API access
- A Qlik Cloud API key
Installation
As a standalone server
Clone this repository:
git clone https://github.com/Balneario-de-Cofrentes/qlik_mcp.git cd qlik_mcpInstall dependencies:
mix deps.getConfigure your Qlik Cloud credentials:
export QLIK_API_KEY="your-api-key" export QLIK_TENANT_URL="https://your-tenant.region.qlikcloud.com"Start the server:
mix run --no-halt
The MCP server will be available at http://localhost:4100/mcp.
Auto-start on macOS (launchd)
For convenience, you can configure the MCP server to start automatically at login using macOS launchd.
-
Create a startup script at
~/.local/bin/qlik-mcp-start:
#!/bin/bash
export HOME="$HOME"
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
# If using asdf for Elixir version management:
# source /opt/homebrew/opt/asdf/libexec/asdf.sh
# Set Qlik credentials
export QLIK_API_KEY="your-api-key"
export QLIK_TENANT_URL="https://your-tenant.region.qlikcloud.com"
cd /path/to/qlik-cloud-mcp
exec mix run --no-haltMake it executable:
chmod +x ~/.local/bin/qlik-mcp-start-
Create a launchd plist at
~/Library/LaunchAgents/com.qlik-mcp.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.org/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.qlik-mcp</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/Users/YOUR_USERNAME/.local/bin/qlik-mcp-start</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/Users/YOUR_USERNAME/.local/log/qlik-mcp.log</string>
<key>StandardErrorPath</key>
<string>/Users/YOUR_USERNAME/.local/log/qlik-mcp.error.log</string>
</dict>
</plist>- Create log directory and load the service:
mkdir -p ~/.local/log
launchctl load ~/Library/LaunchAgents/com.qlik-mcp.plist- Manage the service:
# Check status
launchctl list | grep qlik
# Stop
launchctl unload ~/Library/LaunchAgents/com.qlik-mcp.plist
# Start
launchctl load ~/Library/LaunchAgents/com.qlik-mcp.plist
# View logs
tail -f ~/.local/log/qlik-mcp.logAs a dependency
Add to your mix.exs:
def deps do
[
{:qlik_mcp, "~> 0.2.0"}
]
endConfiguration
Timeout Settings
The server is configured with robust timeout protection to prevent hanging:
- Request Timeout: 120 seconds (2 minutes) - Maximum time for tool execution
- Idle Timeout: 1800 seconds (30 minutes) - SSE connection keepalive
- Inactivity Timeout: 1800 seconds (30 minutes) - Streaming response timeout
- QIX Operation Timeout: 15 seconds - Individual database query timeout
These are configured in lib/qlik_mcp/application.ex and lib/qlik_mcp/tools/helpers.ex.
Environment Variables
| Variable | Required | Description |
|---|---|---|
QLIK_API_KEY | Yes | Your Qlik Cloud API key |
QLIK_TENANT_URL | Yes |
Your tenant URL (e.g., https://tenant.region.qlikcloud.com) |
QLIK_MCP_PORT | No | HTTP port (default: 4100) |
QLIK_MAX_ROWS | No | Max rows per data request (default: 10000) |
Application Config
# config/config.exs
config :qlik_mcp,
api_key: System.get_env("QLIK_API_KEY"),
tenant_url: System.get_env("QLIK_TENANT_URL"),
port: 4100,
max_rows: 10_000Claude Integration
Claude Code (CLI)
Add to your MCP configuration (~/.mcp/global-config.json or project .mcp.json):
{
"mcpServers": {
"qlik": {
"type": "http",
"url": "http://localhost:4100/mcp"
}
}
}Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"qlik": {
"url": "http://localhost:4100/mcp"
}
}
}Available Tools
Data Extraction (Primary Value)
| Tool | Description |
|---|---|
list_apps | List available Qlik apps with optional filtering |
get_app | Get detailed information about a specific app |
list_sheets | List all sheets in an app |
list_charts | List visualizations on a sheet |
get_chart_data | Extract data from a visualization |
evaluate_expression |
Calculate a Qlik expression (e.g., Sum(Sales)) |
App Management
| Tool | Description |
|---|---|
reload_app | Trigger a data reload for an app |
get_reload_status | Check reload progress |
Spaces & Files
| Tool | Description |
|---|---|
list_spaces | List available spaces |
list_files | List data files |
Automation
| Tool | Description |
|---|---|
list_automations | List available automations |
run_automation | Trigger an automation |
MCP Resources
| URI | Description |
|---|---|
qlik://apps | JSON list of all accessible apps |
qlik://spaces | JSON list of all accessible spaces |
Example Interaction
User: "What's our sales by country from the Q4 dashboard?"
Claude:
1. list_apps() → finds "Q4 Sales Dashboard" app
2. list_sheets(app_id) → finds "Regional Sales" sheet
3. list_charts(app_id, sheet_id) → finds "Sales by Country" table
4. get_chart_data(app_id, object_id) → extracts:
| Country | Sales | Margin |
|---------|----------|--------|
| USA | $1.2M | 23% |
| Germany | $987K | 19% |
| UK | $654K | 21% |
5. Claude analyzes and responds with insightsArchitecture
qlik-cloud-mcp/
├── lib/
│ ├── qlik_mcp.ex # Main module
│ ├── qlik_mcp/
│ │ ├── application.ex # OTP Application
│ │ ├── server.ex # MCP Server (Anubis)
│ │ ├── config.ex # Configuration
│ │ ├── router.ex # HTTP Router (Plug)
│ │ ├── mcp_plug.ex # MCP HTTP Transport (Plug)
│ │ ├── tools/ # MCP Tool implementations
│ │ │ ├── list_apps.ex
│ │ │ ├── get_app.ex
│ │ │ ├── list_sheets.ex
│ │ │ ├── list_charts.ex
│ │ │ ├── get_chart_data.ex
│ │ │ ├── evaluate_expression.ex
│ │ │ ├── reload_app.ex
│ │ │ ├── get_reload_status.ex
│ │ │ ├── list_spaces.ex
│ │ │ ├── list_files.ex
│ │ │ ├── list_automations.ex
│ │ │ ├── run_automation.ex
│ │ │ └── helpers.ex
│ │ └── resources/ # MCP Resource implementations
│ │ ├── apps.ex
│ │ └── spaces.ex
├── config/
│ ├── config.exs
│ ├── dev.exs
│ ├── prod.exs
│ ├── runtime.exs
│ └── test.exs
├── test/
│ ├── qlik_mcp_test.exs
│ ├── qlik_mcp/
│ │ ├── config_test.exs
│ │ └── tools/
│ │ └── helpers_test.exs
│ └── test_helper.exs
└── mix.exsTroubleshooting
Server Logs
When running via launchd, logs are written to ~/.local/log/qlik-mcp.log.
Check for errors:
tail -f ~/.local/log/qlik-mcp.log | grep -i errorCommon Issues
Tool hangs or times out:
- Check QIX timeout (15 seconds default for individual queries)
- Check request timeout (120 seconds default for complete tool execution)
-
Verify Qlik Cloud API key is valid:
echo $QLIK_API_KEY - Check network connectivity to Qlik Cloud
Server crashes:
-
Check logs for stack traces in
~/.local/log/qlik-mcp.log - Verify all environment variables are set correctly
-
All tools have comprehensive exception handling via
safe_execute - If crashes persist, open an issue with logs
Connection issues:
-
Verify server is running:
curl http://localhost:4100/health -
Check launchd status:
launchctl list | grep qlik-mcp -
Restart server:
launchctl unload ~/Library/LaunchAgents/com.qlik-mcp.plist && launchctl load ~/Library/LaunchAgents/com.qlik-mcp.plist
Reliability & Robustness
The server includes comprehensive timeout and error handling:
- HTTP Request Timeout - Explicit
request_timeout: 120_000ms prevents indefinite hangs - QIX Operation Timeout - 15-second timeout wrapper for all database queries
- Exception Handling - All tools wrapped with
safe_executeto catch and gracefully handle crashes - Data Structure Handling - Proper extraction of Qlik's complex tuple/map data structures
Dependencies
- Anubis MCP - Elixir MCP SDK
- QlikElixir - Qlik Cloud client library
- Plug Cowboy - HTTP server
Development
# Run tests
mix test
# Run linter
mix lint
# Generate docs
mix docsRelated Projects
- qlik_elixir - The Qlik Cloud Elixir client this MCP server is built on
- qlik-mcp - TypeScript reference implementation
Contributing
- Fork the repository
-
Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests first (TDD encouraged)
-
Ensure all checks pass (
mix format && mix credo --strict && mix test) - Commit your changes
- Push to the branch
- Open a Pull Request
License
MIT License - see LICENSE file for details.
Links
Sponsored by
This project is proudly sponsored by Balneario - Clínica de Longevidad de Cofrentes, a world-class longevity clinic and thermal spa in Valencia, Spain. Their support makes open source development like this possible.
Thank you for investing in the developer community!