Skip to main content

Pinot MCP Server

Build and Test PyPI version Python versions License: Apache 2.0

Table of Contents

Overview

This project is a Python-based Model Context Protocol (MCP) server for interacting with Apache Pinot. It is built using the FastMCP framework. It is designed to integrate with Claude Desktop to enable real-time analytics and metadata queries on a Pinot cluster.

It allows you to

  • List tables, segments, and schema info from Pinot
  • Execute read-only SQL queries
  • View index/column-level metadata
  • Designed to assist business users via Claude integration
  • and much more.
StarTree Server for Apache Pinot MCP server

Pinot MCP in Action

See Pinot MCP in action below:

Fetching Metadata

Pinot MCP fetching metadata

Fetching Data, followed by analysis

Prompt: Can you do a histogram plot on the GitHub events against time Pinot MCP fetching data and analyzing table

Sample Prompts

Once Claude is running, click the hammer 🛠️ icon and try these prompts:

  • Can you help me analyse my data in Pinot? Use the Pinot tool and look at the list of tables to begin with.
  • Can you do a histogram plot on the GitHub events against time

Quick Start

Prerequisites

Install uv (if not already installed)

uv is a fast Python package installer and resolver, written in Rust. It's designed to be a drop-in replacement for pip with significantly better performance.

curl -LsSf https://astral.sh/uv/install.sh | sh

# Reload your bashrc/zshrc to take effect. Alternatively, restart your terminal
# source ~/.bashrc

Installation

# Clone the repository
git clone https://github.com/startreedata/mcp-pinot.git
cd mcp-pinot
uv pip install -e . # Install dependencies

# For development dependencies (including testing tools), use:
# uv pip install -e .[dev] 

Configure Pinot Cluster

The MCP server expects a uvicorn config style .env file in the root directory to configure the Pinot cluster connection. This repo includes a sample .env.example file that assumes a pinot quickstart setup.

mv .env.example .env

Configuration Reference

The server loads configuration from environment variables and from a .env file found from the current working directory. Values in .env override process environment variables, so run the server from the repository directory or pass the same variables through your process manager, container, or Claude Desktop configuration.

Common Profiles

Use case Required settings Notes
Claude Desktop MCP_TRANSPORT=stdio Recommended for local desktop use. No HTTP listener is started unless TLS certs are configured.
Local HTTP MCP_TRANSPORT=http, MCP_HOST=127.0.0.1 Default local development profile. Accessible only from the same machine.
Remote HTTP/HTTPS MCP_TRANSPORT=http, MCP_HOST=0.0.0.0, OAUTH_ENABLED=true The server refuses non-loopback HTTP/HTTPS binds unless OAuth is enabled. Use TLS directly or an authenticated reverse proxy.
Helm exposure service.enabled=true, mcp.host=0.0.0.0, mcp.oauth.enabled=true Helm defaults are local-only and render no Service unless exposure is explicitly enabled.

Pinot Connection

Variable Default Description
PINOT_CONTROLLER_URL http://localhost:9000 Pinot controller endpoint used for metadata and table/schema operations.
PINOT_BROKER_URL http://localhost:8000 Pinot broker endpoint used for SQL queries.
PINOT_BROKER_HOST Parsed from PINOT_BROKER_URL Optional host override for the broker connection.
PINOT_BROKER_PORT Parsed from PINOT_BROKER_URL Optional port override for the broker connection.
PINOT_BROKER_SCHEME Parsed from PINOT_BROKER_URL Optional scheme override, usually http or https.
PINOT_USERNAME / PINOT_PASSWORD unset Basic authentication for Pinot.
PINOT_TOKEN unset Bearer or raw token for Pinot; takes precedence over PINOT_TOKEN_FILENAME.
PINOT_TOKEN_FILENAME unset File containing a Pinot token. A missing or empty file logs a warning and continues without token auth.
PINOT_DATABASE empty Optional database header for multi-database Pinot deployments.
PINOT_USE_MSQE false Enables Pinot multi-stage query engine query option.
PINOT_REQUEST_TIMEOUT 60 HTTP request timeout in seconds.
PINOT_CONNECTION_TIMEOUT 60 HTTP connection timeout in seconds.
PINOT_QUERY_TIMEOUT 60 SQL query timeout in seconds.

