sscli
SQL Server CLI for AI coding agents.
One install. Your agents automatically know how to inspect SQL Server databases, run SQL, and export results.
Command model direction
sql is the canonical raw-SQL surface in this project.
You can run raw SQL either with the explicit subcommand:
or with the top-level shorthand:
For configuration, prefer explicit --env-file over relying on ambient .env
files in the working directory.
Why sscli?
| Token-efficient | Markdown output by default keeps agent context lean |
| SQL-first workflows | Canonical sql command for raw SQL, plus schema/discovery helpers |
| Single binary | Fast startup, no runtime dependencies |
| CLI over MCP | No "tool bloat" from verbose tool descriptions for tools that are rarely used |
| Progressive disclosure | Core commands visible, advanced disclosed when needed |
Why not sqlcmd
sqlcmd is a great general-purpose SQL Server client, especially for interactive sessions and ad-hoc work.
For tool-calling agents, sqlcmd tends to be a poor fit because it's optimized for humans, not for
structured, repeatable automation:
- Output is hard to consume:
sqlcmdoutput is human-oriented text; agents usually want stable markdown tables or a single JSON object they can reliably parse. - Schema discovery is manual: you end up writing catalog queries (
sys.tables,INFORMATION_SCHEMA, etc.) instead of calling purpose-built primitives likesscli tables,sscli describe, andsscli columns. - Structured SQL workflows:
ssclikeeps raw SQL, schema discovery, and machine-readable output in one tool, so agents do not have to switch betweensqlcmdfor execution and a second tool for inspection. - More setup friction:
sqlcmdis typically installed via Microsoft tooling and may require ODBC drivers depending on platform/CI image; sscli is a single binary with config + env var discovery built in. - No agent integration: sscli can install a reusable skill/extension so agents "know the tool" without you pasting usage docs into every prompt.
Keep sqlcmd for interactive SQL. Reach for sscli when you want raw SQL plus fast schema inspection
and output formats that are easy for agents to use.
Quick Start (Agent Users)
1. Install sscli
# macOS/Linux
# Windows (PowerShell)
# or with cargo (any platform)
2. Teach your agents
Done. Your agents now know how to browse schemas, run SQL, and export results.
What changes?
| Before | After |
|---|---|
| You paste schema context into prompts | Agent discovers schema on demand |
| Agent guesses at SQL Server commands | Agent knows sscli sql, sscli tables, sscli describe |
| Raw SQL needs a second tool | Canonical sql command plus schema/discovery helpers |
| Verbose output bloats context | Token-efficient markdown output by default, --json if needed |
Manual Usage
For humans who want to use sscli directly.
1-minute setup (first run)
# Create a starter config in ./.sql-server/config.yaml (safe defaults)
# Set the password env var referenced by passwordEnv in your config. sscli also reads
# Sanity-check connectivity + server metadata
# See the effective settings + which config file was used
Common commands
|
Installation
Homebrew (macOS/Linux)
Scoop (Windows)
scoop bucket add jwcraig https://github.com/jwcraig/scoop-bucket
scoop install sscli
Quick install script
|
The installer verifies the downloaded artifact against the release checksums-sha256.txt.
Cargo binstall (fast, no compilation)
From source
Prebuilt binaries
Download from GitHub Releases.
Development build
Updating
# Check if you're up to date (alias: `sscli upgrade`)
# Homebrew
# Cargo
Automatic update notifications (optional)
By default, sscli does not check for updates automatically.
To enable lightweight update notifications (stderr, TTY-only, cached), create:
~/.config/sscli/settings.json(Linux/XDG default)- macOS often uses
~/Library/Application Support/sscli/settings.jsonby default
Example settings.json:
Agent Integration
Supported agents
| Agent | Command | What it installs |
|---|---|---|
| Claude Code | sscli integrations skills add --global |
~/.claude/skills/sscli/SKILL.md |
| Codex | (same command) | ~/.codex/skills/sscli/SKILL.md |
| Gemini CLI | sscli integrations gemini add --global |
~/.gemini/extensions/sscli/ |
| Other agent harnesses | Via OpenSkills | Bridge to installed skills |
Per-project vs global
| Flag | Installs to | Use case |
|---|---|---|
--global |
~/.claude/skills/ |
Available in all projects |
| (none) | ./.claude/skills/ |
Project-specific override |
What the skill teaches agents
The installed skill file tells agents:
- When to use sscli (database inspection, schema discovery, raw SQL execution)
- Available commands and their purpose
- Output preferences (markdown for context efficiency,
--jsonfor structured data) sqlas the main raw-SQL surface, with top-level shorthand for simple inline queries
Configuration
sscli supports three ways to configure a connection (highest priority wins; env vars are skipped if you pass --profile):
# 1) CLI flags (one-off / scripts)
# 2) Environment variables (CI-friendly)
# 3) Config file (recommended for repeated use)
&& &&
Creating a config file
Generate a commented template (writes ./.sql-server/config.yaml by default):
Or copy the example file in this repo:
Config discovery (where sscli looks)
--config <PATH>SQL_SERVER_CONFIG/SQLSERVER_CONFIG- Walk up from CWD looking for
.sql-server/config.{yaml,yml,json}or.sqlserver/config.{yaml,yml,json} - Global config:
$XDG_CONFIG_HOME/sql-server/config.{yaml,yml,json}(platform-dependent) - Environment variables (only applied when no
--profileis provided) - Hardcoded defaults
Run sscli config to confirm which config file is being used and what values are in effect.
Example config.yaml
defaultProfile: default
profiles:
default:
server: localhost
port: 1433
database: master
user: sa
passwordEnv: SQL_PASSWORD
encrypt: true
trustCert: true
For a fully commented example (including settings.output.*, timeout, and defaultSchemas), see config.example.yaml.
Environment variables
Environment variables override values from the config file when no explicit --profile was passed. If you pass --profile <name>, the profile values win over env vars (flags still win over both).
.env file support: use --env-file to load environment variables from a
specific file, for example --env-file .env.dev. sscli does not implicitly
load .env from the current working directory.
| Purpose | Environment variables (first match wins) |
|---|---|
| Config path | SQL_SERVER_CONFIG, SQLSERVER_CONFIG |
| Profile | SQL_SERVER_PROFILE, SQLSERVER_PROFILE |
| Connection URL | DATABASE_URL, DB_URL, SQLSERVER_URL |
| Server | SQL_SERVER, SQLSERVER_HOST, DB_HOST, MSSQL_HOST |
| Port | SQL_PORT, SQLSERVER_PORT, DB_PORT, MSSQL_PORT |
| Database | SQL_DATABASE, SQLSERVER_DB, DATABASE, DB_NAME, MSSQL_DATABASE |
| User | SQL_USER, SQLSERVER_USER, DB_USER, MSSQL_USER |
| Password | SQL_PASSWORD, SA_PASSWORD, MSSQL_SA_PASSWORD, SQLSERVER_PASSWORD, DB_PASSWORD, MSSQL_PASSWORD |
| Encrypt | SQL_ENCRYPT |
| Trust server certificate | SQL_TRUST_SERVER_CERTIFICATE |
| Connect timeout (ms) | SQL_CONNECT_TIMEOUT, DB_CONNECT_TIMEOUT |
sqlcmd compatibility: The following sqlcmd environment variables are also supported:
| Purpose | Variable |
|---|---|
| Server | SQLCMDSERVER |
| User | SQLCMDUSER |
| Password | SQLCMDPASSWORD |
| Database | SQLCMDDBNAME |
Commands
Core (shown in --help):
| Command | Purpose |
|---|---|
status |
Connectivity check |
databases |
List databases |
tables |
Browse tables and views (--describe for batch DDL) |
describe |
Any object: table, view, trigger, proc, function |
sql |
Execute SQL |
table-data |
Sample rows from a table |
columns |
Find columns across tables/views/procs (first result set) |
Advanced (shown in help --all):
| Command | Purpose |
|---|---|
indexes |
Index details with usage stats |
foreign-keys |
Table relationships |
stored-procs |
List and execute read-only procedures |
sessions |
Active database sessions |
query-stats |
Top cached queries by resource usage |
backups |
Recent backup history |
compare |
Schema drift detection between two connections |
integrations |
Install agent skills/extensions |
Note: sscli sessions filters by client host name using --client-host. --host is reserved as an alias for --server.
Output Formats
| Context | Default |
|---|---|
| Terminal (TTY) | Pretty tables |
| Piped / non-TTY | Markdown tables |
--json flag |
Stable JSON (v1 contract) |
--csv <file> |
CSV export |
JSON output emits exactly one object to stdout. Errors go to stderr.
Safety
- keep
sqlas the canonical raw-SQL command - support full SQL execution, including file/stdin-driven scripts
- keep the existing profile/config connection model
- prefer explicit
--env-fileover ambient cwd configuration - prefer lightweight safety rails and explicit target visibility over hidden parser restrictions
If you need a locked-down distribution, maintain a custom build or wrapper that strips write capability. The shipped tool is intended to be full-capability.
JSON Contract (v1)
Each command returns a stable top-level object:
| Command | Shape |
|---|---|
status |
{ status, latencyMs, serverName, serverVersion, currentDatabase, timestamp, warnings } |
databases |
{ total, count, offset, limit, hasMore, nextOffset, databases: [...] } |
tables |
{ total, count, offset, limit, hasMore, nextOffset, tables: [...] } |
describe |
{ object: {schema, name, type}, columns, ddl?, indexes?, triggers?, foreignKeys?, constraints? } |
table-data |
{ table, columns, rows, total, offset, limit, hasMore, nextOffset } |
sql |
{ success, batches, resultSets, csvPaths? } |
compare |
{ modules, indexes, constraints, tables } when --summary; { source, target } snapshots with full metadata when --json without --summary |
Errors (stderr):
compare (schema drift)
Detects drift between two profiles or explicit connection strings.
Synopsis:
sscli compare --target <profile> [--source <profile>] [--schema web --schema dbo] \
[--summary|--json] [--ignore-whitespace] [--strip-comments] \
[--object dbo.ProcName] [--apply-script [path|-]] [--include-drops]
--target/--right(required): profile to treat as the environment you want to align.--source/--left: reference profile (defaults to global--profileor config default).--source-connection/--left-connection,--target-connection/--right-connection: override profile with a connection string (URL or ADO-styleServer=...;Database=...).--schema/--schemas: limit to specific schemas (repeatable or comma-separated).--object: emit unified diff for a single module (proc/view/function/trigger).--ignore-whitespace,--strip-comments: normalize noise before diffing definitions.--summary: compact drift counts;--prettyrenders text;--jsonrenders JSON.--apply-script [path|-]: generate SQL to align target to source; default pathdb-apply-diff-YYYYMMDD-HHMMSS.sqlin cwd; use-for stdout.--include-drops: include DROP statements (disabled by default).- Profiles are the names in your
.sql-server/config.*(e.g.,dev,stage,prod).--source/--targetexpect those names.
Examples:
# Summary with profile names
# Object diff ignoring whitespace
# Apply script to stdout
# Using explicit connection strings instead of profiles
Exit codes: 0 = no drift, 3 = drift detected (summary/object/apply modes), 1 = error.
Testing
Pre-push hook (local)
This repo ships a local pre-push hook that runs cargo fmt --check, cargo clippy -D warnings, and cargo test. It’s already enabled via core.hooksPath=.githooks. If you need to bypass temporarily:
HUSKY=0 SKIP=1
DB-backed integration tests (opt-in):
SSCLI_INTEGRATION_TESTS=1 SQL_SERVER_CONFIG=/path/to/config.yaml \
SQL_PASSWORD=...