@deepsql/mcp 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,22 @@
1
1
  # DeepSQL — your database DBA consult
2
2
 
3
- You have DeepSQL's MCP tools loaded. **DeepSQL is the source of truth for
4
- the live schema, business rules, FK relationships, and anti-patterns of
5
- the database the user is working against.** Treat it the way a thoughtful
6
- engineer treats a DBA: consult before you commit anything schema-shaped.
3
+ You have two DeepSQL surfaces available:
7
4
 
8
- This skill triggers any time the user is doing database work. The rules
9
- below are non-negotiable.
5
+ 1. **MCP tools** JSON-RPC tools loaded into your session (10 of them).
6
+ Use these for in-session retrieval and SQL execution.
7
+
8
+ 2. **`deepsql` CLI** — a shell binary on the user's PATH (~19 commands).
9
+ Use this for things the MCP doesn't expose (index health, daily
10
+ digest, slow-query streaming, connection management, admin ops, the
11
+ plan-analysis `analyze` command, etc.). You can shell out to the CLI
12
+ yourself when appropriate; you can also point the user at the
13
+ command if it's interactive.
14
+
15
+ **DeepSQL is the source of truth for the live schema, business rules, FK
16
+ relationships, and anti-patterns of the database the user is working
17
+ against.** Treat it the way a thoughtful engineer treats a DBA: consult
18
+ before you commit anything schema-shaped. This skill triggers any time
19
+ the user is doing database work. The rules below are non-negotiable.
10
20
 
11
21
  ---
12
22
 
@@ -65,21 +75,115 @@ usually doesn't know about either; that's exactly why DeepSQL exists.
65
75
 
66
76
  ---
67
77
 
68
- ## Running SQL
78
+ ## MCP tools — your in-session toolkit
69
79
 
70
- | You want to… | Use this tool |
80
+ | Tool | When to call |
71
81
  |---|---|
72
- | Run any SQL (SELECT / EXPLAIN / DML / DDL) | `execute_sql(connectionId, query, ...)` |
73
- | Get AI-enriched plan analysis for a query | `analyze_query_plan(connectionId, query, useAnalyze=false)` |
74
- | Actually execute the query AND get the plan (real timings) | `analyze_query_plan(..., useAnalyze=true)` |
82
+ | `list_connections` | Always first; get the UUID. |
83
+ | `get_brain_context(connectionId, question)` | Step 2 of the checklist above. The most important tool. |
84
+ | `get_schema(connectionId)` | Full column inventory for the tables you're touching. |
85
+ | `get_database_objects(connectionId)` | Tables/views/functions/procedures (broader than schema). |
86
+ | `list_business_rules(connectionId, question?)` | Rules the SQL must respect. |
87
+ | `get_relationships(connectionId)` | Foreign keys (declared + inferred-with-confidence). |
88
+ | `get_anti_patterns(connectionId, kind="table"\|"query")` | Patterns to avoid in this DB. |
89
+ | `analyze_slow_queries(connectionId, thresholdMs?, limit?)` | Snapshot of slow queries from live stats. |
90
+ | `execute_sql(connectionId, query, ...)` | Run any SQL — SELECT for everyone, DML/DDL for admins (two-step confirm). |
91
+ | `analyze_query_plan(connectionId, query, useAnalyze=false)` | AI-enriched plan analysis (issues + index recs + summary). |
75
92
 
76
93
  `EXPLAIN` and `EXPLAIN ANALYZE` are just SQL — type them as the query if
77
94
  you want raw plan output. Use `analyze_query_plan` when you want the
78
- AI-enriched analysis (issues, index recommendations, written summary).
95
+ AI-enriched analysis.
79
96
 
80
- ### Mutations are role-gated and two-step
97
+ ---
81
98
 
