DataForge Semantic MCP Server
Provides a read-only semantic gateway to the DataForge Product API by Business Qlik, enabling AI agents to browse projects and versions, and retrieve normalized metadata including measures, dimensions, and full Relationship Metadata (RMD).
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@DataForge Semantic MCP Serverlist all measures and dimensions for project 392 version 948"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
DataForge Semantic MCP Server
Read-only semantic gateway between AI agents and DataForge Product API. Fetches projects, versions, measures, dimensions and full RMD (Reference Model Data), normalizes and caches the data, and exposes it via MCP protocol or as a Python library.
What This Server Provides
DataForge stores semantic layer metadata — the business definitions of measures and dimensions used in analytics projects. This MCP server gives AI agents structured access to that metadata:
Projects — top-level containers for analytics models
Versions — snapshots of a project's semantic layer (one version can be marked as "global"/production)
Measures — business metrics (e.g. "Total Revenue", "Gross Margin") with formulas, data types, source mappings
Dimensions — attributes for slicing data (e.g. "Customer Segment", "Region") with grouping and source mappings
RMD — full Reference Model Data combining all measures and dimensions in one response
All responses are JSON. The server normalizes raw DataForge API fields into a clean, stable schema so AI agents get consistent data regardless of API changes.
Features
Library-first — use directly from Python, no MCP server required
MCP adapter — 7 tools for Claude Desktop, Cursor and other MCP clients
Caching — file-based cache with TTL and last-known-good fallback
Normalization — inconsistent API fields mapped to clean canonical models
Retry & error handling — exponential backoff on 5xx, proper error codes for auth issues
Quick Start
Installation
pip install -e ".[dev]"Configuration
Copy .env.example to .env and set your values:
DATAFORGE_BASE_URL=https://api.prod-df.businessqlik.com
DATAFORGE_API_KEY=your_api_key_here
DEFAULT_LANGUAGE=ruAs a Python Library
import asyncio
from dataforge_mcp import create_semantic_service
async def main():
service = create_semantic_service()
projects = await service.list_projects()
print(projects)
versions = await service.list_versions(project_id=392)
print(versions)
rmd = await service.get_rmd(project_id=392, version_id=948)
print(f"Measures: {rmd['stats']['measure_count']}")
print(f"Dimensions: {rmd['stats']['dimension_count']}")
asyncio.run(main())As an MCP Server (stdio)
python -m dataforge_mcpAdd to Claude Desktop config (claude_desktop_config.json):
{
"mcpServers": {
"dataforge": {
"command": "python",
"args": ["-m", "dataforge_mcp"],
"env": {
"DATAFORGE_BASE_URL": "https://api.prod-df.businessqlik.com",
"DATAFORGE_API_KEY": "your_api_key_here"
}
}
}
}Docker (SSE mode)
cp .env.example .env
# edit .env with your API key
docker compose upMCP Tools — Detailed Reference
All tools return JSON via MCP TextContent. Every response has a stable schema described below.
df_health
Check server, API and cache status.
Input: none
Output:
{
"server_status": "ok",
"product_api_status": "ok",
"base_url": "https://api.prod-df.businessqlik.com",
"cache_status": "ok"
}Field | Type | Description |
|
| Always |
|
|
|
|
| Configured DataForge API base URL |
|
|
|
df_list_projects
List available DataForge projects accessible with the configured API key.
Input:
Parameter | Type | Default | Description |
|
|
| Page number |
|
|
| Items per page |
|
|
| Use cached data if available |
Output:
{
"projects": [
{
"id": 392,
"name": "Fashion Retail",
"description": "Retail analytics project"
}
],
"pagination": {
"total": 10,
"page": 1,
"page_size": 100,
"total_pages": 1
}
}Project fields:
Field | Type | Description |
|
| Unique project identifier |
|
| Project name |
|
| Project description |
df_list_versions
List versions for a specific project.
Input:
Parameter | Type | Required | Default | Description |
|
| yes | — | Project ID |
|
| no |
| Page number |
|
| no |
| Items per page |
|
| no |
| Use cached data |
Output:
{
"project_id": 392,
"versions": [
{
"id": 948,
"name": "Global Version",
"is_global": true
}
],
"pagination": {
"total": 5,
"page": 1,
"page_size": 100,
"total_pages": 1
}
}Version fields:
Field | Type | Description |
|
| Unique version identifier |
|
| Version name |
|
| Whether this is the global (production) version |
df_get_measures
Get all measures (business metrics) for a project version.
Input:
Parameter | Type | Required | Default | Description |
|
| yes | — | Project ID |
|
| yes | — | Version ID |
|
| no | config default ( | Language for localized names |
|
| no |
| Use cached data |
Output:
{
"project_id": 392,
"version_id": 948,
"measures": [
{
"row_number": "1",
"group": "Sales",
"block": "Revenue",
"name": "Total Revenue",
"description": "Total revenue from all sales",
"data_type": "Numeric",
"measure_type": "Sum",
"formula": "[Revenue]",
"restrictions": null,
"connected_source": {
"db": "Sales DB",
"schema": null,
"table": "sales_table",
"column": null
},
"original_source_type": "Database",
"original_source": "Sales DB",
"original_object": "sales_table",
"report_for_verification": null,
"comment": "Primary revenue metric",
"display_data_type": null,
"status": "Active",
"relevance": "High",
"required": true,
"visibility": "Public",
"responsible_for_data": "Data Team",
"variation": null,
"raw": {}
}
]
}Measure fields:
Field | Type | Description |
|
| Row number from RMD spreadsheet |
|
| Business group (e.g. "Sales", "Finance") |
|
| Block within a group (e.g. "Revenue", "Costs") |
|
| Measure name (localized) |
|
| Human-readable description |
|
| Data type (e.g. "Numeric", "String") |
|
| Aggregation type (e.g. "Sum", "Count", "Average") |
|
| Calculation formula |
|
| Any restrictions or filters applied |
|
| Database source mapping (see below) |
|
| Source type (e.g. "Database") |
|
| Original data source name |
|
| Original object (table/view) name |
|
| Report used to verify this measure |
|
| Additional notes |
|
| Display format type |
|
| Status (e.g. "Active", "Draft") |
|
| Relevance level (e.g. "High", "Medium", "Low") |
|
| Whether the measure is required |
|
| Visibility level (e.g. "Public", "Internal") |
|
| Team/person responsible for data quality |
|
| Measure variation/variant |
|
| Original unmodified API response (empty by default) |
df_get_dimensions
Get all dimensions (attributes for slicing/filtering data) for a project version.
Input: same as df_get_measures.
Output:
{
"project_id": 392,
"version_id": 948,
"dimensions": [
{
"row_number": "1",
"group": "Sales",
"block": "Customer",
"name": "Customer ID",
"description": "Unique customer identifier",
"dimension_group": "Customer Attributes",
"data_type": "String",
"connected_source": {
"db": 161,
"schema": null,
"table": "customers",
"column": "CompanyName"
},
"dimension_type": null,
"original_source_type": "Database",
"original_source": "Sales DB",
"original_object": "customers_table",
"comment": "Primary key for customers",
"formula": null,
"value_options": null,
"display_data_type": null,
"source_data_type": null,
"status": "Active",
"relevance": "High",
"required": true,
"visibility": "Public",
"responsible_for_data": "Data Team",
"raw": {}
}
]
}Dimension fields:
Field | Type | Description |
|
| Row number from RMD spreadsheet |
|
| Business group |
|
| Block within a group |
|
| Dimension name (localized) |
|
| Human-readable description |
|
| Logical grouping of dimensions (e.g. "Customer Attributes") |
|
| Data type (e.g. "String", "Integer", "Date") |
|
| Database source mapping (see below) |
|
| Dimension type classification |
|
| Source type |
|
| Original data source name |
|
| Original object name |
|
| Additional notes |
|
| Calculation formula (if computed) |
|
| Allowed values or value list |
|
| Display format type |
|
| Data type in the source system |
|
| Status (e.g. "Active", "Draft") |
|
| Relevance level |
|
| Whether the dimension is required |
|
| Visibility level |
|
| Team/person responsible for data quality |
|
| Original unmodified API response (empty by default) |
df_get_rmd
Get full RMD — all measures and dimensions for a project version in a single call.
Input:
Parameter | Type | Required | Default | Description |
|
| yes | — | Project ID |
|
| yes | — | Version ID |
|
| no | config default | Language for localized names |
|
| no |
| Use cached data |
|
| no |
| Include raw API response in each entity |
Output:
{
"project": {
"id": 392,
"name": "Fashion Retail",
"description": null
},
"version": {
"id": 948,
"name": "Global Version",
"is_global": true
},
"measures": [ /* array of Measure objects (see df_get_measures) */ ],
"dimensions": [ /* array of Dimension objects (see df_get_dimensions) */ ],
"stats": {
"measure_count": 120,
"dimension_count": 75
}
}When include_raw is false (default), the raw field is stripped from every measure and dimension to reduce response size.
df_refresh_cache
Force refresh cached data for a project version.
Input:
Parameter | Type | Required | Default | Description |
|
| yes | — | Project ID |
|
| yes | — | Version ID |
|
| no | config default | Language |
Output:
{
"status": "refreshed",
"cache_key": "rmd:392:948:ru",
"fetched_at": "2026-03-29T12:00:00+00:00"
}Connected Source Object
Measures and dimensions can reference their physical database source:
{
"db": "Sales DB",
"schema": null,
"table": "sales_table",
"column": "revenue"
}Field | Type | Description |
|
| Database name or ID |
|
| Database schema |
|
| Table or view name |
|
| Column name |
Error Format
All errors follow a consistent format:
{
"error": {
"code": "DATAFORGE_API_KEY_INVALID",
"message": "Invalid API key",
"details": {
"http_status": 401
}
}
}Error codes:
Code | HTTP Status | Description |
| 401 |
|
| 401 | Invalid API key |
| 401 | Unauthorized (IP not whitelisted, account blocked, etc.) |
| 401 | Authentication failed |
| 404 | Project, version, or resource not found |
| 5xx | Server-side error (retried automatically) |
Typical AI Agent Workflow
A typical workflow for an AI agent using this server:
1. df_health → verify connectivity
2. df_list_projects → discover available projects
3. df_list_versions → find the global (production) version
4. df_get_rmd → fetch all measures and dimensions at once
(or df_get_measures / df_get_dimensions separately)
5. Use the semantic metadata to understand the data model,
generate queries, or answer business questionsArchitecture
AI Agent / MCP Client
|
v
MCP Adapter (mcp/) — thin wrappers, no business logic
|
v
SemanticService (application/) — cache-first orchestration (CORE)
|
+--> DataForgeClient (dataforge/) — HTTP calls with retry
+--> Normalizer (semantic/) — raw API -> canonical models
+--> FileCacheStore (cache/) — TTL + last-known-good fallbackSemanticService is the single entry point. MCP tools only delegate to it.
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check src/ tests/
# Format
ruff format src/ tests/Configuration Reference
Variable | Default | Description |
|
| DataForge API base URL |
| — | API key (required) |
|
| Default language for measures/dimensions |
|
| Cache directory path |
|
| Cache TTL in seconds |
|
| Transport: |
|
| Log level |
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/SGromych/dataforge-mcp-gateway'
If you have feedback or need assistance with the MCP directory API, please join our Discord server