Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,44 @@ Postgres MCP Pro supports multiple *access modes* to give you control over the o
To use restricted mode, replace `--access-mode=unrestricted` with `--access-mode=restricted` in the configuration examples above.


##### Transport Security Configuration

Postgres MCP Pro includes DNS rebinding protection to secure the server against certain types of attacks.
By default, the server allows connections from common local and Docker hostnames.
You can customize this behavior using environment variables:

- **`MCP_ENABLE_DNS_REBINDING_PROTECTION`**: Controls whether DNS rebinding protection is enabled. Set to `false` to disable. Default: `true`.
- **`MCP_ALLOWED_HOSTS`**: Comma-separated list of allowed host patterns. Default: `localhost:*,127.0.0.1:*,0.0.0.0:*,postgres-mcp-server:*,host.docker.internal:*`.
- **`MCP_ALLOWED_ORIGINS`**: Comma-separated list of allowed origins. Default: empty (allows any origin).

For example, to restrict allowed hosts in your configuration:

```json
{
"mcpServers": {
"postgres": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"DATABASE_URI",
"-e",
"MCP_ALLOWED_HOSTS",
"crystaldba/postgres-mcp",
"--access-mode=unrestricted"
],
"env": {
"DATABASE_URI": "postgresql://username:password@localhost:5432/dbname",
"MCP_ALLOWED_HOSTS": "localhost:*,myapp.example.com:*"
}
}
}
}
```


#### Other MCP Clients

Many MCP clients have similar configuration files to Claude Desktop, and you can adapt the examples above to work with the client of your choice.
Expand Down
26 changes: 24 additions & 2 deletions src/postgres_mcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import mcp.types as types
from mcp.server.fastmcp import FastMCP
from mcp.server.transport_security import TransportSecuritySettings
from mcp.types import ToolAnnotations
from pydantic import Field
from pydantic import validate_call
Expand All @@ -34,8 +35,29 @@
from .sql import obfuscate_password
from .top_queries import TopQueriesCalc

# Initialize FastMCP with default settings
mcp = FastMCP("postgres-mcp")
# Initialize FastMCP with transport security settings
# Configure to allow requests from localhost, 127.0.0.1, and Docker container names
# These can be customized via environment variables:
# - MCP_ENABLE_DNS_REBINDING_PROTECTION: Set to "false" to disable (default: "true")
# - MCP_ALLOWED_HOSTS: Comma-separated list of allowed hosts (default: localhost:*,127.0.0.1:*,0.0.0.0:*,postgres-mcp-server:*,host.docker.internal:*)
# - MCP_ALLOWED_ORIGINS: Comma-separated list of allowed origins (default: empty, allows any origin)

dns_rebinding_protection = os.environ.get("MCP_ENABLE_DNS_REBINDING_PROTECTION", "true").lower() == "true"

default_allowed_hosts = "localhost:*,127.0.0.1:*,0.0.0.0:*,postgres-mcp-server:*,host.docker.internal:*"
allowed_hosts_str = os.environ.get("MCP_ALLOWED_HOSTS", default_allowed_hosts)
allowed_hosts = [host.strip() for host in allowed_hosts_str.split(",") if host.strip()]

allowed_origins_str = os.environ.get("MCP_ALLOWED_ORIGINS", "")
allowed_origins = [origin.strip() for origin in allowed_origins_str.split(",") if origin.strip()]

transport_security = TransportSecuritySettings(
enable_dns_rebinding_protection=dns_rebinding_protection,
allowed_hosts=allowed_hosts,
allowed_origins=allowed_origins,
)

mcp = FastMCP("postgres-mcp", transport_security=transport_security)

# Constants
PG_STAT_STATEMENTS = "pg_stat_statements"
Expand Down