TL;DR: Your shell knows DATABASE_URL but the MCP server does not, because MCP clients launch servers with a clean environment. Put DATABASE_URL directly in the `env` block of your client config (`.mcp.json`, `claude_desktop_config.json`), not just in your shell profile. Restart the client and the error is gone.

```text
DATABASE_URL is not set
```

## Fix it

1. Open your MCP client config. For Claude Desktop: `claude_desktop_config.json`. For Claude Code / Cursor: `.mcp.json` in the project root.

2. Add the variable to the server's `env` block:

```json
{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres", "YOUR_CONNECTION_URL"],
      "env": {
        "DATABASE_URL": "postgresql://db-host:5432/mydb"
      }
    }
  }
}
```

   Note: several Postgres MCP servers read the URL from the first CLI arg instead of DATABASE_URL. If yours does, make sure the arg and the env var agree.

3. Fully quit and restart the client (not just the chat window). MCP servers are spawned at client launch.

   Expected: the server starts and tools like `query` appear. No startup error in the client logs.

## When to use this

- `echo $DATABASE_URL` works in your terminal but the MCP server still says it is not set.
- You are on Windows, where env vars set in bash or PowerShell profiles are not inherited by servers launched via cmd.

## When NOT to use this

- The error is `password authentication failed` or mentions SSL. The variable is being read fine; the credentials or TLS are the problem.
- The server reads the URL from a CLI argument rather than the environment. Then the arg is what matters.

## Compatibility

- MCP Postgres servers that read DATABASE_URL at startup: yawlabs/postgres-mcp, Tabulus, pgedge-postgres-mcp.
- Claude Desktop, Claude Code, Cursor, Windsurf.

## Why it happens

MCP servers are child processes of the client, and many clients (especially GUI apps on Windows and macOS) do not inherit your interactive shell environment. Variables exported in `.bashrc` or a terminal session simply do not exist in the server's process. The client config `env` block is the only reliable channel.

## Edge cases

- JSON escaping: passwords with quotes or backslashes in the config file need JSON escaping. Prefer percent-encoding special chars.
- If you manage config with a dotfiles repo, remember the client reads its own config path, not your repo copy.
- Some servers validate DATABASE_URL at startup but only connect on the first tool call. A startup success does not prove the credentials work. Run a real query to be sure.