Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
68 changes: 68 additions & 0 deletions .github/workflows/release-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Use Trusted Publishing to stage Python packages through GitHub Actions (GHA) to the Python Package Index (PyPI).
name: "Release: Python package"

on:

# Build and publish packages when running a release.
push:
tags:
- '*'

# Build packages on each pull request for validation purposes.
pull_request:

# Build packages each night for validation purposes.
schedule:
- cron: '0 4 * * *'

# Allow the job to be triggered manually.
workflow_dispatch:

jobs:
build-and-publish:
name: "Build and publish to PyPI"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ["ubuntu-latest"]
python-version: ["3.13"]
env:
OS_TYPE: ${{ matrix.os }}
PYTHON_VERSION: ${{ matrix.python-version }}

# Trusted publishing.
# Specifying a GitHub environment is optional, but strongly encouraged.
environment: pypi
# IMPORTANT: This permission is mandatory for Trusted Publishing.
permissions:
id-token: write

steps:
- name: Acquire sources
uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
cache-dependency-glob: |
pyproject.toml
cache-suffix: ${{ matrix.python-version }}
enable-cache: true
version: "latest"

- name: Build package
run: |
uv build

- name: Publish package to TestPyPI
run: |
# `uv publish` does not understand `--skip-existing`.
# https://github.com/astral-sh/uv/issues/7917
# https://github.com/astral-sh/uv/issues/12369
uvx twine upload --non-interactive --repository-url https://test.pypi.org/legacy/ --skip-existing dist/*

- name: Publish package to PyPI
if: startsWith(github.event.ref, 'refs/tags')
run: |
uv publish
79 changes: 79 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: "Tests"

on:
push:
branches: [ main ]
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

test:
name: "
Python ${{ matrix.python-version }}
"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest']
python-version: [
'3.10',
'3.13',
]
cratedb-version: [
'nightly',
]
Comment on lines +20 to +30
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Consider expanding the Python version matrix for comprehensive compatibility testing.

The PR summary mentions support for Python 3.10 through 3.13, but the test matrix only includes 3.10 and 3.13. Adding 3.11 and 3.12 would provide more comprehensive coverage and ensure compatibility across all supported versions.

python-version: [
  '3.10',
+  '3.11',
+  '3.12',
  '3.13',
]

🌐 Web query:

What are the active maintenance status of Python 3.10, 3.11, 3.12, and 3.13 versions?

💡 Result:

As of May 10, 2025, the maintenance statuses for Python versions 3.10, 3.11, 3.12, and 3.13 are as follows:

  • Python 3.10: Released on October 4, 2021, Python 3.10 has completed its active support phase and is now in the security support phase. This means it receives only security updates and no new features or general bug fixes. Security updates are provided irregularly in source-only form until October 2026. (peps.python.org)

  • Python 3.11: Released on October 24, 2022, Python 3.11 has also completed its active support phase and is now in the security support phase. Similar to Python 3.10, it receives only security updates in source-only form until October 2027. (endoflife.date)

  • Python 3.12: Released on October 2, 2023, Python 3.12 is currently in its active support phase, which includes regular bug fixes and security updates. Active support is scheduled to end on April 2, 2025, after which it will enter the security support phase, receiving only security updates until October 2, 2028. (peps.python.org)

  • Python 3.13: Released on October 7, 2024, Python 3.13 is the latest stable release and is currently in its active support phase, receiving regular updates and new features. Active support is scheduled to end on October 1, 2026, after which it will enter the security support phase, receiving only security updates until October 10, 2029. (endoflife.date)

For the most current information on Python release schedules and support phases, you can refer to the official Python website or the Python Enhancement Proposals (PEPs) related to release schedules.

Citations:


Include Python 3.11 and 3.12 in the CI test matrix

