VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
vsql_mcp extension removes that layer: it runs a Model Context Protocol server inside the VillageSQL process itself, so any MCP client can discover the schema and run queries directly.
What vsql_mcp Does
vsql_mcp is a Rust extension that serves MCP over the Streamable HTTP transport (spec revision 2025-06-18) from a background worker inside the server process. It exposes six tools: list_schemas, list_tables, describe_table, query, explain, and write. The write tool only appears once you enable it, and it is disabled by default.
vsql_mcp is a preview extension. It uses the VEF preview capabilities thread_worker, sys_var, status_var, and sql_query, so the server must be started with preview extensions allowed:
Creating Sample Data
This guide uses a dedicated database and a smallposts table so the agent has something real to query.
Installing the Extension
Creating a Least-Privilege Account
vsql_mcp runs most tool calls, including query, write, explain, and the table-DDL resource, over a loopback connection to the server using an account you configure. Only list_schemas, list_tables, and describe_table run in-process without that account. Create a dedicated account scoped to the one database this guide uses, with SELECT only:
vsql_mcp’s own guardrails, covered below, are enforced on top of these grants, not instead of them.
Configuring and Enabling the Server
Allvsql_mcp settings are SET GLOBAL vsql_mcp.<name> variables. Point db_url at the account created above, scope the server to one schema, require a bearer token, and turn it on:
http_port shows 3100, the default. The server listens on http://127.0.0.1:3100/mcp and binds to 127.0.0.1 only. It never accepts remote connections directly; putting it behind a reverse proxy is your responsibility if you need that.
Verifying the Server Speaks MCP
Before connecting a real client, verify the HTTP endpoint directly with the MCP handshake. A request with no bearer token is rejected:initialize succeeds and returns an Mcp-Session-Id header:
notifications/initialized, then list the available tools using the session ID from the initialize response:
write is missing because allow_write is still OFF, so an agent connecting right now never plans around a tool it cannot use.
Calling Tools Over MCP
list_tables shows the one table in the exposed schema:
query runs a SELECT and returns the actual rows:
posts table, returned through the MCP protocol rather than a direct SQL connection.
query only accepts a single read-only statement. Anything else is refused before it reaches the database:
Connecting a Real Client
The steps above prove the server responds correctly to a raw HTTP client. To prove an agent can actually use it, register the server with Claude Code and let it manage the session:local config scopes the server to this one project. Pass --scope user instead to make it available in every project. claude mcp list shows the connection status:
initialize handshake, negotiated a session, and confirmed the server answers over MCP, the same server this guide configured with SET GLOBAL statements and tested by hand above. From here, asking the agent a question about the mcp_guide database routes through list_tables, describe_table, and query, exactly as demonstrated with curl.
vsql_mcp has no stdio transport. The server runs inside the database process, so there is no child process for a client to spawn. A client that only speaks stdio, or a remote client that proxies through a vendor cloud and cannot reach 127.0.0.1, needs a stdio-to-HTTP bridge or a tunnel in front of the endpoint.
The write Tool
allow_write is OFF by default, and calling write while it is off fails immediately, without touching the database:
allow_write ON makes the tool appear in tools/list, but the account’s own grants still apply. With mcp_user still holding only SELECT, the same call now fails at the database layer instead:
UPDATE on the database lets the same call through, and it genuinely changes the row:
allow_write and the account’s grants are two separate gates, and a real write requires both open. There is no row ceiling on a write the way max_rows caps a read: an unqualified DELETE empties the table regardless of any other setting. An agent with write access to a production database carries the same risk as any other autonomous process with broad write access: it can act on a plan that made sense to it and not to you, faster than a human review step can catch it. Give db_url an account whose grants match exactly the blast radius you are willing to accept, and treat allow_write as a decision made per database, not a default to leave on because a demo needed it.
This guide turns allow_write back off and revokes UPDATE before continuing, which is also the safer resting state for a database an agent has standing access to.
Narrowing What an Agent Can Reach
Two settings narrow an agent’s reach further than the account’s grants alone, useful when one account serves more thanvsql_mcp.
max_rows caps how many rows a single query call returns and marks the result truncated:
allowed_tables restricts which tables a statement may touch, checked by planning the statement with EXPLAIN FORMAT=JSON. Add a second table to see it enforced:
secrets present in the same schema and allowed_tables set to posts only, posts still works and secrets is refused:
list_tables also stops naming the excluded table, so an agent working from list_tables alone never learns secrets exists:
db_url account may call. Treat allowed_tables and max_rows as guardrails layered on top of the account’s grants, not a substitute for scoping the grants themselves.
Frequently Asked Questions
Does an agent need direct access to the database credentials?
No. The agent authenticates tovsql_mcp with the bearer token set in vsql_mcp.bearer_token. The database account named by vsql_mcp.db_url is only used internally by the extension to run tool queries; the agent never sees that account’s password.
Can I expose more than one schema?
Yes, but leavingvsql_mcp.schema empty exposes more than you may expect. list_schemas then returns every schema on the server, mysql, sys and performance_schema included, and it does not filter by what the db_url account can reach: the listing runs in-process against information_schema.SCHEMATA rather than over the account’s connection. Scoping vsql_mcp.schema to one schema is what limits discovery. The account’s grants still govern what query and write can actually read, so a listed schema is not necessarily a readable one.
Does vsql_mcp support TLS?
Yes. Setting bothvsql_mcp.ssl_cert and vsql_mcp.ssl_key to PEM file paths serves HTTPS on vsql_mcp.ssl_port (default 3143). Leaving either one empty turns TLS off regardless of the port setting.
Why does changing the port not take effect immediately?
Port and TLS settings take effect the next time the server is enabled. Togglevsql_mcp.vsql_mcp_enabled OFF and then ON after changing them.
Troubleshooting
See also
- MySQL User Management —
CREATE USER,GRANT, and least-privilege account design - MySQL Security Hardening — broader server hardening beyond a single extension’s guardrails
- Connecting MySQL to AI APIs — the other direction: calling an AI API from inside MySQL with
vsql_ai

