singlestore-mcp-server
# singlestore-mcp-server
A local MCP server for SingleStore, meant to run in **stdio** mode from VS
Code. It's built on two official SDKs rather than reimplementing protocol or
driver code:
- [`mcp`](https://github.com/modelcontextprotocol/python-sdk) — the official
Model Context Protocol Python SDK. It handles the stdio transport, JSON-RPC
framing and tool-schema generation (`FastMCP`).
- [`singlestoredb`](https://github.com/singlestore-labs/singlestoredb-python)
— SingleStore's own official Python client. It handles the actual database
connection.
Everything in [`src/singlestore_mcp`](src/singlestore_mcp) is glue: a
connection wrapper ([`db.py`](src/singlestore_mcp/db.py)) and a set of MCP
tools ([`server.py`](src/singlestore_mcp/server.py)), including first-class
tools for **Pipelines** (SingleStore's mechanism for continuously loading
data from S3/Kafka/Azure/GCS/filesystem sources), which the official
`mcp-server-singlestore` package does not expose as dedicated tools.
Because it connects over the plain MySQL wire protocol via host/port/user/
password, it works identically against **SingleStore Helios (cloud) and
self-managed SingleStore clusters** — there's no dependency on the
Management API or browser OAuth.
## Tools
General:
- `run_sql` — run any SQL statement
- `list_databases`, `list_tables`, `describe_table`
Pipelines:
- `list_pipelines`, `pipeline_status`, `get_pipeline_ddl`
- `create_pipeline`, `alter_pipeline` (take a full statement — pipeline
syntax varies too much by source/format to model as parameters)
- `start_pipeline` (background or `FOREGROUND`, with optional batch limit)
- `stop_pipeline`, `drop_pipeline`, `test_pipeline`
## Setup
Uses [`uv`](https://docs.astral.sh/uv/) to manage the Python environment,
pinned to Python 3.12 via [`.python-version`](.python-version):
```bash
cd singlestore-mcp-server
uv sync
```
This creates `.venv/` and installs everything from `uv.lock`.
Then give the server your SingleStore credentials. Supported variables (see
[`.env.example`](.env.example)):
| Variable | Required | Notes |
|---|---|---|
| `SINGLESTORE_HOST` | yes* | |
| `SINGLESTORE_PORT` | no | default `3306` |
| `SINGLESTORE_USER` | no | default `root` |
| `SINGLESTORE_PASSWORD` | no | |
| `SINGLESTORE_DATABASE` | no | default database for queries |
| `SINGLESTORE_SSL_DISABLED` | no | set `true` for a self-managed cluster without TLS configured |
| `SINGLESTORE_URL` | yes* | alternative to the above: `user:password@host:port/database` |
\* set either `SINGLESTORE_HOST` or `SINGLESTORE_URL`.
How you wire these in depends on which MCP client you're using — the two
below are unrelated mechanisms, use whichever matches your setup.
### Claude Code (in VS Code, or the terminal)
There are two ways to register the server with Claude Code — pick one.
They're independent; you don't need both.
#### Option A: project-scoped, via `.mcp.json` (already done)
[`.mcp.json`](.mcp.json) at the project root already registers the server,
scoped to this project only:
```json
{
"mcpServers": {
"singlestore": {
"command": "uv",
"args": ["run", "--directory", ".", "singlestore-mcp-server"],
"env": {
"SINGLESTORE_HOST": "${SINGLESTORE_HOST}",
"SINGLESTORE_USER": "${SINGLESTORE_USER}",
"SINGLESTORE_PASSWORD": "${SINGLESTORE_PASSWORD}",
"SINGLESTORE_DATABASE": "${SINGLESTORE_DATABASE:-}",
"SINGLESTORE_SSL_DISABLED": "${SINGLESTORE_SSL_DISABLED:-false}"
}
}
}
}
```
Claude Code doesn't have an interactive "prompt me for the secret" flow the
way VS Code Copilot Chat does. Instead, the `${VAR}` syntax above is expanded
from **your actual shell/OS environment** when Claude Code starts, so the
value never has to live in this tracked file — set the real variables
(Windows: System Properties → Environment Variables, or
`setx SINGLESTORE_PASSWORD hunter2`, then restart the terminal/VS Code so it
inherits the change) and `.mcp.json` stays safe to commit as-is.
Once the env vars are set, open **this folder** in VS Code with the Claude
Code extension (or run `claude` from a terminal cd'd into this folder) and
the `singlestore` server connects automatically — there's no separate mode
toggle to flip. Because the registration lives in this folder's `.mcp.json`,
it's only picked up when Claude Code's working directory is this project;
opening a different folder won't see it.
#### Option B: user-scoped, via `claude mcp add` (available everywhere)
To make the server available from *any* project — not just when this folder
is open — register it once at the user level instead, from a terminal (the
CLI reads your already-exported `SINGLESTORE_*` variables and bakes their
current values into the stored config, since `claude mcp add` doesn't do the
`${VAR}` expansion `.mcp.json` does):
```bash
claude mcp add singlestore -s user \
-e SINGLESTORE_HOST="$SINGLESTORE_HOST" \
-e SINGLESTORE_USER="$SINGLESTORE_USER" \
-e SINGLESTORE_PASSWORD="$SINGLESTORE_PASSWORD" \
-- uv run --directory "C:\path\to\singlestore-mcp-server" singlestore-mcp-server
```
(Swap `$SINGLESTORE_HOST` etc. for literal values on Windows PowerShell,
where `$VAR` bash-expansion inside a `bash`-tool call won't apply — or just
type the real host/user/password in place of those placeholders.) If you
later rotate the password, re-run the same command — `claude mcp add`
overwrites an existing entry with the same name.
#### Either way
Run `/mcp` inside a Claude Code session to check the `singlestore` server's
connection status and see the tools it exposes. If you just registered it
(either option) in a session that's already running, its tools won't appear
until you restart that session — MCP servers are only loaded at startup.
### Claude Desktop
Claude Desktop (the standalone app, not Claude Code) uses a different,
app-level config file — there's no per-project `.mcp.json` support and no
`${VAR}` expansion, so credentials have to be written into the file as
literal values.
1. Open the config file for your OS (create it if it doesn't exist yet —
or in the Claude Desktop app, go to **Settings → Developer → Edit
Config**, which creates and opens it for you):
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
2. Add a `singlestore` entry to `mcpServers`, merging with whatever's
already there rather than replacing the whole file:
```json
{
"mcpServers": {
"singlestore": {
"command": "uv",
"args": [
"run",
"--directory", "C:\\Users\\norjni\\claude code\\singlestore-mcp-server",
"singlestore-mcp-server"
],
"env": {
"SINGLESTORE_HOST": "10.104.80.126",
"SINGLESTORE_USER": "admin",
"SINGLESTORE_PASSWORD": "your-actual-password-here",
"SINGLESTORE_SSL_DISABLED": "false"
}
}
}
}
```
Use an absolute path for `--directory` (Desktop doesn't run this from the
project folder the way VS Code does), and escape backslashes as `\\` on
Windows. On macOS the path would look like
`/Users/you/singlestore-mcp-server`.
3. Quit Claude Desktop completely and reopen it — config changes only take
effect on a full restart, not just closing the window.
4. Click the "Add files, connectors, and more" (**+**) control in the
message box, open **Connectors → Manage connectors**, and confirm
`singlestore` is listed and connected.
Since this file stores the password in plain text, treat it like any other
credentials file — don't commit it or share it, and rotate the password if
it ever leaks. Logs for debugging a failed connection live in
`%APPDATA%\Claude\logs\mcp-server-singlestore.log` (Windows) or
`~/Library/Logs/Claude/mcp-server-singlestore.log` (macOS).
### VS Code + GitHub Copilot Chat
If you're using Copilot Chat's own MCP support instead, [`.vscode/mcp.json`](.vscode/mcp.json)
registers the server for that. Copilot Chat *does* support an interactive
prompt via an `inputs` block + `${input:<id>}` placeholders (VS Code pops a
masked input box on first start and caches the value), which is the closest
equivalent to Claude Code's env-var approach above — see the comments in
that file. Switch Copilot Chat's mode dropdown to **Agent** for the
server's tools to show up; they're invisible in Ask/Edit mode.
## Manual smoke test
```bash
SINGLESTORE_HOST=127.0.0.1 SINGLESTORE_USER=root SINGLESTORE_PASSWORD=pw \
uv run singlestore-mcp-server
```
This starts the stdio server and blocks waiting for JSON-RPC on stdin — that
hang is expected; it means it's up. Use the MCP Inspector
(`npx @modelcontextprotocol/inspector uv run singlestore-mcp-server`)
for interactive testing instead of talking to stdin by hand.
## Example: an S3 pipeline
```
create_pipeline(create_pipeline_sql="""
CREATE PIPELINE orders_pipeline AS
LOAD DATA S3 's3://my-bucket/orders/'
CONFIG '{"region": "us-east-1"}'
CREDENTIALS '{"aws_access_key_id": "...", "aws_secret_access_key": "..."}'
INTO TABLE orders
FIELDS TERMINATED BY ','
""")
start_pipeline(pipeline_name="orders_pipeline")
pipeline_status(pipeline_name="orders_pipeline")
```
TDQS
Scored across 13 tools
Each tool targets a distinct resource or action, with clear separation between pipeline lifecycle, SQL execution, and schema introspection. Minor overlap exists between list_pipelines and pipeline_status, and run_sql can technically execute pipeline statements, but the descriptions clearly steer agents toward the dedicated tools.
Most tools follow a predictable verb_noun pattern such as create_pipeline, drop_pipeline, list_tables, and describe_table. The main deviation is pipeline_status, which would fit better as get_pipeline_status for consistency with get_pipeline_ddl.
Thirteen tools is a well-scoped size for this server's purpose. Each tool serves a clear need, covering pipeline lifecycle, query execution, and database/table introspection without unnecessary duplication.
The pipeline domain is thoroughly covered with create, alter, drop, start, stop, test, status, list, and DDL retrieval. The addition of run_sql, list_databases, list_tables, and describe_table provides a complete practical surface for working with SingleStore.