All supported versions (3.10–3.13) are still receiving maintenance—3.10 and 3.11 in security-only support, 3.12 and 3.13 in active support—so we should validate compatibility across the full range.

  • File: .github/workflows/tests.yml (lines 20–30)
  • Update the python-version matrix:
 python-version: [
   '3.10',
+  '3.11',
+  '3.12',
   '3.13',
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
strategy:
fail-fast: false
matrix:
os: ['ubuntu-latest']
python-version: [
'3.10',
'3.13',
]
cratedb-version: [
'nightly',
]
python-version: [
'3.10',
+ '3.11',
+ '3.12',
'3.13',
]
🤖 Prompt for AI Agents (early access)
In .github/workflows/tests.yml around lines 20 to 30, the python-version matrix
currently includes only 3.10 and 3.13, missing 3.11 and 3.12. To ensure
comprehensive compatibility testing across all supported Python versions, add
'3.11' and '3.12' to the python-version list in the matrix section.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@surister: What do you think about it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3.10-3.13 is my range 🔥🔥


env:
OS: ${{ matrix.os }}
PYTHON: ${{ matrix.python-version }}
UV_SYSTEM_PYTHON: true

services:
cratedb:
image: crate/crate:${{ matrix.cratedb-version }}
ports:
- 4200:4200
- 5432:5432
env:
CRATE_HEAP_SIZE: 4g

steps:

- name: Acquire sources
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
cache-dependency-glob: |
pyproject.toml
cache-suffix: ${{ matrix.python-version }}
enable-cache: true
version: "latest"

- name: Set up project
run: |
uv pip install --editable='.[all,develop,test]'
- name: Run linter and software tests
run: poe check

# https://github.com/codecov/codecov-action
- name: Upload coverage results to Codecov
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
env_vars: OS,PYTHON
fail_ci_if_error: true
13 changes: 13 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CrateDB MCP changelog

## Unreleased

## v0.0.1 - 2025-05-xx
- Project: Established project layout
- Features: First working version
- Packaging: Adjusted package dependencies for interoperability
- Packaging: Added basic CLI entry point and server launcher `cratedb-mcp`
- Documentation: Show a simple Claude Desktop configuration
- MCP documentation: Add reference to medium-sized llms.txt context file
- Boilerplate: Added software tests and CI configuration
- Documentation: Added development sandbox section
48 changes: 48 additions & 0 deletions DEVELOP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Development documentation

## Sandbox

Use those commands to set up a development sandbox and install the
project in editable mode.
```shell
git clone https://github.com/crate/cratedb-mcp
cd cratedb-mcp
uv venv --python 3.13 --seed .venv
source .venv/bin/activate
uv pip install --upgrade --editable='.[develop,test]'
```

## Software tests

The project uses the [poethepoet] task runner, which provides convenience entry
points for invoking linters and software tests. The top-level one-shot command
will invoke both and is also used on CI/GHA.
```shell
poe check
```

To invoke individual software tests for working on the spot, use a
traditional `pytest` invocation. Examples:
```shell
pytest --no-cov tests/test_knowledge.py
```
```shell
pytest --no-cov -k query
```

## Release

The project uses [versioningit] so you don't need to do any version bumping
within files because the version number will be derived from the Git tag.

However, you need to designate the new release within the [CHANGES.md](./CHANGES.md)
file, and commit it. The release procedure currently looks like this:
```shell
git commit -m 'Release v0.0.1'
git tag v0.0.1
git push && git push --tags
```


[poethepoet]: https://pypi.org/project/poethepoet/
[versioningit]: https://pypi.org/project/versioningit/
40 changes: 29 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# CrateDB MCP Server

[![Bluesky][badge-bluesky]][target-bluesky]
[![Release Notes][badge-release-notes]][project-release-notes]

[![Status][badge-status]][target-project]
[![License][badge-license]][target-license]
[![CI][badge-ci]][project-ci]
[![Coverage][badge-coverage]][project-coverage]

» [Documentation]
| [Releases]
Expand Down Expand Up @@ -43,23 +47,36 @@ our recommendation.

# Install
```shell
uv pip install --upgrade git+https://github.com/crate/cratedb-mcp
uv tool install --upgrade git+https://github.com/crate/cratedb-mcp
```
Note: We recommend to use `uv tool install` to install the program "user"-wide
into your environment so you can use it across your terminal or MCP client
sessions like Claude.

# Configure

Configure the `CRATEDB_MCP_HTTP_URL` environment variable to match your CrateDB instance.
For example, when connecting to CrateDB Cloud, use a value like
`https://admin:[email protected]:4200/`.
When connecting to CrateDB on localhost, use `http://localhost:4200/`.
```shell
export CRATEDB_MCP_HTTP_URL=https://example.aks1.westeurope.azure.cratedb.net:4200
export CRATEDB_MCP_HTTP_URL="http://localhost:4200/"
```
```shell
export CRATEDB_MCP_HTTP_URL="https://example.aks1.westeurope.azure.cratedb.net:4200"
```

# Usage
Start MCP server with `stdio` transport (default).
```shell
CRATEDB_MCP_TRANSPORT=stdio uv run cratedb-mcp
CRATEDB_MCP_TRANSPORT=stdio cratedb-mcp
```
Start MCP server with `sse` transport.
```shell
CRATEDB_MCP_TRANSPORT=sse uv run cratedb-mcp
CRATEDB_MCP_TRANSPORT=sse cratedb-mcp
```
Note: If you are unable to use `uv tool install`, please use
`uv run cratedb-mcp` to acquire and run the package ephemerally.

# Simple Claude configuration
To use the MCP version within Claude Desktop, you can use the following configuration:
Expand All @@ -79,13 +96,10 @@ To use the MCP version within Claude Desktop, you can use the following configur
}
```

You might have to change `CRATEDB_MCP_HTTP_URL` to match your CrateDB instance. For example, when connecting to CrateDB Cloud, use a value like https://admin:[email protected]:4200/.


NB: You can use `uv tool install` to install the program "system"-wide,
so you can use it across your terminal or Claude sessions. In this case,
omit the `uv run` prefix displayed above.
## Development

To learn how to set up a development sandbox, see the [development documentation](./DEVELOP.md).


[CrateDB]: https://cratedb.com/database
Expand All @@ -99,11 +113,15 @@ omit the `uv run` prefix displayed above.
[Source code]: https://github.com/crate/cratedb-mcp
[Releases]: https://github.com/surister/cratedb-mcp/releases

[badge-ci]: https://github.com/crate/cratedb-mcp/actions/workflows/tests.yml/badge.svg
[badge-coverage]: https://codecov.io/gh/crate/cratedb-mcp/branch/main/graph/badge.svg
[badge-bluesky]: https://img.shields.io/badge/Bluesky-0285FF?logo=bluesky&logoColor=fff&label=Follow%20%40CrateDB
[badge-issues]: https://img.shields.io/github/issues/crate/cratedb-mcp
[badge-license]: https://img.shields.io/github/license/crate/cratedb-mcp
[badge-release-notes]: https://img.shields.io/badge/Release%20Notes-v0.0.0-blue
[badge-release-notes]: https://img.shields.io/github/release/crate/cratedb-mcp?label=Release+Notes
[badge-status]: https://img.shields.io/badge/status--alpha-orange
[project-ci]: https://github.com/crate/cratedb-mcp/actions/workflows/tests.yml
[project-coverage]: https://app.codecov.io/gh/crate/cratedb-mcp
[project-release-notes]: https://github.com/crate/cratedb-mcp/releases
[target-bluesky]: https://bsky.app/search?q=cratedb
[target-license]: https://github.com/crate/cratedb-mcp/blob/main/LICENSE
[target-project]: https://github.com/crate/cratedb-mcp
Expand Down
12 changes: 5 additions & 7 deletions cratedb_mcp/__main__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
import os

import httpx

from mcp.server.fastmcp import FastMCP

from .constants import Queries, DOCUMENTATION_INDEX
from .knowledge import DOCUMENTATION_INDEX, Queries
from .settings import HTTP_URL

mcp = FastMCP("cratedb-mcp")


def query_cratedb(query: str) -> list[dict]:
return httpx.post(f'{os.getenv("CRATEDB_MCP_HTTP_URL")}/_sql', json={'stmt': query}).json()
return httpx.post(f'{HTTP_URL}/_sql', json={'stmt': query}).json()


@mcp.tool(description="Send a SQL query to CrateDB, only 'SELECT' queries are allows, queries that"
" modify data, columns or are otherwise deemed un-safe are rejected.")
def query_sql(query: str):
if not 'select' in query.lower():
if 'select' not in query.lower():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: for future reference, this is very low effort way to avoid un-safe queries and very easy to bypass. We mostly depend on the LLM to understand the description, checking if 'select' is present is weak.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think you've seen GH-11 already, which aims to make it a bit stronger.

raise ValueError('Only queries that have a SELECT statement are allowed.')
return query_cratedb(query)

Expand All @@ -29,7 +27,7 @@ def get_cratedb_documentation_index():
' Only used to download CrateDB docs.')
def fetch_cratedb_docs(link: str):
"""Fetches a CrateDB documentation link from GitHub raw content."""
if not 'https://raw.githubusercontent.com/crate/crate/' in link:
if 'https://raw.githubusercontent.com/crate/crate/' not in link:
raise ValueError('Only github cratedb links can be fetched.')
return httpx.get(link).text

Expand Down
3 changes: 2 additions & 1 deletion cratedb_mcp/cli.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import os
import typing as t

from cratedb_mcp.__main__ import mcp

Expand All @@ -11,4 +12,4 @@ def main():
if transport not in ("stdio", "sse"):
raise ValueError(f"Unsupported transport: '{transport}'. Please use one of 'stdio', 'sse'.")
logger.info(f"Starting CrateDB MCP server using transport '{transport}'")
mcp.run(transport=transport)
mcp.run(transport=t.cast(t.Literal["stdio", "sse"], transport))
2 changes: 2 additions & 0 deletions cratedb_mcp/constants.py → cratedb_mcp/knowledge.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# ruff: noqa: E501

class Queries:
TABLES_METADATA = """
WITH partitions_health AS (SELECT table_name,
Expand Down
3 changes: 3 additions & 0 deletions cratedb_mcp/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import os

HTTP_URL: str = os.getenv("CRATEDB_MCP_HTTP_URL", "http://localhost:4200")
Loading