Skip to main content
Glama
ys1173

duckdb-iceberg-mcp

by ys1173

duckdb-iceberg-mcp

An MCP server that lets AI assistants query Apache Iceberg tables on S3 via AWS Glue Data Catalog. DuckDB is the embedded query engine — Apache Arrow columnar format, vectorized execution, direct S3 reads with no data movement.

Built on the official Python MCP SDK.

This MCP server is complementary to telemetry-iceberg-adaptor, which ingests telemetry data into Apache Iceberg. Use that project to write data and this project to query it through MCP-enabled AI clients.

Architecture

                                              +----------------------+
                                              | MCP Clients          |
                                              | - OpenAI Codex       |
                                              | - Claude Desktop     |
                                              | - OpenCode           |
                                              | - LibreChat          |
                                              +----------------------+
                                                        |
                                                        | MCP Protocol (tools/list · tools/call)
                                                        v
            +--------------------------------------------------------------------------------------------+
            | duckdb-iceberg-mcp                                                                         |
            |                                                                                            |
            | +----------------------------------------------------------------------------------------+ |
            | | MCP Protocol Layer                                                                     | |
            | | stdio · Streamable HTTP · SSE                                                          | |
            | | JWT auth · write guard · row/char limits                                               | |
            | +----------------------------------------------------------------------------------------+ |
            |                                          <-->                                              |
            | +----------------------------------------------------------------------------------------+ |
            | | ⚡ DuckDB                                                                               | |
            | | Apache Arrow columnar engine                                                           | |
            | | Vectorized execution · Direct S3 reads                                                 | |
            | | httpfs · iceberg · aws extensions                                                      | |
            | +----------------------------------------------------------------------------------------+ |
            +--------------------------------------------------------------------------------------------+
                          |                                                  |
                          | httpfs extension                                 | boto3
                          | columnar Parquet reads                           | metadata · schema
                          |                                                  | Iceberg manifest resolution
                          v                                                  v
            +--------------------------------------------------------------------------------------------+
            | AWS                                                                                        |
            | +-------------- Amazon S3 --------------+  +------------ AWS Glue Data Catalog ----------+ |
            | | Apache Iceberg tables                 |  | Databases · Tables · Schema                 | |
            | | Parquet data files                    |  | Iceberg metadata                            | |
            | +---------------------------------------+  +---------------------------------------------+ |
            +--------------------------------------------------------------------------------------------+

Related MCP server: DuckDB MCP Server

Features

  • Query Iceberg tables on S3 via AWS Glue Data Catalog

  • Three transports: stdio, Streamable HTTP, SSE

  • Easy mode — single-tenant, optional static API key, no IdP required

  • Full mode — JWT/JWKS token validation (Auth0, Cognito, Keycloak, Okta, …)

  • Writes disabled by default; only available in full mode with explicit opt-in

  • Configurable row and character limits to prevent runaway responses

Requirements

  • Python 3.12+

  • AWS credentials with access to Glue Data Catalog and S3

Installation

git clone <repo>
cd duckdb-iceberg-mcp
python -m venv .venv
source .venv/bin/activate
pip install -e .

Quick Start

stdio (local AI client)

Copy the example config and fill in your AWS details:

cp config/easy.env.example .env
# .env
MCP_MODE=easy
MCP_TRANSPORT=stdio
CATALOG_TYPE=glue
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...

Run directly:

duckdb-iceberg-mcp

Or configure in your MCP client (Claude Desktop, OpenAI Codex):

{
  "mcpServers": {
    "duckdb-iceberg-mcp": {
      "command": "/path/to/.venv/bin/duckdb-iceberg-mcp",
      "env": {
        "MCP_MODE": "easy",
        "CATALOG_TYPE": "glue",
        "AWS_REGION": "us-east-1",
        "AWS_ACCESS_KEY_ID": "AKIA...",
        "AWS_SECRET_ACCESS_KEY": "..."
      }
    }
  }
}

Streamable HTTP (network clients, e.g. LibreChat in Docker)

MCP_MODE=easy
MCP_TRANSPORT=http
MCP_HOST=0.0.0.0
MCP_PORT=8766
MCP_ALLOWED_HOSTS=host.docker.internal:*,localhost:*
CATALOG_TYPE=glue
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
env $(grep -v '^#' .env | grep -v '^$' | xargs) .venv/bin/duckdb-iceberg-mcp

MCP client URL: http://localhost:8766/mcp

LibreChat (librechat.yaml):

