MSSQL MCP Server

MSSQL MCP Server

A Model Context Protocol server that exposes SQL Server metadata and read-only query execution as a structured HTTP API, with safety validation and allowlist policy enforcement.

Category
访问服务器

README

MSSQL MCP Server — Standalone

A self-contained Model Context Protocol (MCP) server that exposes SQL Server metadata and read-only query execution as a structured HTTP API. It is designed to be consumed by AI orchestration layers (e.g. LangGraph, custom agents) that need reliable, safety-gated access to a SQL Server database.


Contents


What It Does

The MCP server acts as a safe, policy-enforced gateway between an AI agent and a SQL Server instance. It provides:

Capability Details
Schema introspection List databases, schemas, tables, columns, and foreign keys
Read-only SQL execution Run SELECT-only queries with bounded pagination
SQL safety validation Deterministic risk scoring before any query is executed
Allowlist policy Restrict accessible databases/schemas/tables via YAML config
Audit & feedback persistence Record structured audit events and user feedback into SQL Server
Metadata caching In-memory TTL cache reduces redundant introspection roundtrips
OpenTelemetry tracing Optional OTLP export compatible with Arize Phoenix and Jaeger

Architecture

AI Agent / Orchestrator
        |
        |  HTTP (JSON)  POST /list_databases, etc.
        v
+----------------------------------+
|         mcpo REST proxy          |
|         (port 8081)              |
|                                  |
|  OpenAPI/REST  -->  MCP client   |
+----------------------------------+
        |
        |  MCP over SSE
        |  GET  /sse
        |  POST /messages/
        v
+----------------------------------+
|      FastMCP Server              |
|      (port 8082, internal)       |
|                                  |
|  10 tools  -->  MetadataService  |
|               +-- schema-        |
|               |   introspection  |
|               +-- sql-validator  |
|               +-- policy layer   |
|                                  |
|  6 MCP resources (schema, docs)  |
|  Settings loaded from env vars   |
+----------------------------------+
        |
        |  pyodbc / ODBC Driver 18
        v
   SQL Server (any edition)

mcpo is a lightweight proxy that wraps any MCP server and exposes its tools as a standard OpenAPI/REST API. This means you can call the server with plain HTTP POST requests and browse an interactive Swagger UI at http://localhost:8081/docs no MCP client library required.

Three internal packages are bundled alongside the server:

Package Role
packages/shared-types Pydantic request/response models shared across the surface
packages/schema-introspection Low-level pyodbc SQL Server introspection queries
packages/sql-validator Deterministic SQL risk scorer using sqlglot parse trees

Project Structure

mssql-mcp-server-standalone/
+-- app/
|   +-- main.py              # FastMCP server, all tools and resources, entry point
|   +-- config.py            # McpSettings (pydantic-settings, env prefix MCP_)
|   +-- metadata_service.py  # Business logic: wraps introspection + policy + cache
|   +-- metadata_cache.py    # In-memory TTL cache
|   +-- policy.py            # Allowlist policy loader and enforcement
|   +-- tracing.py           # OpenTelemetry setup
+-- packages/
|   +-- shared-types/        # Shared Pydantic models
|   +-- schema-introspection/# pyodbc-based SQL Server introspection
|   +-- sql-validator/       # sqlglot-based SQL risk scorer
+-- tests/
|   +-- test_validator_tools.py
+-- Dockerfile
+-- docker-compose.yml
+-- pyproject.toml
+-- .env.example
+-- allowlist-policy.example.yaml

Quick Start (Docker)

1. Configure environment

cp .env.example .env

Edit .env and set at minimum:

MCP_SQLSERVER_HOST=your-sql-server-host
MCP_SQLSERVER_DATABASE=YourDatabase
MCP_SQLSERVER_USER=readonly_user
MCP_SQLSERVER_PASSWORD=your-password

2. Build and run

docker compose up --build

Two containers start:

  • fastmcp-app — the FastMCP server on internal port 8082
  • mcpo-proxy — the REST proxy on port 8081 (public)

mcpo-proxy waits for fastmcp-app to pass its healthcheck before starting.

3. Verify

Browse the interactive Swagger UI:

http://localhost:8081/docs

Or call the health check tool directly:

curl -s -X POST http://localhost:8081/health_check \
  -H "Content-Type: application/json" \
  -d '{}'

Quick Start (Local Python)

Requires Python 3.11+ and Microsoft ODBC Driver 18 for SQL Server.

Note: Running locally starts the FastMCP server only (port 8082). To get the OpenAPI/REST layer, run mcpo separately pointing at http://localhost:8082/sse.

1. Create and activate a virtual environment

python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux / macOS
source .venv/bin/activate

2. Install packages

pip install -e packages/shared-types -e packages/schema-introspection -e packages/sql-validator -e .

3. Set environment variables

# Windows PowerShell
$env:MCP_SQLSERVER_HOST = "localhost"
$env:MCP_SQLSERVER_DATABASE = "YourDatabase"
$env:MCP_SQLSERVER_USER = "readonly_user"
$env:MCP_SQLSERVER_PASSWORD = "your-password"

# Linux / macOS
export MCP_SQLSERVER_HOST=localhost
export MCP_SQLSERVER_DATABASE=YourDatabase
export MCP_SQLSERVER_USER=readonly_user
export MCP_SQLSERVER_PASSWORD=your-password

Or copy .env.example to .env and load it manually.

4. Run

python -m app.main

The server listens on 0.0.0.0:8082 using SSE transport (GET /sse, POST /messages/).


Configuration Reference

All settings use the MCP_ environment variable prefix.

SQL Server Connection

Variable Default Description
MCP_SQLSERVER_HOST sqlserver-host Hostname or IP of the SQL Server instance
MCP_SQLSERVER_PORT 1433 SQL Server port
MCP_SQLSERVER_DATABASE master Default database to connect to
MCP_SQLSERVER_USER readonly_user SQL login username
MCP_SQLSERVER_PASSWORD change-me SQL login password
MCP_SQLSERVER_CONNECT_TIMEOUT_SECONDS 10 Connection timeout (1-120)
MCP_SQLSERVER_QUERY_TIMEOUT_SECONDS 30 Query timeout (1-300)

Allowlist Policy

Variable Default Description
MCP_ALLOWLIST_ENABLED false Enable database/schema/table allowlist enforcement
MCP_ALLOWLIST_POLICY_PATH (none) Absolute path to allowlist YAML file (required when enabled)

Metadata Cache

Variable Default Description
MCP_METADATA_CACHE_TTL_SECONDS 300 TTL for cached introspection results (1-86400)
MCP_METADATA_MAX_TABLES 200 Max tables returned per listing call (1-10000)
MCP_METADATA_MAX_COLUMNS 1000 Max columns returned per table (1-50000)
MCP_METADATA_MAX_FOREIGN_KEYS 2000 Max foreign keys returned (1-100000)

Query Execution Limits

Variable Default Description
MCP_EXECUTION_DEFAULT_ROW_LIMIT 100 Default row limit when caller does not specify
MCP_EXECUTION_MAX_ROW_LIMIT 1000 Hard cap on rows returned per query (1-10000)

SQL Validator Risk Thresholds

Risk scores are integer values computed from the sqlglot parse tree. Thresholds map scores to risk levels:

Variable Default Description
MCP_VALIDATOR_MEDIUM_MIN_SCORE 3 Minimum score to classify as MEDIUM risk
MCP_VALIDATOR_HIGH_MIN_SCORE 5 Minimum score to classify as HIGH risk
MCP_VALIDATOR_CRITICAL_MIN_SCORE 8 Minimum score to classify as CRITICAL risk
MCP_VALIDATOR_REFUSE_AT_OR_ABOVE critical Refuse SQL execution at or above this risk level (low|medium|high|critical)

OpenTelemetry Tracing

Variable Default Description
MCP_TRACING_ENABLED false Enable OTLP trace export
MCP_TRACING_OTLP_ENDPOINT http://phoenix:4317 OTLP gRPC exporter endpoint
MCP_TRACING_SERVICE_NAME mssql-mcp-server Service name tag in traces
MCP_TRACING_CAPTURE_HTTP_BODIES false Include request/response JSON in trace spans
MCP_TRACING_BODY_MAX_CHARACTERS 4096 Max characters captured per body attribute (128-50000)
MCP_TRACING_EXPORT_TIMEOUT_MILLISECONDS 10000 OTLP export timeout (100-120000)
MCP_TRACING_SAMPLE_RATIO 1.0 Trace sampling ratio (0.0-1.0)

Allowlist Policy

When MCP_ALLOWLIST_ENABLED=true, the server loads a YAML file that restricts which databases, schemas, and tables the server will expose. Any request targeting an object outside the policy returns an error.

Set MCP_ALLOWLIST_POLICY_PATH to the absolute path of your policy file.

Example policy file (allowlist-policy.example.yaml):

databases:
  - SalesDW
  - Reporting

schemas:
  SalesDW:
    - dbo
    - analytics
  Reporting:
    - dbo

tables:
  SalesDW.dbo:
    - FactSales
    - DimCustomer
  Reporting.dbo:
    - DailyKPI

Hierarchy rules:

  • If databases is empty, all databases are allowed.
  • If schemas has no entry for a database, all schemas in that database are allowed.
  • If tables has no entry for a database.schema, all tables in that schema are allowed.

When mounting the file in Docker:

# docker-compose.yml
volumes:
  - ./allowlist-policy.yaml:/etc/mcp/allowlist-policy.yaml:ro
# .env
MCP_ALLOWLIST_ENABLED=true
MCP_ALLOWLIST_POLICY_PATH=/etc/mcp/allowlist-policy.yaml

Endpoints

All tool endpoints are exposed by the mcpo proxy on port 8081 as POST /<tool_name> with a JSON body. Browse http://localhost:8081/docs for the interactive Swagger UI.

The FastMCP server itself listens on internal port 8082 (SSE transport) and is not directly reachable from outside the Docker network.


POST /health_check

Returns server configuration summary and cache statistics. No request body required.

Response (200)

{
  "status": "ok",
  "service": "mssql-mcp-server",
  "sqlserver_host": "localhost",
  "sqlserver_port": 1433,
  "sqlserver_database": "master",
  "tracing_enabled": false,
  "metadata_cache_ttl_seconds": 300,
  "metadata_cache_entries": 0,
  "validator_refuse_at_or_above": "critical"
}

POST /list_databases

Lists all accessible databases on the SQL Server instance.

Request body

{ "include_system": false }
Field Type Default Description
include_system bool false Include system databases (master, model, msdb, tempdb)

Response (200)

{
  "databases": [
    { "name": "SalesDW" },
    { "name": "Reporting" }
  ]
}

POST /list_tables

Lists tables in a database, optionally filtered by schema.

Request body

{
  "database": "SalesDW",
  "schema_name": "dbo"
}
Field Type Required Description
database string Yes Target database
schema_name string No Filter to this schema

Response (200)

{
  "tables": [
    { "schema": "dbo", "name": "FactSales" }
  ]
}

POST /describe_table

Returns column metadata and foreign keys for a single table.

Request body

{
  "database": "SalesDW",
  "schema_name": "dbo",
  "table": "FactSales"
}
Field Type Required Description
database string Yes Target database
schema_name string Yes Target schema
table string Yes Target table

Response (200)

{
  "table": {
    "database": "SalesDW",
    "schema": "dbo",
    "name": "FactSales"
  },
  "columns": [
    {
      "name": "SalesID",
      "data_type": "int",
      "is_nullable": false,
      "is_primary_key": true,
      "max_length": null,
      "precision": 10,
      "scale": 0
    }
  ],
  "foreign_keys": [
    {
      "constraint_name": "FK_FactSales_DimCustomer",
      "column": "CustomerID",
      "referenced_database": "SalesDW",
      "referenced_schema": "dbo",
      "referenced_table": "DimCustomer",
      "referenced_column": "CustomerID"
    }
  ]
}

POST /get_foreign_keys

Returns foreign key constraints for a single table.

Request body

{
  "database": "SalesDW",
  "schema_name": "dbo",
  "table": "FactSales"
}

Response (200)

{
  "foreign_keys": [
    {
      "constraint_name": "FK_FactSales_DimCustomer",
      "column": "CustomerID",
      "referenced_database": "SalesDW",
      "referenced_schema": "dbo",
      "referenced_table": "DimCustomer",
      "referenced_column": "CustomerID"
    }
  ]
}

POST /validate_sql

Validates a SQL statement and returns a deterministic safety and risk analysis. Does not execute the query.

Request body

{
  "sql": "SELECT * FROM dbo.FactSales WHERE SalesDate > '2024-01-01'",
  "policy": null
}
Field Type Required Description
sql string Yes SQL statement to validate
policy ValidatorPolicy No Override validator risk thresholds for this call

Response (200)

{
  "is_valid": true,
  "normalized_sql": "SELECT * FROM dbo.FactSales WHERE SalesDate > '2024-01-01'",
  "risk_level": "low",
  "risk_score": 1,
  "risk_factors": [],
  "blocked_rules": [],
  "refusal_reason": null
}
Field Description
is_valid true if the query is safe to execute under the current policy
normalized_sql Normalized form of the SQL as parsed by sqlglot
risk_level low | medium | high | critical
risk_score Integer score (0 = safest)
risk_factors List of risk signals found in the parse tree
blocked_rules Rules that caused is_valid=false
refusal_reason Human-readable reason if the query was refused

POST /estimate_query_risk

Identical to validate_sql — returns the same risk scoring. This alias is provided for semantic clarity in agent workflows where you want risk estimation as a separate reasoning step from the validation gate.

Request / Response: Same as POST /validate_sql.


POST /run_sql_query

Executes a read-only SQL query. The query is validated first; execution is denied if it fails the safety policy.

Request body

