Skip to main content
Glama
jesse-smith
by jesse-smith

DBMCP: Database MCP Server for SQL Server

CI codecov

MCP server that gives AI assistants full read-only access to SQL Server databases -- schema exploration, query execution, and structural analysis. Designed for legacy databases with undeclared foreign keys. All responses use TOON format for minimal token consumption.

Features

  • Schema exploration (schemas, tables, columns, indexes, constraints)

  • Read-only query execution with CTE support and automatic row limiting

  • Query validation via configurable denylist (sqlglot-based)

  • Primary key candidate discovery

  • Foreign key candidate inference

  • Column statistics and analysis

  • Azure AD integrated authentication

  • TOON-formatted responses (token-efficient for LLM consumers)

  • Async database execution with configurable query timeouts

Related MCP server: sqldb-mcp-server

Requirements

  • Python 3.11+

  • SQL Server (via ODBC Driver 18)

  • uv (Python package manager)

  • MCP-compatible client (Claude Desktop, Claude Code, etc.)

Installation

uv tool install "dbmcp @ git+https://github.com/jesse-smith/dbmcp.git"

2. Local development

git clone https://github.com/jesse-smith/dbmcp.git
cd dbmcp
uv sync

ODBC Driver 18

macOS:

brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew install msodbcsql18

Linux (Ubuntu/Debian):

curl 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 msodbcsql18

Windows: Download from: https://learn.microsoft.com/en-us/sql/connect/odbc/download-odbc-driver-for-sql-server

MCP Client Configuration

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp"
    }
  }
}

Claude Code

Add to .mcp.json or configure via CLI:

{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp",
      "type": "stdio"
    }
  }
}

If installed locally (not via uv tool), use uv run dbmcp as the command and set cwd to the repo directory.

Configuration

dbmcp loads optional configuration from a TOML file. No config file is required — all settings have sensible defaults.

Config file locations

dbmcp searches for a config file in this order (first match wins):

Priority

Path

Use case

1

./dbmcp.toml

Project-level config, committed to repo or kept local

2

~/.dbmcp/config.toml

User-level config, shared across all projects

Setting up a project-level config

Create dbmcp.toml in the directory where the MCP server runs (usually your project root):

[defaults]
query_timeout = 60          # seconds (5–300, default: 30)
row_limit = 5000            # max rows returned (1–10000, default: 1000)
sample_size = 10            # default sample rows (1–1000, default: 5)
text_truncation_limit = 2000  # chars before truncation (100–10000, default: 1000)

[connections.dev]
server = "localhost"
database = "mydb"
authentication_method = "sql"
username = "sa"
password = "${SA_PASSWORD}"   # resolved from env var at connection time
trust_server_cert = true

[connections.prod]
server = "prod-server.example.com"
database = "proddb"
port = 1434
authentication_method = "windows"

allowed_stored_procedures = ["sp_custom_report", "dbo.my_proc"]

Setting up a user-level config

Create ~/.dbmcp/config.toml for connections and defaults you want available everywhere:

mkdir -p ~/.dbmcp
# ~/.dbmcp/config.toml

[defaults]
query_timeout = 60

[connections.staging]
server = "staging-db.internal"
database = "app_staging"
authentication_method = "azure_ad_integrated"
tenant_id = "your-tenant-id"

[connections.local]
server = "localhost"
database = "devdb"
authentication_method = "sql"
username = "sa"
password = "${SA_PASSWORD}"
trust_server_cert = true

Tip: If both files exist, the project-level dbmcp.toml takes precedence and the user-level file is ignored entirely.

Using named connections

Once configured, pass the connection name to connect_database instead of individual parameters:

connect_database(connection_name="dev")

Explicit parameters override config values, so you can use a named connection as a base and override specific fields:

connect_database(connection_name="dev", database="other_db")

Connection fields reference

Field

Type

Default

Description

server

string

(required)

SQL Server hostname or IP

database

string

(required)

Database name

port

int

1433

SQL Server port

authentication_method

string

"sql"

sql, windows, azure_ad, or azure_ad_integrated

username

string

For SQL or Azure AD auth

password

string

Supports ${ENV_VAR} references

trust_server_cert

bool

false

Trust server certificate without validation

connection_timeout

int

30

Connection timeout in seconds

tenant_id

string

Azure AD tenant ID (for azure_ad_integrated)

Environment variable references

Credential fields support ${VAR_NAME} syntax. Variables are resolved at connection time (not when the config is loaded), so the environment variable must be set when you call connect_database:

[connections.prod]
server = "prod-server"
database = "proddb"
password = "${PROD_DB_PASSWORD}"

