Last active
February 24, 2026 18:07
-
-
Save aseba/9dca16dfc23e8a870157a25b57e01efb to your computer and use it in GitHub Desktop.
Install Postgres MCP for Cursor (read-only, with cloud-sql-proxy)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Install Postgres MCP for Cursor | |
| # Usage: bash <(curl -fsSL https://gist.githubusercontent.com/aseba/9dca16dfc23e8a870157a25b57e01efb/raw/install-postgres-mcp.sh) | |
| # | |
| # Installs .cursor/mcp.json and .cursor/start-postgres-mcp.sh into the current directory. | |
| # Installs missing dependencies: brew, gcloud, cloud-sql-proxy, uv/uvx | |
| set -euo pipefail | |
| echo "π§ Installing Postgres MCP for Cursor..." | |
| # --- Create .cursor directory --- | |
| mkdir -p .cursor | |
| # --- Install missing dependencies (runs in terminal, interactive OK) --- | |
| # Homebrew | |
| if ! command -v brew &>/dev/null; then | |
| echo "π¦ Installing Homebrew..." | |
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null || eval "$(/usr/local/bin/brew shellenv)" 2>/dev/null | |
| fi | |
| # gcloud | |
| if ! command -v gcloud &>/dev/null; then | |
| echo "π¦ Installing gcloud CLI..." | |
| brew install --cask google-cloud-sdk | |
| fi | |
| # cloud-sql-proxy | |
| if ! command -v cloud-sql-proxy &>/dev/null; then | |
| echo "π¦ Installing cloud-sql-proxy..." | |
| brew install cloud-sql-proxy | |
| fi | |
| # uv / uvx | |
| if ! command -v uvx &>/dev/null; then | |
| export PATH="$HOME/.local/bin:$PATH" | |
| fi | |
| if ! command -v uvx &>/dev/null; then | |
| echo "π¦ Installing uv..." | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| export PATH="$HOME/.local/bin:$PATH" | |
| fi | |
| # --- Write start-postgres-mcp.sh (check-only, no interactive installs) --- | |
| cat > .cursor/start-postgres-mcp.sh << 'WRAPPER' | |
| #!/bin/bash | |
| # Wrapper script to ensure cloud-sql-proxy is running before starting postgres-mcp. | |
| # Used by Cursor MCP integration (.cursor/mcp.json). | |
| # | |
| # Expects DATABASE_URI env var to be set by Cursor config. | |
| set -euo pipefail | |
| INSTANCE="remotely-platform:us-central1:platform-master-replica" | |
| PROXY_PORT=5432 | |
| # --- Load .env for database credentials --- | |
| if [ -n "${DOTENV_PATH:-}" ] && [ -f "$DOTENV_PATH" ]; then | |
| set -a | |
| source "$DOTENV_PATH" | |
| set +a | |
| fi | |
| export DATABASE_URI="postgresql://ci:${PLATFORM_DB_PASSWORD:-}@127.0.0.1:5432/platform" | |
| # --- Ensure PATH includes common install locations (Cursor launches with minimal env) --- | |
| eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null || eval "$(/usr/local/bin/brew shellenv)" 2>/dev/null || true | |
| export PATH="$HOME/.local/bin:$PATH" | |
| # Find gcloud via Spotlight (instant on macOS) | |
| if ! command -v gcloud &>/dev/null; then | |
| GCLOUD_INC=$(mdfind -name "path.bash.inc" 2>/dev/null | grep google-cloud-sdk | head -1) | |
| if [ -n "$GCLOUD_INC" ]; then | |
| source "$GCLOUD_INC" | |
| fi | |
| fi | |
| # --- Check dependencies (no interactive installs β Cursor runs this non-interactively) --- | |
| MISSING=() | |
| if ! command -v brew &>/dev/null; then | |
| MISSING+=("brew: /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"") | |
| fi | |
| if ! command -v gcloud &>/dev/null; then | |
| MISSING+=("gcloud: brew install --cask google-cloud-sdk && gcloud auth login") | |
| fi | |
| if ! command -v cloud-sql-proxy &>/dev/null; then | |
| MISSING+=("cloud-sql-proxy: brew install cloud-sql-proxy") | |
| fi | |
| if ! command -v uvx &>/dev/null; then | |
| MISSING+=("uvx: curl -LsSf https://astral.sh/uv/install.sh | sh") | |
| fi | |
| if [ ${#MISSING[@]} -gt 0 ]; then | |
| echo "ERROR: Missing dependencies. Run these in your terminal:" >&2 | |
| for m in "${MISSING[@]}"; do | |
| echo " $m" >&2 | |
| done | |
| echo "Then restart Cursor." >&2 | |
| exit 1 | |
| fi | |
| # Start cloud-sql-proxy with gcloud auth if not already running on our port | |
| if ! lsof -i ":$PROXY_PORT" -sTCP:LISTEN &>/dev/null; then | |
| cloud-sql-proxy "$INSTANCE" --port "$PROXY_PORT" -g >/dev/null 2>&1 & | |
| PROXY_PID=$! | |
| # Wait up to 10 seconds for proxy to be ready | |
| for _ in $(seq 1 20); do | |
| if lsof -i ":$PROXY_PORT" -sTCP:LISTEN &>/dev/null; then | |
| break | |
| fi | |
| sleep 0.5 | |
| done | |
| if ! lsof -i ":$PROXY_PORT" -sTCP:LISTEN &>/dev/null; then | |
| echo "ERROR: cloud-sql-proxy failed to start on port $PROXY_PORT" >&2 | |
| echo "Try: gcloud auth login" >&2 | |
| kill "$PROXY_PID" 2>/dev/null | |
| exit 1 | |
| fi | |
| fi | |
| # Start postgres-mcp in restricted (read-only) mode via stdio | |
| exec uvx --python 3.12 postgres-mcp --access-mode=restricted | |
| WRAPPER | |
| chmod +x .cursor/start-postgres-mcp.sh | |
| # --- Write mcp.json --- | |
| cat > .cursor/mcp.json << 'MCPJSON' | |
| { | |
| "mcpServers": { | |
| "postgres": { | |
| "command": "bash", | |
| "args": [ | |
| "${workspaceFolder}/.cursor/start-postgres-mcp.sh" | |
| ], | |
| "env": { | |
| "DOTENV_PATH": "${workspaceFolder}/.cursor/.env" | |
| } | |
| } | |
| } | |
| } | |
| MCPJSON | |
| # --- Prompt for DB password --- | |
| if [ -f .cursor/.env ] && grep -q '[^=]$' .cursor/.env 2>/dev/null; then | |
| echo "β .cursor/.env already has a password set" | |
| else | |
| echo "" | |
| read -rsp "π Enter PLATFORM_DB_PASSWORD (get from platform/database-env or a colleague): " DB_PASS | |
| echo "" | |
| if [ -n "$DB_PASS" ]; then | |
| echo "PLATFORM_DB_PASSWORD=$DB_PASS" > .cursor/.env | |
| else | |
| echo "PLATFORM_DB_PASSWORD=" > .cursor/.env | |
| echo "β οΈ No password entered. Set it later: echo 'PLATFORM_DB_PASSWORD=<PASSWORD>' > .cursor/.env" | |
| fi | |
| fi | |
| echo "" | |
| echo "β Created .cursor/mcp.json" | |
| echo "β Created .cursor/start-postgres-mcp.sh" | |
| echo "β Created .cursor/.env (add your password here)" | |
| echo "" | |
| # --- Check manual steps --- | |
| NEEDS_ACTION=false | |
| if ! gcloud auth list --filter=status:ACTIVE --format="value(account)" 2>/dev/null | grep -q .; then | |
| echo "β οΈ Run: gcloud auth login" | |
| NEEDS_ACTION=true | |
| fi | |
| if ! grep -q '[^=]$' .cursor/.env 2>/dev/null; then | |
| NEEDS_ACTION=true | |
| fi | |
| if [ "$NEEDS_ACTION" = true ]; then | |
| echo "" | |
| echo "After completing the steps above, restart Cursor (Cmd+Q) to activate the MCP." | |
| else | |
| echo "" | |
| echo "π All set! Restart Cursor (Cmd+Q) to activate the Postgres MCP." | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment