MCPRUNNER/mssqlMCP
If you are the rightful owner of mssqlMCP and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
This is a Model Context Protocol (MCP) server that connects to one or more SQL Server databases; designed to be used by Visual Studio Code as a Copilot Agent.
initialize
Initializes the SQL Server connection
executeQuery
Executes a SQL query and returns results as JSON
getTableMetadata
Retrieves metadata about database tables, columns, keys, etc.
getDatabaseObjectsMetadata
Retrieves metadata about tables, views, stored procedures and functions
SQL Server MCP (Model Context Protocol) Server
This is a Model Context Protocol (MCP) server that connects to one or more SQL Server databases; designed to be used by Visual Studio Code as a Copilot Agent.
Overview
This project implements an MCP server for SQL Server database connectivity, enabling VS Code and Copilot to interact with SQL databases via the Model Context Protocol.
Features include:
- SQL query execution
- Database metadata retrieval (tables, views, stored procedures, functions)
- Detailed schema information including primary/foreign keys
- Multi-key API authentication system with master and user-specific keys
- Connection string encryption with AES-256
- Key rotation and security management
- API key usage tracking and analytics
- Async/await for all database operations
- Robust logging with Serilog
- Clean architecture with separation of concerns
- Dependency injection for testable components
- Strongly-typed models for database metadata
How This Works
See for an overview of communication between Copilot, the LLM and this MSSQL Model Context Protocol Server.
API Endpoints
This server provides three types of MCP endpoints:
- Standard MCP Endpoints: Accessible via the ModelContextProtocol.AspNetCore library
- JSON-RPC 2.0 Endpoints: Following the MCP JSON-RPC 2.0 protocol
POST /mcp
: Handlestools/list
andtools/call
methods
- Direct REST API Endpoints: For simpler HTTP access to specific database operations
See the following documentation:
- for details on the JSON-RPC endpoints
- for details on the authentication system
- for C# client examples
- for comprehensive PowerShell testing
Getting Started
Prerequisites
- .NET 9.0 SDK
Runtime Variables
Set mandatory variables prior to starting MCP Server.
Variable Name | Mandatory | Default Value | Recommended Values (Expected Format/Type) | Description |
---|---|---|---|---|
MSSQL_MCP_KEY | Yes | The Start-MCP-Encrypted.ps1 will generate a secure random key if this variable is unset. To generate a secure encryption key you can use Generate-MCP-Key.ps1 , to change the current key use Rotate-Encryption-Key.ps1 | A strong, cryptographically secure random string (e.g., 32 bytes, Base64 encoded). | The master encryption key used for AES-256 encryption of connection strings stored in the connections.db SQLite database. |
MSSQL_MCP_API_KEY | Yes | This is the master API key (Authorization Bearer token). If not set, API key authentication might be disabled or fall back to appsettings.json if configured there. The Set-Api-Key.ps1 script generates one. | A strong, cryptographically secure random string. | The master API key required for administrative access to the MCP server and for creating additional user API keys. User API keys are stored in the SQLite database and managed through the API. |
MSSQL_MCP_DATA | No | Data (A Data subdirectory in the application's root directory) | A valid file system path to a directory. | Overrides the default directory location for storing application data, most notably the connections.db SQLite database file. |
TL;DR The Quick Setup Doc
Project Architecture
This project follows a clean architecture approach with separation of concerns:
See the for diagrams and detailed process flow.
Folder Structure
- Models/: Entity models for database metadata (TableInfo, ColumnInfo, ForeignKeyInfo, etc.)
- Interfaces/: Service interfaces (IDatabaseMetadataProvider, IConnectionStringProvider, ISqlServerTools)
- Services/: Service implementations (DatabaseMetadataProvider, ConnectionManager, ConnectionRepository)
- Configuration/: Configuration-related classes (ConnectionStringProvider)
- Tools/: MCP tool implementations (SqlServerTools, ConnectionManagerTool, SecurityTool)
- Extensions/: Extension methods for service registration (ServiceCollectionExtensions, ApiSecurityExtensions)
- Middleware/: Middleware components (ApiKeyAuthMiddleware)
- Scripts/: Utility and management scripts (Start-MCP-Encrypted.ps1, Rotate-Encryption-Key.ps1, Migrate-To-Encrypted.ps1, Set-Api-Key.ps1, Assess-Connection-Security.ps1, Test-Connection.ps1, Test-Security-Features.ps1, Verify-Encryption-Status.ps1, mcp.json)
- Documentation/: Architecture, security, usage, and API documentation
- Examples/: Example scripts and usage (initialize-mcp.js, test-mcp-curl.sh, test-mcp-powershell.ps1)
- Logs/: Log files (daily rolling logs)
- Tests/: Test code
- Data/: SQLite database for connection storage (connections.db)
- appsettings.json / appsettings.Development.json: Application configuration
- Dockerfile: Containerization support
- mssqlMCP.sln / mssqlMCP.csproj: .NET solution and project files
- CopilotAgent.md / Overview.md: Additional documentation
Key Components
- DatabaseMetadataProvider: Service for retrieving database schema information
- ConnectionStringProvider: Service for managing database connection strings
- ConnectionManager: Manages connection storage and retrieval
- ApiKeyManager: Manages API key lifecycle and validation
- ApiKeyRepository: Stores and retrieves encrypted API keys
- SqlServerTools: MCP tools implementation for SQL Server operations
- ConnectionManagerTool: MCP tool for managing connections
- SecurityTool: MCP tool for security operations (encryption, key rotation, etc.)
- ApiKeyManagementTool: MCP tool for managing API keys
- ServiceCollectionExtensions: Extension methods for registering services with dependency injection
- ApiKeyAuthMiddleware: Middleware for multi-key API authentication
- SQL Server instance (local or remote)
- Visual Studio Code with Copilot extension
Docker Image
To run via a pre-built docker image download and run via hub.docker.com mcprunner/mssqlmcp
Installation and Setup
See
Connection Management
This project includes a robust connection management system that allows you to:
- Store and manage multiple database connections using SQLite as a persistent storage backend
- Add, update, and remove connections programmatically or through the MCP interface
- Test connection strings before saving them
- Use connections across different tools with a unified interface
CORS Configuration
The MCP server includes built-in CORS support that can be configured through appsettings.json
. This is particularly useful when integrating with web-based tools like Open WebUI.
CORS settings can be configured in the Cors
section of appsettings.json
:
{
"Cors": {
"AllowedOrigins": ["http://localhost:3000", "http://localhost:8080"],
"AllowedMethods": ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
"AllowedHeaders": [
"Content-Type",
"Authorization",
"X-API-Key",
"X-Requested-With",
"Accept",
"Origin",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
],
"AllowCredentials": true,
"ExposedHeaders": ["Content-Disposition"]
}
}
- AllowedOrigins: List of origins that can access the API
- AllowedMethods: HTTP methods that are allowed
- AllowedHeaders: HTTP headers that can be used
- AllowCredentials: Whether to allow credentials (cookies, authorization headers)
- ExposedHeaders: Headers that browsers are allowed to access
For production environments, make sure to:
- Replace localhost URLs with your actual domain
- Only include necessary origins, methods, and headers
- Consider setting AllowCredentials to false if cross-origin credentials aren't needed
Connection Storage
Connections are stored in a Sqlite database:
- SQLite database: Located in the
Data/connections.db
file, providing persistent storage - SQLite database override location: Override the Data directory location with Environment Variable
MSSQL_MCP_DATA
Connection Management Tools
The project exposes connection management features through:
- ConnectionManager class: For use within the application
- ConnectionManagerTool: MCP tool for client applications to manage connections
- Connection Security Tools: For encrypting and managing connection string security including key rotation and encryption status verification
Using Connection Management
Starting with Encryption Enabled
See
This script automatically generates a cryptographically secure random key using System.Security.Cryptography.RandomNumberGenerator, sets it as an environment variable, and starts the server with encryption enabled. You can also provide your own key:
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Start-MCP-Encrypted.ps1
For production environments, you should store the key securely and set the environment variable externally using a secrets management solution.
Testing Connection Management
Use the included test script to verify connection management functionality:
./Scripts/test-connection-manager.ps1
This script demonstrates the full lifecycle of connection management including adding, testing, updating, and removing connections.
Database Metadata Features
This MCP server provides comprehensive metadata retrieval functionality for SQL Server databases, allowing Copilot to understand and work with your database schemas effectively.
Table Metadata
You can retrieve detailed information about database tables using the GetTableMetadata
tool:
#GetTableMetadata connectionName="YourConnection" schema="dbo"
This provides complete table metadata including:
- Table names and schemas
- Column details (name, type, nullability, constraints)
- Primary keys
- Foreign key relationships
View Metadata (New!)
As of May 2025, the MCP server now supports retrieving metadata from SQL Server views in addition to tables. This allows Copilot to understand the structure of views and use them in queries.
You can retrieve metadata for both tables and views using the new GetDatabaseObjectsMetadata
tool:
#GetDatabaseObjectsMetadata connectionName="YourConnection" schema="dbo" includeViews=true
Stored Procedure Metadata (New!)
The MCP server now also supports retrieving metadata from SQL Server stored procedures, including procedure definitions and parameters. This allows Copilot to understand and work with stored procedures in your database.
You can retrieve stored procedure metadata using the GetDatabaseObjectsMetadata
tool with the objectType
parameter:
#GetDatabaseObjectsMetadata connectionName="YourConnection" objectType=PROCEDURE
This provides detailed procedure metadata including:
- Procedure names and schemas
- Parameter details (name, type, direction)
- SQL definition (when not encrypted)
Filtering Database Objects
You can filter database objects by type using the objectType
parameter:
# Get only tables
#GetDatabaseObjectsMetadata connectionName="YourConnection" objectType=TABLE
# Get only views
#GetDatabaseObjectsMetadata connectionName="YourConnection" objectType=VIEW
# Get only stored procedures
#GetDatabaseObjectsMetadata connectionName="YourConnection" objectType=PROCEDURE
# Get all database objects
#GetDatabaseObjectsMetadata connectionName="YourConnection" objectType=ALL
You can also filter by schema:
# Get objects from a specific schema
#GetDatabaseObjectsMetadata connectionName="YourConnection" schema="dbo" objectType=ALL
You can also filter by specific object types using the objectType parameter:
#GetDatabaseObjectsMetadata connectionName="YourConnection" schema="dbo" objectType="VIEW"
Valid objectType values are:
- "TABLE" or "TABLES" - Returns only base tables
- "VIEW" or "VIEWS" - Returns only views
- "ALL" (default) - Returns all database objects
The view metadata includes:
- View names and schemas
- Column details
- SQL definition of the view
- Relationships to base tables (where applicable)
By setting includeViews=false
, you can retrieve only table metadata, similar to the original GetTableMetadata
tool.
Example Usage
Here's an example of retrieving both tables and views from a database:
User: Show me all the database objects in my AdventureWorks2022 database, including views
Copilot: I'll retrieve the metadata for all database objects in the AdventureWorks2022 database, including both tables and views.
[Tool used: GetDatabaseObjectsMetadata with connectionName="AdventureWorks2022" includeViews=true]
Results:
The AdventureWorks2022 database contains 68 tables and 20 views across multiple schemas:
Tables:
1. Person.Person - Information about customers, employees, and other individuals
2. Production.Product - Products sold by the company
// ...existing tables...
Views:
1. HumanResources.vEmployee - Employee information combining various related tables
2. Sales.vSalesPerson - Sales person information with their sales data
3. Person.vAdditionalContactInfo - Additional contact information for individuals
A testing script is available in Scripts/test-view-metadata.ps1
that demonstrates how to use the new view metadata functionality.
Using with GitHub Copilot
This MCP server is designed to work seamlessly with GitHub Copilot in VS Code, allowing you to interact with SQL Server databases using natural language.
Setting Up as a Copilot Agent
-
Start the MCP server using the provided script:
# Start with encryption and API security enabled (recommended) $env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption" $env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess" ./Scripts/Start-MCP-Encrypted.ps1
-
Configure Copilot to use this MCP server:
- Copy the file to your VS Code workspace's
.vscode
folder - When prompted, enter the API key that was generated during server startup
- Copy the file to your VS Code workspace's
-
Start asking Copilot about your SQL databases!
Example Copilot Interactions
You can ask Copilot questions like:
- "What tables are in my AdventureWorks database?"
- "Show me the schema of the Sales.Customer table"
- "Write a query to find the top 5 customers by total sales"
- "What are the foreign key relationships in the Sales schema?"
Behind the scenes, Copilot will use the MCP tools to:
- Initialize connection to the database
- Retrieve metadata about tables and schemas
- Execute SQL queries based on your questions
- Format and present the results
For detailed instructions, see the .
MCP Tools for Copilot
The following MCP tools are available for Copilot:
- initialize: Set up the database connection
- executeQuery: Run SQL queries against your database
- getTableMetadata: Get metadata about database tables
- getDatabaseObjectsMetadata: Get metadata about tables, views, and stored procedures
- connectionManager/...: Manage database connections
See the for examples and detailed usage information.
Advanced Copilot Chat Examples
Exploring Database Relationships
User: Show me the relationships between tables in the Sales schema
Copilot: I'll get the foreign key relationships in the Sales schema for you.
[Tool used: GetTableMetadata with connectionName="AdventureWorks2022", schema="Sales"]
Results:
I found the following relationships in the Sales schema:
1. SalesOrderDetail.SalesOrderID → SalesOrderHeader.SalesOrderID
2. SalesOrderDetail.ProductID → Production.Product.ProductID
3. SalesOrderHeader.CustomerID → Customer.CustomerID
4. SalesOrderHeader.SalesPersonID → SalesPerson.BusinessEntityID
5. SalesOrderHeader.TerritoryID → SalesTerritory.TerritoryID
6. SalesPerson.TerritoryID → SalesTerritory.TerritoryID
This shows that:
- SalesOrderDetail records are linked to SalesOrderHeader records
- SalesOrderDetail also references products from the Production schema
- SalesOrderHeader connects to Customer, SalesPerson, and SalesTerritory
- SalesPerson is associated with a specific SalesTerritory
Advanced SQL Queries
User: Find the top 3 product categories by sales amount in the AdventureWorks2022 database
Copilot: I'll query the AdventureWorks2022 database to find the top product categories by sales.
[Tool used: ExecuteQuery with connectionName="AdventureWorks2022"]
Query:
SELECT TOP 3
PC.Name AS CategoryName,
SUM(SOD.LineTotal) AS SalesAmount
FROM Production.ProductCategory PC
JOIN Production.ProductSubcategory PSC ON PC.ProductCategoryID = PSC.ProductCategoryID
JOIN Production.Product P ON PSC.ProductSubcategoryID = P.ProductSubcategoryID
JOIN Sales.SalesOrderDetail SOD ON P.ProductID = SOD.ProductID
GROUP BY PC.Name
ORDER BY SalesAmount DESC
Results:
[
{
"CategoryName": "Bikes",
"SalesAmount": 28318144.9706
},
{
"CategoryName": "Components",
"SalesAmount": 1319863.9132
},
{
"CategoryName": "Clothing",
"SalesAmount": 340253.1788
}
]
The top 3 product categories by sales in the AdventureWorks2022 database are:
1. "Bikes" with $28,318,144.97 in sales
2. "Components" with $1,319,863.91 in sales
3. "Clothing" with $340,253.18 in sales
Querying Across Tables
User: Get the sales summary for the top 3 sales territories in the most recent year
Copilot: I'll retrieve the sales summary for the top territories from the AdventureWorks2022 database.
[Tool used: ExecuteQuery with connectionName="AdventureWorks2022"]
Query:
WITH RecentYear AS (
SELECT MAX(YEAR(OrderDate)) AS MostRecentYear
FROM Sales.SalesOrderHeader
)
SELECT TOP 3
ST.Name AS Territory,
ST.CountryRegionCode AS Country,
SUM(SOH.TotalDue) AS TotalSales,
COUNT(DISTINCT SOH.CustomerID) AS CustomerCount,
COUNT(SOH.SalesOrderID) AS OrderCount,
MIN(SOH.OrderDate) AS FirstOrder,
MAX(SOH.OrderDate) AS LastOrder
FROM Sales.SalesTerritory ST
JOIN Sales.SalesOrderHeader SOH ON ST.TerritoryID = SOH.TerritoryID
JOIN RecentYear RY ON YEAR(SOH.OrderDate) = RY.MostRecentYear
GROUP BY ST.Name, ST.CountryRegionCode
ORDER BY TotalSales DESC
Results:
[
{
"Territory": "North America",
"Country": "US",
"TotalSales": 3519153.4118,
"CustomerCount": 487,
"OrderCount": 1573,
"FirstOrder": "2014-01-01T00:00:00.000Z",
"LastOrder": "2014-12-31T00:00:00.000Z"
},
{
"Territory": "Europe",
"Country": "GB",
"TotalSales": 2897231.9182,
"CustomerCount": 378,
"OrderCount": 1041,
"FirstOrder": "2014-01-01T00:00:00.000Z",
"LastOrder": "2014-12-31T00:00:00.000Z"
},
{
"Territory": "Pacific",
"Country": "AU",
"TotalSales": 1457240.8527,
"CustomerCount": 192,
"OrderCount": 531,
"FirstOrder": "2014-01-01T00:00:00.000Z",
"LastOrder": "2014-12-30T00:00:00.000Z"
}
]
These examples demonstrate how Copilot can help you explore relationships between tables, analyze data patterns, and perform complex queries across multiple tables in your SQL Server databases.
Available Tools
initialize
: Initializes the SQL Server connectionexecuteQuery
: Executes a SQL query and returns results as JSONgetTableMetadata
: Retrieves metadata about database tables, columns, keys, etc. You can filter by schema or get all schemas.getDatabaseObjectsMetadata
: Retrieves metadata about tables, views, stored procedures and functions, including schemas, columns, and relationships.
Copilot Tool Usage
When used with GitHub Copilot in Visual Studio Code, the tools are available as functions that can be invoked in chat:
// Tool invocation pattern
f1e_Initialize({ connectionName: "DefaultConnection" });
f1e_ExecuteQuery({
connectionName: "AdventureWorks2022",
query: "SELECT TOP 5 * FROM Production.Product",
});
f1e_GetTableMetadata({ connectionName: "AdventureWorks2022", schema: "Sales" });
f1e_GetDatabaseObjectsMetadata({
connectionName: "AdventureWorks2022",
schema: "Person",
includeViews: true,
});
You'll typically interact with these tools by asking questions in natural language, and Copilot will handle the function calls automatically.
Schema Filtering
The getTableMetadata
tool supports schema filtering, which allows you to retrieve metadata for tables in a specific schema:
Usage Examples
// Get all database metadata (all schemas)
var metadata = await GetTableMetadata();
// Get metadata for a specific connection (all schemas)
var awMetadata = await GetTableMetadata("AdventureWorks");
// Get metadata for tables in a specific schema
var dboSchemaMetadata = await GetTableMetadata("DefaultConnection", "dbo");
// Get metadata for a specific schema in a specific database
var awSalesSchema = await GetTableMetadata("AdventureWorks", "Sales");
This feature is particularly useful when working with large databases that have many schemas, allowing you to focus on just the relevant parts of the database structure.
Example Usage
Initializing Connection
// Initialize the default connection
var result = await Initialize();
// Or specify a specific connection
var adventureWorksResult = await Initialize("AdventureWorks");
Executing SQL Queries
// Basic SELECT query
var users = await ExecuteQuery("SELECT TOP 10 * FROM Users");
// Query with parameters (handle SQL injection carefully)
var productQuery = "SELECT * FROM Products WHERE Category = 'Electronics' AND Price < 500";
var products = await ExecuteQuery(productQuery);
// Query with specific connection
var salesData = await ExecuteQuery("SELECT * FROM Sales.SalesOrderHeader", "AdventureWorks");
Getting Database Metadata
// Get all database metadata (all schemas)
var metadata = await GetTableMetadata();
// Get metadata for a specific connection (all schemas)
var awMetadata = await GetTableMetadata("AdventureWorks");
// Get metadata for tables in a specific schema
var dboSchemaMetadata = await GetTableMetadata("DefaultConnection", "dbo");
// Get metadata for a specific schema in a specific database
var awSalesSchema = await GetTableMetadata("AdventureWorks", "Sales");
Common SQL Query Examples
-- Get all tables in the database
SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
ORDER BY TABLE_SCHEMA, TABLE_NAME
-- Get column information for a specific table
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'YourTableName'
ORDER BY ORDINAL_POSITION
-- Get primary key information
SELECT TC.TABLE_SCHEMA, TC.TABLE_NAME, KCU.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU
ON TC.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME
WHERE TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
ORDER BY TC.TABLE_SCHEMA, TC.TABLE_NAME
Troubleshooting Copilot Tools
When using the MCP tools with GitHub Copilot, you might encounter some common issues:
Connection Issues
If Copilot cannot connect to your database:
User: Show me all tables in the AdventureWorksLT database
Copilot: I'll try to retrieve the metadata from the AdventureWorksLT database.
[Tool used: GetTableMetadata with connectionName="AdventureWorksLT"]
Error: Connection string 'AdventureWorksLT' was not found in the configuration.
Solution: Make sure the connection string is properly defined via #ListConnections
.
Query Syntax Errors
If your SQL query has syntax errors:
User: Run this query: SELECT FROM Production.Product WHERE ListPrice < 100
Copilot: I'll execute this query for you.
[Tool used: ExecuteQuery with connectionName="AdventureWorks2022"]
Query: SELECT FROM Production.Product WHERE ListPrice < 100
Error: Incorrect syntax near the keyword 'FROM'.
Solution: Check that your SQL query follows proper syntax. In this case, you need to specify columns after SELECT.
Connection Name Mismatch
When the connection name doesn't match exactly what's in your configuration:
User: Get tables from AdventureWorks database
Copilot: I'll get the tables from the AdventureWorks database.
[Tool used: GetTableMetadata with connectionName="AdventureWorks"]
Error: Connection string 'AdventureWorks' was not found in the configuration.
Solution: Use the exact connection string name as defined in your configuration. In this case, use "AdventureWorks2022" instead of "AdventureWorks".
Table or Schema Not Found
When querying non-existent objects:
User: Show me data from the Customers table
Copilot: I'll query the Customers table for you.
[Tool used: ExecuteQuery with connectionName="AdventureWorks2022"]
Query: SELECT TOP 10 * FROM Customers
Error: Invalid object name 'Customers'.
Solution: First use GetTableMetadata to see which tables are available, then query the correct table name with the proper schema prefix if needed, e.g., "Sales.Customer".
Performance Tips
- Be specific about which schema you're interested in when using GetTableMetadata
- Limit the number of rows returned in queries with TOP or LIMIT clauses
- Consider adding WHERE clauses to filter data and improve query performance
- For large databases, query only the columns you need instead of using SELECT *
Security
Connection String Encryption
To enhance security, connection strings are encrypted with AES-256 encryption before being stored in the SQLite database. The encryption key is derived from the environment variable MSSQL_MCP_KEY
.
To enable secure connection string encryption:
- Set the
MSSQL_MCP_KEY
environment variable to a strong random value, or - Use the provided
Start-MCP-Encrypted.ps1
script which will generate a cryptographically secure random key for you and start the server with encryption enabled.
# Option 1: Set the encryption key manually (should be a strong random value)
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
dotnet run
# Option 2: Use the automated script that handles key generation and server startup
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Start-MCP-Encrypted.ps1
The Scripts/Start-MCP-Encrypted.ps1
script:
- Checks if the encryption key is already set
- Generates a cryptographically secure random key (using System.Security.Cryptography.RandomNumberGenerator) if none exists
- Sets the environment variable for the current session
- Displays the key (securely store this for later use)
- Starts the MCP server with encryption enabled
If the MSSQL_MCP_KEY
environment variable is not set and you don't use the script, the server will still function but will use a default insecure key. This is not recommended for production use. For production environments, consider using a secure secrets management solution to store and retrieve your encryption key.
Security Best Practices
- Always use encrypted connections when possible (e.g., use
Encrypt=True
in your connection strings) - Use separate SQL accounts with minimal permissions for different applications
- Regularly update the
MSSQL_MCP_KEY
environment variable to rotate encryption keys - Do not store the encryption key in plaintext files or source code
- Consider using a secrets manager for the encryption key in production environments
Starting
For more detailed testing, you can use the individual scripts:
# Start the server with encryption enabled
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Start-MCP-Encrypted.ps1
# Rotate the encryption key
./Scripts/Rotate-Encryption-Key.ps1
# Migrate unencrypted connections to encrypted format
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Migrate-To-Encrypted.ps1
Logs
Logs are stored in the Logs
directory with daily rolling files. The logging configuration can be customized in the appsettings.json
file under the Serilog
section.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Security Features
The SQL Server MCP server includes robust security features to protect sensitive information such as connection strings.
Connection String Encryption
All connection strings stored in the SQLite database are encrypted using AES-256 encryption with the following security measures:
- AES-256 Encryption: Industry-standard encryption algorithm
- Environment Variable Key: The encryption key is derived from the
MSSQL_MCP_KEY
environment variable - Unique IV Per Connection: Each connection string uses a unique Initialization Vector
- PBKDF2 Key Derivation: Key is derived with 10,000 iterations for enhanced security
Starting with Encryption Enabled
To run the server with encryption enabled, use the provided script:
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Start-MCP-Encrypted.ps1
This script:
- Generates a cryptographically secure random key if one is not provided
- Sets the key as an environment variable for the current session
- Displays the key for you to save securely
- Starts the MCP server with encryption enabled
You can also provide your own key:
$env:MSSQL_MCP_KEY = "ReplaceWithMyKeyForTheConnectionEncryption"
$env:MSSQL_MCP_API_KEY = "ReplaceWithMyApiKeyForClientAccess"
./Scripts/Start-MCP-Encrypted.ps1
For production environments, you should store the key securely and set the environment variable externally using a secrets management solution.
Key Rotation
The server supports rotating the encryption key to comply with security best practices. To rotate the key:
./Scripts/Rotate-Encryption-Key.ps1
This script:
- Generates a new random encryption key (or you can provide your own)
- Re-encrypts all connection strings using the new key
- Displays the new key for you to save
After running the key rotation script, you must restart the server with the new key.
Migrating Unencrypted Connections
To migrate existing unencrypted connection strings to encrypted format:
./Scripts/Migrate-To-Encrypted.ps1
This script will encrypt any unencrypted connection strings in the database.
MCP Security Commands
The following MCP commands are available for security operations:
# Rotate the encryption key
#security.rotateKey newKey="your-new-key"
# Migrate unencrypted connections to encrypted format
#security.migrateConnectionsToEncrypted
# Generate a secure random key for encryption
#security.generateSecureKey length=32
# Verify encryption status of connections
#security.verifyEncryptionStatus
# Assess connection security
#security.assessConnectionSecurity
Each of these commands connects to the functionality in the SecurityTool.cs
class, which implements the MCP server tools for security operations. These commands follow the standard MCP command syntax with the # prefix.
Connection Validation and Security Assessment
The SQL Server MCP server includes enhanced security features for validating connections and assessing security status:
Connection Validation
When rotating keys or encrypting connections, the system:
- Validates input connections before processing
- Verifies encryption round-trip to ensure data integrity
- Tracks and reports any failures during the process
- Provides detailed logs of operations
Security Assessment
Use the included security assessment script to evaluate your connection security:
./Scripts/Assess-Connection-Security.ps1
This script:
- Analyzes all connections to identify encrypted vs unencrypted connections
- Reports the encryption status of each connection
- Checks if the encryption key is properly set
- Offers to generate a new secure key if needed
- Provides guidance on securing your connections
Enhanced Testing
For comprehensive security testing, use:
./Test-Security-Features.ps1
This enhanced testing script:
- Tests connection creation with encryption
- Verifies connections work after encryption
- Tests key rotation with validation
- Includes connection testing after key rotation
- Uses proper error handling for API communication
For detailed security information, see the .
API Security
Multi-Key API Authentication System
The MCP server implements a robust multi-key API authentication system to secure API endpoints. This system supports both a master API key for administrative access and multiple user-specific API keys for regular access.
Key Authentication Features
- Master API key for administrative access to all endpoints
- User-specific API keys with optional expiration dates
- API key usage tracking and analytics
- API key revocation capabilities
- Encrypted storage of API keys in SQLite database
- Multiple key types (user, service, admin)
For detailed information about the multi-key authentication system, see .
Setting Up API Key Authentication
- Generate and set a master API key using the provided script:
./Scripts/Set-Api-Key.ps1
This script will:
- Generate a cryptographically secure random API key
- Set it as the environment variable
MSSQL_MCP_API_KEY
for the current session - Display usage examples for making authenticated API calls
- Additional user-specific API keys can be created using the CreateApiKey endpoint:
# PowerShell example to create a new user API key
Invoke-RestMethod -Uri "http://localhost:3001/mcp" -Method Post `
-Headers @{"Authorization" = "Bearer your-master-api-key"; "Content-Type" = "application/json"} `
-Body '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "CreateApiKey",
"arguments": {
"name": "User API Key",
"userId": "user123",
"keyType": "user",
"expirationDate": "2026-06-29T00:00:00Z"
}
}
}'
API Key Configuration
The master API key can be configured in different ways:
-
Environment Variable: Set
MSSQL_MCP_API_KEY
environment variable$env:MSSQL_MCP_API_KEY = "your-secure-master-api-key"
-
Application Settings: Configure in
appsettings.json
under the ApiSecurity section:"ApiSecurity": { "HeaderName": "X-API-Key", "ApiKey": "your-secure-master-api-key" }
User-specific API keys are managed through the API endpoints and stored securely in the SQLite database.
Making Authenticated Requests
When API key authentication is enabled, all HTTP requests to the server must include either the master API key or a valid user API key as a Bearer token in the Authorization header:
# PowerShell example
Invoke-RestMethod -Uri "http://localhost:3001/" -Method Post `
-Headers @{"Authorization" = "Bearer your-api-key"; "Content-Type" = "application/json"} `
-Body '{"jsonrpc": "2.0", "id": 1, "method": "#TestConnection", "params": {"ConnectionName": "My_DBCONNECTION_Name"}}'
# curl example
curl -X POST http://localhost:3001/ -H "Authorization: Bearer your-api-key" -H "Content-Type: application/json" `
-d '{"jsonrpc": "2.0", "id": 1, "method": "#TestConnection", "params": {"ConnectionName": "My_DBCONNECTION_Name"}}'
API Key Management
The MCP server provides endpoints for managing API keys:
-
CreateApiKey: Create a new API key for a specific user
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "CreateApiKey", "arguments": { "name": "My Test API Key", "userId": "SomeUserId", "keyType": "user", "expirationDate": "2026-06-29T00:00:00Z" } } }
-
ListUserApiKeys: List all API keys for a specific user
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "ListUserApiKeys", "arguments": { "userId": "SomeUserId" } } }
-
ListAllApiKeys: List all API keys in the system (admin only)
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "ListAllApiKeys", "arguments": {} } }
-
RevokeApiKey: Revoke an API key (mark as inactive)
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "RevokeApiKey", "arguments": { "request": { "id": "key-id-to-revoke" } } } }
-
DeleteApiKey: Permanently delete an API key
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "DeleteApiKey", "arguments": { "id": "key-id-to-delete" } } }
-
GetApiKeyUsageLogs: Get usage logs for a specific API key
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "GetApiKeyUsageLogs", "arguments": { "apiKeyId": "target-key-id", "limit": 100 } } }
-
GetUserUsageLogs: Get API usage logs for a specific user
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "GetUserUsageLogs", "arguments": { "userId": "target-user-id", "limit": 100 } } }
Security Considerations
- Store API keys securely and never expose them in client-side code
- Use the master API key only for administrative tasks
- Create user-specific API keys with appropriate expiration dates for regular access
- Rotate API keys periodically for enhanced security
- Monitor API usage logs for suspicious activity
- Revoke compromised API keys immediately
- Use HTTPS in production environments when exposing the API
- Consider implementing additional security measures for high-security environments