Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Claude Mysql

FreeNot checked

Connect Claude to a free MySQL database via MCP — Claude Desktop and Claude Code, no local server

GitHubEmbed

About

Connect Claude to a free MySQL database via MCP — Claude Desktop and Claude Code, no local server

README

MySQL Claude Code Spec MIT

Sixty seconds:

# 1. get a MySQL session and an MCP token at https://freebase.cloud
# 2. register it with Claude Code, project scope, so the repo carries it
claude mcp add --transport http bugs https://freebase.cloud/api/mcp/YOUR_TOKEN --scope project

# 3. check it loaded
claude mcp list

# 4. from inside a session
#    > describe the schema of the bugs database, then write a migration that adds
#      a severity column with a sensible default and backfills it from priority

That is the setup, once you have a MySQL 8.0 session to point at. The rest of this file is about the part that is actually hard: getting a coding agent to write migrations that fit the database you have, rather than the database it assumed.


The problem with schema-blind agents

Ask any model to "add a severity column" and it will produce a migration. It will also, with no particular malice, guess your table name, guess whether the primary key is id or bug_id, guess that a status column is a VARCHAR when you made it an ENUM, and pick a default that violates a CHECK constraint you added last spring. The migration looks right in review and fails on apply.

The failure is not reasoning. It is input. The model was asked to write DDL for a schema it had never seen.

Wiring a database into the session over MCP removes the guessing. Before writing the migration the agent runs bugs_list_tables and a couple of information_schema queries, sees the real column types, the real indexes and the real constraint names, and writes DDL against those. When it is wrong afterwards, it is wrong about intent — which is a review problem, and reviewable.

What a working session looks like

Illustrative. Written out to show the sequence of tool calls, not copied from a run.

You: We need to track how long tickets sit in triage. Look at the schema and propose the smallest change that gets us that, then write the migration.

Claude: (calls bugs_list_tables)

tickets already has created_at and status (ENUM('new','triaged','in_progress','closed')), but no record of when the status changed. Two options:

  1. Add triaged_at DATETIME NULL to tickets. One column, one backfill, no history.
  2. Add a status_transitions table. Full history, more code, needs writes at every status change.

You asked for the smallest change, so option 1 — but note it only answers the question once per ticket. If you expect to ask "how long in each state" later, option 2 now is cheaper than option 2 in six months.

You: Option 1 for now.

Claude: (writes migrations/003_triage_time.sql, then calls bugs_query with the statements one at a time)

ALTER TABLE tickets
  ADD COLUMN triaged_at DATETIME NULL AFTER created_at;

UPDATE tickets
   SET triaged_at = updated_at
 WHERE status <> 'new' AND triaged_at IS NULL;

CREATE INDEX tickets_triaged_idx ON tickets (triaged_at);

The backfill uses updated_at as a proxy, which is only accurate for tickets that have been touched exactly once. 214 of the 890 rows have been updated more than once — those numbers will be wrong and I have left them out of the index-backed report.

The last paragraph is the reason to bother. It required knowing the row counts.


Setup, in more detail

Get the endpoint

Sign up at freebase.cloud, create a session, pick MySQL (8.0.36). Then Settings → MCP → New Token, choose the connection, copy the URL:

https://freebase.cloud/api/mcp/YOUR_TOKEN

The token travels in the path, so no Authorization header is needed and no secret-injection mechanism is required for clients that only take a URL.

Register it

# this project only, written to ./.mcp.json
claude mcp add --transport http bugs https://freebase.cloud/api/mcp/YOUR_TOKEN --scope project

# every project on this machine
claude mcp add --transport http bugs https://freebase.cloud/api/mcp/YOUR_TOKEN --scope user

Or write the file by hand:

{
  "mcpServers": {
    "bugs": {
      "type": "http",
      "url": "https://freebase.cloud/api/mcp/YOUR_TOKEN"
    }
  }
}

"type" is required. Claude Code rejects a url entry with no type rather than inferring the transport — the server simply will not load and the failure is easy to misread as a network problem. "streamable-http" works as a synonym for "http".

Committing .mcp.json

Project scope exists so the server definition travels with the repo. That is genuinely useful for a team, and it is also how a live database credential ends up in git history. Two workable patterns:

  • Shared scratch database. Commit the file, point it at a throwaway MySQL session that holds seeded fixture data and nothing real. Everyone gets the same schema, nobody can leak anything.
  • Per-developer token. Commit a .mcp.json.example with YOUR_TOKEN in it, gitignore the real file, and let each person run the claude mcp add line once.

The first is better for schema work, which is what this repo is about. The second is the only option if the data is not disposable.

Claude Desktop

Desktop takes the same URL, but only through Settings → Connectors → Add custom connector (newer builds: Customize → Connectors), and you enable it per conversation with the + button. There is no way to put a remote HTTP MCP server in claude_desktop_config.json; that file only starts local stdio processes. mcp-remote bridges the gap if you truly need a file-based config, at the cost of an extra experimental process in the chain.


