# sqlglass (pypi · sqlglass)

SQL Server / Azure SQL for agents: real schema, lint, read-only runs, plans, write previews.

- Trust score: 65/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-23

## Components

- pypi · `sqlglass`: 65/100 (this document), [markdown](https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass.md), [page](https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass)

## Channel facts

- Registry: `pypi`
- Package: `sqlglass`
- Version: `0.1.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-23.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it.
  - 1 of 31 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 1 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 75/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 3079 tokens (~106/item across 29 items; 29 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 0/100
  - Stability not yet verified: not enough scan history yet (needs a 30-day window).
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.
  - An AI judge read all 30 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a current MCP spec version (2026-07-28).

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### How do I install the sqlglass MCP server?

sqlglass runs locally as a PyPI package, launched with uvx sqlglass. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add s-curvelabs-sqlglass -- uvx sqlglass
```

### Cursor

```json
{
  "mcpServers": {
    "s-curvelabs-sqlglass": {
      "command": "uvx",
      "args": [
        "sqlglass"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "s-curvelabs-sqlglass": {
      "command": "uvx",
      "args": [
        "sqlglass"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add s-curvelabs-sqlglass -- uvx sqlglass
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "s-curvelabs-sqlglass": {
      "type": "local",
      "command": [
        "uvx",
        "sqlglass"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add s-curvelabs-sqlglass --command uvx --arg sqlglass
```

### Hermes

```yaml
mcp_servers:
  s-curvelabs-sqlglass:
    command: "uvx"
    args: ["sqlglass"]
```

### Netclaw

```json
{
  "McpServers": {
    "s-curvelabs-sqlglass": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "sqlglass"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add s-curvelabs-sqlglass -t stdio -c uvx -a sqlglass
```

### Other