mcpServers:
  duckdb-iceberg-mcp:
    type: streamable-http
    url: 'http://host.docker.internal:8766/mcp'
    timeout: 60000
    initTimeout: 20000

OpenAI Codex: add via the Codex UI — Streamable HTTP, URL http://localhost:8766/mcp.


AWS Authentication

Configure credentials using one of these methods (key/secret takes priority if both are set):

Method

Env vars

Explicit credentials

AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY

Named profile

AWS_PROFILE=my-profile

Default chain

Set neither — falls back to env vars, ~/.aws/credentials, instance role


MCP Tools

list_tables(database?)

Lists Glue catalog tables. Optionally filter by database name.

describe_table(table_name)

Returns column names, types, and partition keys. Use database.table format.

glue_table(table_name)

Registers a Glue Iceberg table as a queryable DuckDB view. Required for tables where data files live outside the Glue-registered table root (a common layout with shared S3 prefixes).

glue_table('mydb.mytable')
→ Registered view 'mydb__mytable'. Query with: SELECT * FROM mydb__mytable

query_lakehouse(sql)

Executes a SQL query against registered views or direct S3 paths (read_parquet(), iceberg_scan()).


Configuration Reference

Variable

Default

Description

MCP_MODE

easy

easy or full

MCP_TRANSPORT

stdio

stdio, http (Streamable HTTP), sse

MCP_HOST

127.0.0.1

Bind address for HTTP/SSE

MCP_PORT

8000

Port for HTTP/SSE

MCP_ALLOWED_HOSTS

(empty)

Comma-separated allowed Host headers (e.g. host.docker.internal:*,localhost:*). Empty = SDK default

MCP_API_KEY

(empty)

Static bearer token for easy mode HTTP. Empty = no auth

JWKS_URL

(required in full mode)

JWKS endpoint for JWT validation

JWT_AUDIENCE

duckdb-iceberg-mcp

Expected aud claim in JWTs

CATALOG_TYPE

glue

Only glue supported

AWS_REGION

us-east-1

AWS region

AWS_PROFILE

(empty)

Named AWS profile

AWS_ACCESS_KEY_ID

(empty)

AWS access key

AWS_SECRET_ACCESS_KEY

(empty)

AWS secret key

WRITE_MODE

disabled

disabled or enabled. Always disabled in easy mode

MAX_ROWS

250

Maximum rows returned per query

MAX_CHARS

40000

Maximum characters in a query response


Full Mode (JWT Auth)

Full mode validates a JWT bearer token on every request. All authenticated users share one DuckDB connection — per-user session isolation is deferred to a future release.

MCP_MODE=full
MCP_TRANSPORT=http
MCP_HOST=0.0.0.0
MCP_PORT=8766
JWKS_URL=https://your-idp.example.com/.well-known/jwks.json
JWT_AUDIENCE=duckdb-iceberg-mcp
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...

The client passes a JWT as Authorization: Bearer <token>. The server validates it against the JWKS endpoint. Any IdP that issues standard JWTs works (Auth0, AWS Cognito, Keycloak, Okta).

See config/full.env.example for a full template.


Smoke Test

Run a quick end-to-end check against your real Glue catalog:

cp config/easy.env.example .env  # fill in AWS credentials
.venv/bin/python scripts/smoke_test.py

Run Tests

pip install -e ".[dev]"
pytest

Available Tools

4 tools
describe_tableB

Describe a table's schema. Use 'database.table' format for Glue.

ParametersJSON Schema
NameRequiredDescriptionDefault
table_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, and the description only states the purpose. It does not disclose behavioral traits beyond being a read operation, such as error handling or required permissions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no wasted words. The purpose and a key usage hint are front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has only one parameter and an output schema, reducing the need for extensive description. However, without annotations, the description lacks safety and error context, making it minimally complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema coverage is 0%, so the description must compensate. It adds a formatting hint for table_name, which adds meaning beyond the schema's title, but does not provide full semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states it describes a table's schema, which is a specific verb+resource. It does not explicitly differentiate from sibling tools like glue_table, but the purpose is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a formatting hint for the parameter ('Use 'database.table' format for Glue'), but does not provide guidance on when to use this tool versus siblings or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

glue_tableA

Register a Glue Iceberg table as a queryable DuckDB view.

Resolves the actual data files from the Iceberg manifest (handles tables where data files live outside the Glue-registered table root).

Usage: glue_table('database.table_name') After calling this, query with: SELECT * FROM database__table_name

