SqlPeek 0.1.6

dotnet tool install --global SqlPeek --version 0.1.6
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local SqlPeek --version 0.1.6
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=SqlPeek&version=0.1.6
                    
nuke :add-package SqlPeek --version 0.1.6
                    

πŸ”Ž SqlPeek

Live, read-only SQL Server access for your AI agent — straight from your codebase's own config, with EF Core entity→table mapping built in.

Stop context-switching to SSMS. Ask your agent "show me the last 20 orders with the customer name" and it queries the real database β€” using the connection strings already in your repo, resolving the right table even when it's a renamed view in a non-default schema.

SqlPeek is a Model Context Protocol server. It plugs into Claude Code, Cursor, or any MCP client.


✨ Why SqlPeek

  • Zero setup data access. It reads the connection strings your project already has β€” appsettings.json, Web.config, a shared master file, or an injected ConnectionStrings__* environment variable. No new credentials, no config duplication.
  • Read-only, enforced in layers. A statement guard blocks writes and the tricks that escape a rollback (stacked writes, OPENQUERY, xp_*, COMMIT…), every query runs in a rolled-back transaction, and each connection is probed so you're told if the login could write. There is no write code in the server at all.
  • EF Core aware. It maps an entity class to its actual physical table/view β€” schema, rename, and convention resolved β€” so the agent queries Config.WorkflowAssignment or analytics.V_LatestStep, not a guessed dbo.WorkflowAssignments.
  • Portable. Any SQL Server, any repo. Connection can come from a file, a master file, or an env var.
  • Fast & self-contained. Pure syntactic code parsing (no MSBuild/solution load). Starts instantly.

πŸš€ Quick start

Prerequisites: .NET 10 SDK, a reachable SQL Server, an MCP client (e.g. Claude Code).

# 1. Install the global tool (creates the `sqlpeek` command)
dotnet tool install --global SqlPeek

# 2. Register it with your MCP client (local, stdio)
claude mcp add -s user sqlpeek -- sqlpeek

Registered at user scope, sqlpeek is available in every project. It scans whichever repo you have open β€” the MCP client launches it in that directory β€” so there's nothing per-project to configure. (Pass --root <dir> only to point it somewhere other than the current project.)

Restart your client. The sqlpeek tools are now available. Ask:

Using sqlpeek, what SQL connections are configured?

Tip: Building from source instead? dotnet pack src/SqlPeek -c Release -o ./nupkg, then dotnet tool install --global --add-source ./nupkg SqlPeek.


βš™οΈ Configuration

SqlPeek is launched by your MCP client with CLI arguments:

Argument Purpose Default
--root <dir> Directory scanned for config files and EF code current working directory
--connections <file> Authoritative single connection-strings file (skips the tree scan) β€”
--solution <path> Optional .sln; its folder is used as --root β€”
--timeout <seconds> Per-query timeout 30
--max-rows <n> Hard cap on rows run_query can return 200
--max-result-chars <n> Byte cap on a result's serialized size (bounds agent context) 50000
--require-readonly Refuse a write-capable login outright (fail-closed) off
--data-dir <path> Base folder for on-disk state (audit log, caches) C:\SqlPeek
--audit-retention-days <n> Prune audit files older than this at startup 1
--transport stdio\|http Run over stdio (local) or as an HTTP server (central) stdio
--port <n> Port for the HTTP transport 5000
--server / --user / --password Enumerate all databases on one instance instead of reading config β€”
--export-mappings <file> Write EF mappings to JSON and exit (CI) β€”
--mappings-dir <path> Load prebuilt EF mappings instead of scanning source β€”

All flags are optional with working defaults; with none, SqlPeek runs as a local stdio server exactly as it always has. The scan credentials can also be supplied via environment variables β€” SQLPEEK_SERVER / SQLPEEK_USER / SQLPEEK_PASSWORD β€” which is how a Windows Service passes them so the password stays off the command line (flags win when both are present).

Where connection strings come from (in order of authority)

  1. --connections <file> β€” read only that file. Best when your repo has one source-of-truth connection file. Tolerates non-strict JSON (lone backslashes like Data Source=HOST\INSTANCE).
  2. Environment variables β€” the .NET ConnectionStrings__Name convention, always read. For apps that inject the connection at runtime (e.g. a container env_file).
  3. .env files β€” any *connectionstring*.env (e.g. .connectionstrings.local.env from a docker env_file), read for ConnectionStrings__* lines. Not project-scoped β€” these sit at the solution root.
  4. .NET User Secrets β€” for dotnet run / Visual Studio, read from each project's <UserSecretsId> store (ConnectionStrings:Name, flat or nested).
  5. Project-scoped tree scan β€” appsettings*.json, connectionStrings.json, Web.config, App.config under --root, but only files owned by a .csproj (ignores bin/obj and non-project config dumps).

Non-SQL strings (LDAP, etc.) are filtered out. TrustServerCertificate is added when absent. When one name maps to several databases it must be disambiguated with a qualified id name@host/catalog; SQL-auth is preferred over Windows-auth for the same target.


🧰 Tools

