@deepsql/mcp 0.11.0 → 0.13.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.
- package/AGENT-SETUP.md +72 -29
- package/CLAUDE.md +382 -0
- package/deepsql-phase1-lib.js +102 -25
- package/package.json +3 -2
- package/skills/SKILL_BODY.md +125 -0
- package/src/api/client.js +35 -1
- package/src/cli.js +65 -20
- package/src/cli.test.js +1 -1
- package/src/commands/analyze.js +165 -0
- package/src/commands/analyze.test.js +180 -0
- package/src/commands/explain.js +18 -34
- package/src/commands/mcp.js +439 -7
- package/src/commands/mcp.test.js +384 -0
- package/src/commands/query.js +95 -13
- package/src/commands/query.test.js +214 -0
package/AGENT-SETUP.md
CHANGED
|
@@ -188,54 +188,97 @@ can switch later with another `connections use`.
|
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
191
|
-
## Step 7 — Wire the MCP integration into the editor
|
|
191
|
+
## Step 7 — Wire the MCP integration + the DBA-consult skill into the editor
|
|
192
192
|
|
|
193
|
-
|
|
194
|
-
> *Until then, use the manual steps below.*
|
|
193
|
+
Pick the user's editor and run one of:
|
|
195
194
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
195
|
+
```bash
|
|
196
|
+
deepsql mcp config --install --for claude-code # MCP: ~/.claude/settings.json
|
|
197
|
+
# Skill: ~/.claude/skills/deepsql/SKILL.md
|
|
198
|
+
deepsql mcp config --install --for claude-desktop # MCP: ~/Library/Application Support/Claude/...
|
|
199
|
+
# (no skill — Claude Desktop has no skills surface)
|
|
200
|
+
deepsql mcp config --install --for cursor # MCP: ~/.cursor/mcp.json
|
|
201
|
+
# Skill: ~/.cursor/rules/deepsql.mdc
|
|
202
|
+
deepsql mcp config --install --for codex # MCP: ~/.codex/config.toml
|
|
203
|
+
# Skill: ~/.codex/AGENTS.md (guarded section appended)
|
|
208
204
|
```
|
|
209
205
|
|
|
210
|
-
|
|
206
|
+
Each invocation does **two** things in one shot:
|
|
207
|
+
|
|
208
|
+
1. **MCP server config** — writes a `deepsql` entry into the editor's MCP
|
|
209
|
+
config file. The entry is intentionally tiny:
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{ "command": "deepsql", "args": ["mcp"] }
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The spawned `deepsql mcp` process reads the saved auth token from
|
|
216
|
+
`~/.config/deepsql/auth.json` (mode 0600), so **no token is embedded
|
|
217
|
+
in the editor config**.
|
|
211
218
|
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
2. **DBA-consult skill** — installs an editor-native skill file that
|
|
220
|
+
auto-triggers when the user does database work. The skill encodes the
|
|
221
|
+
"consult DeepSQL before generating DDL or non-trivial SQL" pattern, so
|
|
222
|
+
the agent reaches for `get_brain_context` / `get_schema` /
|
|
223
|
+
`list_business_rules` reflexively rather than inventing schema in a
|
|
224
|
+
vacuum. Trigger phrases the skill recognizes: "add a table", "write a
|
|
225
|
+
migration", "create a column", "design a model", "schema change",
|
|
226
|
+
"query the database", "SQL", "ORM model", "foreign key", "index".
|
|
214
227
|
|
|
215
|
-
The
|
|
216
|
-
|
|
228
|
+
The installer:
|
|
229
|
+
|
|
230
|
+
- creates each target file + parent directory if missing,
|
|
231
|
+
- backs up the existing file to `<path>.bak.<timestamp>` before changing it,
|
|
232
|
+
- merges into the existing MCP server list without touching siblings,
|
|
233
|
+
- refuses to overwrite an existing `deepsql` entry unless `--force` is set,
|
|
234
|
+
- for Codex's `AGENTS.md`, wraps the skill in guarded
|
|
235
|
+
`<!-- BEGIN DEEPSQL ... -->` / `<!-- END DEEPSQL ... -->` markers and
|
|
236
|
+
preserves the user's surrounding content,
|
|
237
|
+
- emits the destination path and any backup path so the user can revert.
|
|
238
|
+
|
|
239
|
+
If the user wants to see the snippets before installing, swap `--install`
|
|
240
|
+
for `--print`. If they want the MCP server config but NOT the skill (e.g.,
|
|
241
|
+
they have their own DBA prompt), pass `--no-skill`. For a non-default
|
|
242
|
+
MCP config path, pass `--path <p>`.
|
|
243
|
+
|
|
244
|
+
Restart the editor for the entries to load.
|
|
217
245
|
|
|
218
246
|
---
|
|
219
247
|
|
|
220
248
|
## Step 8 — Validate end-to-end
|
|
221
249
|
|
|
250
|
+
Two quick checks — one for retrieval, one for execution:
|
|
251
|
+
|
|
222
252
|
```bash
|
|
223
253
|
deepsql brain-context "list a few tables on this database" --top-k 5 --json
|
|
254
|
+
deepsql query "SELECT 1 AS deepsql_ok"
|
|
224
255
|
```
|
|
225
256
|
|
|
226
|
-
|
|
227
|
-
is empty
|
|
228
|
-
|
|
257
|
+
The first should return 5 ranked results pointing at real tables. If the
|
|
258
|
+
response is empty, re-run with a more semantic question
|
|
259
|
+
(`"what is the primary fact table for orders"`).
|
|
229
260
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
261
|
+
The second runs through the canonical Editor SQL endpoint — same policy
|
|
262
|
+
gate, audit log, and RBAC the web UI uses. A successful row confirms the
|
|
263
|
+
auth token, the connection, and the policy pipeline are all wired up.
|
|
233
264
|
|
|
234
|
-
If
|
|
265
|
+
If both work, setup is complete. Tell the user that:
|
|
235
266
|
|
|
236
|
-
- They can now use DeepSQL from their editor (the MCP tools
|
|
237
|
-
`get_brain_context`, `
|
|
267
|
+
- They can now use DeepSQL from their editor (the MCP tools
|
|
268
|
+
`list_connections`, `get_brain_context`, `execute_sql`, `analyze_query_plan`,
|
|
238
269
|
`analyze_slow_queries`, etc. are all available there).
|
|
270
|
+
- **From now on, when the user asks the agent to add a table, add a
|
|
271
|
+
column, write a migration, or design a new query against this database,
|
|
272
|
+
the agent will consult DeepSQL first** — checking existing schema,
|
|
273
|
+
business rules, and inferred relationships before generating any DDL.
|
|
274
|
+
This is the explicit pattern in `CLAUDE.md` ("Treat DeepSQL like your
|
|
275
|
+
DBA"). Users should expect the agent to narrate what DeepSQL found
|
|
276
|
+
("there's already a `customers` table — I'll extend that instead of
|
|
277
|
+
adding `users`") before proposing schema. If the agent skips that step,
|
|
278
|
+
it's a bug in the agent's prompt handling, not in DeepSQL.
|
|
279
|
+
- For mutations (DDL/DML), admins can pass `--write` to `deepsql query` to
|
|
280
|
+
skip the interactive confirmation, or just run without it and confirm
|
|
281
|
+
when prompted.
|
|
239
282
|
- The companion file `CLAUDE.md` (in this same npm package, at
|
|
240
283
|
`node_modules/@deepsql/mcp/CLAUDE.md`) covers the day-to-day usage
|
|
241
284
|
patterns and common mistakes for editor agents.
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# DeepSQL — runtime guidance for AI agents
|
|
2
|
+
|
|
3
|
+
> You are an AI agent (Claude Code, Cursor, Codex, etc.) with DeepSQL's MCP
|
|
4
|
+
> tools loaded. This file tells you how to use them well. Read once; the
|
|
5
|
+
> patterns here will save you and your user real pain.
|
|
6
|
+
|
|
7
|
+
DeepSQL is a self-hosted AI database performance assistant. It indexes the
|
|
8
|
+
user's schemas into a retrieval brain, audits query workloads, and exposes
|
|
9
|
+
two SQL surfaces through MCP plus a `deepsql` CLI.
|
|
10
|
+
|
|
11
|
+
You'll use it in two distinct modes, and you need to recognize which one
|
|
12
|
+
you're in:
|
|
13
|
+
|
|
14
|
+
1. **Answer a question about the data.** The user asked something like
|
|
15
|
+
"how many orders did we ship last week?" You write SQL, run it, return
|
|
16
|
+
the answer. The "decision tree" below covers this flow.
|
|
17
|
+
|
|
18
|
+
2. **Build a feature against an existing database.** The user is in their
|
|
19
|
+
codebase asking you to add a table, add a column, write a migration,
|
|
20
|
+
model a new relationship, design a query for the new ORM model, etc.
|
|
21
|
+
**This is where most agents fail silently** — they generate plausible
|
|
22
|
+
schema without consulting the existing one, and the developer ends up
|
|
23
|
+
with `users` next to `customers` and `cancelled_at` next to a
|
|
24
|
+
`status_history` table that already tracks the same thing. The "DBA
|
|
25
|
+
consult" section below covers this flow. **Read it before you generate
|
|
26
|
+
any DDL.**
|
|
27
|
+
|
|
28
|
+
**Every call you make runs through the same policy gate as the web SQL
|
|
29
|
+
Editor and is logged with your identity, the editor that invoked the MCP
|
|
30
|
+
server, and the statement you ran.** Don't be sloppy.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## The tools you have
|
|
35
|
+
|
|
36
|
+
The MCP server exposes 10 tools. They all take a `connectionId` (UUID
|
|
37
|
+
returned by `list_connections`).
|
|
38
|
+
|
|
39
|
+
| Tool | Purpose |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `list_connections` | List databases the user has access to. Always call this first — you need IDs for everything else. |
|
|
42
|
+
| `get_schema` | Cached schema metadata (tables, columns, FKs, types). Cheap and fast — call freely. |
|
|
43
|
+
| `get_database_objects` | Tables, views, functions, procedures. Use when you need DDL-level objects, not just columns. |
|
|
44
|
+
| `get_brain_context` | **Your primary retrieval tool.** Given a question, returns the tables/columns/FKs/training docs/business rules/anti-patterns most relevant to it. |
|
|
45
|
+
| `list_business_rules` | Active business rules and SQL guardrails. Honor these — they encode domain semantics. |
|
|
46
|
+
| `get_relationships` | Inferred + validated foreign keys with confidence scores. Many real DBs lack declared FKs; this fills the gap. |
|
|
47
|
+
| `get_anti_patterns` | Schema-level (`kind=table`) or query-level (`kind=query`) anti-patterns. |
|
|
48
|
+
| `analyze_slow_queries` | Recent slow queries with fingerprints, durations, examples. Read-only; doesn't trigger new work. |
|
|
49
|
+
| **`execute_sql`** | **Run any SQL statement.** Policy is server-enforced: developers can run SELECT/WITH/SHOW/EXPLAIN; admins can also run DML/DDL with a two-step confirmation. EXPLAIN and EXPLAIN ANALYZE are just SQL — no separate flag. |
|
|
50
|
+
| **`analyze_query_plan`** | **AI-enriched plan analysis** for a query. Returns the parsed plan tree, performance issues, index recommendations, and a written summary that takes the connection's schema and business rules into account. Pass `useAnalyze: true` to run `EXPLAIN ANALYZE` (actually executes the query). |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Hard rules
|
|
55
|
+
|
|
56
|
+
1. **One execution tool, one analysis tool — that's it.** If you find yourself
|
|
57
|
+
reaching for `execute_sql` to get a plan, stop. Use `analyze_query_plan`.
|
|
58
|
+
If you find yourself wrapping queries in `EXPLAIN` by hand to avoid running
|
|
59
|
+
them, stop. Plain EXPLAIN is read-only on every database engine; just type
|
|
60
|
+
the SQL.
|
|
61
|
+
|
|
62
|
+
2. **The policy gate is real.** If `execute_sql` returns
|
|
63
|
+
`{ requiresConfirmation: true, warnings: [...] }`, the statement is a
|
|
64
|
+
mutation that needs admin confirmation. Show the warnings to the user,
|
|
65
|
+
wait for their explicit OK, then re-call with `confirmMutation: true`.
|
|
66
|
+
Do not silently retry with `confirmMutation: true` on the user's behalf —
|
|
67
|
+
that defeats the whole point of the gate.
|
|
68
|
+
|
|
69
|
+
3. **Developers cannot run mutations.** If the user's token has
|
|
70
|
+
`Role.DEVELOPER` and they ask you to `UPDATE users …`, the server will
|
|
71
|
+
return `EDITOR_MUTATION_FORBIDDEN`. Don't try to work around it. Tell the
|
|
72
|
+
user: "Your DeepSQL role doesn't allow DML/DDL on this connection; ask
|
|
73
|
+
the workspace admin to grant write access or to run the change."
|
|
74
|
+
|
|
75
|
+
4. **Pass `connectionId`, not names.** Names are user-facing; tools take UUIDs.
|
|
76
|
+
Get them from `list_connections` once and cache for the session.
|
|
77
|
+
|
|
78
|
+
5. **Always call `get_brain_context` before generating non-trivial SQL.** The
|
|
79
|
+
brain knows about business rules, anti-patterns, and inferred FKs that
|
|
80
|
+
aren't in the raw schema. Skipping it produces "technically valid,
|
|
81
|
+
semantically wrong" SQL — the worst kind of failure.
|
|
82
|
+
|
|
83
|
+
6. **`execute_sql` limits matter.** Default 100 rows, max 1000. Asking for
|
|
84
|
+
"all customers" and getting 100 is the limit kicking in — not the real
|
|
85
|
+
count. Either bump `limit` (max 1000) or `SELECT COUNT(*)` first.
|
|
86
|
+
|
|
87
|
+
7. **Honor business rules silently.** If `list_business_rules` returns
|
|
88
|
+
`always_filter_cancelled` for a connection, your `SELECT * FROM orders`
|
|
89
|
+
suggestion is wrong without `WHERE status != 'CANCELLED'`. Apply the rule
|
|
90
|
+
in the SQL you generate; don't ask the user permission to follow their
|
|
91
|
+
own rules.
|
|
92
|
+
|
|
93
|
+
8. **Treat DeepSQL like the DBA. Consult before you commit schema.** This
|
|
94
|
+
is the most important rule for feature-development work — it gets its
|
|
95
|
+
own section below.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Treat DeepSQL like your DBA — consult before you commit
|
|
100
|
+
|
|
101
|
+
If you're helping a developer build a feature, **the moment they say "add
|
|
102
|
+
a table for X," "track Y," "save Z somewhere," or "let's write a
|
|
103
|
+
migration" is the moment to call DeepSQL.** The brain has things the raw
|
|
104
|
+
codebase doesn't:
|
|
105
|
+
|
|
106
|
+
- business rules the team's previous DBA encoded
|
|
107
|
+
- foreign-key relationships the schema infers but doesn't declare
|
|
108
|
+
- anti-patterns that have already burned this team in this database
|
|
109
|
+
- columns and tables that exist but live on parts of the schema the
|
|
110
|
+
developer hasn't seen yet
|
|
111
|
+
|
|
112
|
+
Skipping the consult is the most common way agents make a database worse:
|
|
113
|
+
|
|
114
|
+
- The developer asks for a `users` table. You create one. There's already
|
|
115
|
+
a `customers` table doing 90% of the same thing, and now half the new
|
|
116
|
+
feature's data lives in the wrong place forever.
|
|
117
|
+
- The developer asks to "track when an order was cancelled." You add a
|
|
118
|
+
`cancelled_at` column. The team's existing pattern is `status` +
|
|
119
|
+
`order_status_history` — your column is now an inconsistent third
|
|
120
|
+
source of truth.
|
|
121
|
+
- The developer asks for "an index on `email`." There's already a unique
|
|
122
|
+
constraint on `(tenant_id, email)` covering most lookups, and your
|
|
123
|
+
single-column index is dead weight that the optimizer will rarely pick.
|
|
124
|
+
|
|
125
|
+
The consult takes one to three tool calls and saves the user months of
|
|
126
|
+
cleanup. **Make it a reflex.**
|
|
127
|
+
|
|
128
|
+
### The before-you-commit checklist
|
|
129
|
+
|
|
130
|
+
Run these *before* you generate any DDL, migration file, ORM model, or
|
|
131
|
+
schema-shaped design proposal:
|
|
132
|
+
|
|
133
|
+
1. **`get_brain_context(connectionId, "<one-line description of the feature>")`** —
|
|
134
|
+
surfaces the tables, columns, FKs, training docs, and business rules
|
|
135
|
+
most relevant. Read the results, don't just regurgitate them.
|
|
136
|
+
|
|
137
|
+
2. **`get_schema(connectionId)`** if you need the full column inventory
|
|
138
|
+
for the tables `get_brain_context` surfaced. Confirm exact column names
|
|
139
|
+
and types before you reference them.
|
|
140
|
+
|
|
141
|
+
3. **`list_business_rules(connectionId, question="<feature>")`** — active
|
|
142
|
+
rules the new feature MUST respect. `always_filter_cancelled` means
|
|
143
|
+
your new aggregate view inherits that filter from day one.
|
|
144
|
+
|
|
145
|
+
4. **`get_relationships(connectionId)`** if you're about to declare a new
|
|
146
|
+
foreign key. The brain may already infer the relationship — and the
|
|
147
|
+
inferred FK column has a confidence score telling you whether the
|
|
148
|
+
convention is reliable enough to follow without explicitly declaring.
|
|
149
|
+
|
|
150
|
+
5. **`get_anti_patterns(connectionId, kind="table")`** if you're about to
|
|
151
|
+
commit a schema shape (single fat table, denormalized JSON column,
|
|
152
|
+
unindexed FK, …). The brain has flagged these patterns elsewhere in
|
|
153
|
+
this exact database; don't add to the pile.
|
|
154
|
+
|
|
155
|
+
### Narrate what you found, then propose
|
|
156
|
+
|
|
157
|
+
When the checklist is done, **explain to the developer what you found
|
|
158
|
+
before you propose schema**. Example:
|
|
159
|
+
|
|
160
|
+
> "DeepSQL says you already have a `customers` table with `email`,
|
|
161
|
+
> `tenant_id`, `created_at`, plus an inferred FK to `accounts.customer_id`
|
|
162
|
+
> at 0.94 confidence. The team's business rule `always_filter_cancelled`
|
|
163
|
+
> is on `customers.status`. The `kind=table` anti-pattern report flagged
|
|
164
|
+
> 'wide-table' on `customer_profiles` — adding more columns there is
|
|
165
|
+
> discouraged. **I'd extend `customers` with the two new fields you need
|
|
166
|
+
> rather than adding a `users` table. Want me to draft the migration?**"
|
|
167
|
+
|
|
168
|
+
That explicit handoff is the difference between an agent that ships
|
|
169
|
+
features fast and an agent that earns the DBA's trust.
|
|
170
|
+
|
|
171
|
+
### When the consult tells you to stop
|
|
172
|
+
|
|
173
|
+
Sometimes the right answer is "don't add this." If `get_brain_context`
|
|
174
|
+
surfaces an existing table that already does what the user is asking for,
|
|
175
|
+
say so. If `get_anti_patterns` flags the shape they're about to add, say
|
|
176
|
+
so. The user usually doesn't know about either; that's exactly why
|
|
177
|
+
DeepSQL exists. Push back politely and propose the better path.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## The "I need to…" decision tree
|
|
182
|
+
|
|
183
|
+
**"What tables exist?"** → `get_schema` (or `list_connections` first if you
|
|
184
|
+
don't know which connection). Don't ask `execute_sql` to query
|
|
185
|
+
`information_schema` — `get_schema` is faster and cached.
|
|
186
|
+
|
|
187
|
+
**"Write a SQL query to answer X."** → `get_brain_context` with X as the
|
|
188
|
+
question, then generate SQL using only the columns/tables it surfaced.
|
|
189
|
+
|
|
190
|
+
**"Run this SQL and tell me what it returns."** → `execute_sql`. If you're
|
|
191
|
+
unsure whether the query is correct, call `analyze_query_plan` first (plain
|
|
192
|
+
EXPLAIN, no execution) — costs nothing and catches bad joins.
|
|
193
|
+
|
|
194
|
+
**"Why is this query slow?"** → `analyze_query_plan`. The AI summary points
|
|
195
|
+
at the slow nodes, missing indexes, and bad estimates. For workload-level
|
|
196
|
+
problems use `analyze_slow_queries`.
|
|
197
|
+
|
|
198
|
+
**"What's the real execution time for this query?"** → `analyze_query_plan`
|
|
199
|
+
with `useAnalyze: true`. **This actually runs the query**, so if the
|
|
200
|
+
statement mutates the database, the same admin role + WHERE-clause + confirm
|
|
201
|
+
gates that protect `execute_sql` kick in. You'll get back
|
|
202
|
+
`requiresConfirmation` if you forgot.
|
|
203
|
+
|
|
204
|
+
**"Apply this migration"** / **"Add this column"** / **"Delete these rows"**
|
|
205
|
+
→ `execute_sql` with the DDL/DML. Only admins can do it. On first call you'll
|
|
206
|
+
get `requiresConfirmation` — surface the warnings to the user verbatim, wait
|
|
207
|
+
for them to say yes, then re-call with `confirmMutation: true`.
|
|
208
|
+
|
|
209
|
+
**"What indexes should we add?"** → Not exposed via MCP yet. Tell the user
|
|
210
|
+
to run `deepsql indexes missing` or `deepsql indexes health` in their
|
|
211
|
+
terminal.
|
|
212
|
+
|
|
213
|
+
**"What changed recently / what should I worry about?"** → Tell the user to
|
|
214
|
+
run `deepsql digest` (today) or `deepsql digest 7` (last seven). The digest
|
|
215
|
+
isn't MCP-exposed.
|
|
216
|
+
|
|
217
|
+
**"Are there foreign keys between X and Y?"** → `get_relationships`. Many
|
|
218
|
+
real-world DBs lack declared FKs but DeepSQL's brain infers them; check the
|
|
219
|
+
`confidence` field and `validationStatus`.
|
|
220
|
+
|
|
221
|
+
### Feature-development questions (the DBA-consult flow)
|
|
222
|
+
|
|
223
|
+
**"I'm building a feature that needs a `<thing>` table."** → STOP. Call
|
|
224
|
+
`get_brain_context(connectionId, "<thing>")` first. Read the "Treat
|
|
225
|
+
DeepSQL like your DBA" section above before generating any DDL. There's
|
|
226
|
+
almost always an existing table or column to extend instead of
|
|
227
|
+
duplicate.
|
|
228
|
+
|
|
229
|
+
**"I'm about to write a migration."** → STOP. Run the before-you-commit
|
|
230
|
+
checklist (`get_brain_context` + `list_business_rules` +
|
|
231
|
+
`get_anti_patterns`). Walk the developer through what you found, THEN
|
|
232
|
+
write the migration. The user should see your reasoning, not just the
|
|
233
|
+
final SQL.
|
|
234
|
+
|
|
235
|
+
**"I'm adding a new column to `<table>`."** → STOP. `get_schema` first to
|
|
236
|
+
confirm the column doesn't already exist (sometimes under a different
|
|
237
|
+
name — `cancelled_at` vs `voided_at` vs `status_history.changed_at`).
|
|
238
|
+
`list_business_rules` to check whether nullability, default, or naming
|
|
239
|
+
conventions are constrained.
|
|
240
|
+
|
|
241
|
+
**"I'm naming a foreign key / index."** → `get_relationships` for the FK
|
|
242
|
+
convention this team uses, and `get_schema` to see how existing indexes
|
|
243
|
+
on the parent table are named. Pick the convention; don't invent a new
|
|
244
|
+
one.
|
|
245
|
+
|
|
246
|
+
**"I'm designing an ORM model / type definition for table `X`."** →
|
|
247
|
+
`get_schema(connectionId)` and pull the exact column list, types, and
|
|
248
|
+
nullability. Don't infer column types from variable names in the
|
|
249
|
+
codebase — they're often stale.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Foot-guns we've watched agents step on
|
|
254
|
+
|
|
255
|
+
**"I'll write a 4-statement script to set up some temp tables, run my
|
|
256
|
+
analysis, and clean up."** → `execute_sql` rejects multi-statement input.
|
|
257
|
+
Run each statement separately, or use CTEs (`WITH foo AS (...) SELECT ...`).
|
|
258
|
+
|
|
259
|
+
**"I'll skip the confirmation step and re-call with `confirmMutation: true`
|
|
260
|
+
right away."** → That's an end-run around safety. The confirmation step
|
|
261
|
+
exists so a human gets a chance to see the warnings (especially the
|
|
262
|
+
"this DELETE has no WHERE clause"-style ones). Always surface the warnings,
|
|
263
|
+
always wait for the human.
|
|
264
|
+
|
|
265
|
+
**"`EXPLAIN ANALYZE` is just better EXPLAIN, I'll always use it."** → No.
|
|
266
|
+
ANALYZE executes the query. For SELECTs it's just slower; for mutations it
|
|
267
|
+
actually mutates. Default to `useAnalyze: false` and only bump to `true`
|
|
268
|
+
when the user actually wants real timings.
|
|
269
|
+
|
|
270
|
+
**"I don't trust the cached schema; let me query `information_schema`
|
|
271
|
+
fresh."** → The cache is invalidated whenever the brain re-indexes the
|
|
272
|
+
connection. Trust it. If you really suspect drift, ask the user to run
|
|
273
|
+
`deepsql connections init <name> --wait`.
|
|
274
|
+
|
|
275
|
+
**"I'll just retry on 403."** → A 403 from DeepSQL means the user's token
|
|
276
|
+
doesn't have access to that specific connection (RBAC) or role doesn't
|
|
277
|
+
allow the action (developer trying to mutate). Surface the error verbatim;
|
|
278
|
+
don't pretend it's transient.
|
|
279
|
+
|
|
280
|
+
**"The SQL looks fine; I'll skip the plan check."** → A cheap
|
|
281
|
+
`analyze_query_plan` call has saved more bad joins than any other habit.
|
|
282
|
+
Always check the plan before suggesting a query to a user, especially
|
|
283
|
+
against unfamiliar schemas.
|
|
284
|
+
|
|
285
|
+
**"The developer asked for table X, so I'll just create it."** → That's
|
|
286
|
+
how databases get fragmented over a year. The brain almost always has a
|
|
287
|
+
table doing most of what the new feature needs; you'll find it in 30
|
|
288
|
+
seconds with `get_brain_context`. Skipping that step makes you the agent
|
|
289
|
+
future engineers curse when they're refactoring around your duplicate
|
|
290
|
+
schema. Run the before-you-commit checklist every single time.
|
|
291
|
+
|
|
292
|
+
**"I read the codebase's models, I know the schema."** → Codebase models
|
|
293
|
+
drift from the live schema. Columns get renamed in a migration, the model
|
|
294
|
+
class doesn't update. A `User.email` field in TypeScript can be
|
|
295
|
+
`users.email_address` in Postgres. `get_schema` is the source of truth;
|
|
296
|
+
trust it over `grep`.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## What lives in the CLI but not the MCP (yet)
|
|
301
|
+
|
|
302
|
+
A few categories are CLI-only for now — if the user asks for them, point
|
|
303
|
+
them at the terminal command rather than trying to fake it through
|
|
304
|
+
`execute_sql`:
|
|
305
|
+
|
|
306
|
+
| Capability | CLI command |
|
|
307
|
+
|---|---|
|
|
308
|
+
| Index recommendations / missing-index advisor | `deepsql indexes list`, `deepsql indexes missing` |
|
|
309
|
+
| Unused / duplicate index detection | `deepsql indexes unused`, `deepsql indexes duplicates` |
|
|
310
|
+
| Per-table index usage stats | `deepsql indexes usage <table>` |
|
|
311
|
+
| Index health report | `deepsql indexes health` |
|
|
312
|
+
| Daily digest (anomalies + AI commentary) | `deepsql digest`, `deepsql digest 7` |
|
|
313
|
+
| Streaming AI optimization for a slow query | `deepsql slow-queries optimize --query-id <id>` |
|
|
314
|
+
|
|
315
|
+
These are reachable from any terminal where `deepsql` is installed and
|
|
316
|
+
logged in; the saved profile is shared with the MCP server.
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## A typical session
|
|
321
|
+
|
|
322
|
+
1. `list_connections` → grab the UUID for the connection the user means.
|
|
323
|
+
2. `get_brain_context(connectionId, "the question")` → harvest tables,
|
|
324
|
+
columns, business rules.
|
|
325
|
+
3. Write SQL using only the columns the brain surfaced; respect the rules.
|
|
326
|
+
4. `analyze_query_plan(connectionId, sql)` → sanity-check the plan
|
|
327
|
+
(`useAnalyze: false`).
|
|
328
|
+
5. `execute_sql(connectionId, sql, limit=…)` → fetch results.
|
|
329
|
+
6. Summarize, citing which tables you used and which rules you applied.
|
|
330
|
+
|
|
331
|
+
If you need to mutate (DDL/DML, admin role required):
|
|
332
|
+
|
|
333
|
+
1–3. Same as above.
|
|
334
|
+
4. Show the user the SQL you intend to run, in plain text. **Get their OK.**
|
|
335
|
+
5. `execute_sql(connectionId, sql)` → expect `requiresConfirmation: true`
|
|
336
|
+
with warnings.
|
|
337
|
+
6. Show the warnings to the user verbatim. Get their **second** OK.
|
|
338
|
+
7. `execute_sql(connectionId, sql, confirmMutation: true)` → executes.
|
|
339
|
+
8. Tell the user it succeeded; show the `rowCount` of affected rows.
|
|
340
|
+
|
|
341
|
+
If you're helping a developer build a feature (the DBA-consult flow):
|
|
342
|
+
|
|
343
|
+
1. Have the developer describe the feature in one or two sentences.
|
|
344
|
+
2. `get_brain_context(connectionId, "<feature in one line>")` → surfaces
|
|
345
|
+
existing tables, columns, FKs, and rules in scope.
|
|
346
|
+
3. Fill in any gaps: `get_schema(connectionId)` for full column lists,
|
|
347
|
+
`list_business_rules(connectionId, …)` for constraints,
|
|
348
|
+
`get_relationships(connectionId)` for FK conventions,
|
|
349
|
+
`get_anti_patterns(connectionId, kind="table")` for shapes to avoid.
|
|
350
|
+
4. **Narrate to the developer what you found before proposing schema.**
|
|
351
|
+
"There's already an X. The team's convention is Y. Anti-pattern Z is
|
|
352
|
+
on watch. Here's what I'd propose, given all that."
|
|
353
|
+
5. Once the developer agrees on the *shape*, generate the migration. For
|
|
354
|
+
admins this lands via `execute_sql`; follow the mutation playbook
|
|
355
|
+
above to actually run it. For developers without write access, hand
|
|
356
|
+
the SQL to the user to commit through your codebase's migration
|
|
357
|
+
tooling instead — but make sure the schema you generate already
|
|
358
|
+
reflects everything DeepSQL told you in step 2–3.
|
|
359
|
+
6. After the migration runs, `get_schema(connectionId)` to verify the new
|
|
360
|
+
columns exist with the expected types, and optionally re-run
|
|
361
|
+
`analyze_query_plan` on the canonical queries the new feature will
|
|
362
|
+
issue.
|
|
363
|
+
|
|
364
|
+
If any step returns nothing useful, ask the user to be more specific
|
|
365
|
+
rather than guessing. DeepSQL is conservative by design — empty results
|
|
366
|
+
from `get_brain_context` usually mean the question was too short or too
|
|
367
|
+
schema-y, not that the brain is broken.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Audit, in case you wondered
|
|
372
|
+
|
|
373
|
+
Every call you make is logged to `security_events` with:
|
|
374
|
+
|
|
375
|
+
- the user's identity (from the bearer token)
|
|
376
|
+
- the editor that invoked the MCP (claude-desktop, cursor-mcp, codex-mcp —
|
|
377
|
+
whatever `DEEPSQL_MCP_USER_ID` is set to in the editor config)
|
|
378
|
+
- the connection, statement hash, truncated text, outcome
|
|
379
|
+
- whether confirmation was required and given
|
|
380
|
+
|
|
381
|
+
Workspace admins can search this via the Security tab. Don't do anything
|
|
382
|
+
through the MCP that you wouldn't be willing to defend in that view.
|