82
- `execute_sql` enforces the same policy as the SQL Editor:
99
+ ## `deepsql` CLI for everything the MCP doesn't expose
100
+
101
+ The CLI is the user's primary interface to DeepSQL. As a coding agent,
102
+ **you can shell out to it** to do things the MCP doesn't have, or to
103
+ help the user when interactive setup is required (login, MCP install,
104
+ new connection registration). Always pass `--caller-agent <your-name>`
105
+ on shell-outs so the audit log captures the chain ("deepsql query
106
+ called by claude-code via deepsql CLI").
107
+
108
+ ```bash
109
+ deepsql query "SELECT 1" --connection prod-pg --caller-agent claude-code --json
110
+ ```
111
+
112
+ ### Command catalog (19 top-level commands)
113
+
114
+ | Command | What it does | MCP equivalent? |
115
+ |---|---|---|
116
+ | `deepsql login` | Authorize CLI against a DeepSQL host (browser PKCE / device code / password) | none — interactive only |
117
+ | `deepsql logout` | Revoke the saved token | none |
118
+ | `deepsql whoami` | Show the logged-in user, role, URL, pinned connection | none |
119
+ | `deepsql config show\|set-default <url>\|path` | Manage saved profiles | none |
120
+ | `deepsql mcp` | Run the stdio MCP server | this skill spawns it |
121
+ | `deepsql mcp config --install --for <editor>` | Install MCP entry + this skill into editor config | none — interactive |
122
+ | `deepsql connections list\|use\|current\|unset\|schema\|add\|update\|remove\|test\|show\|init` | Full connection CRUD | partial: `list_connections`, `get_schema` |
123
+ | `deepsql query "<sql>" --connection <c>` | Execute SQL (admin: `--write` for mutations) | `execute_sql` |
124
+ | `deepsql analyze "<sql>" --connection <c>` | AI plan analysis (`--analyze` for EXPLAIN ANALYZE) | `analyze_query_plan` |
125
+ | `deepsql schema [tables\|objects] --connection <c>` | Dump full schema as JSON | `get_schema` / `get_database_objects` |
126
+ | `deepsql brain-context "<question>" --connection <c>` | Same retrieval as the MCP tool | `get_brain_context` |
127
+ | `deepsql business-rules --connection <c>` | List active business rules | `list_business_rules` |
128
+ | `deepsql relationships --connection <c>` | Inferred + validated FKs | `get_relationships` |
129
+ | `deepsql anti-patterns --connection <c> [--kind table\|query]` | Anti-patterns | `get_anti_patterns` |
130
+ | `deepsql digest [N]\|list\|show <id>` | **CLI-only**: daily digest of slow queries + AI commentary | none |
131
+ | `deepsql indexes list\|missing\|health\|unused\|duplicates\|usage <table>` | **CLI-only**: index recommendations and usage stats | none |
132
+ | `deepsql slow-queries latest\|history\|analyze\|optimize\|delete` | Slow-query analyses; `optimize` streams AI optimization steps live (SSE) | partial: `analyze_slow_queries` |
133
+ | `deepsql users list\|get\|add\|set-role\|lock\|unlock\|disable\|resend-invite\|reset-password\|delete` | **Admin-only, CLI-only**: workspace user management | none |
134
+ | `deepsql access list\|grant\|revoke\|policy <user> <conn>` | **Admin-only, CLI-only**: per-connection access grants + chat policy editing in $EDITOR | none |
135
+ | `deepsql permissions list\|override\|reset` | **Admin-only, CLI-only**: role-based permission overrides | none |
136
+ | `deepsql setup` | **Admin-only**: post-install wizard for SMTP/email + Slack | none |
137
+
138
+ Run `deepsql <command> --help` for option-level detail. Run
139
+ `deepsql --help` for the live catalog (the CLI is the source of truth
140
+ if this table goes stale).
141
+
142
+ ### CLI-only capabilities — point the user at these or run them
143
+
144
+ When the user asks for something only the CLI does, either run it via
145
+ shell-out (with `--caller-agent`) or tell the user the exact command:
146
+
147
+ | User asks for | Run / suggest |
148
+ |---|---|
149
+ | "What changed in the database recently?" / "Today's report" | `deepsql digest` (most recent) or `deepsql digest 7` (last week) |
150
+ | "What indexes are we missing?" / "Index advice" | `deepsql indexes missing --connection <c>` |
151
+ | "Are any indexes unused?" / "Index bloat" | `deepsql indexes unused --connection <c>` |
152
+ | "Duplicate indexes?" | `deepsql indexes duplicates --connection <c>` |
153
+ | "Index health on this connection" | `deepsql indexes health --connection <c>` |
154
+ | "Indexes on `<table>` and how often they're used" | `deepsql indexes usage <table> --connection <c>` |
155
+ | "Optimize this slow query with AI" / "Stream me a fix" | `deepsql slow-queries optimize --connection <c> --query-id <id>` |
156
+ | "Add a new database connection" | `deepsql connections add` (interactive) or `--from-file <path>` |
157
+ | "Test a connection without saving" | `deepsql connections test --from-file <path>` |
158
+ | "Trigger brain re-initialization for this connection" | `deepsql connections init <name> --wait` |
159
+ | "Add a user / change a user's role" | `deepsql users add` / `deepsql users set-role <ref> <role>` |
160
+ | "Grant / revoke connection access" | `deepsql access grant --user <ref> --connection <c> --level read\|write\|admin` |
161
+ | "Edit the chat data-access policy for `<user>` on `<conn>`" | `deepsql access policy <user> <conn>` (opens `$EDITOR`) |
162
+
163
+ ### Shelling out from the agent — the convention
164
+
165
+ When you run `deepsql` yourself:
166
+
167
+ ```bash
168
+ deepsql <command> [options] --caller-agent <your-agent-id> --json
169
+ ```
170
+
171
+ - **Always pass `--caller-agent`** (or set `DEEPSQL_CALLER_AGENT` env
172
+ var once) so the audit row captures the chain. Use a stable id like
173
+ `claude-code`, `cursor`, or `codex`.
174
+ - **Prefer `--json`** for parseable output. Without it, output is
175
+ pretty-printed for humans and harder to parse.
176
+ - **Don't chain destructive ops without confirmation.** `deepsql
177
+ connections remove`, `deepsql users delete`, `deepsql permissions
178
+ override --revoke`, etc. all support `--yes` to skip the prompt — but
179
+ YOU should not pass `--yes` unless the user has explicitly approved
180
+ the specific action.
181
+
182
+ ---
183
+
184
+ ## Mutations are role-gated and two-step (both MCP and CLI)
185
+
186
+ `execute_sql` (MCP) and `deepsql query` (CLI) enforce the same policy:
83
187
 
84
188
  - **Developer + SELECT/WITH/SHOW/EXPLAIN** → runs immediately.
85
189
  - **Developer + DML/DDL** → 403 `EDITOR_MUTATION_FORBIDDEN`. Don't retry.
@@ -89,26 +193,51 @@ AI-enriched analysis (issues, index recommendations, written summary).
89
193
  - **Admin + DML/DDL (no `confirmMutation`)** → returns
90
194
  `requiresConfirmation: true` with a `warnings` array. **Show the
91
195
  warnings to the user verbatim. Wait for explicit OK.** Then re-call
92
- with `confirmMutation: true`. **Do not silently retry with
93
- `confirmMutation: true` on the user's behalf** — that defeats the
196
+ with `confirmMutation: true` (MCP) or `--write` (CLI). **Do not
197
+ silently retry on the user's behalf** — that defeats the
94
198
  confirmation step.
95
199
 
96
- ### Row limits
200
+ ## Row limits
201
+
202
+ `execute_sql` / `deepsql query` defaults to 100 rows, max 1000. If you
203
+ asked for "all customers" and got 100, that's the limit kicking in —
204
+ not the real count. Either bump `--limit`/`limit:` or `SELECT COUNT(*)`
205
+ first.
97
206
 
98
- `execute_sql` defaults to 100 rows, max 1000. If you asked for "all
99
- customers" and got 100, that's the limit kicking in — not the real count.
100
- Either bump `limit` or `SELECT COUNT(*)` first.
207
+ ---
208
+
209
+ ## Helping the user when DeepSQL itself isn't set up
210
+
211
+ The user might not have DeepSQL fully wired up when they ask their
212
+ first database question. If you get a clear "not configured" error,
213
+ run / suggest these:
214
+
215
+ | Symptom | Fix |
216
+ |---|---|
217
+ | `deepsql --version` not found / not on PATH | `npm install -g @deepsql/mcp@latest` (Node ≥ 20). |
218
+ | MCP tools missing from your session | Run `deepsql mcp config --install --for claude-code` (or `cursor`/`codex`/`claude-desktop`) on the user's machine. They restart the editor. |
219
+ | CLI says "No saved DeepSQL profile" | `deepsql login --url https://<their-deepsql-host>` (browser flow on desktop, `--device` for SSH boxes). |
220
+ | MCP tools error with 401 | Token expired. `deepsql logout && deepsql login --url <host>` then restart the editor. |
221
+ | `connections list` is empty | Walk the user through `deepsql connections add` interactively, or use `--from-file <path>` with a JSON config file. |
222
+ | `connections test` reports "Missing privileges: SELECT, ..." | The DB user has insufficient grants. The connection saves anyway (read access is enough for some features), but flag it. |
223
+ | Connection config schema | `deepsql connections schema --json` (JSON Schema for the input format). |
101
224
 
102
225
  ---
103
226
 
104
- ## Every call is audited
227
+ ## Every call is audited (both surfaces)
105
228
 
106
- Every tool call you make is logged to the DeepSQL `security_events` table
107
- with the user's identity, the editor that invoked the MCP server
108
- (claude-desktop, cursor-mcp, codex-mcp), the connection, the truncated
109
- statement, and the outcome. Workspace admins can search this. Don't do
110
- anything through these tools you wouldn't be willing to defend in that
111
- view.
229
+ Every MCP tool call AND every `deepsql` CLI invocation that hits the
230
+ backend is logged to the DeepSQL `security_events` table with:
231
+
232
+ - the user's identity (from the bearer token or saved profile)
233
+ - the editor / agent that originated the request (`claude-code`,
234
+ `cursor`, `codex`, etc. — from the `--caller-agent` flag or
235
+ `DEEPSQL_MCP_USER_ID` env var)
236
+ - the surface (`mcp` vs `cli`)
237
+ - the connection, the truncated statement, and the outcome
238
+
239
+ Workspace admins can search this. Don't do anything through these
240
+ tools you wouldn't be willing to defend in that view.
112
241
 
113
242
  ---
114
243
 
@@ -116,10 +245,17 @@ view.
116
245
 
117
246
  The complete runtime guide — every decision-tree branch, every foot-gun,
118
247
  all three session playbooks (answer-a-question, mutation, DBA-consult) —
119
- lives in `node_modules/@deepsql/mcp/CLAUDE.md`. Read it the first time
120
- you handle a non-trivial database request.
248
+ lives in the package's `CLAUDE.md`. After install:
249
+
250
+ ```
251
+ node_modules/@deepsql/mcp/CLAUDE.md # local install
252
+ $(npm root -g)/@deepsql/mcp/CLAUDE.md # global install
253
+ ```
254
+
255
+ The CLI is its own source of truth too — if this table drifts from
256
+ reality, run:
121
257
 
122
- Capabilities that aren't MCP-exposed yet (index recommendations, daily
123
- digest, slow-query streaming optimization) live in the CLI: `deepsql
124
- indexes`, `deepsql digest`, `deepsql slow-queries optimize`. Point the
125
- user at them.
258
+ ```bash
259
+ deepsql --help # live command list
260
+ deepsql <command> --help # full options for one command
261
+ ```
package/src/cli.js CHANGED
@@ -36,6 +36,7 @@ const COMMANDS = {
36
36
  access: () => require("./commands/access"),
37
37
  permissions: () => require("./commands/permissions"),
38
38
  "slow-queries": () => require("./commands/slow-queries"),
39
+ "index-recommendations": () => require("./commands/index-recommendations"),
39
40
  setup: () => require("./commands/setup"),
40
41
  };