The tools

Every MySQL connection you create exposes the same four, prefixed with the connection name:

Tool Arguments What to use it for
bugs_list_tables — First call of any schema task. Tables, columns, row counts, annotations.
bugs_query query Any MySQL 8.0 statement — SELECT, EXPLAIN, SHOW CREATE TABLE, DDL.
bugs_store table, rows, mode Bulk insert from a JSON array. mode: "replace" overwrites.
bugs_annotate_table table, description, format Persistent notes about intent, read on every reconnect.

SHOW CREATE TABLE tickets through bugs_query is the highest-value single call in a migration workflow — it returns the exact DDL including collation, engine, constraint names and index definitions, which is more than list_tables gives you.

Annotations earn their keep for the things DDL cannot express:

Annotate tickets: status transitions are one-way except closed → in_progress on reopen. priority is caller-reported and unreliable; severity is set by triage and is the one to trust. Never delete rows — set status = 'closed'.

Access model

MySQL on freebase.cloud is reached over the MCP endpoint and over the HTTP query API. Unlike PostgreSQL, Redis and MongoDB, it does not expose a raw TCP port you can point mysql -h at — so if your workflow depends on a local socket connection, know that before you build on it. The dialect is genuine MySQL 8.0.36: InnoDB, window functions, CTEs, JSON functions, stored procedures, triggers, utf8mb4, invisible indexes.

For scripts, the HTTP path looks like this:

curl -X POST https://freebase.cloud/api/wire/query \
  -H "Content-Type: application/json" \
  -d '{"namespace":"mydb","protocol":"mysql","query":"SELECT VERSION()"}'

Both example scripts in this repo go through MCP instead, since that is the same route Claude takes and therefore the one worth understanding.

Repository contents

examples/
  migrations/001_init.sql            initial bug-triage schema
  migrations/002_severity.sql        adds severity, backfills from priority
  migrations/003_triage_time.sql     the migration from the exchange above
  apply_migrations.mjs               applies pending files over MCP, tracks state
  schema_digest.py                   prints a Markdown schema summary for CLAUDE.md
  triage_queries.sql                 reports to hand an agent as a starting point
  README.md

schema_digest.py is the one to steal. It queries information_schema and emits a compact Markdown table per table, suitable for pasting into CLAUDE.md so the agent has the shape of the database in context before it makes its first tool call. Cheaper than a list_tables round trip on every session, and it keeps the schema visible in code review.

Gotchas

  • MySQL DDL is not transactional. ALTER TABLE commits implicitly. A migration that fails halfway leaves the table half-altered, and no ROLLBACK will save you. Write each migration so re-running it is safe, or so its failure mode is obvious.
  • One statement per call. Multi-statement strings are rejected by many drivers and are ambiguous to error-report through a tool interface. apply_migrations.mjs splits on ; at statement boundaries for this reason.
  • Row counts influence advice. An agent that knows a table has 900 rows will suggest different things than one told it has 900 million. Say which environment it is looking at.
  • Know what the free tier is sized for: development, prototyping and small production workloads. This repo makes no claims about quotas, retention or availability — check the dashboard.
  • The token is full access. Anyone with the URL can drop a table. Rotate it in Settings → MCP if it leaks, and do not point a committed config at anything you care about.

FAQ

Can the agent apply migrations itself, or only write them? Both. bugs_query executes DDL. Whether you want that is a judgement call; on a scratch database it is a large speed-up, on anything shared it is worth keeping the apply step manual.

Does mysqldump work? Not against a TCP socket, since there is no open MySQL port. Export by querying the data out — schema_digest.py shows the information_schema pattern, and SELECT through bugs_query returns rows you can serialise.

Can two agents use the same database? Yes, and they will happily contradict each other. MySQL's locking applies as normal, but nothing coordinates intent. One writer at a time for schema changes.

Why MySQL rather than PostgreSQL for this? Mostly because your production database is MySQL. If you are choosing fresh, PostgreSQL on the same service gives you transactional DDL, which materially reduces the pain of a failed migration.

Links

MIT licensed.

freebase.cloud is an independent service and is not affiliated with Oracle Corporation or Anthropic, PBC.

from github.com/freebase-cloud/claude-mysql-mcp

Installing Claude Mysql

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/freebase-cloud/claude-mysql-mcp

FAQ

Is Claude Mysql MCP free?

Yes, Claude Mysql MCP is free — one-click install via Unyly at no cost.

Does Claude Mysql need an API key?

No, Claude Mysql runs without API keys or environment variables.

Is Claude Mysql hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Claude Mysql in Claude Desktop, Claude Code or Cursor?

Open Claude Mysql on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Claude Mysql with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All data MCPs