MCP Server

Variable Default Description
MCP_TRANSPORT http Transport mode. Use stdio for Claude Desktop and http for HTTP/SSE clients.
MCP_HOST 127.0.0.1 HTTP bind host. Set 0.0.0.0 only with OAuth enabled.
MCP_PORT 8080 HTTP listen port.
MCP_PATH /mcp MCP HTTP path.
MCP_SSL_KEYFILE unset TLS private key path. Requires MCP_SSL_CERTFILE.
MCP_SSL_CERTFILE unset TLS certificate path. Requires MCP_SSL_KEYFILE.

OAuth

OAuth is required before binding HTTP or HTTPS to a non-loopback host.

Variable Default Description
OAUTH_ENABLED false Enables OAuth authentication.
OAUTH_CLIENT_ID empty OAuth client ID.
OAUTH_CLIENT_SECRET empty OAuth client secret.
OAUTH_BASE_URL http://localhost:8080 Public base URL for this MCP server.
OAUTH_AUTHORIZATION_ENDPOINT empty Upstream authorization endpoint.
OAUTH_TOKEN_ENDPOINT empty Upstream token endpoint.
OAUTH_JWKS_URI empty JWKS URI used for token verification.
OAUTH_ISSUER empty Expected token issuer.
OAUTH_AUDIENCE unset Optional expected audience claim.
OAUTH_EXTRA_AUTH_PARAMS unset Optional JSON object with additional authorization parameters.

Table Filtering

Variable Default Description
PINOT_TABLE_FILTER_FILE unset YAML file with included_tables glob patterns. If configured and missing, startup fails.

See SECURITY.md for the production exposure checklist and vulnerability reporting process.

Configure Table Filtering (Optional)

⚠️ Security Note: For production access control, use Pinot's native table-level ACLs (available since Pinot 0.8.0+). Table filtering in this MCP server is a convenience feature for organizing tables and improving UX, not a security boundary. It uses best-effort SQL parsing and should not be relied upon for security.

Table filtering allows you to control which Pinot tables are visible through the MCP server. This is useful for:

  • Reduce Cognitive Load: Focus on relevant tables when your Pinot cluster has hundreds or thousands of tables
  • Multi-Tenancy UX: Run multiple MCP server instances against the same Pinot cluster, each showing different table subsets for different teams or use cases
  • Environment Separation: Deploy different MCP server instances (dev, staging, prod) that show only environment-specific tables
  • Hide System Tables: Filter out internal, test, or deprecated tables from end-user view

When table filtering is enabled, all table operations are filtered to show only the configured tables.

What Gets Filtered

Table filtering applies across all MCP operations:

  1. Table Listing - Only configured tables appear in table lists
  2. Query Execution - SQL queries are checked to ensure all referenced tables (in FROM, JOIN, subqueries, CTEs, etc.) match the configured patterns
  3. Table Operations - Direct table access operations filter by table name:
    • Get table details, size, and metadata
    • Get table segments and segment metadata
    • Get index/column details
    • Get/update table configurations
  4. Schema Operations - Schema operations filter by schema name:
    • Get/create/update schemas
    • Create table configurations

Setup

Copy the example configuration file:

cp table_filters.yaml.example table_filters.yaml

Edit table_filters.yaml to specify which tables to include:

included_tables:
  - production_*        # All tables starting with "production_"
  - analytics_events    # Specific table name
  - metrics_*          # All tables starting with "metrics_"

Configure the filter file path in your .env:

PINOT_TABLE_FILTER_FILE=table_filters.yaml

Pattern Matching

