🚀 Termalin launches on Product Hunt · September 5 — get notified →
termal.in

← Blog

Let Claude Code and Cursor query your database (safely) — the MCP setup

· Termalin team claude-codecursormcpdatabasetutorial

An agent that can read your database answers questions you’d otherwise open a SQL editor for. “Why did signups drop on Tuesday?” “Which orders have been stuck in pending for more than an hour?” “What’s actually in the events table?” With a query capability the model answers in seconds; without one it guesses. The useful part isn’t the SQL — Claude Code and Cursor both write SQL fine — it’s giving the agent a way to run a read without handing it your credentials. That handoff is the whole friction, and it’s what this post walks through for both tools.

We’ve written separately about why pasting a database connection string into an agent is the move you can’t undo — the credential is bearer access, it can write and drop as well as read, and once it’s passed through a model’s context you can’t un-share it. Read that for the safety model; here we take it as settled and get the wiring done. The short version: the client holds the credential, the agent gets a scoped, read-only-by-default ask.

What you need

  • Termalin — the desktop app, free tier is fine. It’s an SSH and database client with a built-in MCP server; that local server is what your agent will talk to.
  • At least one database connection saved in Termalin’s Data client — Postgres, MySQL, SQLite, SQL Server, ClickHouse, MongoDB, Redis, and more. Pick something low-stakes for the first run: an analytics replica, a staging database, a copy.
  • Claude Code or Cursor on the same machine as the app. The database tools drive the live desktop app, so the agent and the app share a box.

One expectation to set: database access is through the local stdio MCP server only. The hosted endpoint at termal.in/api/v1/mcp covers SSH and files, not databases — so the agent needs to be where your unlocked desktop app is running.

Step 1 — turn agent data access on

This is off by default, and deliberately so. Open Settings → Agent and enable “Let agents query your databases.” The subtitle spells out the posture: off by default, and stays read-only unless a connection grants full access. Until you flip it, every database tool returns database access for agents is off — enable it in Settings → Agent, full stop.

Two defaults are worth internalizing before you go further:

  • It’s a second opt-in, on top of the running app. Turning on agent access to servers doesn’t turn on database access — this is its own switch. Nothing is exposed until you make the decision.
  • Every connection is read-only for the agent. Even with the master switch on, each query is checked before it runs. A write only goes through if you’ve raised that specific connection’s agent policy to full access — a per-connection choice, not a global one. Leave it read-only for now.

The credential itself never moves: the connection’s host, port and password stay in the app’s vault, and the agent only gets to ask the running app to run a query and hand back rows. There’s no connection string in a config file for the agent — or a prompt injection — to read.

Step 2 — register the local MCP server

Claude Code — one command:

claude mcp add termalin -- <path>/termalin-mcp

Replace <path> with wherever the termalin-mcp binary lives (the app can point you at it). Restart Claude Code and it picks up the tools.

Cursor — Cursor reads MCP servers from a JSON file: .cursor/mcp.json in a project root for that project only, or ~/.cursor/mcp.json to make the server available everywhere. For a local stdio server the entry is a command and its arguments:

{
  "mcpServers": {
    "termalin": {
      "command": "<path>/termalin-mcp",
      "args": []
    }
  }
}

The global file is the sensible choice — database access isn’t a per-repo concern. Restart Cursor (or reload the MCP list in its settings) and confirm the server shows as running. This is the same registration the Cursor SSH walkthrough and the Claude Code one use — one server, and it now carries the database tools alongside the SSH ones.

Step 3 — the tools, and a real first task

With the server registered and the switch on, the agent sees four database tools:

data_list     # your saved connections: id, name, engine, and whether the agent may write
data_tables   # tables / collections / measurements for a connection, with row counts
data_schema   # one table's columns: name, type, nullable, primary key
data_query    # run a query in the connection's own language; default cap 200 rows

They mirror how you’d explore a database by hand: list what’s connected, see the tables, describe a table, run the query. data_query speaks whatever the connection speaks — SQL for the relational engines and ClickHouse, Cypher for Neo4j, a Redis command, a collection {filter} for MongoDB — and returns rows up to a cap you can raise per call (maxRows), defaulting to 200 so an agent can’t accidentally pull a million rows into its context.

Now give it a question you’d actually ask, not a demo query:

Signups dropped on Tuesday according to the dashboard. Using the analytics database, figure out what happened.

Watch the agent work the tools in order:

  1. data_list — it finds your analytics connection, sees the engine is Postgres, and notes it’s read-only for the agent.
  2. data_tables — it lists the tables, spots signups and signup_events, and reads the row counts to know what’s worth querying.
  3. data_schema on signups — it learns the columns (created_at, source, status, …) and now knows how to slice by day and by source.
  4. data_query — it runs something like SELECT date_trunc('day', created_at) AS day, source, count(*) FROM signups WHERE created_at >= now() - interval '10 days' GROUP BY 1, 2 ORDER BY 1 and reads the rows back.

The rows tell the story — maybe one source went to zero on Tuesday (a broken referral link), maybe the total held but status = 'failed' spiked (a provider outage). Either way the agent formed its query from the real schema, not a guess, and never held anything more than the ability to ask. If a result truncates at the 200-row cap, it says so and narrows the query rather than pushing for more.

Where the boundaries are

Brief, because the safety post covers it in full — but the defaults you’re relying on:

  • Read-only by default. On the SQL-family engines only read verbs pass — SELECT, SHOW, DESCRIBE, EXPLAIN, WITH, PRAGMA. On Redis, only read commands; on MongoDB, an aggregation with $out/$merge is blocked; on Neo4j, CREATE/MERGE/DELETE/SET/DROP are blocked. A confused or hijacked model gets a read, not a DROP.
  • Per connection, not global. Your analytics replica is a separate decision from your production primary; raising one to full write access doesn’t touch the other.
  • Off with one toggle, and the app holds the credential — nothing was ever shared, so turning it off leaves no copies and no password to rotate.

For anything sensitive, do both: point the Data connection at a read replica or a least-privilege database role and leave the agent read-only. The client-side gate catches mistakes; the database grant sets the ceiling.

Tool-specific notes

  • Cursor asks before each tool call by default. Leave that on for the first sessions — you’ll see every data_query before it runs and can read the SQL the agent proposes. Auto-approval is a convenience to extend one tool at a time: data_list and data_schema are safe to wave through first, data_query the one to keep on manual longest.
  • Claude Code surfaces each tool call inline with its arguments, so the query text is in the transcript before it executes. You’re reading the agent’s SQL, not trusting a summary of it — and every call is attributed to the agent, so at 2 a.m. you can tell “it read this” from “I read this.”

Where Termalin fits

Most “connect your agent to a database” guides end at pasting a connection string into a config file, which quietly grants an agent the same write-and-drop power your app has. Termalin’s Data client inverts that: the app is the custodian, the agent gets four scoped tools driven through the running window, and the whole capability is read-only until you decide otherwise and off with a single switch. It’s the same custody idea we apply to SSH access for agents and to what an MCP server actually is — a database is just the version where a bad write is measured in rows. Start with one connection, keep it read-only, and ask something real before you consider widening anything.


Termalin is a free, cross-platform SSH and database client with a built-in MCP server and a per-connection agent policy — download it, or read how it handles credentials safely.

Try it on one host.

Termalin is a fast SSH client for you — and your agents.

Free tier · 14-day Pro trial · pricing