使用说明
StarRocks MCP Server Docker Image
A containerized Model Context Protocol (MCP) server for StarRocks, enabling AI assistants to interact with StarRocks databases.
Overview
This Docker image packages the mcp-server-starrocks Python package with a custom wrapper that adds:
- Health check endpoints (
/health,/ready) for container orchestration. - Mandatory OAuth 2.1 authentication via Keycloak (OIDC), in front of the MCP endpoint.
- Per-request JWT pass-through — each MCP tool call runs its StarRocks queries under the authenticated user's identity. This component holds no StarRocks credentials.
It runs in streamable-http mode, exposing an HTTP endpoint for MCP clients. KEYCLOAK_REALM_URL is required — the server refuses to boot without it.
Quick Start
docker run -d \
-p 8000:8000 \
-e STARROCKS_HOST=your-starrocks-host \
-e STARROCKS_PORT=9030 \
-e STARROCKS_DB=your-database \
-e KEYCLOAK_REALM_URL=https://kc.example.com/realms/radiant \
-e MCP_BASE_URL=https://mcp.example.com \
ghcr.io/radiant-network/radiant-mcp:latest
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/mcp |
POST | MCP protocol endpoint (JSON-RPC over HTTP) |
/health |
GET | Liveness check — the process is up (does not touch StarRocks) |
/ready |
GET | Readiness check - returns server status |
Health Check Response
{"status": "healthy"}
Returns HTTP 200 while the process is running. It does not probe StarRocks — this component holds no StarRocks credentials.
Readiness Check Response
{"status": "ready"}
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
STARROCKS_HOST |
Yes | - | StarRocks FE (Frontend) hostname or IP (connection target only) |
STARROCKS_PORT |
No | 9030 |
StarRocks FE query port |
STARROCKS_DB |
No | - | Default database to use |
STARROCKS_OVERVIEW_LIMIT |
No | - | Limit for overview queries (memory management) |
RADIANT_API_URL |
No | - | Radiant portal API base URL. When set, registers the search_cases, get_case_context and list_tenants tools (the caller's JWT is forwarded as a Bearer token) |
No
STARROCKS_USER/STARROCKS_PASSWORD: this component authenticates to StarRocks with each caller's JWT, never a static credential.STARROCKS_HOSTandSTARROCKS_PORTonly tell it where to connect.
Authentication (OAuth 2.1 + Keycloak)
Authentication is mandatory: the server requires KEYCLOAK_REALM_URL and refuses to boot without it. It supports two kinds of clients simultaneously:
- Self-discovering MCP clients (e.g. Claude Desktop) — complete the full OAuth 2.1 + PKCE flow, with dynamic client registration, discovered automatically from the server's
.well-knownmetadata. - Clients that already hold a Keycloak token (e.g. a web portal) — present the existing token directly as a
Bearerheader.
In both cases the user's Keycloak JWT is forwarded to StarRocks, which validates it against Keycloak's JWKS (the authentication_jwt plugin, v3.5.0+) and executes queries under that user's identity. There is no static-credential fallback: a request without a valid JWT is rejected. The user (the JWT sub) must exist in StarRocks as IDENTIFIED WITH authentication_jwt (principal_field: sub), and StarRocks must have SSL enabled (JWT auth requires it).
The server uses fastmcp's native KeycloakAuthProvider — a pure JWT resource server. It holds no client id/secret and mints no tokens; it only validates incoming Bearer JWTs against the realm's JWKS. Requires Keycloak ≥ 26.6.0 for the DCR path.
OAuth Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
KEYCLOAK_REALM_URL |
Yes | - | Bare realm URL, e.g. https://kc.example.com/realms/radiant |
MCP_BASE_URL |
No | http://localhost:8000 |
Server root URL (not /mcp); the provider derives the resource + metadata URLs from it |
OAUTH_REQUIRED_SCOPES |
No | openid |
Comma-separated scopes required on tokens |
KEYCLOAK_AUDIENCE |
No | - | Expected JWT aud claim (leave unset unless you add a matching audience mapper) |
Building the Image
docker build -t radiant-mcp:latest .
Container Configuration
Port Mapping
The server listens on port 8000 inside the container.
Health Check
For container orchestration (Docker Compose, Kubernetes, ECS):
curl -f http://localhost:8000/health
Example Docker Compose
services:
radiant-mcp:
image: ghcr.io/radiant-network/radiant-mcp:latest
ports:
- "8000:8000"
environment:
STARROCKS_HOST: starrocks-fe
STARROCKS_PORT: 9030
STARROCKS_DB: my_database
KEYCLOAK_REALM_URL: https://kc.example.com/realms/radiant
MCP_BASE_URL: https://mcp.example.com
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
Deployment Considerations
- Memory: Recommend at least 1GB due to pandas/pyarrow dependencies
- Credentials: None to store — the component holds no StarRocks user/password. Access is governed entirely by the caller's Keycloak JWT and the matching StarRocks JWT user.
MCP Client Configuration
Configure your MCP client to connect to the server:
{
"mcpServers": {
"starrocks": {
"url": "http://localhost:8000/mcp"
}
}
}
Available MCP Tools
| Tool | Description |
|---|---|
read_query |
Execute SELECT queries |
write_query |
Execute DDL/DML commands |
analyze_query |
Analyze query performance |
table_overview |
Get table schema and sample data |
db_summary |
Get database summary with table schemas |
query_and_plotly_chart |
Execute query and generate Plotly chart |
With RADIANT_API_URL set, two additional tools backed by the Radiant portal
API are registered. They forward the caller's Keycloak JWT as a Bearer token,
so the API applies its own per-user authorization:
| Tool | Description |
|---|---|
search_cases |
Find cases by exact-match filters (status, type, panel, project, MRN, patient id, ...) and/or a free-text identifier prefix (resolved through the cases autocomplete endpoint). Returns case summaries and total count |
get_case_context |
Full clinical context of a case: metadata, patients with phenotypes, tasks, sequencing experiments, and the (case_id, seq_id, task_id, data_type) keys needed to query its variant occurrences. tenant is optional and auto-resolved when the user belongs to a single tenant |
list_tenants |
Tenants the authenticated user belongs to (codes to pass as tenant) |
Local Development
A docker-compose.yml brings up a full local stack — Keycloak (IdP), StarRocks (with TLS + a JWT-authenticated testuser), and radiant-mcp wired to both:
docker compose up --build
The MCP server is then at http://localhost:8000/mcp and Keycloak at http://localhost:8080 (realm radiant).
Querying StarRocks directly with a JWT
The local stack ships a Keycloak user (testuser / testpass, in realm radiant) and a matching StarRocks user authenticated with authentication_jwt. You can use the same token the MCP server forwards to query StarRocks yourself with the mysql CLI.
1. Get an access token (the compose realm's radiant-mcp-server client allows the password grant) and save it to a file — the mysql client reads the token from a file:
TOKEN=$(curl -sf -X POST http://localhost:8080/realms/radiant/protocol/openid-connect/token \
-d grant_type=password \
-d client_id=radiant-mcp-server \
-d client_secret=test-client-secret \
-d username=testuser \
-d password=testpass \
-d scope=openid \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
printf '%s' "$TOKEN" > /tmp/token.jwt
chmod 600 /tmp/token.jwt
To inspect the claims (notably sub):
echo "$TOKEN" | cut -d. -f2 | tr '_-' '/+' | base64 -d 2>/dev/null | python3 -m json.tool
2. Connect with the mysql CLI. The StarRocks username is the token's sub claim (a UUID), not the Keycloak login name. For testuser the sub is pinned in keycloak-import/radiant-realm.json and created by starrocks-init:
mysql -h127.0.0.1 -P9030 \
-u 11111111-1111-1111-1111-111111111111 \
--authentication-openid-connect-client-id-token-file=/tmp/token.jwt
SELECT current_user();
SELECT * FROM test_db.users;
Notes:
--authentication-openid-connect-client-id-token-filerequires a MySQL client that ships theauthentication_openid_connect_clientplugin (MySQL client ≥ 9.1, e.g. Homebrewmysql-client). The 8.0 client bundled in the StarRocks image does not have it — run this from the host.- Passing the token as a password (
--enable-cleartext-plugin -p"$TOKEN") does not work; StarRocks answersThe path to ID token file is not set. - Keycloak access tokens are short-lived (5 minutes by default). On an authentication error, fetch a new token and reconnect.
- The FE has TLS enabled; the client negotiates SSL automatically (
--ssl-mode=REQUIREDalso works).
Integration Tests
An end-to-end test exercises the OAuth 2.1 + JWT → StarRocks flow (health, OAuth metadata, token issuance, authenticated read_query, and the unauthenticated → 401 case):
docker compose --profile test run --rm test-runner
Use
run --rm test-runner, notup --abort-on-container-exit— the one-shotstarrocks-initcontainer exits 0 on success, which would abort the whole stack before the test runs.
License
See the upstream repository for license information.