The filter supports glob-style patterns using standard Unix filename pattern matching:

  • exact_table_name - Matches exactly this table
  • prefix_* - Matches all tables starting with "prefix_"
  • *_suffix - Matches all tables ending with "_suffix"
  • *pattern* - Matches all tables containing "pattern"
  • sharded_table_? - Matches tables with exactly one character after the underscore (e.g., sharded_table_1, sharded_table_a)

Query Filtering

When filtering is enabled, SQL queries are checked before execution:

  • Supported SQL Features: FROM clauses, JOIN clauses (INNER, LEFT, RIGHT, OUTER, CROSS), subqueries, CTEs (WITH), UNION queries, comma-separated table lists
  • Quoted Identifiers: Supports both double-quoted ("table name") and backtick-quoted (`table_name`) table names
  • Schema Prefixes: Handles schema-qualified table names (e.g., database.schema.table)
  • Comments: Removes SQL comments before checking

Example filtered query:

SELECT * FROM allowed_table
JOIN other_table ON allowed_table.id = other_table.id

Error: Query references unauthorized tables: other_table. Allowed tables: allowed_table, prod_*

Configuration Features

Fail-Fast Validation:

  • ⚠️ If PINOT_TABLE_FILTER_FILE is configured but the file doesn't exist, the server will fail to start with a FileNotFoundError
  • This prevents accidentally showing all tables due to misconfiguration
  • Empty filter files or missing included_tables key will show all tables (no filtering)

Comprehensive Filtering:

  • All MCP tools that access tables apply filtering before execution
  • Consistent filtering across all table access points
  • Clear error messages indicate which tables don't match the configured patterns

Disabling Table Filtering

To disable table filtering, either:

  1. Remove the PINOT_TABLE_FILTER_FILE environment variable, or
  2. Don't configure it in your .env file

When not configured, all tables in the Pinot cluster are visible.

Read-only Query Enforcement

The read-query tool always validates SQL before forwarding it to Pinot. It accepts one statement only, and that statement must be a read-only SELECT or WITH ... SELECT query. SQL comments are stripped, semicolon-stacked statements are rejected, and write/DDL/admin keywords are blocked.

Configure OAuth Authentication (Optional)

To enable OAuth authentication, set the following environment variables in your .env file:

Required variables (when OAUTH_ENABLED=true):

  • OAUTH_CLIENT_ID: OAuth client ID
  • OAUTH_CLIENT_SECRET: OAuth client secret
  • OAUTH_BASE_URL: Your MCP server base URL
  • OAUTH_AUTHORIZATION_ENDPOINT: OAuth authorization endpoint URL
  • OAUTH_TOKEN_ENDPOINT: OAuth token endpoint URL
  • OAUTH_JWKS_URI: JSON Web Key Set URI for token verification
  • OAUTH_ISSUER: Token issuer identifier

Optional variables:

  • OAUTH_AUDIENCE: Expected audience claim for token validation
  • OAUTH_EXTRA_AUTH_PARAMS: Additional authorization parameters as JSON object (e.g., {"scope": "openid profile"})

Example configuration:

OAUTH_ENABLED=true
OAUTH_CLIENT_ID=client-id
OAUTH_CLIENT_SECRET=client-secret
OAUTH_BASE_URL=http://localhost:8000
OAUTH_AUTHORIZATION_ENDPOINT=https://example.com/oauth/authorize
OAUTH_TOKEN_ENDPOINT=https://example.com/oauth/token
OAUTH_JWKS_URI=https://example.com/.well-known/jwks.json
OAUTH_ISSUER=https://example.com
OAUTH_AUDIENCE=client-id
OAUTH_EXTRA_AUTH_PARAMS={"scope": "openid profile"}

Run the server

uv --directory . run mcp_pinot/server.py

You should see logs indicating that the server is running.

