From cb643427ef29e79fe41ef846ff55c8ca6b6eaedd Mon Sep 17 00:00:00 2001 From: Babacar Diop Date: Thu, 11 Dec 2025 12:30:16 -0500 Subject: [PATCH] Enhance MSSQL MCP Node configuration to support multiple authentication types. Added SQL Server authentication options in README and updated connection logic to handle both SQL and Entra ID authentication. Updated sample configurations to reflect new authentication settings. --- MssqlMcp/Node/README.md | 27 ++++++++ MssqlMcp/Node/src/index.ts | 62 ++++++++++++++++--- .../src/samples/claude_desktop_config.json | 1 + .../Node/src/samples/vscode_agent_config.json | 1 + 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/MssqlMcp/Node/README.md b/MssqlMcp/Node/README.md index 3f7e687..c72e1a6 100644 --- a/MssqlMcp/Node/README.md +++ b/MssqlMcp/Node/README.md @@ -142,11 +142,38 @@ This server leverages the Model Context Protocol (MCP), a versatile framework th - **SERVER_NAME**: Your MSSQL Database server name (e.g., `my-server.database.windows.net`) - **DATABASE_NAME**: Your database name +- **AUTHENTICATION_TYPE**: Authentication method to use. Options: + - `"entra"` - Use Microsoft Entra ID (Azure AD) authentication with interactive browser login (default) + - `"sql"` - Use SQL Server authentication with username/password +- **SQL_USER**: (Required when `AUTHENTICATION_TYPE` is `"sql"`) SQL Server username +- **SQL_PASSWORD**: (Required when `AUTHENTICATION_TYPE` is `"sql"`) SQL Server password - **READONLY**: Set to `"true"` to restrict to read-only operations, `"false"` for full access - **Path**: Update the path in `args` to point to your actual project location. - **CONNECTION_TIMEOUT**: (Optional) Connection timeout in seconds. Defaults to `30` if not set. - **TRUST_SERVER_CERTIFICATE**: (Optional) Set to `"true"` to trust self-signed server certificates (useful for development or when connecting to servers with self-signed certs). Defaults to `"false"`. +### Example: SQL Server Authentication + +```json +{ + "mcpServers": { + "mssql": { + "command": "node", + "args": ["C:/path/to/your/Node/dist/index.js"], + "env": { + "SERVER_NAME": "your-server-name", + "DATABASE_NAME": "your-database-name", + "AUTHENTICATION_TYPE": "sql", + "SQL_USER": "your_username", + "SQL_PASSWORD": "your_password", + "TRUST_SERVER_CERTIFICATE": "true", + "READONLY": "true" + } + } + } +} +``` + ## Sample Configurations You can find sample configuration files in the `src/samples/` folder: diff --git a/MssqlMcp/Node/src/index.ts b/MssqlMcp/Node/src/index.ts index 8dc1f30..c41197e 100644 --- a/MssqlMcp/Node/src/index.ts +++ b/MssqlMcp/Node/src/index.ts @@ -24,22 +24,62 @@ import { DescribeTableTool } from "./tools/DescribeTableTool.js"; // MSSQL Database connection configuration // const credential = new DefaultAzureCredential(); +// Authentication types +type AuthenticationType = 'sql' | 'entra'; + // Globals for connection and token reuse let globalSqlPool: sql.ConnectionPool | null = null; let globalAccessToken: string | null = null; let globalTokenExpiresOn: Date | null = null; -// Function to create SQL config with fresh access token, returns token and expiry -export async function createSqlConfig(): Promise<{ config: sql.config, token: string, expiresOn: Date }> { +// Get authentication type from environment variable (defaults to 'entra' for backward compatibility) +function getAuthenticationType(): AuthenticationType { + const authType = process.env.AUTHENTICATION_TYPE?.toLowerCase(); + if (authType === 'sql') return 'sql'; + if (authType === 'entra') return 'entra'; + // Default to 'entra' for backward compatibility + return 'entra'; +} + +// Function to create SQL config - supports both SQL auth and Entra ID auth +export async function createSqlConfig(): Promise<{ config: sql.config, token: string | null, expiresOn: Date | null }> { + const trustServerCertificate = process.env.TRUST_SERVER_CERTIFICATE?.toLowerCase() === 'true'; + const connectionTimeout = process.env.CONNECTION_TIMEOUT ? parseInt(process.env.CONNECTION_TIMEOUT, 10) : 30; + const authType = getAuthenticationType(); + + if (authType === 'sql') { + // Use SQL Server authentication (username/password) + const sqlUser = process.env.SQL_USER; + const sqlPassword = process.env.SQL_PASSWORD; + + if (!sqlUser || !sqlPassword) { + throw new Error('SQL authentication requires SQL_USER and SQL_PASSWORD environment variables'); + } + + return { + config: { + server: process.env.SERVER_NAME!, + database: process.env.DATABASE_NAME!, + user: sqlUser, + password: sqlPassword, + options: { + encrypt: true, + trustServerCertificate + }, + connectionTimeout: connectionTimeout * 1000, // convert seconds to milliseconds + }, + token: null, + expiresOn: null + }; + } + + // Use Entra ID (Azure AD) authentication const credential = new InteractiveBrowserCredential({ redirectUri: 'http://localhost' // disableAutomaticAuthentication : true }); const accessToken = await credential.getToken('https://database.windows.net/.default'); - const trustServerCertificate = process.env.TRUST_SERVER_CERTIFICATE?.toLowerCase() === 'true'; - const connectionTimeout = process.env.CONNECTION_TIMEOUT ? parseInt(process.env.CONNECTION_TIMEOUT, 10) : 30; - return { config: { server: process.env.SERVER_NAME!, @@ -164,8 +204,16 @@ runServer().catch((error) => { // Connect to SQL only when handling a request async function ensureSqlConnection() { - // If we have a pool and it's connected, and the token is still valid, reuse it + const authType = getAuthenticationType(); + + // If using SQL auth, just check if pool is connected (no token expiry to worry about) + if (authType === 'sql' && globalSqlPool && globalSqlPool.connected) { + return; + } + + // If using Entra ID auth, check if pool is connected and token is still valid if ( + authType === 'entra' && globalSqlPool && globalSqlPool.connected && globalAccessToken && @@ -175,7 +223,7 @@ async function ensureSqlConnection() { return; } - // Otherwise, get a new token and reconnect + // Otherwise, get config (and new token if using Entra ID) and reconnect const { config, token, expiresOn } = await createSqlConfig(); globalAccessToken = token; globalTokenExpiresOn = expiresOn; diff --git a/MssqlMcp/Node/src/samples/claude_desktop_config.json b/MssqlMcp/Node/src/samples/claude_desktop_config.json index 5f2c0fa..8714389 100644 --- a/MssqlMcp/Node/src/samples/claude_desktop_config.json +++ b/MssqlMcp/Node/src/samples/claude_desktop_config.json @@ -6,6 +6,7 @@ "env": { "SERVER_NAME": "your-server-name.database.windows.net", "DATABASE_NAME": "your-database-name", + "AUTHENTICATION_TYPE": "entra", "READONLY": "false" } } diff --git a/MssqlMcp/Node/src/samples/vscode_agent_config.json b/MssqlMcp/Node/src/samples/vscode_agent_config.json index a8f91ff..85cfe24 100644 --- a/MssqlMcp/Node/src/samples/vscode_agent_config.json +++ b/MssqlMcp/Node/src/samples/vscode_agent_config.json @@ -8,6 +8,7 @@ "env": { "SERVER_NAME": "your-server-name.database.windows.net", "DATABASE_NAME": "your-database-name", + "AUTHENTICATION_TYPE": "entra", "READONLY": "false" } }