```json
{
  "mcpServers": {
    "s-curvelabs-sqlglass": {
      "command": "uvx",
      "args": [
        "sqlglass"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-23 (score 65, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-22 (score 50)

First indexed and scored.

## MCP tools (29)

### `list_connections` (~41 tokens)

List the configured database connections (from sqlglass.toml), which is the default, where the query
library lives, and whether each connection has a cached schema.

### `refresh_schema` (~55 tokens)

Re-read tables, views, columns, keys, indexes and foreign keys from the database into the local cache.
Run this when a table or column seems to be missing, or after the database changed.

Input parameters:

- `connection` (string)

### `list_tables` (~68 tokens)

List tables and views with row counts and descriptions. Filter by schema name and/or a name pattern
('*invoice*'). For a big database prefer search_schema.

Input parameters:

- `connection` (string)
- `limit` (integer)
- `pattern` (string)
- `schema` (string)

### `describe_table` (~63 tokens)

Columns (type, nullability, identity/computed), primary key, indexes, foreign keys in both directions and
row count of one table or view. Always do this before writing SQL against a table.

Input parameters:

- `connection` (string)
- `table` (string, required)

### `search_schema` (~58 tokens)

Find tables and columns whose name contains the text (or matches a * ? wildcard pattern), plus tables whose
description mentions it. The way to locate data in an unfamiliar database.

Input parameters:

- `connection` (string)
- `pattern` (string, required)

### `find_join_path` (~54 tokens)

How two tables relate: the shortest chain of declared foreign keys between them, as ready-to-use JOIN lines.

Input parameters:

- `connection` (string)
- `from_table` (string, required)
- `to_table` (string, required)

### `build_select` (~242 tokens)

Generate a SELECT from the cached schema: names validated, joins inferred from foreign keys (bridge tables
added automatically), aliases assigned, GROUP BY derived. Returns SQL text only; nothing is executed.

tables:     ["dbo.PoHeader", "dbo.Vendor"]  (first = FROM; the rest are joined)
columns:    ["Vendor.Name", "PoHeader.OrderDate"]  (Table.Column, or a bare Column when unambiguous)
aggregates: [{"fn": "SUM", "column": "PoLine.Amount", "alias": "Total"}]  fn: SUM COUNT COUNT_DISTINCT AVG MIN MAX
filters:    ["PoHeader.OrderDate >= @Start", "Vendor.Country = 'US'"]  (ANDed; use @params for values)
order_by:   ["Total DESC"]        top: 50        join_type: INNER | LEFT

Input parameters:

- `aggregates`
- `columns`
- `connection` (string)
- `distinct` (boolean)
- `filters`
- `join_type` (string)
- `order_by`
- `tables` (array, required)
- `top`

### `lint_sql` (~89 tokens)

Check a query for correctness traps (NOT IN + NULLs, LEFT JOIN turned INNER by WHERE, join without ON,
TOP without ORDER BY), performance problems (functions on filtered columns, SELECT *, NOLOCK, leading-wildcard LIKE)
and style. With a connection whose schema is cached, also verifies every table and column exists.

Input parameters:

- `connection` (string)
- `sql` (string, required)

### `analyze_sql` (~37 tokens)

What a query touches: tables/views, columns per table, CTEs, parameters and its output columns.

Input parameters:

- `sql` (string, required)

### `format_sql` (~62 tokens)

Pretty-print T-SQL in one canonical style. Normalises cosmetics (adds AS to aliases, rewrites
'[x] = expr' aliases to 'expr AS [x]'); meaning is unchanged. Comments inside expressions may move.

Input parameters:

- `sql` (string, required)

### `translate_sql` (~90 tokens)

Translate a query between dialects (tsql, postgres, mysql, sqlite, snowflake, bigquery, databricks, oracle,
duckdb, redshift): TOP<->LIMIT, ISNULL/COALESCE, GETDATE, DATEADD, string functions, quoting.

Input parameters:

- `from_dialect` (string)
- `sql` (string, required)
- `to_dialect` (string, required)

### `build_create_table` (~295 tokens)

Generate a CREATE TABLE script (TEXT ONLY -- this server never runs DDL; the user reviews and runs it).
Checked against the cached schema: the name must be free, foreign keys must point at a real primary/unique key
with the same column types, FK columns get an index, constraints get conventional names, and the script is
wrapped in IF OBJECT_ID(...) IS NULL so it can be re-run. Returns sql + undo_sql + notes.

name:         "dbo.VendorScore"
columns:      [{"name": "VendorScoreId", "type": "int", "identity": true},
               {"name": "VendorId", "type": "int", "nullable": false},
               {"name": "Score", "type": "decimal(5,2)", "nullable": false, "default": "0", "description": "0-100"}]
primary_key:  ["VendorScoreId"]
foreign_keys: [{"columns": ["VendorId"], "references": "dbo.Vendor"}]   (ref_columns default to the parent's primary key)
indexes:      [{"columns": ["ScoredOn"], "include": ["Score"], "unique": false}]

Input parameters:

- `columns` (array, required)
- `connection` (string)
- `description` (string)
- `foreign_keys`
- `indexes`
- `name` (string, required)
- `primary_key`

### `build_procedure` (~153 tokens)

Generate a CREATE OR ALTER PROCEDURE script (TEXT ONLY -- never executed here) around a query.
Give inline 'sql', or a library 'query' -- then its header params (name, type, default) become the procedure's
parameters automatically. Every @variable in the body must be a typed parameter.
params: [{"name": "@StartDate", "type": "date", "default": "'2026-01-01'", "description": "first order date"}]
Returns sql + undo_sql + notes (including an EXEC example).

Input parameters:

- `description` (string)
- `name` (string, required)
- `params`
- `query` (string)
- `sql` (string)

### `build_view` (~77 tokens)

Generate a CREATE OR ALTER VIEW script (TEXT ONLY -- never executed here) from a SELECT or a library query.
Refuses what a view cannot contain: parameters, DECLARE, ORDER BY without TOP.

Input parameters:

- `description` (string)
- `name` (string, required)
- `query` (string)
- `sql` (string)

### `run_query` (~132 tokens)

Run a read-only query and return the first rows. Give either inline 'sql' or a library 'query' (id or name).
params: {"@Start": "2026-01-01"}; library queries fall back to their header defaults.
Anything but SELECT/WITH is refused before reaching the database. Rows are capped at the connection's
max_rows (lower it with max_rows=); to look at big data, aggregate in SQL.

Input parameters:

- `connection` (string)
- `max_rows`
- `params`
- `query` (string)
- `sql` (string)

### `explain_query` (~92 tokens)

Estimated execution plan, summarised: the expensive operators, scans on big tables, key lookups, sorts,
implicit conversions, optimizer warnings and missing-index suggestions. The query is compiled, NOT executed,
so this is safe on heavy queries. (SQL Server login needs the SHOWPLAN permission.)

Input parameters:

- `connection` (string)
- `params`
- `query` (string)
- `sql` (string)

### `preview_write` (~197 tokens)

Dry-run a write WITHOUT writing: converts one UPDATE / DELETE / INSERT into the read-only SELECT that shows
what it would do, plus a COUNT(*) of affected rows. The write statement itself is never sent to the database.
  UPDATE -> key columns + each SET column as '[col (current)]' / '[col (new)]'   (changed_only=true hides no-op rows)
  DELETE -> the rows that would be removed (and which child tables reference them)
  INSERT -> the rows that would be added, under the target's column names
run=true also executes the preview (read-only, row-capped) and returns the affected-row count and first rows.
This server cannot apply the write; hand the reviewed statement to the user to run themselves.

Input parameters:

- `changed_only` (boolean)
- `connection` (string)
- `params`
- `run` (boolean)
- `sql` (string, required)

### `sample_table` (~52 tokens)

A few rows of a table or view, to see what the values actually look like.

Input parameters:

- `columns`
- `connection` (string)
- `rows` (integer)
- `table` (string, required)

### `profile_table` (~73 tokens)

Per-column row count, NULLs, distinct values, min and max, in one aggregate query. Use it to learn a
column's grain and range before filtering or joining on it. Up to 15 columns per call.

Input parameters:

- `columns`
- `connection` (string)
- `table` (string, required)

### `list_queries` (~49 tokens)

Browse the saved-query library. 'search' matches id, name, description and the SQL text; 'tag' filters by tag.

Input parameters:

- `search` (string)
- `tag` (string)

### `get_query` (~36 tokens)

One saved query: header fields, parameters, the SQL, what tables it touches, and lint findings.

Input parameters:

- `query` (string, required)

### `save_query` (~223 tokens)

Save a query to the library as <id>.sql (id may contain folders: 'purchasing/open-pos-by-vendor').
sql is the body only -- do not DECLARE the parameters in it; describe them in params:
  [{"name": "@Start", "type": "date", "default": "'2026-01-01'", "description": "first order date"}]
Updating an existing query needs overwrite=true; header fields left empty keep their current value.
kind='script' stores DDL text from build_create_table / build_procedure / build_view (e.g. id 'ddl/usp_open_pos'):
kept and versioned with the queries, but never linted as a query and never executed.

Input parameters:

- `connection` (string)
- `description` (string)
- `dry_run` (boolean)
- `id` (string, required)
- `kind` (string)
- `name` (string)
- `overwrite` (boolean)
- `params`
- `sql` (string, required)
- `tags`

### `delete_query` (~45 tokens)

Remove a query from the library. Its text is kept in a snapshot, so restore_snapshot brings it back.

Input parameters:

- `dry_run` (boolean)
- `query` (string, required)

### `find_usage` (~56 tokens)

Impact analysis: which saved queries read a given table/view (and optionally a given column of it).
Ask this before a table or column is changed, renamed or retired.

Input parameters:

- `column` (string)
- `table` (string, required)

### `lint_library` (~49 tokens)

Lint every saved query (against each query's cached connection schema when available). Catches queries
broken by a schema change: run it after refresh_schema.

Input parameters:

- `min_severity` (string)

### `rename_in_library` (~139 tokens)

Follow a database rename through every saved query, token-aware (strings and comments untouched).
kind='table':  old='dbo.Vendor', new='dbo.Supplier'
kind='column': table='dbo.Vendor', old='Name', new='VendorName' (alias-qualified references, and bare ones
               in single-table queries; ambiguous bare references are reported, not changed).
dry_run defaults to TRUE: review the diff, then call again with dry_run=false.

Input parameters:

- `dry_run` (boolean)
- `kind` (string, required)
- `new` (string, required)
- `old` (string, required)
- `table` (string)

### `extract_parameter` (~95 tokens)

Turn a hard-coded value in a saved query into a parameter: every occurrence of the literal ('2026-01-01', 100)
becomes @param, and a '-- param:' header line is added with the old value as its default.

Input parameters:

- `description` (string)
- `dry_run` (boolean)
- `literal` (string, required)
- `param` (string, required)
- `query` (string, required)

### `list_snapshots` (~22 tokens)

Before-images taken automatically ahead of every library write, newest first.

### `restore_snapshot` (~62 tokens)

Put the queries in a snapshot back to how they were before that write ('latest' = undo the last write).
The restore is itself snapshotted, so it can be undone too.

Input parameters:

- `dry_run` (boolean)
- `snapshot_id` (string)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass#diagnostics

## Score history

- 2026-09-23: 65
- 2026-09-22: 50

## Common questions

### What is the sqlglass MCP server?

sqlglass is an MCP server listed in the public MCP registry as io.github.S-CurveLabs/sqlglass. SQL Server / Azure SQL for agents: real schema, lint, read-only runs, plans, write previews. This page covers its PyPI package (sqlglass).

### Is the sqlglass MCP server safe to use?

sqlglass scores 65 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 23 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the sqlglass MCP server expose?

sqlglass exposes 29 tools: list_connections, refresh_schema, list_tables, describe_table, search_schema, and 24 more. Their descriptions and schemas cost roughly 2,706 tokens of context every time the server is loaded.

### Is the sqlglass MCP server still maintained?

sqlglass is still listed as active in the MCP registry. We last reached this channel on 23 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- PyPI project: https://pypi.org/project/sqlglass/
- Socket report: https://socket.dev/pypi/package/sqlglass
- Repository: https://github.com/S-CurveLabs/sqlglass
- Changelog RSS feed: https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass.xml
- Changelog JSON feed: https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass.json
- HTML version of this page: https://verifymcp.io/servers/s-curvelabs-sqlglass/sqlglass
