sqlserver-mcp 0.5.0

SQL Server 2025/2022/2019/2017 - master/msdb/sandbox combined catalog MCP server, generated by mcpify.
Documentation
// SQL Server 2025 - master/msdb/sandbox combined catalog MCP server — generated by mcpify. Do not hand-edit.

use serde::{Deserialize, Serialize};

/// One variant per TDS authentication mode the merged spec's
/// `components.securitySchemes` documents (`sqlAuth`/`windowsAuth`/
/// `azureADAuth` — see docs/sqlserver-eda-openapi-pipeline/README.md's
/// "OpenAPI mapping convention"). mcpify's OpenAPI-auth-scheme classifier
/// only recognizes `sqlAuth` (`http`/`basic` -> mapped here as
/// `SqlServer`) and `azureADAuth` (`oauth2` -> `AzureAd`) — `windowsAuth`
/// (`http`/`negotiate`) isn't a scheme shape mcpify's classifier knows, so
/// `Windows` was added by hand rather than generated.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AuthMethod {
    #[serde(rename = "sql_server")]
    SqlServer,
    #[serde(rename = "windows")]
    Windows,
    #[serde(rename = "azure_ad")]
    AzureAd,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Transport {
    Stdio,
    Http,
}

fn default_log_level() -> String {
    "info".to_string()
}
fn default_rate_limit() -> u32 {
    100
}
fn default_timeout_ms() -> u64 {
    30_000
}
fn default_cache_size() -> u32 {
    500
}
fn default_retry_attempts() -> u32 {
    3
}
fn default_transport() -> Transport {
    Transport::Stdio
}
fn default_host() -> String {
    "127.0.0.1".to_string()
}
fn default_port() -> u16 {
    3000
}
fn default_sql_port() -> u16 {
    1433
}
fn default_pool_max_size() -> u32 {
    10
}
fn default_trust_server_cert() -> bool {
    true
}

// mcpify:versions:begin
fn default_api_version() -> String {
    "2025".to_string()
}
// mcpify:versions:end

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    /// The SQL Server instance to connect to: `host` or `host:port` (TDS,
    /// not HTTP — mcpify's originally-generated field name/semantics for
    /// "where the target API lives" carried over unchanged, only what it
    /// means changed). Falls back to `sql_port`/the TDS default (1433) when
    /// no `:port` suffix is present — see `Config::host_and_port`.
    pub url: String,
    pub auth_method: AuthMethod,
    #[serde(default = "default_sql_port")]
    pub sql_port: u16,
    /// Maximum size of the pooled SQL Server connections
    /// (`services::sql_pool`) kept open at once.
    #[serde(default = "default_pool_max_size")]
    pub pool_max_size: u32,
    /// Whether to trust the server's TLS certificate without verifying it
    /// against a CA — on by default since this project's primary use case
    /// is a local Docker/dev instance with a self-signed cert (see
    /// docs/sqlserver-eda-openapi-pipeline/docker-compose.yml); set to
    /// `false` for a production instance with a real CA-signed cert.
    #[serde(default = "default_trust_server_cert")]
    pub trust_server_cert: bool,
    /// v8 multi-version support: an opaque label (not a compile-time enum
    /// like `AuthMethod` — version labels are arbitrary operator-supplied
    /// strings such as `"10.2.14"`, which can't cleanly become Rust
    /// identifiers), validated at runtime against the known version list
    /// in `data::store::resolve_store_path`/`validation::validator`.
    #[serde(default = "default_api_version")]
    pub api_version: String,
    #[serde(default = "default_log_level")]
    pub log_level: String,
    #[serde(default = "default_rate_limit")]
    pub rate_limit: u32,
    #[serde(default = "default_timeout_ms")]
    pub timeout_ms: u64,
    #[serde(default = "default_cache_size")]
    pub cache_size: u32,
    #[serde(default = "default_retry_attempts")]
    pub retry_attempts: u32,
    #[serde(default = "default_transport")]
    pub transport: Transport,
    #[serde(default = "default_host")]
    pub host: String,
    #[serde(default = "default_port")]
    pub port: u16,
    #[serde(default)]
    pub cors_allow: Option<String>,
}

impl Config {
    /// Splits `url` into `(host, port)`, using `sql_port` (default 1433,
    /// TDS's standard port) when `url` carries no explicit `:port` suffix.
    pub fn host_and_port(&self) -> (&str, u16) {
        if let Some((host, port)) = self.url.rsplit_once(':')
            && let Ok(port) = port.parse()
        {
            return (host, port);
        }
        (self.url.as_str(), self.sql_port)
    }
}