Security notes:

  • The HTTP transport binds to 127.0.0.1 by default. Prefer the stdio transport for Claude Desktop; set MCP_HOST=0.0.0.0 only when the server is protected by OAuth and TLS or an authenticated reverse proxy.
  • The server refuses to start when HTTP is bound to a non-loopback host and OAUTH_ENABLED is not true.
  • read-query enforces a single read-only SQL statement before execution. This is a guardrail, not a replacement for Pinot authentication and authorization.
  • Ensure you are using mcp[cli] version >=1.10.0, which includes DNS rebinding protections for the HTTP/SSE server.

Launch Pinot Quickstart (Optional)

Start Pinot QuickStart using docker:

docker run --name pinot-quickstart -p 2123:2123 -p 9000:9000 -p 8000:8000 -d apachepinot/pinot:latest QuickStart -type batch

Query MCP Server

uv --directory . run examples/example_client.py

This quickstart just checks all the tools and queries the airlineStats table.

Claude Desktop Integration

Open Claude's config file

vi ~/Library/Application\ Support/Claude/claude_desktop_config.json

Add an MCP server entry

{
  "mcpServers": {
      "pinot_mcp": {
          "command": "/path/to/uv",
          "args": [
              "--directory",
              "/path/to/mcp-pinot-repo",
              "run",
              "mcp_pinot/server.py"
          ],
          "env": {
            // You can also include your .env config here
          }
      }
  }
}

Replace /path/to/uv with the absolute path to the uv command, you can run which uv to figure it out.

Replace /path/to/mcp-pinot with the absolute path to the folder where you cloned this repo.

Note: you must use stdio transport when running your server to use with Claude desktop.

You could also configure environment variables here instead of the .env file, in case you want to connect to multiple pinot clusters as MCP servers.

Restart Claude Desktop

Claude will now auto-launch the MCP server on startup and recognize the new Pinot-based tools.

Using DXT Extension

Apache Pinot MCP server now supports DXT desktop extensions file

To use it, you first need to install dxt via

npm install -g @anthropic-ai/dxt

then you can run the following commands:

uv pip install -r pyproject.toml --target mcp_pinot/lib
uv pip install . --target mcp_pinot/lib 
dxt pack

After this you'll get a .dxt file in your dir. Double click on that file to install it in claude desktop

Security and Vulnerability Reporting

See SECURITY.md for vulnerability reporting instructions, security categories, and the checklist for safely exposing the MCP HTTP endpoint.

Developer

  • All tools are defined in the Pinot class in utils/pinot_client.py

Build

Build the project with

pip install -e ".[dev]"

Test

Test the repo with:

pytest

Build the Docker image

docker build -t mcp-pinot .

Run the container

docker run -v $(pwd)/.env:/app/.env mcp-pinot

Note: Make sure to have your .env file configured with the appropriate Pinot cluster settings before running the container.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mcp_pinot_server-3.2.0.tar.gz (59.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mcp_pinot_server-3.2.0-py3-none-any.whl (37.9 kB view details)

Uploaded Python 3

File details

Details for the file mcp_pinot_server-3.2.0.tar.gz.

File metadata

  • Download URL: mcp_pinot_server-3.2.0.tar.gz
  • Upload date:
  • Size: 59.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for mcp_pinot_server-3.2.0.tar.gz
Algorithm Hash digest
SHA256 d70945250d3c4774bd574dc1130109b7f3afa38a52421a967f9eb6e1be999b1e
MD5 80b80d6c122290e4aa929fbb402010b9
BLAKE2b-256 817b4fa85806e749cb794e91e47d0c0954f3dcc55e23a6bca60abe2f6658ba3b

See more details on using hashes here.

File details

Details for the file mcp_pinot_server-3.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mcp_pinot_server-3.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3da6aa1a5ce4f3ef15bf37156ae8813e556111f9b3b3cef271b966588b271145
MD5 68574b7f4f62c152a84b20f98bfc35cb
BLAKE2b-256 80514a9500daa6d3b69a198de310b7e967d6aabe46f7c0bd1f459726cef1a16d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page