Tool What it does
list_connections Discovered connections (host + catalog only, never credentials); flags ambiguity and auth type
list_databases Databases on a connection
get_schema All tables and views with columns, types, nullability, PKs, defaults
get_table_detail One table/view: columns, indexes, estimated row count
run_query Read-only SELECT/WITH; JSON rows + which server/database + row cap + read-only advisory
list_ef_contexts All discovered EF DbContext classes and the entity classes they own
get_migrations EF migration history for a context, ordered by timestamp
get_entity_mapping EF entity class β†’ physical schema.table / schema.view (+ kind, DbContext)
get_ef_entity Entity mapping + properties (incl. inherited base-class properties) with column-name overrides

Credentials are never returned by any tool.


πŸ’¬ Examples

You type plain English; the agent picks the tools. (Replace the sample names with your own.)

Discover & explore

Using sqlpeek, what connections are configured, and what tables and views are in SalesDb?

Simple read

Show me the 10 most recent rows in Orders, newest first.

Entity mapping β†’ live query (chained automatically)

What table does the Order entity map to, then show me its 5 latest rows.

β†’ get_entity_mapping("Order") β†’ sales.Orders β†’ run_query(SELECT TOP 5 … FROM sales.Orders ORDER BY …)

Harder β€” a 3-table join

For each of the last 15 orders, show the customer name, the number of line items, and the total line-item amount.

The agent writes the Orders–Customers–OrderItems join, runs it, and presents the result β€” telling you it came from e.g. SQL01 / SalesDb.

Analytics

Top 10 customers by total spend: name, order count, total β€” highest first.


🌐 Central deployment (optional)

By default SqlPeek runs locally over stdio. For a team, run it once as an HTTP server everyone connects to:

sqlpeek --transport http --port 5000 --root /path/to/repo --data-dir C:\SqlPeek
claude mcp add -s user sqlpeek-central --transport http http://<host>:5000/
  • Audit log β€” every run_query (success or rejection) is appended to {data-dir}/audit/*.jsonl: timestamp, client, connection, duration. Never SQL text or credentials. Client identity comes from an X-Client-Id request header.
  • Whole-instance access β€” --server/--user/--password enumerates every database on an instance (no repo config needed); the database-name list is cached under {data-dir}/dbcache/ (names only).
  • Source-less hosts β€” precompute mappings in CI with --export-mappings, then load them with --mappings-dir so the EF tools work where no source is checked out.

Run it as a Windows Service (SqlPeek self-hosts under the Service Control Manager) or under IIS. For a service, pass the read-only login via the SQLPEEK_USER / SQLPEEK_PASSWORD environment variables rather than command-line flags.


πŸ”’ Read-only safety

Three independent layers, so a write can't happen even with a write-capable login:

  1. Statement guard β€” only SELECT/WITH; rejects DML/DDL and rollback-escape constructs (INSERT/UPDATE/DELETE/MERGE, COMMIT/ROLLBACK, OPENQUERY/OPENROWSET, xp_*, EXEC, SELECT … INTO, GRANT…). String literals, bracketed identifiers, and comments are stripped first, so a column named create_date or a value 'deleted' is never a false positive.
  2. Rolled-back transaction β€” every query runs in a transaction rolled back unconditionally.
  3. Login probe β€” each result reports loginIsReadOnly, and advises using a read-only login if not.
> delete the oldest row from Orders
Read-only guard rejected the query: 'DELETE' is not allowed. Only pure reads are permitted.

Important: For a hard, database-enforced guarantee, point SqlPeek at a login that is a member of db_datareader only. The server behaves identically and the database itself refuses every write.


🧠 How it works

  • DB layer β€” Microsoft.Data.SqlClient. Connections opened per query and closed immediately; schema read from INFORMATION_SCHEMA/sys; results streamed up to the row cap.
  • Entity layer β€” Roslyn syntax trees only (no MSBuildWorkspace, no compilation), so it's version-agnostic and instant. Mapping precedence: EF ModelSnapshot (authoritative) β†’ fluent ToTable/ToView β†’ DbSet convention. The snapshot carries every final name with conventions, schema, and renames already resolved by EF β€” which is why SqlPeek gets schema-qualified and view-backed entities right.
MCP client ──stdioβ”‚http──▢ sqlpeek
                            β”œβ”€ ConnectionManager   (discover: server-scan / file / env / secrets / tree)
                            β”œβ”€ SchemaInspector      (tables + views)
                            β”œβ”€ QueryExecutor        (guard + rollback txn + login probe + byte cap)
                            β”œβ”€ AuditLogger          (JSONL per-query audit)
                            └─ EntityCatalog        (ModelSnapshot + fluent parsing; JSON export/load)

🚧 Limitations

  • Same-name entity collisions (an entity vs. an unrelated class of the same name) are resolved by a heuristic β€” exact resolution would need a semantic model (MSBuildWorkspace), deliberately avoided.
  • Portable mappings join to a live DB by exact database-name match; a repo logical name that differs from the physical customer DB name won't attach the EF tools (raw run_query still works).
  • Mappings are read once at startup; a long-running HTTP server picks up source/artifact changes on restart.
  • The statement guard is defense-in-depth, not a substitute for a db_datareader login against adversarial input.

πŸ’Œ Support & feedback

Built by Shyam Agrawal. Questions, bugs, or feature ideas β€” reach out on LinkedIn.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
0.1.6 103 8/28/2026
0.1.5 100 8/28/2026
0.1.4 91 8/28/2026