ParametersJSON Schema
NameRequiredDescriptionDefault
table_nameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so description carries full burden. It discloses that the tool resolves actual data files from Iceberg manifest and handles non-standard data locations. It also indicates the side effect of creating a view. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is six lines, each adding unique value: main action, behavioral details, usage syntax, and post-call query example. No redundant or filler content.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of registering a view and the presence of an output schema (though not shown), the description covers the essential behavioral and usage aspects. It could mention what the tool returns, but output schema likely fills that gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by specifying the parameter format 'database.table_name'. The input schema only has a title 'Table Name', so description adds significant meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool registers a Glue Iceberg table as a queryable DuckDB view, with specific verb 'Register' and resource 'Glue Iceberg table'. It also explains it resolves data files from Iceberg manifest, distinguishing it from siblings like describe_table or list_tables.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage syntax 'glue_table('database.table_name')' and post-call query example 'SELECT * FROM database__table_name'. It implicitly guides when to use this tool, but does not explicitly state when not to use or mention alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tablesA

List available tables. Optionally filter by database name.

ParametersJSON Schema
NameRequiredDescriptionDefault
databaseNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It states the main action and filtering option but does not disclose any behavioral traits such as permissions, performance implications, or edge cases (e.g., empty result). It is minimally adequate for a simple listing tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise with a single sentence that front-loads the main action. Every word earns its place, with no superfluous text.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simplicity (1 optional param, output schema exists), the description is fairly complete. It covers the core functionality and filtering. However, it could clarify the scope of 'tables' (e.g., database tables versus other entities) to enhance completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema coverage is 0%, so the description must add meaning. It explains that the 'database' parameter is optional and filters results, which adds value beyond the schema. However, it does not specify the expected format or behavior when the parameter is empty.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('List available tables') and resource, and mentions optional filtering. It is distinct from sibling tools like describe_table and query_lakehouse.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives like describe_table or query_lakehouse. Implicit usage context is minimal.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_lakehouseA

Execute a SQL query. Use read_parquet() or iceberg_scan() for S3 paths, or use the glue_table tool first to register a Glue table by name.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It only states 'Execute a SQL query' without detailing important traits like whether it is read-only, destructive, authentication requirements, rate limits, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, with two sentences that front-load the purpose and provide actionable tips. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has a single parameter and an output schema (so return format need not be described), the description is fairly complete. It covers the main action and usage hints, but could add minor details about potential errors or timeouts.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has one parameter (sql) with no description, but the tool description adds meaning by specifying it should be a SQL query and suggests using certain functions for different data sources. This compensates for the lack of schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool executes a SQL query, which is the primary action. It differentiates from siblings by suggesting a workflow involving glue_table for Glue tables, but could be more explicit about what distinguishes this tool from similar ones.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides usage guidance: use read_parquet() or iceberg_scan() for S3 paths, or use glue_table first for Glue tables. This gives context on how to use the tool effectively, though it does not explicitly state when not to use it or list alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A3.7/5.0
Disambiguation5/5

Each tool has a distinct purpose: describe_table shows schema, glue_table registers a view, list_tables enumerates tables, and query_lakehouse executes SQL. No overlap in functionality.

Naming Consistency3/5

Most names follow verb_noun (describe_table, list_tables, query_lakehouse), but 'glue_table' is a noun_noun that breaks the pattern, introducing inconsistency.

Tool Count5/5

Four tools cover the essential operations for an Iceberg query server: listing, describing, registering, and querying tables. This is minimal but well-scoped for the stated domain.

Completeness3/5

The server supports read and schema-discovery operations but lacks write or lifecycle management tools (e.g., create, delete, update). This is acceptable for a query-focused tool but leaves gaps for full table management.

Maintenance

ActivityInactive
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    A Model Context Protocol server that provides a SQL interface for querying and managing Apache Iceberg tables through Claude desktop, allowing natural language interaction with Iceberg data lakes.
    1
    8
  • A
    license
    Not graded
    quality
    D
    maintenance
    A Model Context Protocol server implementation that connects AI assistants to DuckDB, enabling them to query and analyze data from various sources including CSV, Parquet, JSON, and cloud storage through SQL.
    18
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI assistants and IDEs to execute SQL queries on local DuckDB databases, in-memory databases, or cloud-stored databases with support for flexible connections and configurable result limits.
    1
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to query S3 data lakes using natural language, with support for CSV, JSON, Parquet and tools for data discovery, analysis, and metadata exploration.
    1
    MIT

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/ys1173/duckdb-iceberg-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server