Local MySQL MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Local MySQL MCP Servershow me the first 10 rows from the customers table"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Local MySQL Database MCP Server
A TypeScript Model Context Protocol (MCP) server that exposes read-only, least-privileged access to a locally hosted MySQL database for approved AI-agent workflows.
Status
Implemented (Phases 0–8 of the plan). Unit, security, and integration tests all run against your local MySQL — no container runtime is required.
Related MCP server: vmysql-mcp
Table of contents
Prerequisites
Tool | Version | Notes |
Node.js | 22 LTS | The repo pins |
npm | 10+ | Bundled with Node 22. |
MySQL Server | 8.x | Local install on |
Git | recent | To clone the repo. |
OS support: tested on Windows 11, macOS 14, and Ubuntu 22.04. The pool defaults to
127.0.0.1(TCP loopback), not the Unix socket — works identically across platforms.
Required command-line tools
Make sure each of these resolves on your PATH:
node --version # v22.x
npm --version # 10.x
mysql --version # 8.x
git --versionClone and first build
# 1. Clone
git clone https://github.com/<your-org>/db-mcp-server.git
cd db-mcp-server
# 2. Use the pinned Node version
nvm install # only if you don't already have Node 22
nvm use # reads .nvmrc
# 3. Install dependencies
npm install
# 4. Sanity-check the source
npm run typecheck
npm run lint
# 5. Build the dist/ that MCP clients will invoke
npm run buildAfter this you should see a populated dist/ directory and the file
dist/index.js will be the MCP server entrypoint. The shipped .mcp.json
points at this exact path, so any MCP client that auto-reads .mcp.json
(Claude Code, puku-cli, Cursor) will pick up the server as soon as
dist/index.js exists.
Set up MySQL and the read-only user
This server connects with a dedicated, read-only MySQL account. It does
not use your root or app credentials. The bootstrap script
scripts/setup-mysql-user.sql creates the user mcp_readonly, creates the
mavenmovies schema if it is missing, grants SELECT only, and revokes
everything else.
Step 1 — edit the SQL script
Open scripts/setup-mysql-user.sql and replace the two placeholders at the
top:
SET @mcp_user = 'mcp_readonly';
SET @mcp_pass = 'CHANGE_ME_BEFORE_RUNNING'; -- use a strong password
SET @mcp_schema = 'mavenmovies'; -- your schema nameDo not commit the real password. The repo's .gitignore already excludes
.env; treat scripts/setup-mysql-user.sql the same way if you paste a real
password into it.
Step 2 — apply the grants
Run as a MySQL administrator (root or equivalent):
mysql -u root -p < scripts/setup-mysql-user.sqlStep 3 — load a test schema (optional but recommended)
The mavenmovies schema is a small, free sample DB. If you don't already
have it, you can download it from the official MySQL sample and load it:
# Example: load the official mavenmovies dump.
# Replace the path with wherever you saved it.
mysql -u root -p mavenmovies < /path/to/mavenmovies.sqlYou can use any schema; just set MYSQL_DATABASE and MCP_ALLOWED_SCHEMAS
in .env to match.
Step 4 — verify the user can read
mysql -u mcp_readonly -p -h 127.0.0.1 -e "SELECT COUNT(*) FROM mavenmovies.actor;"You should see a count. The same connection should fail for any write:
mysql -u mcp_readonly -p -h 127.0.0.1 -e "DELETE FROM mavenmovies.actor WHERE 1=0;"
# ERROR 1142 (42000): DELETE command denied to user 'mcp_readonly'@'...' for table 'actor'If the write succeeds, the grants were not applied correctly — re-run
scripts/setup-mysql-user.sql after fixing it.
Configure the server
The server reads configuration in two layers, both of which you should set up:
Layer 1 — .env (secrets and connection details)
Copy the example file and edit the secrets:
cp .env.example .envOpen .env and fill in at least:
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=mavenmovies
MYSQL_USER=mcp_readonly
MYSQL_PASSWORD=<the password you set in step 1>
MCP_ALLOWED_SCHEMAS=mavenmovies.env is gitignored, so this is the right place for the MySQL password.
The complete reference (every variable, defaults, validation rules, and safety overrides) lives in docs/CONFIGURATION.md.
Layer 2 — .mcp.json (MCP client wiring, committed)
A .mcp.json is checked into the repo root. It registers the server under
the name mysql-db and points at the built entry point dist/index.js
with a relative path. The env block lists non-secret configuration
(loopback host, schema, policy, row cap, log level) and intentionally
omits MYSQL_PASSWORD — the server picks that up from .env.
Most MCP clients (Claude Code, puku-cli, Cursor) read .mcp.json
automatically. For clients that read a different config file, see
Connect an MCP client below.
The full .env.example:
# ---- MySQL connection ----
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_DATABASE=example_db
MYSQL_USER=
MYSQL_PASSWORD=
# ---- Pool / timeouts (all bounded) ----
MYSQL_CONNECTION_LIMIT=5
MYSQL_CONNECT_TIMEOUT_MS=5000
MYSQL_QUERY_TIMEOUT_MS=3000
# ---- MCP policy ----
MCP_ALLOWED_SCHEMAS=mavenmovies
MCP_ALLOWED_TABLES=
MCP_MAX_ROWS=1000
MCP_AUDIT_LOG=
# ---- Logging ----
LOG_LEVEL=info
# ---- Safety overrides ----
ALLOW_REMOTE_MYSQL=0
ALLOW_WILDCARD_SCHEMAS=0Verify the server
The server speaks stdio. There is no HTTP listener. To verify it boots and
connects to MySQL without an MCP client, use the included health_check MCP
method via any MCP client, or simply start it and watch the logs.
Quick stdio smoke test
In one terminal, start the server in dev mode (uses tsx, no build needed):
npm run devYou should see one JSON log line on stderr like:
{"ts":"...","level":"info","msg":"boot","config":{"MYSQL_HOST":"127.0.0.1", ... "MYSQL_PASSWORD":"***", ...}}
{"ts":"...","level":"info","msg":"mcp.stdio.connected"}The server is now waiting for an MCP JSON-RPC message on stdin. You can poke it with a hand-rolled request in another terminal:
# macOS / Linux
(echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}'; sleep 1; echo '{"jsonrpc":"2.0","method":"notifications/initialized"}'; echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"health_check","arguments":{}}}'; sleep 1) | node dist/index.jsYou should see a JSON-RPC response with result.content[0].text containing
{"ok":true,"latencyMs":<number>}. Press Ctrl+C to shut down cleanly.
A faster check is to wire it into one of the MCP clients below and call
health_check from there.
Connect an MCP client
All clients below invoke the server as a stdio subprocess. They differ only in where they store their config file and which env-var names they use.
Path note (Windows): the examples below use the Windows path
D:/projects/db-mcp-server/dist/index.js. On macOS/Linux substitute your own path (e.g./Users/you/code/db-mcp-server/dist/index.js). The forward slashes work in JSON on every platform; do not escape them.
Secrets: never commit real
MYSQL_PASSWORD/DB_PASSWORDvalues to the JSON config files below. Either use a placeholder and load the real value from your shell environment, or use a.envfile consumed by the server. The server readsprocess.env, then loads.envviadotenvwithoverride: false(the default), so any value already present inprocess.envwins — this is why shipped client configs can omitMYSQL_PASSWORDand still authenticate against the password in.env.
Claude Code
Claude Code reads MCP config from ~/.claude.json (user-wide) or
.mcp.json in the project directory.
Project-local (recommended for this repo) — a .mcp.json is already
shipped at the repo root and registers the server under the name
mysql-db with a relative dist/index.js path, so no per-clone wiring is
needed. Just npm run build, restart Claude Code, and the server will be
loaded.
If you want to customize it (different schema, different user, etc.), edit
.mcp.json directly. Keep MYSQL_PASSWORD unset there and let .env
provide it — see the secrets callout above.
The shipped .mcp.json looks like this:
{
"mcpServers": {
"mysql-db": {
"type": "stdio",
"command": "node",
"args": ["dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MCP_ALLOWED_SCHEMAS": "mavenmovies",
"MCP_MAX_ROWS": "1000",
"LOG_LEVEL": "info",
"ALLOW_REMOTE_MYSQL": "0",
"ALLOW_WILDCARD_SCHEMAS": "0"
}
}
}
}Note:
MYSQL_PASSWORDis intentionally absent from the committed.mcp.json. The server picks it up from.envat boot. If you setMYSQL_PASSWORDin.mcp.jsonto anything (including an empty string), it will override.envand may break auth.
User-wide — add the same mcpServers block to ~/.claude.json.
Restart Claude Code. Confirm the server is loaded with
/mcp — you should see mysql-db listed with four tools
(list_tables, describe_table, get_rows, health_check).
Claude Desktop
Edit the Claude Desktop config file:
Windows:
%APPDATA%\Claude\claude_desktop_config.jsonmacOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"local-mysql": {
"command": "node",
"args": ["D:/projects/db-mcp-server/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MYSQL_PASSWORD": "<set-locally>",
"MCP_ALLOWED_SCHEMAS": "mavenmovies"
}
}
}
}Fully quit and reopen Claude Desktop. The hammer icon should show the four tools.
Cursor IDE
Create or edit .cursor/mcp.json in the project root:
{
"mcpServers": {
"local-mysql": {
"command": "node",
"args": ["D:/projects/db-mcp-server/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MYSQL_PASSWORD": "<set-locally>",
"MCP_ALLOWED_SCHEMAS": "mavenmovies"
}
}
}
}In Cursor: Settings → MCP → local-mysql → Refresh. The four tools should
appear under the tools list.
VS Code (Copilot Chat / Continue)
VS Code reads MCP config from .vscode/mcp.json in the workspace (Copilot
Chat and Continue both support this format).
{
"servers": {
"local-mysql": {
"type": "stdio",
"command": "node",
"args": ["D:/projects/db-mcp-server/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MYSQL_PASSWORD": "<set-locally>",
"MCP_ALLOWED_SCHEMAS": "mavenmovies"
}
}
}
}For Continue (.continue/config.json) the same server block goes under
mcpServers:
{
"mcpServers": [
{
"name": "local-mysql",
"command": "node",
"args": ["D:/projects/db-mcp-server/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MYSQL_PASSWORD": "<set-locally>",
"MCP_ALLOWED_SCHEMAS": "mavenmovies"
}
}
]
}Reload the VS Code window after editing.
puku CLI
puku-cli reads MCP config from .mcp.json at the project root (loaded
automatically) and from ~/.puku-cli/settings.json (global). The shipped
.mcp.json in this repo already registers the server as mysql-db — no
extra steps are required beyond npm run build and a session restart.
Auto-approval note: the first time a session launches the server, puku-cli
will prompt you to approve the MCP server it discovered in .mcp.json. If
you want to skip the prompt for this project, add the following to
~/.puku-cli/settings.json:
{
"enableAllProjectMcpServers": true
}Or, to approve only this one server explicitly:
{
"enabledMcpjsonServers": ["mysql-db"]
}For a user-wide install (one entry used across all your projects, with
an absolute path), add this to ~/.puku-cli/settings.json:
{
"mcpServers": {
"local-mysql": {
"type": "stdio",
"command": "node",
"args": ["D:/projects/db-mcp-server/dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MCP_ALLOWED_SCHEMAS": "mavenmovies"
}
}
}
}Verify with /mcp inside puku-cli; you should see mysql-db (project
config) and/or local-mysql (user config) and four tools
(list_tables, describe_table, get_rows, health_check).
Project-root-wide MCP configuration (.mcp.json)
A project-root-wide MCP configuration is the recommended way to wire
this server into any client. The repo ships a .mcp.json at the project
root that registers the server under the name mysql-db and points at the
built entrypoint dist/index.js with a relative path, so the same
config works for every contributor regardless of where they cloned the
repo.
{
"mcpServers": {
"mysql-db": {
"type": "stdio",
"command": "node",
"args": ["dist/index.js"],
"env": {
"MYSQL_HOST": "127.0.0.1",
"MYSQL_PORT": "3306",
"MYSQL_DATABASE": "mavenmovies",
"MYSQL_USER": "mcp_readonly",
"MYSQL_CONNECTION_LIMIT": "5",
"MYSQL_CONNECT_TIMEOUT_MS": "5000",
"MYSQL_QUERY_TIMEOUT_MS": "3000",
"MCP_ALLOWED_SCHEMAS": "mavenmovies",
"MCP_ALLOWED_TABLES": "",
"MCP_MAX_ROWS": "1000",
"MCP_AUDIT_LOG": "",
"LOG_LEVEL": "info",
"ALLOW_REMOTE_MYSQL": "0",
"ALLOW_WILDCARD_SCHEMAS": "0"
}
}
}
}Why project-root-wide?
One file, every client. Claude Code, puku-cli, and Cursor all auto-read
.mcp.jsonfrom the working directory. Drop the file in the repo root and every contributor gets the same server wiring with zero per-machine setup.Relative paths are portable.
args: ["dist/index.js"]resolves against the project root, so the same JSON works on Windows, macOS, and Linux without edits. Use absolute paths (e.g.D:/projects/db-mcp-server/dist/index.js) only when you need to launch the server from outside the project root.Secrets stay out of version control. The shipped
.mcp.jsonintentionally omitsMYSQL_PASSWORD. The server reads.envat boot viadotenvwithoverride: false, so any value already present inprocess.envwins — your.envprovides the password and the committed config never has to.
Customizing for your environment
Edit the .mcp.json block in place when you need to:
Target a different schema — change
MYSQL_DATABASEandMCP_ALLOWED_SCHEMAStogether (both must be set; the allowlist is enforced server-side).Use a different read-only user — change
MYSQL_USERand the matchingMYSQL_PASSWORDin.env.Raise/lower the row cap — change
MCP_MAX_ROWS.Allow a non-loopback MySQL — change
ALLOW_REMOTE_MYSQLto"1". The server still requires a non-emptyMYSQL_PASSWORD.Allow wildcards in
MCP_ALLOWED_SCHEMAS— changeALLOW_WILDCARD_SCHEMASto"1". Off by default for safety.
Auto-loading per client
Client | Reads | Where to place it |
Claude Code | Yes (project-local) | repo root ( |
puku-cli | Yes (project-local) | repo root ( |
Cursor IDE | Yes (project-local) | repo root ( |
Claude Desktop | No — uses | see Claude Desktop |
VS Code | No — uses | see VS Code |
Continue | No — uses | see VS Code |
After editing .mcp.json, restart your client. Confirm the server is
loaded with /mcp — you should see mysql-db listed with four tools
(list_tables, describe_table, get_rows, health_check).
Other stdio MCP clients
Any MCP client that supports stdio transport can launch the server with:
command: node
args: ["<absolute-path>/db-mcp-server/dist/index.js"]
env: { MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE, MYSQL_USER,
MYSQL_PASSWORD, MCP_ALLOWED_SCHEMAS, ... }Use the env-var names listed in docs/CONFIGURATION.md.
The server refuses to start against non-loopback hosts unless
ALLOW_REMOTE_MYSQL=1, and refuses wildcards in MCP_ALLOWED_SCHEMAS
unless ALLOW_WILDCARD_SCHEMAS=1.
Troubleshooting
Symptom | Cause | Fix |
|
| Confirm |
| You set | Use |
|
| Use an explicit comma-separated list of schemas, or set |
| Wrong user/password or user not bound to the host you're connecting from | Re-run |
| MySQL not running, or wrong port | Start MySQL; verify with |
| Slow query, lock wait, or | Raise |
|
| Edit |
|
| Pass a |
MCP client lists zero tools from | Stdio path wrong, or server crashed at startup | Run |
|
|
|
MCP client shows | Some clients only watch | Restart the client, or open |
|
| Remove the |
Tests, lint, build
npm run typecheck # strict TypeScript
npm run lint # ESLint
npm run format:check # Prettier
npm test # unit + security + integration suites
npm run build # produces dist/
npm start # runs dist/index.js with source maps
npm run dev # tsx src/index.ts (no build step)Integration tests run against the MySQL you configured in .env
(MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD). They assume
the schema and grants from scripts/setup-mysql-user.sql are in place —
the read-only user must be able to SELECT from every schema listed in
MCP_ALLOWED_SCHEMAS.
Run a single suite:
npm run test:unit
npm run test:integration
npm run test:securityPrivacy and logging
Tool descriptions and error responses never include credentials, SQL strings, or result sets beyond what each tool is designed to return. See docs/TOOLS.md.
The structured logger redacts well-known secret keys (
password,passwd,token,secret,api[_-]?key,authorization,credential,access[_-]?token) and any string containingpassword=…. See docs/LOGGING.md.Set
MCP_AUDIT_LOG=/path/to/audit.logto write JSONL audit events per tool call. Without it, audit events go to stderr.The server is loopback-only by default. To target a remote MySQL, you must set
ALLOW_REMOTE_MYSQL=1and the server still requires a non-emptyMYSQL_PASSWORD.
License
MIT — see LICENSE.
Available Tools
4 toolsdescribe_tableA
Describe a single allowlisted MySQL table: columns, types, nullability, and key metadata. Sensitive columns may be redacted. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden. It discloses that the operation is read-only, that sensitive columns may be redacted, and that only allowlisted tables are accessible. These are meaningful behavioral traits that go beyond a simple 'describe' statement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences, front-loaded with the core purpose followed by two concise caveats. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description clearly lists the returned metadata (columns, types, nullability, key metadata) and covers key behavioral caveats (redaction, read-only, allowlisting). It omits details like error behavior or permission enforcement, but for a simple describe tool, it is fairly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The two parameters (schema, table) have no descriptions in the schema, and the description's only mention is 'single allowlisted MySQL table', which does not clarify what the schema parameter represents or how the two parameters relate. With 0% schema description coverage, the description should compensate by explaining each parameter, but it does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (describe), the target (a single allowlisted MySQL table), and the specific metadata returned (columns, types, nullability, and key metadata). This distinguishes it from sibling tools like list_tables (listing tables) and get_rows (retrieving rows).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool (to get schema details for one table) via the word 'single', but does not explicitly mention alternatives or exclusions. No 'use this instead of X' guidance is provided, though the purpose statement makes the context clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rowsA
Read rows from a single allowlisted MySQL table. Requires an explicit column list, supports equality/IN/range filters and pagination. Read-only. Sensitive columns are masked. Cap is MCP_MAX_ROWS.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| table | Yes | ||
| offset | No | ||
| schema | Yes | ||
| columns | Yes | ||
| filters | No | ||
| columnAllowlist | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description carries the full burden and does so well. It discloses read-only nature, sensitive column masking, a row cap (MCP_MAX_ROWS), and supported filter/pagination behaviors, which are critical behavioral traits not apparent from the schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences, front-loaded with the core action. Each sentence provides distinct value (purpose, requirements/capabilities, safety/limits) with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 7 parameters, no output schema, and no annotations, the description covers essential usage constraints and safety behaviors. It does not explain the return payload structure or fully clarify the 'columnAllowlist' parameter, but it gives an agent enough context to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description must compensate. It adds meaning to columns (explicit list required), filters (equality/IN/range), and pagination (limit/offset). However, the 'columnAllowlist' parameter is not mentioned, and 'schema' is only implied via 'MySQL table', leaving gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description uses a specific verb ('Read rows') and resource ('single allowlisted MySQL table'), clearly distinguishing from sibling tools like describe_table and list_tables. The scope and action are unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description provides clear context for when to use (reading row data) and specifies prerequisites ('Requires an explicit column list') and capabilities (filter types, pagination). However, it does not explicitly name alternatives or exclusions relative to sibling tools, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_checkA
Report server/database reachability. Returns ok=true and a latencyMs value when the configured MySQL is reachable. Does NOT expose host, user, password, or version.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of behavioral disclosure. It discloses the success response (ok=true, latencyMs) and explicitly states what is NOT exposed (host, user, password, version). It does not describe failure behavior, but for a health check with no side effects, this is reasonable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose, and every word earns its place. It includes a useful disclaimer about sensitive data without any fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless health check, the description is almost complete. It states the success condition and output, and the limitation about not exposing credentials. The only gap is the unreachable case, but the tool is simple enough that this does not significantly impair understanding.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the description needs no parameter details. The baseline of 4 applies, and the description adds context about the tool's scope without needing to explain parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Report server/database reachability.' It specifies the return values (ok=true, latencyMs) and explicitly distinguishes itself from the sibling table tools by focusing on connectivity rather than data operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool (to check server/database reachability) and clearly, if implicitly, differentiates from the sibling tools. It lacks explicit exclusions or alternative tool references, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesA
List tables in allowlisted MySQL schemas. Returns table metadata (schema, name, type). Always read-only. No raw SQL.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| schemas | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden. It discloses read-only guarantee, prohibition on raw SQL, and return format. This is appropriate transparency for a list operation, though it doesn't cover edge cases like limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, all informative: purpose, return metadata, and safety constraints. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, return type, and safety, but lacks parameter usage details, making it slightly incomplete for invoking with optional filters. However, given the simple nature, it's mostly adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description makes no mention of the 'limit' and 'schemas' parameters, and schema description coverage is 0%. The tool name and description imply schemas are pre-allowlisted, but the schemas parameter's filtering role is not explained. This fails to compensate for the low schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists tables in allowlisted MySQL schemas and returns metadata (schema, name, type). This distinguishes it from siblings like describe_table (single table details) and get_rows (row data).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear context: always read-only, no raw SQL, operates only on allowlisted schemas. This guides safe usage and sets expectations, though it doesn't explicitly name alternative tools or when-not-to-use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
describe_table - First observed
get_rows - First observed
health_check - First observed
list_tables
TDQS
Each tool has a clearly distinct purpose: describe_table for schema metadata, list_tables for table enumeration, get_rows for data retrieval, and health_check for connectivity status. There is no overlap or ambiguity between them.
All tool names follow a consistent verb_noun pattern: describe_table, list_tables, get_rows, health_check. The naming is uniform and predictable.
The server has 4 tools, which is well-scoped for a read-only MySQL access layer. Each tool provides a necessary capability without redundancy or bloat.
For its stated purpose of safe, read-only access to allowlisted tables, the toolset covers the full lifecycle: listing tables, describing schema, reading rows, and verifying connectivity. No obvious gaps or dead ends exist.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
- mcpOAuthcom.airtable
Official Airtable MCP server — database and operations layer for agents.
The Grafbase MCP server sits in front of a GraphQL API and exposes an MCP protocol-compliant interface that allows AI agents and LLMs to explore and query GraphQL APIs using natural language. It provides tools to search schemas, introspect types and fields, and execute GraphQL queries while minimizing context bloat by returning only relevant schema subsets, with built-in support for authentication, authorization, and configurable access control.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA secure MySQL Model Context Protocol server that enables AI agents to interact with MySQL databases through standardized operations. Features comprehensive security with SQL injection prevention, connection pooling, and configurable tool access for database operations.1-
- AlicenseAqualityCmaintenanceA lightweight, multi-environment MySQL MCP server that provides secure, policy-gated database access through simplified query and execution tools. It enables AI agents to interact with multiple database environments safely using environment-based routing and strict security constraints.219ISC
- AlicenseNot gradedqualityDmaintenanceA MySQL MCP server for secure database interaction, enabling schema inspection, query execution, and RBAC via AI coding assistants.1,0815MIT
- AlicenseNot gradedqualityDmaintenanceA secure and efficient MCP server for MySQL database operations, enabling LLMs to execute SQL queries with read-only access by default and optional write permissions.3MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kamrul-dev/local-mysql-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server