Skip to content

Commit 52f1b98

Browse files
authored
Migrate to fastmcp - it's receiving more regular updates (#59)
1. Also >= python 3.10 2. Allow for configurable transports 3. Add comprehensive test suite using mcp client as well
1 parent ac3d5b5 commit 52f1b98

File tree

8 files changed

+1006
-219
lines changed

8 files changed

+1006
-219
lines changed

.github/workflows/ci.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646

4747
docker-build:
4848
runs-on: ubuntu-latest
49-
49+
5050
steps:
5151
- name: Checkout repository
5252
uses: actions/checkout@v4
@@ -67,7 +67,11 @@ jobs:
6767
- name: Test Docker image import
6868
run: |
6969
docker run --rm mcp-clickhouse:test python -c "import mcp_clickhouse; print('✅ MCP ClickHouse Docker image works!')"
70-
70+
7171
- name: Test Docker image default command
7272
run: |
73-
timeout 10s docker run --rm mcp-clickhouse:test || [ $? = 124 ] && echo "✅ Docker container starts successfully"
73+
timeout 10s docker run --rm \
74+
-e CLICKHOUSE_HOST=localhost \
75+
-e CLICKHOUSE_USER=default \
76+
-e CLICKHOUSE_PASSWORD="" \
77+
mcp-clickhouse:test || [ $? = 124 ] && echo "✅ Docker container starts successfully"

mcp_clickhouse/main.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from .mcp_server import mcp
2+
from .mcp_env import get_config
23

34

45
def main():
5-
mcp.run()
6+
config = get_config()
7+
transport = config.mcp_server_transport
8+
mcp.run(transport=transport)
69

710

811
if __name__ == "__main__":

mcp_clickhouse/mcp_env.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ClickHouseConfig:
2929
CLICKHOUSE_SEND_RECEIVE_TIMEOUT: Send/receive timeout in seconds (default: 300)
3030
CLICKHOUSE_DATABASE: Default database to use (default: None)
3131
CLICKHOUSE_PROXY_PATH: Path to be added to the host URL. For instance, for servers behind an HTTP proxy (default: None)
32+
CLICKHOUSE_MCP_SERVER_TRANSPORT: MCP server transport method - "stdio", "http", or "sse" (default: stdio)
3233
"""
3334

3435
def __init__(self):
@@ -97,11 +98,26 @@ def send_receive_timeout(self) -> int:
9798
Default: 300 (ClickHouse default)
9899
"""
99100
return int(os.getenv("CLICKHOUSE_SEND_RECEIVE_TIMEOUT", "300"))
100-
101+
101102
@property
102103
def proxy_path(self) -> str:
103104
return os.getenv("CLICKHOUSE_PROXY_PATH")
104105

106+
@property
107+
def mcp_server_transport(self) -> str:
108+
"""Get the MCP server transport method.
109+
110+
Valid options: "stdio", "http", "sse"
111+
Default: "stdio"
112+
"""
113+
transport = os.getenv("CLICKHOUSE_MCP_SERVER_TRANSPORT", "stdio").lower()
114+
valid_transports = "stdio", "http", "streamable-http", "sse"
115+
if transport not in valid_transports:
116+
raise ValueError(
117+
f"Invalid transport '{transport}'. Valid options: {', '.join(valid_transports)}"
118+
)
119+
return transport
120+
105121
def get_client_config(self) -> dict:
106122
"""Get the configuration dictionary for clickhouse_connect client.
107123
@@ -123,7 +139,7 @@ def get_client_config(self) -> dict:
123139
# Add optional database if set
124140
if self.database:
125141
config["database"] = self.database
126-
142+
127143
if self.proxy_path:
128144
config["proxy_path"] = self.proxy_path
129145

mcp_clickhouse/mcp_server.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import clickhouse_connect
88
from clickhouse_connect.driver.binding import format_query_value
99
from dotenv import load_dotenv
10-
from mcp.server.fastmcp import FastMCP
10+
from fastmcp import FastMCP
1111
from dataclasses import dataclass, field, asdict, is_dataclass
1212

1313
from mcp_clickhouse.mcp_env import get_config
@@ -59,14 +59,14 @@ class Table:
5959

6060
load_dotenv()
6161

62-
deps = [
63-
"clickhouse-connect",
64-
"python-dotenv",
65-
"uvicorn",
66-
"pip-system-certs",
67-
]
68-
69-
mcp = FastMCP(MCP_SERVER_NAME, dependencies=deps)
62+
mcp = FastMCP(
63+
name=MCP_SERVER_NAME,
64+
dependencies=[
65+
"clickhouse-connect",
66+
"python-dotenv",
67+
"pip-system-certs",
68+
],
69+
)
7070

7171

7272
def result_to_table(query_columns, result) -> List[Table]:
@@ -93,14 +93,19 @@ def list_databases():
9393
logger.info("Listing all databases")
9494
client = create_clickhouse_client()
9595
result = client.command("SHOW DATABASES")
96-
logger.info(f"Found {len(result) if isinstance(result, list) else 1} databases")
97-
return result
96+
97+
# Convert newline-separated string to list and trim whitespace
98+
if isinstance(result, str):
99+
databases = [db.strip() for db in result.strip().split("\n")]
100+
else:
101+
databases = [result]
102+
103+
logger.info(f"Found {len(databases)} databases")
104+
return json.dumps(databases)
98105

99106

100107
@mcp.tool()
101-
def list_tables(
102-
database: str, like: Optional[str] = None, not_like: Optional[str] = None
103-
):
108+
def list_tables(database: str, like: Optional[str] = None, not_like: Optional[str] = None):
104109
"""List available ClickHouse tables in a database, including schema, comment,
105110
row count, and column count."""
106111
logger.info(f"Listing tables in database '{database}'")
@@ -165,9 +170,7 @@ def run_select_query(query: str):
165170
}
166171
return result
167172
except concurrent.futures.TimeoutError:
168-
logger.warning(
169-
f"Query timed out after {SELECT_QUERY_TIMEOUT_SECS} seconds: {query}"
170-
)
173+
logger.warning(f"Query timed out after {SELECT_QUERY_TIMEOUT_SECS} seconds: {query}")
171174
future.cancel()
172175
# Return a properly structured response for timeout errors
173176
return {

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ description = "An MCP server for ClickHouse."
55
readme = "README.md"
66
license = "Apache-2.0"
77
license-files = ["LICENSE"]
8-
requires-python = ">=3.13"
8+
requires-python = ">=3.10"
99
dependencies = [
10-
"mcp[cli]>=1.3.0",
10+
"fastmcp>=2.0.0",
1111
"python-dotenv>=1.0.1",
12-
"uvicorn>=0.34.0",
1312
"clickhouse-connect>=0.8.16",
1413
"pip-system-certs>=4.0",
1514
]
@@ -23,7 +22,8 @@ Home = "https://github.com/ClickHouse/mcp-clickhouse"
2322
[project.optional-dependencies]
2423
dev = [
2524
"ruff",
26-
"pytest"
25+
"pytest",
26+
"pytest-asyncio"
2727
]
2828

2929
[tool.hatch.build.targets.wheel]

0 commit comments

Comments
 (0)