Skip to main content
Glama
Fattan-malva

mcp-sqlserv

by Fattan-malva

mcp-sqlserv

MCP Server for read-only access to SQL Server databases — anti SQL-injection by construction, managed via the Web Admin UI.

License: MIT Node TypeScript Docker MCP Tests

Zero raw SQL · Default deny · Bind parameter 100% · Full audit


About

mcp-sqlserv lets AI agents (Claude, Cursor, Claude Code, any MCP client) read SQL Server databases safely and in a controlled way:

  • All queries are built structurally by the server — the AI never writes raw SQL.

  • Identifiers (tables/columns) are validated against real database metadata (sys.tables, sys.columns).

  • Values are always bound parametersSQL injection is impossible by construction.

  • Per-table permissions are default deny: without explicit permission, a table cannot be touched.

  • Every request is recorded in the audit log — key, tool, filter, row count, and duration.

Related MCP server: safedb-mcp

Features

Feature

Description

MCP Streamable HTTP

/mcp endpoint, compatible with all MCP clients via HTTP

Multi-project

Per-project URL /mcp/<projectId>, separate storage & permissions

API Key

Create / revoke key per AI consumer

OAuth 2.1

Authorization Code + PKCE, DCR (RFC 7591), refresh rotation, revoke

SQL Server Connection

Host/port/user/pass (encrypted AES-256-GCM), optional TLS

Granular permissions

Per table: read data and/or view metadata. Default = DENY

Audit log

All AI requests are logged: key, tool, table, filter, rows, duration, status

Rate limit

60 requests/min per API key (configurable)

Fully read-only

Tools only produce SELECT; no write path exists anywhere

Agent Test

Chat with the Gemini model directly from the Web UI for end-to-end testing

Architecture

┌──────────────┐   HTTPS    ┌─────────────┐          ┌──────────────────────────────┐
│  AI Agent    ├───────────►│    nginx    ├─────────►│  mcp-sqlserv (Docker)        │
│  (MCP client)│  Bearer    │  reverse    │ app-net  │  Express + MCP + OAuth       │
└──────────────┘  token     │  proxy+SSL  │  work    │      │            │          │
                            └─────────────┘          │      ▼            ▼          │