{
  "sql": "SELECT TOP 10 * FROM dbo.FactSales",
  "database": "SalesDW",
  "row_limit": 100,
  "offset": 0,
  "policy": null
}
Field Type Required Description
sql string Yes SQL SELECT statement to execute
database string No Database context (overrides server default)
row_limit int No Max rows to return (default 100, bounded by MCP_EXECUTION_MAX_ROW_LIMIT)
offset int No Row offset for pagination (default 0)
policy ValidatorPolicy No Override validator thresholds for this call

Response (200)

{
  "columns": ["SalesID", "CustomerID", "SalesDate", "Amount"],
  "rows": [
    { "SalesID": 1, "CustomerID": 42, "SalesDate": "2024-03-15", "Amount": 199.99 }
  ],
  "returned_rows": 1,
  "row_limit": 100,
  "offset": 0,
  "has_more": false,
  "next_offset": null,
  "execution_time_ms": 12
}

Important: Only SELECT statements pass validation. Any INSERT, UPDATE, DELETE, DROP, or other mutating statement will be refused.


POST /record_audit_event

Persists a structured audit event to the SQL Server audit store.

Request body

{
  "endpoint": "run_sql_query",
  "event_type": "QUERY_EXECUTED",
  "sequence_no": 1,
  "conversation_id": "conv-abc123",
  "correlation_id": "req-xyz456",
  "stage_name": "execution",
  "decision_type": "ALLOW",
  "refusal_reason": null,
  "duration_ms": 12,
  "event_utc": "2024-03-15T10:30:00Z",
  "payload": {}
}
Field Type Required Description
endpoint string Yes Tool name that triggered the event
event_type string Yes Event classification string
sequence_no int No Ordering sequence within a conversation
conversation_id string No Correlates events in a single agent conversation
correlation_id string No Correlates events across services
stage_name string No Pipeline stage (e.g. validation, execution)
decision_type string No ALLOW or DENY
refusal_reason string No Populated when decision_type=DENY
duration_ms int No Elapsed time of the operation
event_utc string No ISO 8601 timestamp (defaults to server time)
payload object No Arbitrary extra data

Response (200)

{
  "accepted": true,
  "event_id": 42
}

POST /record_feedback

Persists user feedback for a SQL copilot interaction.

Request body

{
  "conversation_id": "conv-abc123",
  "sql": "SELECT * FROM dbo.FactSales",
  "label": "correct",
  "rating": 5,
  "comments": "Exactly what I needed."
}

Response (200)

{
  "accepted": true,
  "feedback_id": 7
}

MCP Resources

In addition to tools, the server exposes 6 MCP resources accessible to MCP clients that connect directly to the SSE endpoint (http://localhost:8082/sse). Resources are read-only, cacheable views and are not exposed as REST endpoints through mcpo.

Resource URI Description
schema://index Hierarchical catalog (databases -> schemas -> tables), system DBs excluded
schema://index/with-system Same catalog including system databases
schema://table/{database}/{schema_name}/{table_name} Full column + FK definition for one table
schema://relationships/{database}/{schema_name}/{table_name} Foreign key relationships for one table
mcp://guidelines Operational guidelines for safe use of this server
mcp://policy Snapshot of the currently active allowlist policy

Error Handling

When a tool encounters an error (SQL Server connection failure, policy violation, object not found, etc.), it raises a runtime error with a structured code prefix. mcpo propagates the error message as a string in the response.

Common error codes embedded in error messages:

Code Description
CONNECTION_FAILED Cannot connect to SQL Server
TIMEOUT Query or connection timed out
POLICY_VIOLATION Request blocked by allowlist policy
ACCESS_DENIED Insufficient database permissions
TABLE_NOT_FOUND Requested table does not exist
SCHEMA_NOT_FOUND Requested schema does not exist
INVALID_REQUEST Malformed request or invalid SQL
UNKNOWN_ERROR Unexpected internal error

SQL safety refusals (from validate_sql / run_sql_query) are returned inline in the response body with is_valid: false and a refusal_reason string — they are not errors at the HTTP level.


OpenTelemetry Tracing

When MCP_TRACING_ENABLED=true, the server exports traces via OTLP/gRPC to MCP_TRACING_OTLP_ENDPOINT. Every tool call becomes a span under the service name MCP_TRACING_SERVICE_NAME.

Compatible receivers include:

  • Arize Phoenix (default endpoint: http://phoenix:4317)
  • Jaeger (http://jaeger:4317)
  • OpenTelemetry Collector

Running Tests

The test suite uses pytest with direct unit tests — no live SQL Server or MCP client required.

pip install pytest
pytest tests/ packages/sql-validator/tests/ -v

Tests cover:

  • SQL validation logic and risk scoring (direct validate_sql_query() calls)
  • run_sql_query execution guard (mocked metadata service)
  • Audit event and feedback recording stubs
  • Allowlist policy enforcement

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选