MCP SQL Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP SQL ServerShow me the schema for the customers table"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP SQL Server
A secure and production-ready MCP (Model Context Protocol) server for SQL Server database inspection and querying, designed for seamless integration with Claude Desktop and Claude Code.
Features
Connection Pooling: Efficient connection management with configurable pool size
Advanced Security:
SQL injection prevention with prepared statements
Table blacklist with wildcard support (
sys_*,*_audit, etc.)Schema whitelist for access control
Query validation (SELECT-only with dangerous keyword detection)
Identifier validation to prevent injection
Robust Error Handling: Detailed logging with configurable levels
Complete MCP Tools:
list_tables: List all accessible tables with metrics (row count, size)describe_table: Show complete schema with sample dataexecute_query: Execute safe SELECT queries with timeoutget_table_relationships: Analyze foreign key relationshipsget_table_indexes: Show indexes with type, columns, uniqueness and fill factorsearch_columns: Search columns by name across all tables (wildcard support)get_table_statistics: Per-column statistics (distinct values, NULLs, min/max)get_views: List database views with optional SQL definitions
Semantic Dictionary: Per-server Markdown file that Claude auto-populates as it discovers business-name → table/column mappings. Exposed as
db://dictionaryResource (auto-loaded each session) and writable viaupdate_dictionaryTool. Editable from the Manager UI.MCP Resources:
db://schema/overview: Full database schema overview (all tables, columns, types, PKs)db://schema/tables/{table_name}: Detailed schema for a single tabledb://dictionary: Semantic dictionary — business language → schema mappings accumulated by Claude
Related MCP server: mcp-sqlserver
SQL MCP Manager
A built-in web UI for managing SQL Server MCP connections — add, edit, delete, and test all your configured databases from a single page, without editing JSON manually.
Install & Run
Windows (recommended):
setup.bat # install everything the first time
start-manager.bat # start the manager (double-click from Explorer)Manual:
pip install -e ".[manager]"
python -m manager.server
# → http://localhost:8090If the manager is already running,
start-manager.batopens the browser directly without restarting.
What It Does
Add / Edit / Delete SQL Server connections stored in
claude_desktop_config.jsonTest any connection string before saving — shows ✅ or ❌ with the error message
Live status — on page load, all configured servers are tested in parallel and shown as green/red dots
Register on Claude Code — one click on the CC button runs
claude mcp add --scope userto make the server available in all Claude Code sessions (note: Claude Code stores this separately fromclaude_desktop_config.json)Preserves all other entries in your Claude Desktop config untouched
Auto-detects the config file path on Windows, macOS, and Linux
Interface
Each configured connection appears as a card:
● db-vendite 🖥 srv1 › Vendite schema: dbo max 100 righe [⚡] [CC] [✏️] [🗑]
● db-magazzino 🖥 srv2 › Magazzino schema: dbo [⚡] [CC] [✏️] [🗑]
✗ db-contabilita 🖥 srv1 › Contabilita ✗ Connessione fallita [⚡] [CC] [✏️] [🗑]The form (add/edit) includes: Name, Connection String, Max Rows, Allowed Schemas, Blacklist Tables, Query Timeout, Pool Size, Pool Timeout, Dictionary File.
Button | Action |
⚡ | Test the connection on the fly |
CC | Register in Claude Code via |
📖 | Open the semantic dictionary editor |
✏️ | Edit the configuration |
🗑 | Delete the connection |
Semantic Dictionary
Every business database has an internal vocabulary that can't be inferred from the schema alone: anagra means nothing on its own, but customers does. The semantic dictionary is a Markdown file where Claude accumulates this knowledge as it chats with you — no manual documentation required.
How it works
You ask: "how many sales did Mario Rossi make?"
Claude explores the schema, discovers that
Mario Rossiis stored inanagra.cognome + nomeClaude saves this discovery to the dictionary (in the background, no confirmation required)
Claude replies: "I saved to the dictionary that 'customer by name' maps to fields
cognome, nomein tableanagra"Next sessions: Claude loads
db://dictionaryat startup and starts already informed
File format
# Semantic Dictionary
> Automatically updated by Claude. Can be edited manually.
## Business Entities
| User term | Table | Key fields | Notes |
|-----------|-------|------------|-------|
| customer | anagra | codice, cognome, nome | |
| product | tabArt | codart, descr | |
## Filters and Aliases
| User expression | SQL equivalent | Notes |
|-----------------|----------------|-------|
| "active" | stato = 'A' | |
| "current year" | YEAR(data_doc) = YEAR(GETDATE()) | |
## Notable Relationships
| From table | Field | To table | Field | Description |
|------------|-------|----------|-------|-------------|
| anagra | codice | ordini | codcli | customers and their orders |Configuration
Add --dictionary-file to the MCP server args (recommended: absolute path):
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "...",
"--dictionary-file", "C:\\dictionaries\\sales_dictionary.md"
]In a multi-server setup, each server has its own dictionary file — different domains, different vocabularies.
Editor in Manager UI
Each server card in the Manager has a 📖 button that opens a modal editor to view and edit the dictionary manually (useful for corrections or copying sections between databases).
Full documentation:
docs/manuale-dizionario-semantico.md
Quick Start
Prerequisites
Python 3.10 or higher
SQL Server (any version)
ODBC Driver 17+ for SQL Server
Claude Desktop or Claude Code
Installation
Option 1: Automated Setup (Recommended)
Windows:
git clone https://github.com/Attilio81/MCP-Sql-Server.git
cd MCP-Sql-Server
setup.batLinux/macOS:
git clone https://github.com/Attilio81/MCP-Sql-Server.git
cd MCP-Sql-Server
chmod +x setup.sh
./setup.shOption 2: Manual Setup
# Clone repository
git clone https://github.com/Attilio81/MCP-Sql-Server.git
cd MCP-Sql-Server
# Install package
pip install -e .
# Configure environment
cp .env.example .env
# Edit .env with your credentials
# Test connection
python test_connection.pyODBC Driver Installation
Download from Microsoft
Or via Chocolatey:
choco install sqlserver-odbcdrivercurl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew update
brew install msodbcsql17Configuration
All parameters are passed as command-line arguments directly in the Claude config file — no .env file required. CLI arguments take precedence over environment variables and .env.
Claude Desktop Configuration
Edit claude_desktop_config.json:
Platform | Path |
Windows |
|
macOS |
|
Linux |
|
{
"mcpServers": {
"sqlserver": {
"command": "python",
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=YOUR_SERVER;Database=YOUR_DB;UID=user;PWD=password",
"--max-rows", "100",
"--query-timeout", "30",
"--pool-size", "5",
"--pool-timeout", "30",
"--blacklist-tables", "sys_*,*_audit,*_temp",
"--allowed-schemas", "dbo",
"--log-level", "INFO"
]
}
}
}Restart Claude Desktop after editing.
Windows Trusted Authentication (no password)
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=YOUR_SERVER;Database=YOUR_DB;Trusted_Connection=yes"Azure SQL
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=YOUR_SERVER.database.windows.net;Database=YOUR_DB;Authentication=ActiveDirectoryInteractive"Multiple Databases
Define one MCP server entry per database — Claude will have all of them available simultaneously and will route queries to the right one based on the server name or your instructions:
{
"mcpServers": {
"db-vendite": {
"command": "python",
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=srv1;Database=Vendite;Trusted_Connection=yes",
"--allowed-schemas", "dbo",
"--max-rows", "100"
]
},
"db-magazzino": {
"command": "python",
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=srv2;Database=Magazzino;UID=user;PWD=password",
"--allowed-schemas", "dbo,wms"
]
},
"db-contabilita": {
"command": "python",
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=srv1;Database=Contabilita;Trusted_Connection=yes",
"--blacklist-tables", "*_audit,sys_*"
]
}
}
}In the chat you can then ask:
"On the Magazzino database, show me all tables" "On the Vendite database, how many orders were placed in 2026?"
Claude Code Configuration
Claude Code stores MCP servers separately from Claude Desktop. There are two approaches:
Option A — Via Manager (recommended): Add the server in the Manager, then click CC on the card. This runs claude mcp add --scope user and registers it globally for all Claude Code sessions.
Option B — CLI:
claude mcp add mydb --scope user -- python -m mcp_sqlserver.server \
--connection-string "Driver={ODBC Driver 17 for SQL Server};Server=YOUR_SERVER;Database=YOUR_DB;Trusted_Connection=yes" \
--max-rows 100
# Verify
claude mcp listOption C — Per-project .claude/mcp.json:
{
"mcpServers": {
"sqlserver": {
"command": "python",
"args": [
"-m", "mcp_sqlserver.server",
"--connection-string", "Driver={ODBC Driver 17 for SQL Server};Server=YOUR_SERVER;Database=YOUR_DB;Trusted_Connection=yes"
]
}
}
}The Manager reads/writes only
claude_desktop_config.json. Servers registered viaclaude mcp add --scope user(or the CC button) live in Claude Code's own store and are not visible in the Manager unless also added there.
See CLAUDE_CODE_USAGE.md for full details.
All Available Parameters
CLI Argument | Env Variable | Default | Description |
|
| (required) | ODBC connection string |
|
|
| Max rows returned per query |
|
|
| Query timeout in seconds |
|
|
| Connection pool size |
|
|
| Pool acquisition timeout (s) |
|
| (none) | Comma-separated patterns, wildcards ok |
|
| (all) | Comma-separated schema whitelist |
|
|
|
|
|
|
| Path to the semantic dictionary file (recommended: absolute path) |
Usage
You never need to pass credentials or connection strings in the chat. The connection is configured once in the config file and is transparent in every conversation.
Example Chat Session
You: Show me all the tables in the database
Claude: (calls list_tables)
# Database Tables — 12 found
## Schema: dbo
- **Customers** (15,432 rows, 2.14 MB)
- **Orders** (98,201 rows, 8.77 MB)
- **Products** (1,203 rows, 0.43 MB)
- ~~audit_trail~~ 🔒 matches blacklist pattern *_trailYou: Describe the Orders table with 5 sample rows
Claude: (calls describe_table)
# Schema: dbo.Orders
| Column | Type | Nullable | Key |
|-------------|---------------|----------|-----|
| OrderID | int(10) | NO | PK |
| CustomerID | int(10) | NO | |
| OrderDate | datetime | NO | |
| TotalAmount | decimal(18,2) | YES | |You: How many orders per month in 2026?
Claude: (calls execute_query)
SELECT TOP 100 MONTH(OrderDate) AS Month, COUNT(*) AS Orders
FROM dbo.Orders
WHERE YEAR(OrderDate) = 2026
GROUP BY MONTH(OrderDate)
ORDER BY MonthMonth | Orders |
1 | 1,203 |
2 | 987 |
3 | 1,456 |
You: Run: SELECT * FROM users; DROP TABLE Orders--
Claude: 🔒 Query not valid: Stacked statements (semicolons) are not allowed
With Multiple Databases
When multiple servers are configured, address them by name:
"On the db-vendite database, show me all tables"
"On db-magazzino, describe the Stock table"
"Compare orders between db-vendite and db-contabilita"
With Claude Code
# Start Claude Code in your project directory
cd your-project
claude
# Then ask naturally:
"List all tables in the database"
"Analyze the Users table and generate a SQLAlchemy model"
"Find all orders from 2026 and summarize them by customer"Available Tools
list_tables
Lists all accessible tables with metrics.
Parameters:
schema_filter(optional): Filter by specific schema
Example:
List all tables in the sales schemadescribe_table
Shows complete table schema with optional sample data.
Parameters:
table_name(required): Table name (format:schema.tableortable)sample_rows(optional): Number of sample rows (default: 10, max: 50)
Example:
Describe the dbo.Users table with 5 sample rowsexecute_query
Executes SELECT queries with safety checks.
Parameters:
query(required): SQL SELECT query
Example:
Execute: SELECT TOP 20 * FROM Products WHERE Price > 100get_table_relationships
Shows foreign key relationships for a table.
Parameters:
table_name(required): Table name
Example:
Show relationships for OrderDetails tableget_table_indexes
Shows all indexes on a table with type, columns, uniqueness and fill factor.
Parameters:
table_name(required): Table name (format:schema.tableortable)
Example:
Show indexes for the Orders tablesearch_columns
Searches for columns by name across the entire database, with wildcard support.
Parameters:
column_pattern(required): Search pattern (supports*and?wildcards, e.g.*email*,user_*)schema_filter(optional): Filter by specific schema
Example:
Find all columns containing "email" in their nameget_table_statistics
Shows per-column statistics: distinct values, NULL count, min/max for numeric and date columns.
Parameters:
table_name(required): Table name (format:schema.tableortable)
Example:
Show statistics for the Customers tableget_views
Lists all database views with optional SQL definitions.
Parameters:
schema_filter(optional): Filter by specific schemainclude_definition(optional): Include SQL definition (default: true)
Example:
List all views in the dbo schemaupdate_dictionary
Saves a semantic mapping to the per-server dictionary file. Called automatically by Claude when it discovers a non-obvious link between business language and database schema — no user action required.
Parameters:
section(required):"entities"|"filters"|"relations"key(required): First-column value, used for deduplicationrow(required): Complete Markdown table row
Claude calls this automatically when it learns:
Which table/columns correspond to a business entity named by the user
A recurring filter expression (e.g. "attivo" →
stato = 'A')A non-obvious join relationship between tables
Available Resources
MCP Resources provide read-only context data that clients can retrieve automatically.
db://schema/overview
Full database schema overview — all accessible tables with columns, types and primary keys.
Example:
Show me the database schema overviewdb://schema/tables/{table_name}
Detailed schema for a single table via URI template.
Example URI: db://schema/tables/dbo.Orders
db://dictionary
Semantic dictionary for this database — business language mapped to physical schema. Claude loads this automatically at session start. Returns empty string if no dictionary has been created yet.
See Dizionario Semantico and docs/manuale-dizionario-semantico.md.
Security
Connection String Security
Recommended: Use Windows Authentication (Windows only)
SQL_CONNECTION_STRING=Driver={ODBC Driver 17 for SQL Server};Server=localhost;Database=MyDB;Trusted_Connection=yesAzure SQL with AAD:
SQL_CONNECTION_STRING=Driver={ODBC Driver 17 for SQL Server};Server=myserver.database.windows.net;Database=MyDB;Authentication=ActiveDirectoryInteractiveTable Blacklist
Supports wildcards for pattern matching:
# Block specific tables
BLACKLIST_TABLES=sys_logs,audit_trail
# Block patterns
BLACKLIST_TABLES=sys_*,*_temp,internal_*
# Block with schema
BLACKLIST_TABLES=dbo.sensitive_*,admin.*Schema Whitelist
Restrict access to specific schemas (case-insensitive matching):
# Only allow these schemas
ALLOWED_SCHEMAS=dbo,sales,hr
# Empty = all schemas allowed
ALLOWED_SCHEMAS=Query Validation
The server automatically blocks:
Non-SELECT statements (INSERT, UPDATE, DELETE, DROP, etc.)
SQL injection patterns
SQL comments (
--,/* */)Dangerous functions (
xp_cmdshell,sp_executesql)System stored procedures
Best Practices
Never commit credentials -
.envis in.gitignoreUse least privilege - Create a dedicated read-only SQL user
Enable logging - Set
LOG_LEVEL=INFOorDEBUGfor monitoringSet appropriate limits - Configure
MAX_ROWSandQUERY_TIMEOUTUse schema whitelist - Restrict access to specific schemas only
See SECURITY.md for detailed security guidelines.
Architecture
Connection Pooling
Maintains a pool of reusable database connections
Configurable size:
POOL_SIZE(default: 5)Automatic reconnection for dead connections
Automatic transaction rollback on release
Security Validator
Multi-layered query validation (applied in order):
Length cap: Rejects queries exceeding 4096 characters (DoS prevention)
Null-byte rejection: Blocks null bytes before normalisation
Unicode / whitespace normalisation: Collapses whitespace, replaces full-width lookalike characters
SELECT-only enforcement: Only SELECT statements are allowed
Injection pattern detection: Regex-based detection of semicolons, comments, UNION, EXEC(), encoding tricks, timing attacks, etc.
Dangerous keyword check: Word-boundary match against DML/DDL/admin keywords
Additional layers for table access:
Blacklist matching: Pattern-based table filtering with wildcards
Schema whitelist: Case-insensitive schema restriction
Identifier validation: Regex validation of table/schema names to prevent injection
Error Handling
Stratified error management:
TimeoutError: Pool exhausted or slow queriespyodbc.Error: Database-specific errors (connection, syntax, permissions)Exception: Generic fallback with full stack trace logging
All connection pool errors are now logged with specific exception types (no silent failures).
Query timeout is enforced at the cursor level via cursor.timeout.
Testing
Connection Test
python test_connection.pyRuns 6 automated tests:
pyodbc installation check
ODBC driver verification
Connection string validation
Database connection test
Basic query execution
MCP package verification
Manual Testing
# Test server startup (should wait for stdin)
python -m mcp_sqlserver.server
# Test with MCP Inspector (requires Node.js)
npx @modelcontextprotocol/inspector python -m mcp_sqlserver.serverTroubleshooting
"Data source name not found"
Solution: Verify ODBC driver is installed:
python -c "import pyodbc; print(pyodbc.drivers())"Update connection string with correct driver name (e.g., ODBC Driver 18 for SQL Server).
"Timeout acquiring connection from pool"
Solution: Increase pool settings in .env:
POOL_SIZE=10
POOL_TIMEOUT=60"Access denied: Schema 'xyz' not authorized"
Solution: Add schema to whitelist:
ALLOWED_SCHEMAS=dbo,xyzEnable Debug Logging
For detailed troubleshooting:
LOG_LEVEL=DEBUGView logs in Claude Desktop: Help → Show Logs
Development
Project Structure
mcp-sqlserver/
├── src/mcp_sqlserver/
│ ├── __init__.py
│ ├── server.py # MCP app setup, tool routing, entry point
│ ├── config.py # CLI args, env vars, global settings
│ ├── security.py # SecurityValidator, dangerous keywords & patterns
│ ├── pool.py # ConnectionPool with auto-reconnection
│ ├── helpers.py # Output formatting (Markdown tables)
│ ├── resources.py # MCP Resources (schema overview, table schema, dictionary)
│ └── tools/
│ ├── __init__.py # Re-exports all tool handlers
│ ├── list_tables.py
│ ├── describe_table.py
│ ├── execute_query.py
│ ├── relationships.py
│ ├── indexes.py
│ ├── search_columns.py
│ ├── statistics.py
│ ├── views.py
│ └── dictionary.py # update_dictionary tool + _upsert_row
├── manager/ # SQL MCP Manager — local web UI
│ ├── __init__.py
│ ├── server.py # FastAPI app: API routes + serve index.html
│ ├── config_manager.py # Read/write claude_desktop_config.json (atomic)
│ ├── connection_tester.py # Test a connection string via pyodbc
│ └── static/
│ └── index.html # Single-page app (vanilla HTML/CSS/JS)
├── tests/
│ ├── test_security_validator.py # Unit tests for SecurityValidator & helpers
│ ├── test_config_manager.py # Unit tests for config_manager
│ ├── test_connection_tester.py # Unit tests for connection_tester
│ ├── test_api.py # API tests via FastAPI TestClient
│ └── test_dictionary.py # Unit tests for dictionary tool (no DB required)
├── .env.example # Environment template
├── pyproject.toml # Package configuration
├── README.md # This file
├── CLAUDE_CODE_USAGE.md # Claude Code integration guide
├── SECURITY.md # Security best practices
├── CONTRIBUTING.md # Contribution guidelines
├── LICENSE # MIT License
└── test_connection.py # Connection test scriptRunning Tests
# Install dev dependencies
pip install -e ".[dev,manager]"
# Run all unit tests (no database required)
pytest tests/ -vThe unit test suite covers:
test_security_validator.py— table access validation, query injection patterns, SQL helperstest_config_manager.py— config read/write/parse, atomic writes, multi-platform pathstest_connection_tester.py— pyodbc connection test (mocked)test_api.py— all FastAPI endpoints via TestClient (mocked config_manager)
Code Quality
# Linting
pip install ruff
ruff check src/
# Formatting
ruff format src/Contributing
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
Development Setup
# Clone repository
git clone https://github.com/Attilio81/MCP-Sql-Server.git
cd MCP-Sql-Server
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/macOS
# or
venv\Scripts\activate # Windows
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Install pre-commit hooks
pre-commit installRoadmap
PostgreSQL support
MySQL/MariaDB support
Query result caching
Data export (CSV, JSON, Excel)
ER diagram visualization
Query performance statistics
Async query execution
Multi-database support in single server
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Built with Model Context Protocol
Powered by pyodbc
Inspired by the MCP Servers project
Support
Documentation: See documentation files in this repository
Issues: GitHub Issues
Discussions: GitHub Discussions
Related Projects
Made with ❤️ for the Claude community
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
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/Attilio81/MCP-Sql-Server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server