Skip to main content
Glama
dguerrar

MCP Apache Superset

by dguerrar
README.md
# MCP Apache Superset

A minimal [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that connects LLM clients (Claude Code, Claude Desktop, Cursor, etc.) to a local or remote [Apache Superset](https://superset.apache.org/) instance.

## Table of Contents

- [Features](#features)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Configuration](#configuration)
- [Authentication](#authentication)
  - [Database Auth (Default)](#database-auth-default)
  - [SSO / OAuth2 / OIDC](#sso--oauth2--oidc)
  - [LDAP](#ldap)
  - [Access Token (Pre-authenticated)](#access-token-pre-authenticated)
- [Usage](#usage)
  - [Claude Code](#claude-code)
  - [Claude Desktop](#claude-desktop)
  - [Development Mode](#development-mode)
- [Available Tools](#available-tools)
- [Running Superset Locally](#running-superset-locally)
- [Architecture](#architecture)

---

## Features

- 12 tools covering charts, dashboards, datasets, databases, SQL execution, and query history
- Automatic authentication with token refresh on 401
- CSRF token handling for write operations
- Supports database auth, OAuth2/OIDC SSO, LDAP, and pre-authenticated access tokens
- Zero external dependencies beyond the MCP SDK and Zod

---

## Prerequisites

- **Node.js** >= 18
- **Apache Superset** running and accessible (local or remote)

---

## Installation

```bash
git clone <this-repo>
cd mcp-apache
npm install
npm run build
```

---

## Configuration

All configuration is done via environment variables:

| Variable | Default | Description |
|---|---|---|
| `SUPERSET_URL` | `http://localhost:8088` | Superset base URL |
| `SUPERSET_USERNAME` | `admin` | Username for database/LDAP auth |
| `SUPERSET_PASSWORD` | `admin` | Password for database/LDAP auth |
| `SUPERSET_ACCESS_TOKEN` | _(none)_ | Pre-authenticated JWT access token (skips login) |
| `SUPERSET_AUTH_PROVIDER` | `db` | Auth provider: `db`, `ldap`, `oauth`, or `token` |

Copy the example file to get started:

```bash
cp .env.example .env
```

---

## Authentication

The MCP server supports multiple authentication methods to match your Superset deployment.

### Database Auth (Default)

The simplest method. Superset stores users in its own metadata database.

```bash
SUPERSET_AUTH_PROVIDER=db
SUPERSET_USERNAME=admin
SUPERSET_PASSWORD=admin
```

The server calls `POST /api/v1/security/login` with provider `"db"` and receives a JWT access token.

---

### SSO / OAuth2 / OIDC

When Superset is configured with OAuth2 or OpenID Connect (Azure AD, Okta, Keycloak, Google, etc.), you cannot log in via the REST API directly because the flow requires a browser redirect. There are two approaches:

#### Option A: Use a pre-authenticated access token

This is the **recommended approach for MCP servers**. You obtain a token outside the MCP flow and pass it directly.

**Step 1:** Configure Superset for OAuth2/OIDC in `superset_config.py`:

```python
from flask_appbuilder.security.manager import AUTH_OAUTH

AUTH_TYPE = AUTH_OAUTH

OAUTH_PROVIDERS = [
    {
        "name": "keycloak",  # or "azure", "okta", "google", etc.
        "icon": "fa-key",
        "token_key": "access_token",
        "remote_app": {
            "client_id": "superset-client",
            "client_secret": "YOUR_CLIENT_SECRET",
            "server_metadata_url": "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration",
            "api_base_url": "https://keycloak.example.com/realms/myrealm/protocol/openid-connect",
            "access_token_url": "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token",
            "authorize_url": "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth",
            "client_kwargs": {
                "scope": "openid email profile"
            },
        },
    }
]

# Map OAuth roles to Superset roles
AUTH_ROLES_MAPPING = {
    "superset_admin": ["Admin"],
    "superset_alpha": ["Alpha"],
    "superset_gamma": ["Gamma"],
}
AUTH_ROLES_SYNC_AT_LOGIN = True
```

**Step 2:** Obtain a token via OAuth2 Client Credentials or Resource Owner Password Grant (for service accounts):

```bash
# Client Credentials Grant (service-to-service, no user context)
curl -X POST https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token \
  -d "grant_type=client_credentials" \
  -d "client_id=superset-client" \
  -d "client_secret=YOUR_CLIENT_SECRET"

# Resource Owner Password Grant (if enabled by your IdP)
curl -X POST https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token \
  -d "grant_type=password" \
  -d "client_id=superset-client" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "username=svc-mcp" \
  -d "password=SVC_PASSWORD" \
  -d "scope=openid"
```

**Step 3:** Pass the token to the MCP server:

```bash
SUPERSET_AUTH_PROVIDER=token
SUPERSET_ACCESS_TOKEN=eyJhbGciOiJSUzI1NiIs...
```

**Step 4 (optional):** Automate token refresh with a wrapper script:

```bash
#!/bin/bash
# refresh-and-run.sh
export SUPERSET_ACCESS_TOKEN=$(curl -s -X POST \
  https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token \
  -d "grant_type=client_credentials" \
  -d "client_id=superset-client" \
  -d "client_secret=$OAUTH_CLIENT_SECRET" | jq -r '.access_token')

export SUPERSET_AUTH_PROVIDER=token
export SUPERSET_URL=http://localhost:8088
node /path/to/mcp-apache/dist/index.js
```

Then in your MCP config:

```json
{
  "mcpServers": {
    "superset": {
      "command": "/path/to/refresh-and-run.sh"
    }
  }
}
```

#### Option B: Use Superset's login endpoint with OAuth (limited)

Some Superset deployments expose the standard login endpoint even when OAuth is configured (as a fallback). In that case, you can still use database auth for the MCP server by creating a local service account:

```bash
# Create a local DB user in Superset even if OAuth is primary auth
superset fab create-admin \
  --username mcp-service \
  --firstname MCP \
  --lastname Service \
  --email mcp@internal \
  --password STRONG_PASSWORD
```

Then configure the MCP server with `SUPERSET_AUTH_PROVIDER=db` and the service account credentials.

---

### LDAP

When Superset uses LDAP authentication:

```python
# superset_config.py
from flask_appbuilder.security.manager import AUTH_LDAP

AUTH_TYPE = AUTH_LDAP
AUTH_LDAP_SERVER = "ldap://ldap.example.com"
AUTH_LDAP_USE_TLS = True
AUTH_LDAP_SEARCH = "ou=users,dc=example,dc=com"
AUTH_LDAP_UID_FIELD = "sAMAccountName"
AUTH_LDAP_BIND_USER = "CN=superset-svc,OU=ServiceAccounts,DC=example,DC=com"
AUTH_LDAP_BIND_PASSWORD = "BIND_PASSWORD"
```

The MCP server configuration:

```bash
SUPERSET_AUTH_PROVIDER=ldap
SUPERSET_USERNAME=your.ldap.user
SUPERSET_PASSWORD=your_ldap_password
```

Internally this calls the same `/api/v1/security/login` endpoint but with `provider: "ldap"`.

---

### Access Token (Pre-authenticated)

If you already have a valid Superset JWT (from any method), skip the login flow entirely:

```bash
SUPERSET_AUTH_PROVIDER=token
SUPERSET_ACCESS_TOKEN=eyJhbGciOiJIUzI1NiIs...
```

The server will use this token directly in the `Authorization: Bearer` header. **Note:** when the token expires, requests will fail with 401. Use the wrapper script approach above for automatic refresh.

---

## Usage

### Claude Code

Add to your project's `.claude/settings.json` or global `~/.claude/settings.json`:

```json
{
  "mcpServers": {
    "superset": {
      "command": "node",
      "args": ["C:/development/git/mcp-apache/dist/index.js"],
      "env": {
        "SUPERSET_URL": "http://localhost:8088",
        "SUPERSET_USERNAME": "admin",
        "SUPERSET_PASSWORD": "admin"
      }
    }
  }
}
```

### Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "superset": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-apache/dist/index.js"],
      "env": {
        "SUPERSET_URL": "http://localhost:8088",
        "SUPERSET_USERNAME": "admin",
        "SUPERSET_PASSWORD": "admin"
      }
    }
  }
}
```

### Development Mode

Run without compiling (uses `tsx`):

```bash
npm run dev
```

Or in your MCP config:

```json
{
  "mcpServers": {
    "superset": {
      "command": "npx",
      "args": ["tsx", "/path/to/mcp-apache/src/index.ts"],
      "env": {
        "SUPERSET_URL": "http://localhost:8088",
        "SUPERSET_USERNAME": "admin",
        "SUPERSET_PASSWORD": "admin"
      }
    }
  }
}
```

---

## Available Tools

### Charts

| Tool | Parameters | Description |
|---|---|---|
| `list_charts` | `page?`, `page_size?` | List all charts with pagination |
| `get_chart` | `id` | Get chart metadata (type, datasource, params) |
| `get_chart_data` | `id` | Execute the chart's query and return result data |

### Dashboards

| Tool | Parameters | Description |
|---|---|---|
| `list_dashboards` | `page?`, `page_size?` | List all dashboards |
| `get_dashboard` | `id` | Get dashboard metadata and layout |

### Datasets

| Tool | Parameters | Description |
|---|---|---|
| `list_datasets` | `page?`, `page_size?` | List registered datasets (tables/views) |
| `get_dataset` | `id` | Get dataset schema, columns, and metrics |

### Databases

| Tool | Parameters | Description |
|---|---|---|
| `list_databases` | _(none)_ | List all configured database connections |
| `get_database` | `id` | Get connection details for a database |

### SQL Execution

| Tool | Parameters | Description |
|---|---|---|
| `execute_sql` | `database_id`, `sql`, `schema?` | Run an arbitrary SQL query via SQL Lab |
| `list_saved_queries` | `page?`, `page_size?` | List saved SQL Lab queries |
| `list_queries` | `page?`, `page_size?` | List recent query execution history |

---

## Running Superset Locally

### Docker (quickest)

```bash
docker run -d -p 8088:8088 --name superset apache/superset

# First-time initialization
docker exec -it superset superset fab create-admin \
  --username admin \
  --firstname Admin \
  --lastname Admin \
  --email admin@example.com \
  --password admin

docker exec -it superset superset db upgrade
docker exec -it superset superset init
```

Access at http://localhost:8088

### Docker Compose (full stack with examples)

```bash
git clone https://github.com/apache/superset.git
cd superset
docker compose -f docker-compose-non-dev.yml up -d
```

This starts Superset with Redis, PostgreSQL, and example dashboards pre-loaded.

---

## Architecture

```
┌─────────────────┐       stdio        ┌──────────────────────┐
│  LLM Client     │◄──────────────────►│  MCP Server          │
│  (Claude Code)  │   MCP Protocol     │  (this project)      │
└─────────────────┘                    └──────────┬───────────┘
                                                  │ HTTP/REST
                                                  ▼
                                       ┌──────────────────────┐
                                       │  Apache Superset     │
                                       │  /api/v1/*           │
                                       └──────────┬───────────┘
                                                  │
                                       ┌──────────▼───────────┐
                                       │  Data Sources        │
                                       │  (PostgreSQL, MySQL,  │
                                       │   BigQuery, etc.)    │
                                       └──────────────────────┘
```

**Auth flow:**
1. MCP server starts → calls `POST /api/v1/security/login` (or uses pre-configured token)
2. Receives JWT access token + fetches CSRF token
3. All subsequent API calls include `Authorization: Bearer <token>` + `X-CSRFToken`
4. On 401 response → automatic re-authentication and retry

---

## License

MIT

TDQS

B3.2/5.0

Scored across 12 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: execution, individual detail retrieval, or listing. No two tools overlap in functionality, as get_chart returns metadata while get_chart_data executes the chart's query, and listers are separate from getters.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern (e.g., execute_sql, get_chart, list_dashboards). Compound names like get_chart_data are clear and do not break the pattern.

Tool Count5/5

12 tools is a well-scoped set for an Apache Superset MCP server, covering the major read operations and SQL execution without being excessive or insufficient.

Completeness3/5

The tool set is heavily read-only, lacking any create, update, or delete operations for charts, dashboards, databases, or datasets. While execute_sql allows data modification, management of Superset resources is absent, which is a notable gap for a server named after the full platform.

Maintenance

ActivityStale
ResponsivenessNo issues