Connect an MCP tool to Postgres, MySQL or Redis
Give an AI assistant safe access to your database: an MCP tool with an approved address, the password in the vault, and fixed queries. Python, TypeScript and Go.

In this post
- Declare the address and the password
- Connect from Python, TypeScript or Go
- Keep TLS on
- Safe defaults for a database user
A function tool can open TCP connections, so it can talk to Postgres, MySQL, Redis, MongoDB and other services that don't speak HTTPS. Every connection goes through Glxymesh's egress gateway. It allows only the addresses you approved, refuses private addresses, and logs each connection with its bytes and duration.
1. Declare the address and the password#
In the tool's tool.yml, list the address under network.connect and the connection string as a passed-in secret:
spec: glxymesh/tool@v1
name: list-orders
kind: function
description: Lists a customer's orders from the shop's database, newest first.
read_only: true
inputs:
customer: {type: string, description: "The customer's email, e.g. ada@example.com"}
network:
connect: ["db.example.com:5432"]
secrets:
PG_URL:
hosts: [db.example.com]
mode: pass-in| Line | What it means |
|---|---|
network.connect | The host:port pairs the code may connect to, up to 10. A person approves each new one. |
mode: pass-in | The code can read this secret's value. A person approves it before it goes live. |
PG_URL | The connection string, stored on the console's Secrets page |
Database on your own server? Keep its address in the vault too: write "{PG_HOST}:5432" under network.connect and store the server's public name or IP as PG_HOST.
2. Connect from code#
Let the driver use the platform's connection instead of opening its own. In Python, ctx.forward gives the driver a local address that carries the connection out:
import psycopg
from glxymesh import Ctx
from .tool_gen import Input
def run(ctx: Ctx, input: Input) -> list[dict]:
host, port = ctx.forward("db.example.com:5432")
with psycopg.connect(ctx.secret_value("PG_URL"), host=host, port=port) as conn:
rows = conn.execute(
"SELECT id, total FROM orders WHERE customer = %s LIMIT 20", (input["customer"],)
).fetchall()
return [{"id": r[0], "total": float(r[1])} for r in rows]| Language | Use |
|---|---|
| Python | ctx.forward(address) for psycopg and asyncpg, or ctx.connect(address) for a socket |
| TypeScript | ctx.forward(address) for pg, or ctx.connect(address) for a socket |
| Go | ctx.DialContext as the driver's dial hook, such as pgx's DialFunc |
Open one connection per call and close it. Connections end with the call. The database guide has the full TypeScript and Go versions.
3. Keep TLS on#
In Go, the driver still knows the real server name, so sslmode=verify-full works. With ctx.forward the driver connects to 127.0.0.1, so tell it the server's name where it can (pg's ssl.servername), or use sslmode=require.
4. Test it on your machine#
gxmesh call connects the same way, with keys from .env.local. For a database on your own machine or network, add --allow-private:
$ gxmesh call list-orders '{"customer":"ada@example.com"}' --allow-privateSafe defaults#
- Give the tool its own database user, with only the rights it needs. Read-only if it only reads.
- Use fixed, parameterized queries. Don't let the caller write SQL.
- Allow Glxymesh's addresses in your firewall and require TLS.
- Mark read-only tools with
read_only: true, so clients know they're safe to call.
Not possible: UDP, interactive SSH sessions and listening for incoming connections.
Explore MCP guides by task: creation, hosting, connections and security.