┌──────────────┐   HTTPS                              │  SQLite         mssql pool   │
│ Web Admin UI ├─────────────────────────────────────►│  (data/, keys,   │           │
│  (browser)   │            REST /api/*               │   audit, izin)   ▼           │
└──────────────┘                                      │              ┌──────────┐    │
                                                      │              │ SQL Srvr │    │
                                                      └──────────────┴──────────┴────┘

Quick To Start

# 1. Clone & siapkan environment
git clone https://github.com/<username>/mcp-sqlserv.git
cd mcp-sqlserv
cp .env.example .env            # isi ADMIN_USER / ADMIN_PASSWORD (min 8 karakter)

# 2. Build & jalankan
docker compose up -d --build

# 3. Verifikasi
curl http://localhost:4000/healthz

Server runs on http://localhost:4000 — Web admin UI at /, MCP endpoint at /mcp.

Environment Variables

Variable

Default

Description

PORT

4000

Server port

DATA_DIR

./data

SQLite data folder (mounted as /mnt/data volume in Compose)

ADMIN_USER

admin

Web admin UI user

ADMIN_PASSWORD

required

Password for admin UI (minimum 8 characters юq)

SESSION_SECRET

automatic

JWT/encryption secret (auto-generated & persisted if empty)

QUERY_TIMEOUT_MS

30000

SQL query timeout

RATE_LIMIT_PER_MIN

60

Rate limit limiting per API key

OAUTH_ENABLED

1

Disable OAuth by setting 0

OAUTH_CODE_TTL_S

600

Authorization code lifetime (seconds)

OAUTH_ACCESS_TTL_S

3600

Access token lifetime (seconds)

OAUTH_REFRESH_TTL_S

2592000

Refresh token lifetime (seconds; 30 days)

Usage Flow

  1. Log in to the Web UI → DB Connection menu → fill in host/port/user/pass/database, safest option — Test Connection.

    For Docker cases, SQL Server on the host can be reached via host.docker.internal.

  2. API Keys menu → create a key (view once, store it!).

  3. Table Permissions menu → check the maritime identifier table allowed for AISave Permissions. Default deny.

  4. Connect the Agent to URL https://<domain>/mcp with a header Authorization: Bearer <api-key>.

Connecting an Arbitrary MCP Client

{
  "mcpServers": {
    "sql-server": {
      "url": "https://<domain>/mcp",
      "headers": { "Authorization": "Bearer sk-xxxx" }
    }
  }
}

Quick test with curl:

curl -X POST https://<domain>/mcp \
  -H "Authorization: Bearer sk-xxxx" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'

Claude Custom Connector (claude.ai / Desktop)

  1. Open Customize → Connectors → Add custom connector.

  2. Set Remote MCP server URL: https://<domain>/mcp.

  3. In Advanced settings, fill in an OAuth Client ID + Secret from the OAuth Clients menu (redirect URI: https://claude.ai/api/mcp/auth_callback).

    Could be left blank — Claude auto registers via Dynamic Client Registration (RFC 7591).

  4. Click Add → Connect — browser opens the administrator login page → Allow access.

  5. Claude stores a refresh token and sends MCP requests with a bearer token.

Claude Code (CLI):

claude mcp add mcp-sqlserv https://<domain>/mcp --transport http \
  ... # bila client pre-registered: --client-id <id> --client-secret --callback-port

Endpoints OAuth

Endpoint

Standard

GET /.well-known/oauth-protected-resource

RFC 9728

GET /.well-known/oauth-authorization-server

RFC 8414

POST /oauth/register

RFC 7591 (DCR, public + confidential)

GET /oauth/authorize (operator login + consent)

RFC 6749 + PKCE S256

POST /oauth/token (code exchange + refresh rotation)

RFC 6749 / 7636

POST /oauth/revoke

RFC 7009

OAuth identity = operator session. Access token maps mapped to an internal API key oauth:<client_id>` — all table permissions, rate limit, and audit logging also apply to Claude connection. Revoking the client invalidates this client’s tokens instantly.

MCP Tools

Tool

Description

list_tables

Returns the permitted tables with approximate row counts

get_table_schema

Columns: type, nullable, identity, primary key, indexes

read_records

Read lines, applied structured filter, ORDER BY, pagination

count_records

Count rows with optional filter

get_record_by_pk

Fetch one row via primary key

server_info

Server / database info

Table names must be specified without schema prefix (users, not dbo.users). Columns are validated against sys.columns; all values are 100% bound parameters.

Supported structured filters: eq, neq, lt, lte, gt, gte, like, startsWith, endsWith, in, between, isNull, isNotNull.

Security

  • No raw SQL — only the structured query builder

  • Identifier allowlist — regex + check against real DB metadata

  • Default deny — without grant, a table cannot be touched

  • Hard limits — max 1000 rows/query, 20 filters, 50 INS · time out 30s

  • API key + rate limiter per key + audit log of all requests

  • Read-only (recommend through SQL Server-only GRANT SELECT)

  • DB password stored encrypted AES-256-GCM in SQLite

Deployment

Deploy with Docker to the app-network, behind nginx, as a reverse proxy (wildcard SSL cert, SSE-buffering disabled, CORS for web‑based MCP clients).

Migrating Between VPS

Code and Docker will run automatically, but the following — not track in Git (they’re in .gitignore) — have to be carried manually:

Item

Contents

How to move

.env

Admin credentials & secrets

Copy from old server, or regenerate from .env.example

data/

SQLite storage (API keys, grants, audit log, DB connection)

rsync / copy old folder

# Di VPS baru
git clone https://github.com/<username>/mcp-sqlserv.git && cd mcp-sqlserv

# Migrasi state dari VPS lama (opsional)
rsync -av vps-lama:/path/mcp-sqlserv/.env .env
rsync -av vps-lama:/path/mcp-sqlserv/data ./data

# Network eksternal harus ada dulu (dipakai docker-compose.yaml)
docker network create app-network   # abaikan jika sudah ada

docker compose up -d --build

Leaving data/ behind means the server still runs — you only have to recreate the DB connection, API keys, grant list from admin UI.

Project Structure

mcp-sqlserv/
├── src/
│   ├── index.ts            # Bootstrap Express + routing
│   ├── config.ts           # Env config
│   ├── db/storage.ts       # SQLite: api_keys, db_config, permissions, audit_log
│   ├── sqlserver/          # Connection pool, metadata (sys.tables), query builder
│   ├── mcp/                # MCP server (per-session) + tools
│   ├── oauth/              # OAuth 2.1: router, PKCE, discovery
│   ├── api/                # REST admin (auth, config, keys, permissions, audit)
│   └── ui/                 # SPA vanilla JS (public/)
├── public/                 # Web UI admin (tanpa build step)
├── test/                   # Test suite keamanan + OAuth + smoke
├── Dockerfile              # Multi-stage build (node:20-alpine)
├── docker-compose.yaml     # Attach ke app-network, host.docker.internal
└── LICENSE                 # MIT

Admin REST API

Method

Path

Description

POST

/api/auth/login

Admin login (httpOnly cookie)

GET

/api/status

DB status, key, permissions

GET/PUT

/api/config : full-photo

Read / save DB connection config

POST

/api/config/test

Test connection

GET/POST/

/api/keys

List / create API key

PUT/DELETE

/api/keys/:id

Rename / revoke

GET/PUT

/api/activity

List / save table-security rules

GET

/api/audit

Audit log

GET

/api/info

MCP URL info + sample configuration

GET

/healthz

No auth available

Testing

npm run test:smoke      # smoke test dasar
npm run test:security   # 29 test: injection, permission, limit, pagination, auth
npm run test:oauth      # 46 test: discovery, DCR, PKCE, consent, token, refresh, revoke

test/oauth.mjs starts its own server (port: 4100, data-dir: oauth-test-data/) — no further config required.

Contribution

Contributions are welcome ! Open an issue or a pull request. For larger changes, please discuss the idea first via Issue, to stay aligned with the product principle: Security is the product. Every surface (MCP, UI, Agent Test) must meet the same standards:

License

This project is licensed under the [MIT License

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to securely connect to and query Microsoft SQL Server databases with read-only access, schema discovery, and relationship mapping. Features advanced security protections, health monitoring, and bulk operations for production environments.
    9
    75
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Secure MCP server for safe, read-only DB access by AI agents, with SQL guardrails, table allowlists, PII masking, and audit logs
    6
    34
    7
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    An MCP server that connects AI assistants to Microsoft SQL Server databases, enabling schema exploration and read-only queries safely.
    49
    23
    4
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to connect to Microsoft SQL Server via the MCP protocol, supporting database schema queries, data reading, and arbitrary SQL execution.

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

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/Fattan-malva/mcp-sqlserver'

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