Corporate MITM TLS Gateways (Databricks)

If your Databricks workspace is reached via a corporate TLS-rewriting gateway (e.g. Cloudflare Zero Trust), Python won't trust the gateway's CA by default (it ignores NODE_EXTRA_CA_CERTS). Set ca_bundle in your Databricks connection config to point at the gateway CA file:

[connections.databricks-prod]
dialect = "databricks"
host = "${DATABRICKS_HOST}"
http_path = "${DATABRICKS_HTTP_PATH}"
token = "${DATABRICKS_TOKEN}"
catalog = "main"
ca_bundle = "~/.ssl-certs/gateway-ca.pem"  # PEM with the gateway CA

Alternatively, set DBMCP_CA_BUNDLE=/path/to/ca.pem in your shell as a process-wide fallback (applies to every Databricks connection that doesn't set ca_bundle explicitly). Tilde and ${VAR} are both expanded. Precedence: explicit per-connection ca_bundle > URL ?ca_bundle= query param > DBMCP_CA_BUNDLE env > unset (connector falls back to certifi).

Point ca_bundle at the gateway CA file alone — dbmcp automatically merges it with certifi's bundle at connect time, so standard intermediates (DigiCert, etc.) remain trusted alongside the gateway root.

This setting is currently Databricks-only; MSSQL and generic dialects do not have an equivalent hook yet.

MCP Tools Reference

Tool

Description

connect_database

Connect to a SQL Server instance (Windows auth, SQL auth, or Azure AD)

list_schemas

List all schemas with table/view counts

list_tables

List tables with filtering, sorting, and pagination

get_table_schema

Get detailed table schema (columns, indexes, foreign keys)

get_sample_data

Retrieve sample rows from a table

execute_query

Execute read-only SQL queries (supports CTEs)

get_column_info

Get column-level statistics and value distributions

find_pk_candidates

Discover likely primary key columns via uniqueness analysis

find_fk_candidates

Infer potential foreign key relationships between tables

Development

uv sync --group dev
uv run pytest tests/
uv run ruff check src/

Project Structure

dbmcp/
  src/
    mcp_server/    # FastMCP server, tool definitions
    db/            # Connection, metadata, query execution, validation
    analysis/      # PK discovery, FK inference, column stats
    models/        # Data models (schema, relationship, analysis)
  tests/
    unit/
    integration/
    compliance/
    performance/
  specs/           # Feature specifications

License

MIT

Available Tools

9 tools
connect_databaseA

Connect to a database.

Establishes a pooled connection to a database. Required before any other database operations. Returns a connection_id for subsequent calls.

Two connection methods:

  • connection_name: Use a named connection from dbmcp.toml config file

  • sqlalchemy_url: Connect directly with a SQLAlchemy URL (e.g., 'postgresql://user:pass@host/db')

Provide exactly one of connection_name or sqlalchemy_url.

MSSQL URL query parameters (mssql+pyodbc://...):

  • authentication_method: sql | windows | azure_ad | azure_ad_integrated (default: sql when credentials are present, else windows)

  • trust_server_cert: true | false (default: false)

  • tenant_id: Azure AD tenant (optional)

Example (MSSQL): mssql+pyodbc://user:pass@host/db?authentication_method=sql&trust_server_cert=true

Args: connection_name: Named connection from config file (optional) sqlalchemy_url: SQLAlchemy connection URL (optional)

Returns: TOON-encoded string with connection details:

    status: "success" | "error"
    connection_id: string              // on success only
    message: string                    // on success only
    dialect: string                    // on success only
    schema_count: int                  // on success only
    has_cached_docs: bool              // on success only
    error_message: string              // on error only
ParametersJSON Schema
NameRequiredDescriptionDefault
sqlalchemy_urlNo
connection_nameNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses pooled-connection behavior, the prerequisite requirement, MSSQL-specific defaults, and a detailed TOON-encoded success/error return contract. It does not cover connection lifecycle, cleanup, or authentication requirements beyond URL details, but the transparency is still substantial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well organized and front-loaded, with the purpose and prerequisite stated first, followed by connection methods, MSSQL details, and the return format. The 'Args' section partially repeats earlier prose, but it usefully maps concepts to actual parameter names, so the length is justified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and an uninformative schema, the description covers the connection lifecycle, input methods, mutual exclusivity, error handling, and response fields. The sibling tools are all downstream consumers, and the prerequisite relationship is explicit. No significant missing information prevents an agent from calling this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema provides only two unannotated optional strings with 0% description coverage, so the description must compensate. It defines connection_name versus sqlalchemy_url, gives example URLs, documents MSSQL query parameters with defaults, and enforces the useful 'exactly one' constraint. This fully compensates for the uninformative schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: 'Connect to a database' and 'Establishes a pooled connection' that returns a connection_id. It also positions the tool as 'Required before any other database operations', which differentiates it from the sibling query and inspection tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a clear when-to-use signal: 'Required before any other database operations.' It also explains the two mutually exclusive connection methods and explicitly says 'Provide exactly one of connection_name or sqlalchemy_url', which is strong usage guidance. It does not name alternative tools or state when not to use the tool, so it stops short of a perfect score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

execute_queryA

Execute a SQL SELECT query and return results.

Executes ad-hoc SELECT queries with automatic row limiting for safety. Write operations (INSERT, UPDATE, DELETE) are blocked. Results are returned as a structured JSON with columns and rows.

Large text values (>1000 chars) and binary data are automatically truncated to keep responses token-efficient.

Args: connection_id: Connection ID from connect_database query_text: SQL query to execute (SELECT only) row_limit: Maximum rows to return, 1-10000 (default: 1000)

Returns: TOON-encoded string with query results:

    status: "success" | "blocked" | "error"
    query_id: string                   // on success only
    query_type: string                 // on success only
    columns: list of string            // on success only
    rows: list of object               // on success only
    rows_returned: int                 // on success only
    rows_available: int                // on success only
    limited: bool                      // on success only
    execution_time_ms: float           // on success only
    error_message: string              // on error/blocked only
ParametersJSON Schema
NameRequiredDescriptionDefault
row_limitNo
query_textYes
connection_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It covers blocking of writes, automatic row limiting, truncation of large text and binary data, and the status/error model. This is far beyond a minimal description and gives the agent a realistic picture of side effects and constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a purpose, behavior notes, Args, and Returns sections. Every section earns its place; the detailed return format is useful given the tool's output complexity. No filler or redundant restating of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a query-execution tool with no annotations and low schema coverage, this description is essentially complete. It covers input semantics, safety behavior, output encoding, statuses, and error/blocked cases. An agent has enough information to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for all three parameters. It does so clearly: connection_id comes from connect_database, query_text is SELECT-only, and row_limit has an explicit range and default. This adds meaningful semantics that the raw schema lacks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Execute a SQL SELECT query and return results.' It further clarifies scope with 'ad-hoc SELECT queries' and explicitly excludes write operations, making it clearly distinct from the sibling schema/metadata tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides clear context: this tool is for ad-hoc SELECT queries against an existing connection, with a prerequisite indicated via 'connection_id: Connection ID from connect_database.' It also states when not to use it by noting write operations are blocked. It does not explicitly name sibling alternatives, but the usage context is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_fk_candidatesA

Discover potential foreign key relationships for a source column.

EXPERIMENTAL — Results are based on common heuristics but have not been battle-tested for utility. They may contain false positives or exclude valid candidates. Use as a starting point for investigation, not as definitive answers.

Searches for target columns that could be the referenced side of a foreign key relationship. Matches by compatible data type. By default only considers target columns that are PK candidates (constraint-backed or structurally unique); set pk_candidates_only=False to broaden the search to all type-compatible columns. Optionally computes value overlap between source and target via SQL INTERSECT.

Args: connection_id: Connection ID from connect_database table_name: Source table name. May be dotted (e.g. 'schema.table' or 'catalog.schema.table') and is resolved against the dialect. column_name: Source column name schema_name: Source schema name. Defaults to the dialect's default schema (e.g. 'dbo' on MSSQL) when omitted. target_schema: Filter targets to this schema. Defaults to source schema. target_tables: Explicit list of target table names target_table_pattern: SQL LIKE pattern for target table names pk_candidates_only: Only compare against PK-candidate columns (default: True) include_overlap: Compute value overlap metrics (default: False) limit: Maximum candidates to return, 0 = no limit (default: 100) catalog: Optional Databricks catalog name. Rejected on non-Databricks dialects (returns an error response). On Databricks the catalog is threaded end-to-end (IDENT-08): the existence check, source-column type reflection, and FK search run against the requested catalog via catalog-scoped reflection (cross-catalog supported — no default-catalog binding required).

Returns: TOON-encoded string with status, source metadata, candidates list, and search info:

    status: "success" | "error"
    source: object                     // on success only
        column_name: string
        table_name: string
        schema_name: string
        data_type: string
    candidates: list                   // on success only
        source_column: string
        source_table: string
        source_schema: string
        source_data_type: string
        target_column: string
        target_table: string
        target_schema: string
        target_data_type: string
        target_is_primary_key: bool
        target_is_unique: bool
        target_is_nullable: bool
        target_has_index: bool
        overlap_count: int             // only when include_overlap=True
        overlap_percentage: float      // only when include_overlap=True
    total_found: int                   // on success only
    was_limited: bool                  // on success only
    search_scope: string               // on success only
    type_incompatible_skipped: int     // only when > 0 (type-incompatible targets skipped)
    error_message: string              // on error only

Error conditions: - Invalid connection_id: returns status "error" with error_message - Table not found: returns status "error" with error_message - Column not found: returns status "error" with error_message - No candidates: returns status "success" with empty candidates list

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
catalogNo
table_nameYes
column_nameYes
schema_nameNo
connection_idYes
target_schemaNo
target_tablesNo
include_overlapNo
pk_candidates_onlyNo
target_table_patternNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden and handles it thoroughly. It discloses the experimental/heuristic nature, false-positive risk, type-compatibility matching, default PK-candidate restriction, optional SQL INTERSECT overlap computation, Databricks catalog behavior, and complete error conditions. This gives an agent a realistic model of what the tool will and will not do.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured into Args, Returns, and Error conditions sections. Every paragraph serves a purpose, with the core purpose front-loaded before the experimental caveat and detailed parameter semantics. No filler or redundant restatements of the schema are present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (11 parameters, dialect-sensitive behavior, no annotations, and a bespoke TOON-encoded return format), the description is complete. It covers invocation context, parameter behavior, output shape, error handling, and edge cases such as Databricks catalog threading and empty candidate results. An agent has everything needed to select and call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must fully compensate for the input schema's lack of per-property descriptions. The Args section explains every parameter, including dotted table name resolution, default schema behavior, target filtering options, pk_candidates_only semantics, overlap behavior, limit interpretation, and the dialect-specific catalog rule. This is exactly the compensation needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Discover potential foreign key relationships for a source column' and then clearly defines the tool as searching for target columns that could be the referenced side of a foreign key. This sharply distinguishes it from siblings like find_pk_candidates or get_column_info even without naming them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong contextual guidance: it is experimental, a starting point, not definitive, and explains how to broaden or narrow the search via pk_candidates_only, target_schema, target_tables, and target_table_pattern. However, it never explicitly names sibling tools or states when to choose this tool over get_column_info, find_pk_candidates, or execute_query, so the 'when vs alternatives' guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_pk_candidatesA

Identify columns that meet primary key candidacy criteria.

EXPERIMENTAL — Results are based on common heuristics but have not been battle-tested for utility. They may contain false positives or exclude valid candidates. Use as a starting point for investigation, not as definitive answers.

Discovers PK candidates via two approaches:

  1. Constraint-backed: Columns with declared PK or UNIQUE constraints

  2. Structural: Columns that are unique, non-null, and match the type filter

Does not detect composite keys. Structural uniqueness checks query the full table and may be slow on very large tables.

Args: connection_id: Connection ID from connect_database table_name: Table to search for PK candidates. May be dotted (e.g. 'schema.table' or 'catalog.schema.table') and is resolved against the dialect. schema_name: Schema name. Defaults to the dialect's default schema (e.g. 'dbo' on MSSQL) when omitted. type_filter: SQL types considered for structural PK candidacy. Default: ["int", "bigint", "smallint", "tinyint", "uniqueidentifier"]. Set to empty list to disable type filtering. catalog: Optional Databricks catalog name. Rejected on non-Databricks dialects (returns an error response). On Databricks the catalog is threaded end-to-end (IDENT-08): the existence check and PK discovery run against the requested catalog via catalog-scoped reflection (cross-catalog supported — no default-catalog binding required).

Returns: TOON-encoded string with status, table/schema metadata, and candidates list:

    status: "success" | "error"
    table_name: string                 // on success only
    schema_name: string                // on success only
    candidates: list                   // on success only
        column_name: string
        data_type: string
        is_constraint_backed: bool
        constraint_type: "PRIMARY KEY" | "UNIQUE" | null
        is_unique: bool                // all values distinct
        is_non_null: bool              // no nulls
        is_pk_type: bool               // data_type matches type_filter
    error_message: string              // on error only

Error conditions: - Invalid connection_id: returns status "error" with error_message - Table not found: returns status "error" with error_message - No candidates found: returns status "success" with empty candidates list

ParametersJSON Schema
NameRequiredDescriptionDefault
catalogNo
table_nameYes
schema_nameNo
type_filterNo
connection_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly. It discloses the experimental heuristic nature, potential false positives, inability to detect composite keys, full-table scanning behavior, Databricks catalog threading, and error conditions. This goes well beyond a minimal safety profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but it is well structured into sections (purpose, args, returns, errors) and nearly every sentence adds necessary detail for a tool with five parameters and a structured result. It could be slightly trimmed without losing meaning, hence not a perfect 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete for safe invocation: it documents all parameters, the output schema fields, error conditions, edge cases like empty candidate lists, and dialect-specific behavior. An agent has enough to select and invoke the tool correctly without needing additional sources.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must explain every parameter, and it does. It defines connection_id, table_name with dotted-name resolution, schema_name defaults, type_filter defaults and empty-list behavior, and catalog's Databricks-specific semantics. This fully compensates for the schema's lack of narrative detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Identify columns that meet primary key candidacy criteria.' It further clarifies two discovery approaches (constraint-backed and structural), which makes the tool's scope precise and distinct from sibling tools like find_fk_candidates and get_column_info.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context: it is experimental, meant as a starting point for investigation rather than definitive answers, and warns that structural checks may be slow on large tables. It does not explicitly name alternative tools or state when not to use it, so it stops short of a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_column_infoA

Retrieve per-column statistical profiles for a table.

EXPERIMENTAL — Statistics are based on common practices but have not been battle-tested for utility. Use as a starting point for investigation, not as definitive answers.

Computes row counts, distinct counts, null counts/percentages, and type-specific statistics for each column. Numeric columns get min/max/mean/stddev. Datetime columns get min/max dates, range in days, and whether a time component is present. String columns get min/max/avg length and a sample of top frequent values.

Args: connection_id: Connection ID from connect_database table_name: Name of the table. May be dotted (e.g. 'schema.table' or 'catalog.schema.table') and is resolved against the dialect. schema_name: Schema name. Defaults to the dialect's default schema (e.g. 'dbo' on MSSQL) when omitted. columns: Explicit list of column names to analyze (takes precedence over pattern) column_pattern: SQL LIKE pattern to filter column names (e.g., '%_id') sample_size: Number of top frequent value samples for string columns (default: 10) catalog: Optional Databricks catalog name. Rejected on non-Databricks dialects (returns an error response). On Databricks the catalog is threaded end-to-end: the existence check and column statistics are computed against the requested catalog (cross-catalog supported via catalog-scoped reflection — IDENT-08).

Returns: TOON-encoded string with status, table/schema metadata, and column statistics:

    status: "success" | "error"
    table_name: string                 // on success only
    schema_name: string                // on success only
    total_columns_analyzed: int        // on success only
    columns: list                      // on success only
        column_name: string
        data_type: string
        total_rows: int
        distinct_count: int
        distinct_count_approximate: bool   // true = HLL-approximate (Databricks fast path)
        null_count: int
        null_percentage: float
        numeric_stats: object          // numeric columns only
            min_value: float | null
            max_value: float | null
            mean_value: float | null
            std_dev: float | null
        datetime_stats: object         // datetime columns only
            min_date: ISO 8601 string | null
            max_date: ISO 8601 string | null
            date_range_days: int | null
            has_time_component: bool
        string_stats: object           // string columns only
            min_length: int | null
            max_length: int | null
            avg_length: float | null
            sample_values: list of [string, int] pairs
    error_message: string              // on error only

Error conditions: - Invalid connection_id: returns status "error" with error_message - Table not found: returns status "error" with error_message - Column not found (explicit list): returns status "error" with error_message - No columns match pattern: returns status "success" with empty columns list

ParametersJSON Schema
NameRequiredDescriptionDefault
catalogNo
columnsNo
table_nameYes
sample_sizeNo
schema_nameNo
connection_idYes
column_patternNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It reveals experimental status, approximate counts (HLL on Databricks fast path), type-specific behavior, error conditions, and dialect-specific catalog handling (rejected on non-Databricks). This is exceptionally transparent and goes far beyond a minimal 'get stats' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear sections (Description, Args, Returns, Error conditions). It front-loads the core purpose and then provides necessary details. No sentence is redundant, but the length is higher than minimal; however, given the parameter count and return format complexity, it earns its length. It is appropriately structured and readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter tool with no annotations and no formal output schema, the description is remarkably complete. It documents all parameters, return structure with field types and notes, error conditions, and even edge cases like empty column lists. An agent has everything needed to invoke it correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does thoroughly. Every parameter (connection_id, table_name, schema_name, columns, column_pattern, sample_size, catalog) is explained with defaults, precedence (columns over pattern), dotted-name resolution, and catalog behavior. This adds substantial meaning beyond the raw schema fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Retrieve per-column statistical profiles for a table.' This clearly distinguishes it from sibling tools like get_table_schema (schema only) and get_sample_data (sample rows). The term 'statistical profiles' is unambiguous, and the experimental caveat adds honest context without obscuring purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states 'Use as a starting point for investigation, not as definitive answers,' which gives context on when to apply results. However, it does not explicitly contrast this tool with siblings like get_table_schema or get_sample_data. The differentiation is implied by the description but not stated outright, leaving the agent to infer when this is the right choice over alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sample_dataA

Retrieve sample data from a table.

Returns representative sample rows from a table with support for multiple sampling strategies. Automatically truncates large text (>1000 chars) and binary data (shows first 32 bytes as hex) to keep responses token-efficient.

Args: connection_id: Connection ID from connect_database table_name: Name of the table. May be dotted (e.g. 'schema.table' or 'catalog.schema.table') and is resolved against the dialect. schema_name: Schema name. Defaults to the dialect's default schema (e.g. 'dbo' on MSSQL) when omitted. sample_size: Number of rows to return, 1-1000 (default: 5) sampling_method: Sampling strategy - 'top', 'tablesample', or 'modulo' (default: 'top') - 'top': Fast SELECT TOP N (not representative, just first N rows) - 'tablesample': SQL Server statistical sampling (more representative) - 'modulo': Deterministic sampling using modulo on row number (repeatable) columns: Optional list of column names to include (default: all columns) catalog: Optional Databricks catalog name. Rejected on non-Databricks dialects (returns an error response).

Returns: TOON-encoded string with sample rows and metadata:

    status: "success" | "error"
    sample_id: string                  // on success only
    table_id: string                   // on success only
    sample_size: int                   // on success only
    actual_rows_returned: int          // on success only
    sampling_method: "top" | "tablesample" | "modulo"  // on success only
    rows: list of object               // on success only
    truncated_columns: list of string  // on success only
    sampled_at: ISO 8601 string        // on success only
    error_message: string              // on error only
ParametersJSON Schema
NameRequiredDescriptionDefault
catalogNo
columnsNo
table_nameYes
sample_sizeNo
schema_nameNo
connection_idYes
sampling_methodNotop

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure and does so thoroughly. It discloses truncation of large text and binary data, sampling-method semantics, default behaviors, rejection of catalog on non-Databricks dialects, and a detailed error/success response envelope. This goes well beyond a minimal operation summary.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a one-sentence summary followed by logically grouped Args and Returns sections. Every sentence earns its place: parameter details, defaults, edge-case behavior, and return metadata are all useful to an agent. It is long because the tool is complex, not because of redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 7 parameters, no annotations, zero schema-level descriptions, and no sibling differentiation in metadata, the description is complete enough to invoke the tool correctly. It covers parameter semantics, defaults, output format, success/error fields, and dialect-specific rejection. No critical operational detail appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it fully does. Every parameter gets meaningful explanation: connection_id source, dotted table_name resolution, schema default behavior, sample_size range and default, each sampling_method value, optional columns, and catalog restrictions. This adds significant semantic value beyond the bare input schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Retrieve sample data from a table' and expands with 'representative sample rows' plus sampling-strategy details. This clearly distinguishes the tool from siblings like get_table_schema, list_tables, and execute_query, since it is explicitly about sampled row data rather than metadata or arbitrary query results.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives strong context about how sampling strategies work and defaults, so an agent can choose among top, tablesample, and modulo. However, it never explicitly says when to use this tool instead of execute_query or get_table_schema, nor does it state exclusions or alternatives. The intended usage is implied by the 'sample' framing rather than stated as guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_table_schemaA

Get detailed schema for a specific table.

Returns complete table metadata including columns, data types, constraints, indexes, and declared foreign key relationships.

Args: connection_id: Connection ID from connect_database table_name: Name of the table. May be dotted (e.g. 'schema.table' or 'catalog.schema.table') and is resolved against the dialect. schema_name: Schema name. Defaults to the dialect's default schema (e.g. 'dbo' on MSSQL) when omitted. include_indexes: Include index information (default: True) include_relationships: Include declared foreign keys (default: True) catalog: Optional Databricks catalog name. Overrides the connection's default catalog. Rejected on non-Databricks dialects (raises an error).

Returns: TOON-encoded string with table schema details:

    status: "success" | "error"
    table: object                          // on success only
        table_name: string
        schema_name: string
        columns: list
            column_name: string
            ordinal_position: int
            data_type: string
            max_length: int | null
            is_nullable: bool
            default_value: string | null
            is_identity: bool
            is_computed: bool
            is_primary_key: bool
            is_foreign_key: bool
        indexes: list                      // if include_indexes=True
            index_name: string
            is_unique: bool
            is_primary_key: bool
            is_clustered: bool
            columns: list of string
            included_columns: list of string
        foreign_keys: list                 // if include_relationships=True
            constraint_name: string | null
            source_columns: list of string
            target_schema: string
            target_table: string
            target_columns: list of string
    error_message: string                  // on error only
ParametersJSON Schema
NameRequiredDescriptionDefault
catalogNo
table_nameYes
schema_nameNo
connection_idYes
include_indexesNo
include_relationshipsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral disclosure burden and satisfies it: it reveals that the result is a TOON-encoded string with success/error status, explains catalog rejection on non-Databricks dialects, documents default behaviors for schema_name and include flags, and specifies which fields appear conditionally. This goes far beyond what the input schema provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with a one-sentence summary followed by a well-organized Args/Returns layout. The return schema block is lengthy, but it is justified by the output's complexity and the lack of a separately visible structured output schema. No filler or redundant wording is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The definition covers all six parameters, required vs optional, defaults, error handling, return formatting, and dialect-specific behavior. An agent has all necessary information to call the tool and interpret the result without consulting additional sources.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the Args section must carry all parameter meaning, and it does. It explains dotted table_name resolution against the dialect, schema_name defaulting behavior, catalog override semantics, the non-Databricks rejection, and the boolean flag defaults. Every parameter gains material context beyond its bare schema definition.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description starts with a specific verb-resource statement: 'Get detailed schema for a specific table.' It enumerates the exact metadata returned (columns, data types, constraints, indexes, foreign keys), making the tool's purpose unambiguous and distinct from siblings like get_column_info or list_tables.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context for when to use the tool: whenever detailed table schema is needed. It does not explicitly name alternatives or exclusions, but the context is strong enough for an agent to route correctly. The catalog parameter's dialect restriction also supplies a concrete usage constraint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_schemasA

List all schemas in the connected database.

Returns schemas with table and view counts, sorted by table count descending. Excludes system schemas (sys, INFORMATION_SCHEMA, guest).

Args: connection_id: Connection ID from connect_database catalog: Optional Databricks catalog name. Overrides the connection's default catalog. If omitted on a Databricks connection, the connection's configured default catalog is used (SHOW SCHEMAS IN). Rejected on non-Databricks dialects (raises an error).

Returns: TOON-encoded string with schema list:

    status: "success" | "error"
    total_schemas: int                 // on success only
    schemas: list                      // on success only
        schema_name: string
        table_count: int
        view_count: int
    error_message: string              // on error only

Error conditions: - Invalid connection_id: returns status "error" with error_message

ParametersJSON Schema
NameRequiredDescriptionDefault
catalogNo
connection_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the exact return format (TOON-encoded string with status, total_schemas, schemas list, error_message), error conditions (invalid connection_id), and dialect-specific behavior (catalog override, rejection on non-Databricks). This is exceptionally transparent about what the tool does and what the agent can expect, going beyond basic operation details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with clear sections (Args, Returns, Error conditions). It leads with the core purpose, then details parameters and return format. Every sentence adds necessary information; there is no fluff. The length is appropriate for the tool's complexity, and the format aids scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (2 parameters, dialect-specific behavior, structured output), the description is complete. It covers purpose, parameter semantics, return format, error handling, and even the sorting and filtering behavior. An agent has everything needed to invoke the tool correctly and interpret results, even without relying on the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It does so thoroughly: connection_id is explained as coming from connect_database, and catalog is fully described with its Databricks-specific override behavior and the error raised on non-Databricks dialects. This adds substantial meaning beyond the schema's type-only definitions, making parameter usage clear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('List'), resource ('all schemas'), and scope ('in the connected database'). It also adds distinguishing details: returns table/view counts, sorted by table count descending, excludes system schemas. This clearly separates it from siblings like list_tables (which lists tables) and get_table_schema (which targets a specific table).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: it requires a connection_id from connect_database and explains the optional catalog parameter with dialect-specific behavior. It implies this is the tool for schema discovery, but it does not explicitly name alternatives or state when not to use it. No exclusions beyond system schemas are mentioned, and no sibling alternatives are referenced, so it stops short of explicit when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tablesA

List tables in specified schema(s) with row counts and metadata.

Efficiently retrieves table metadata using SQL Server DMVs. Supports filtering by schema, name pattern, and minimum row count. Supports pagination via offset parameter. Supports filtering by object type to include/exclude views.

Args: connection_id: Connection ID from connect_database schema_filter: List of schema names to include (empty = all schemas) name_pattern: Table name filter using SQL LIKE pattern (e.g., 'Customer%') min_row_count: Minimum row count threshold to filter tables sort_by: Sort criterion - 'name', 'row_count', or 'last_modified' (default: 'row_count') sort_order: Sort order - 'asc' or 'desc' (default: 'desc') limit: Maximum tables to return, 1-1000 (default: 100) offset: Number of results to skip for pagination (default: 0) object_type: Filter by type - 'table', 'view', or None for all (default: None) output_mode: 'summary' (names+row counts) or 'detailed' (includes columns) (default: 'summary') catalog: Optional Databricks catalog name. Overrides the connection's default catalog. Rejected on non-Databricks dialects (raises an error).

Returns: TOON-encoded string with table list and pagination metadata:

    status: "success" | "error"
    returned_count: int                // on success only
    total_count: int                   // on success only
    offset: int                        // on success only
    limit: int                         // on success only
    has_more: bool                     // on success only
    tables: list                       // on success only
        schema_name: string
        table_name: string
        table_type: "table" | "view"
        row_count: int
        has_primary_key: bool
        last_modified: ISO 8601 string | null
        access_denied: bool
        columns: list              // detailed mode only
    error_message: string          // on error only
ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
catalogNo
sort_byNorow_count
sort_orderNodesc
object_typeNo
output_modeNosummary
name_patternNo
connection_idYes
min_row_countNo
schema_filterNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and discloses substantial behavior: it uses SQL Server DMVs, supports filtering and pagination, includes an access_denied flag, and notes that catalog is rejected on non-Databricks dialects. It also details the return structure and error handling, covering expectations beyond the basic operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description opens with a one-line summary, follows with a brief capability paragraph, and then uses a structured Args/Returns layout. Each sentence, including the detailed return block, earns its place given the tool's 11 parameters and complex output.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 11 parameters, no annotations, and a complex return payload, the description covers all parameters, defaults, filters, pagination, output modes, error cases, and dialect-specific behavior. The only missing piece would be a note on how to establish a connection, but it correctly references connect_database.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the Args section supplies per-parameter semantics: source of connection_id, empty-list behavior for schema_filter, SQL LIKE syntax for name_pattern, allowed values and defaults for sort_by/sort_order, range for limit, type choices for object_type, and mode semantics for output_mode. This fully compensates for the schema's lack of descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific action ('List tables'), a target resource ('tables in specified schema(s)'), and the delivered information ('row counts and metadata'). The supported filters and mention of views make it clear this is a metadata listing tool, distinct from siblings like list_schemas or get_table_schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description communicates its purpose and prerequisite (connection_id from connect_database) but does not explicitly name any sibling tool or state conditions for when to choose an alternative. The mention of SQL Server DMVs gives context but no exclusions, so an agent must infer when to use this vs. other schema inspection tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 9 tool updatesv0.1.0
    • First observedconnect_database
    • First observedexecute_query
    • First observedfind_fk_candidates
    • First observedfind_pk_candidates
    • First observedget_column_info
    • First observedget_sample_data
    • First observedget_table_schema
    • First observedlist_schemas
    • First observedlist_tables

TDQS

A4.6/5.0

Scored across 9 tools

Disambiguation5/5

Each tool targets a distinct operation: connection, schema/table listing, table schema, column statistics, PK/FK discovery, sampling, and ad-hoc querying. Although get_table_schema and get_column_info both describe columns, one returns structural metadata and the other statistical profiles, so selection should be unambiguous.

Naming Consistency5/5

All tools use snake_case verb_noun names with predictable prefixes: connect_, list_, get_, find_, execute_. Related pairs like find_pk_candidates/find_fk_candidates and list_schemas/list_tables follow clear parallel patterns.

Tool Count5/5

Nine tools is well-scoped for a database exploration and profiling server. Each tool covers a distinct workflow step without redundancy or bloat.

Completeness4/5

The surface covers the full read-only exploration lifecycle: connect, discover schemas/tables, inspect schema, profile columns, discover key candidates, sample data, and run SELECT queries. Minor gaps are the absence of a database/catalog listing tool and no explicit disconnect, but these are not blocking for the stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    An MCP server that connects AI assistants to Microsoft SQL Server databases, enabling schema exploration and read-only queries safely.
    49
    9 npm
    4
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    A read-only MCP server that exposes SQL database access to LLMs, supporting multiple database types, compact columnar results, pagination, and file export.
    6
    12 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Cross-platform MCP server for SQL Server that enables AI assistants to explore schemas, relationships, and run read-only queries via natural language.
    1
    MIT