41
42
 
@@ -60,6 +61,7 @@ const COMMAND_LIST = [
60
61
  ["relationships", false, "List inferred and validated FK relationships"],
61
62
  ["anti-patterns", false, "List schema- or query-level anti-patterns"],
62
63
  ["indexes", true, "Index suggestions, usage, and health (read-only)"],
64
+ ["index-recommendations", true, "Workload-weighted index advisor + HypoPG-validated apply tool"],
63
65
  ["users", true, "Manage workspace users (admin)"],
64
66
  ["access", true, "Manage per-connection access grants (admin)"],
65
67
  ["permissions", true, "Manage role-based permission overrides (admin)"],
@@ -360,6 +362,34 @@ const COMMAND_HELP = {
360
362
  ],
361
363
  notes: "Org and LLM config are set at install time and are NOT touched by this wizard.",
362
364
  },
365
+
366
+ "index-recommendations": {
367
+ description:
368
+ "DBA-grade workload-weighted index advisor. Default `top` shows pending " +
369
+ "recommendations ranked by net benefit (workload − write-cost). `apply` " +
370
+ "is the only mutation — dry-run uses HypoPG (Postgres-only) so no writes " +
371
+ "leak; the two write modes require --confirm.",
372
+ usage:
373
+ "deepsql index-recommendations <top|list|show|refresh|apply|dismiss> [options]",
374
+ subcommands: [
375
+ ["top --connection <name> [--limit N]", "Pre-computed top-N (default 5, max 50), evidence-bearing"],
376
+ ["list --connection <name>", "All pending recommendations for the connection"],
377
+ ["show <id> --connection <name>", "Full detail: workload, HypoPG cost, contributing queries"],
378
+ ["refresh --connection <name>", "Force a fresh accumulation cycle (POST /generate)"],
379
+ ["apply <id> [--mode <m>] [--confirm]", "Run / dry-run with before/after measurement"],
380
+ ["dismiss <id>", "Mark a recommendation as DISMISSED"],
381
+ ],
382
+ options: [
383
+ ["--limit <n>", "top: number of recommendations (default 5, max 50)"],
384
+ ["--mode <m>", "apply: dry-run (default) | apply | apply-and-measure"],
385
+ ["--confirm", "apply: required for apply / apply-and-measure (write modes)"],
386
+ ["--no-concurrent", "apply: skip CREATE/DROP INDEX CONCURRENTLY (dev / small tables)"],
387
+ ["--json", "Emit raw backend JSON instead of the terminal-friendly table"],
388
+ ],
389
+ notes:
390
+ "Complements `deepsql indexes` (catalog-level usage / health). " +
391
+ "This namespace surfaces the workload-weighted advisor + the apply tool.",
392
+ },
363
393
  };
364
394
 
365
395
  // ─── Color helpers ──────────────────────────────────────────────────────────
@@ -564,6 +594,10 @@ function buildOpts(parsed) {
564
594
  skipComplete: !!f.skipComplete,
565
595
  // Confirmations
566
596
  yes: !!f.yes || !!f.y,
597
+ // Index recommendations (apply tool)
598
+ mode: f.mode || null,
599
+ confirm: !!f.confirm,
600
+ noConcurrent: !!f.noConcurrent,
567
601
  // Connection management
568
602
  fromFile: f.fromFile || null,
569
603
  fromStdin: !!f.fromStdin,