Skip to main content
Glama
Gowsi31

sql-mcp

by Gowsi31
README.md
# sql-mcp
# sql-mcp

An MCP server for read-only SQL Server access, plus a chat app (Express + React) that lets you ask
questions about your databases in plain English.

Two things live in this repo:

1. **An MCP server** ([src/index.ts](src/index.ts)) exposing `query`, `list_tables`, `describe_table`,
   and `list_databases` tools — usable from Claude Desktop, Claude Code, or any other MCP client.
2. **A standalone chat app** ([src/server.ts](src/server.ts) + [web/](web/)) that drives that same MCP
   server with an LLM (Gemini, with free OpenRouter models as a fallback), so you can just type a
   question instead of writing SQL.

See [ARCHITECTURE.md](ARCHITECTURE.md) for how it's built and why (in particular, why it talks to SQL
Server via `sqlcmd` instead of a normal Node driver).

## Prerequisites

- Node.js 18+ (20+ recommended)
- `sqlcmd` on `PATH` — ships with the [ODBC Driver 17 (or later) for SQL Server](https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server) Client SDK
- A SQL Server instance reachable from this machine (Shared Memory, Named Pipes, or TCP — `sqlcmd` handles whichever is available; no manual protocol configuration needed)

## Setup

1. Install dependencies:
   ```bash
   npm install
   cd web && npm install && cd ..
   ```
2. Create a `.env` file in the project root:
   ```bash
   SQL_SERVER=your-server-name
   SQL_DATABASE=your-database-name
   SQL_USER=sa
   SQL_PASSWORD=your-password

   GEMINI_API_KEY=your-gemini-api-key
   ```
   `GEMINI_API_KEY` is required for the chat app (get one from [Google AI Studio](https://aistudio.google.com/apikey)); the MCP server on its own doesn't need it.

3. Build:
   ```bash
   npm run build
   ```

## Running

**MCP server** (for use with an MCP client like Claude Desktop):
```bash
npm start          # runs the compiled dist/index.js
npm run dev         # runs src/index.ts directly via tsx, no build step
```

**Chat app** (two terminals):
```bash
npm run server       # backend, http://localhost:3001
cd web && npm run dev  # frontend, http://localhost:5173
```

**Quick connection sanity check:**
```bash
npm run test-connection
```

## MCP tools

| Tool | Description |
|---|---|
| `query` | Run a read-only `SELECT`/`WITH` statement. Writes are rejected. |
| `list_tables` | List all tables and views. |
| `describe_table` | List a table's columns, types, and nullability. |
| `list_databases` | List the configured database aliases (see below). |

Every tool takes an optional `database` argument to target a specific configured database.

## Multiple databases

By default there's one database, aliased `app`, configured via `SQL_SERVER`/`SQL_DATABASE`/`SQL_USER`/`SQL_PASSWORD`. To add more:

```bash
SQL_CONNECTIONS=idp,billing
SQL_IDP_SERVER=...
SQL_IDP_DATABASE=...
SQL_IDP_USER=...
SQL_IDP_PASSWORD=...
SQL_BILLING_SERVER=...
# etc.
```

Each alias in `SQL_CONNECTIONS` needs its own `SQL_<ALIAS>_SERVER` / `_DATABASE` / `_USER` / `_PASSWORD` set. The chat UI's database picker and the `list_databases` tool pick these up automatically.

## Optional: OpenRouter fallback

If `GEMINI_API_KEY` hits its rate limit, the chat backend can fall back to free models on
[OpenRouter](https://openrouter.ai/):

```bash
OPENROUTER_API_KEY=your-openrouter-key
# OPENROUTER_MODELS=openai/gpt-oss-20b:free,nvidia/nemotron-3-nano-30b-a3b:free,google/gemma-4-31b-it:free
```

Leaving `OPENROUTER_API_KEY` unset disables this fallback entirely — Gemini alone is used.

You can also override which Gemini models are tried, and in what order:
```bash
# GEMINI_MODELS=gemini-flash-latest,gemini-flash-lite-latest,gemini-2.5-flash-lite,gemini-pro-latest
```

## Scripts

| Script | What it does |
|---|---|
| `npm run build` | Compile TypeScript (`src/` → `dist/`) |
| `npm start` | Run the compiled MCP server |
| `npm run dev` | Run the MCP server from source (no build) |
| `npm run server` | Build, then run the chat backend on port 3001 |
| `npm run test-connection` | Verify the database connection and print the table list |

## Security notes

- The `query` tool only allows `SELECT`/`WITH` statements — no `INSERT`/`UPDATE`/`DELETE`/`DROP`/etc., enforced in [src/db.ts](src/db.ts).
- `.env` is gitignored. Never commit real credentials or API keys.

TDQS

A4/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a distinct purpose: list_tables returns the table list, describe_table provides schema for one table, list_databases shows configured connections, and query executes arbitrary SELECT statements. There's no overlap; an agent can easily determine which tool to use for a given task.

Naming Consistency4/5

The first three tools follow a clear verb_noun pattern (list_tables, describe_table, list_databases). The fourth tool, 'query', is a single verb and doesn't fit the pattern cleanly, but it's still intuitive and not confusing.

Tool Count5/5

With only 4 tools, the server is well-scoped for its purpose. Each tool is essential for database exploration and querying, and the count is within the ideal 3-15 range. The small number avoids redundancy and keeps the interface focused.

Completeness5/5

For a read-only SQL query server, the surface is complete: list databases to see connections, list tables, describe a table's schema, and run arbitrary SELECT queries. There are no obvious gaps for the stated purpose, and the read-only constraint is explicit.

Maintenance

ActivitySlowing
ResponsivenessNo issues