DBMCP
Enables read-only access to Databricks databases, supporting schema exploration, query execution, and structural analysis via a Databricks dialect connection.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@DBMCPshow me the tables in the dbo schema"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
DBMCP: Database MCP Server for SQL Server
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
1. Global install (recommended for MCP clients)
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 syncODBC Driver 18
macOS:
brew tap microsoft/mssql-release https://github.com/Microsoft/homebrew-mssql-release
brew install msodbcsql18Linux (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 msodbcsql18Windows: 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), useuv run dbmcpas the command and setcwdto 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 |
| Project-level config, committed to repo or kept local |
2 |
| 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 = trueTip: If both files exist, the project-level
dbmcp.tomltakes 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 |
| string | (required) | SQL Server hostname or IP |
| string | (required) | Database name |
| int |
| SQL Server port |
| string |
|
|
| string | — | For SQL or Azure AD auth |
| string | — | Supports |
| bool |
| Trust server certificate without validation |
| int |
| Connection timeout in seconds |
| string | — | Azure AD tenant ID (for |
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 CAAlternatively, 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 to a SQL Server instance (Windows auth, SQL auth, or Azure AD) |
| List all schemas with table/view counts |
| List tables with filtering, sorting, and pagination |
| Get detailed table schema (columns, indexes, foreign keys) |
| Retrieve sample rows from a table |
| Execute read-only SQL queries (supports CTEs) |
| Get column-level statistics and value distributions |
| Discover likely primary key columns via uniqueness analysis |
| 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 specificationsLicense
MIT
Available Tools
9 toolsconnect_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
| Name | Required | Description | Default |
|---|---|---|---|
| sqlalchemy_url | No | ||
| connection_name | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| row_limit | No | ||
| query_text | Yes | ||
| connection_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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 onlyError 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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| catalog | No | ||
| table_name | Yes | ||
| column_name | Yes | ||
| schema_name | No | ||
| connection_id | Yes | ||
| target_schema | No | ||
| target_tables | No | ||
| include_overlap | No | ||
| pk_candidates_only | No | ||
| target_table_pattern | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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:
Constraint-backed: Columns with declared PK or UNIQUE constraints
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 onlyError 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
| Name | Required | Description | Default |
|---|---|---|---|
| catalog | No | ||
| table_name | Yes | ||
| schema_name | No | ||
| type_filter | No | ||
| connection_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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 onlyError 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
| Name | Required | Description | Default |
|---|---|---|---|
| catalog | No | ||
| columns | No | ||
| table_name | Yes | ||
| sample_size | No | ||
| schema_name | No | ||
| connection_id | Yes | ||
| column_pattern | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| catalog | No | ||
| columns | No | ||
| table_name | Yes | ||
| sample_size | No | ||
| schema_name | No | ||
| connection_id | Yes | ||
| sampling_method | No | top |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| catalog | No | ||
| table_name | Yes | ||
| schema_name | No | ||
| connection_id | Yes | ||
| include_indexes | No | ||
| include_relationships | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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 onlyError conditions: - Invalid connection_id: returns status "error" with error_message
| Name | Required | Description | Default |
|---|---|---|---|
| catalog | No | ||
| connection_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No | ||
| catalog | No | ||
| sort_by | No | row_count | |
| sort_order | No | desc | |
| object_type | No | ||
| output_mode | No | summary | |
| name_pattern | No | ||
| connection_id | Yes | ||
| min_row_count | No | ||
| schema_filter | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
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.
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.
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.
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.
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.
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.
9 tool updates
v0.1.0- First observed
connect_database - First observed
execute_query - First observed
find_fk_candidates - First observed
find_pk_candidates - First observed
get_column_info - First observed
get_sample_data - First observed
get_table_schema - First observed
list_schemas - First observed
list_tables
TDQS
Scored across 9 tools
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.
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.
Nine tools is well-scoped for a database exploration and profiling server. Each tool covers a distinct workflow step without redundancy or bloat.
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
Related MCP Connectors
Draxlr's remote MCP server connects AI assistants to your SQL databases and dashboards. Explore schemas, run read-only queries, manage saved queries and dashboards, and export results, all with row-level security so each user sees only their own data.
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
- mcpOAuthcom.gibsonai
GibsonAI MCP server: manage your databases with natural language
MCP server that lets AI assistants use all OneSchema features exposed via the public API.
Related MCP Servers
- AlicenseBqualityDmaintenanceAn MCP server that connects AI assistants to Microsoft SQL Server databases, enabling schema exploration and read-only queries safely.499 npm4MIT
- AlicenseAqualityCmaintenanceA read-only MCP server that exposes SQL database access to LLMs, supporting multiple database types, compact columnar results, pagination, and file export.612 npmMIT
- AlicenseNot gradedqualityAmaintenanceMCP server for safely exposing SQL Server database capabilities to LLM clients, with read-only mode, security features, and observability.28MIT
- AlicenseNot gradedqualityCmaintenanceCross-platform MCP server for SQL Server that enables AI assistants to explore schemas, relationships, and run read-only queries via natural language.1MIT