Skip to content

Commit 040cf58

Browse files
authored
SSE support (#57)
1 parent b0a3f51 commit 040cf58

File tree

4 files changed

+93
-4
lines changed

4 files changed

+93
-4
lines changed

Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ RUN apt-get update && apt-get install -y \
5050
COPY docker-entrypoint.sh /app/
5151
RUN chmod +x /app/docker-entrypoint.sh
5252

53+
# Expose the SSE port
54+
EXPOSE 8000
55+
5356
# Run the postgres-mcp server
5457
# Users can pass a database URI or individual connection arguments:
5558
# docker run -it --rm postgres-mcp postgres://user:pass@host:port/dbname

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,30 @@ Many MCP clients have similar configuration files to Claude Desktop, and you can
249249
- If you are using Windsurf, you can navigate to from the `Command Palette` to `Open Windsurf Settings Page` to access the configuration file.
250250
- If you are using Goose run `goose configure`, then select `Add Extension`.
251251

252+
## SSE Transport
253+
254+
Postgres Pro supports the SSE transport, which allows you to connect to the server using a web browser.
255+
To use the SSE transport, you need to start the server with the `--transport sse` flag.
256+
257+
```bash
258+
docker run -p 8000:8000 -e DATABASE_URI=postgresql://username:password@localhost:5432/dbname crystaldba/postgres-mcp --transport sse
259+
```
260+
261+
Then update your MCP client configuration to call the the MCP server.
262+
For example, in Windsurf's `mcp_config.json` you can put:
263+
264+
```json
265+
{
266+
"mcpServers": {
267+
"postgres": {
268+
"type": "sse",
269+
"serverUrl": "http://localhost:8000/sse"
270+
}
271+
}
272+
}
273+
```
274+
275+
252276
## Postgres Extension Installation (Optional)
253277

254278
To enable index tuning and comprehensive performance analysis you need to load the `pg_statements` and `hypopg` extensions on your database.

docker-entrypoint.sh

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
replace_localhost() {
88
local input_str="$1"
99
local docker_host=""
10-
10+
1111
# Try to determine Docker host address
1212
if ping -c 1 -w 1 host.docker.internal >/dev/null 2>&1; then
1313
docker_host="host.docker.internal"
@@ -19,15 +19,15 @@ replace_localhost() {
1919
echo "WARNING: Cannot determine Docker host IP. Using original address." >&2
2020
return 1
2121
fi
22-
22+
2323
# Replace localhost with Docker host
2424
if [[ -n "$docker_host" ]]; then
2525
local new_str="${input_str/localhost/$docker_host}"
2626
echo " Remapping: $input_str --> $new_str" >&2
2727
echo "$new_str"
2828
return 0
2929
fi
30-
30+
3131
# No replacement made
3232
echo "$input_str"
3333
return 1
@@ -53,6 +53,41 @@ for arg in "$@"; do
5353
fi
5454
done
5555

56+
# Check and replace localhost in DATABASE_URI if it exists
57+
if [[ -n "$DATABASE_URI" && "$DATABASE_URI" == *"postgres"*"://"*"localhost"* ]]; then
58+
echo "Found localhost in DATABASE_URI: $DATABASE_URI" >&2
59+
new_uri=$(replace_localhost "$DATABASE_URI")
60+
if [[ $? -eq 0 ]]; then
61+
export DATABASE_URI="$new_uri"
62+
fi
63+
fi
64+
65+
# Check if SSE transport is specified and --sse-host is not already set
66+
has_sse=false
67+
has_sse_host=false
68+
69+
for arg in "${processed_args[@]}"; do
70+
if [[ "$arg" == "--transport" ]]; then
71+
# Check next argument for "sse"
72+
for next_arg in "${processed_args[@]}"; do
73+
if [[ "$next_arg" == "sse" ]]; then
74+
has_sse=true
75+
break
76+
fi
77+
done
78+
elif [[ "$arg" == "--transport=sse" ]]; then
79+
has_sse=true
80+
elif [[ "$arg" == "--sse-host"* ]]; then
81+
has_sse_host=true
82+
fi
83+
done
84+
85+
# Add --sse-host if needed
86+
if [[ "$has_sse" == true ]] && [[ "$has_sse_host" == false ]]; then
87+
echo "SSE transport detected, adding --sse-host=0.0.0.0" >&2
88+
processed_args+=("--sse-host=0.0.0.0")
89+
fi
90+
5691
echo "----------------" >&2
5792
echo "Executing command:" >&2
5893
echo "${processed_args[@]}" >&2

src/postgres_mcp/server.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from .sql import obfuscate_password
2828
from .top_queries import TopQueriesCalc
2929

30+
# Initialize FastMCP with default settings
3031
mcp = FastMCP("postgres-mcp")
3132

3233
# Constants
@@ -501,6 +502,25 @@ async def main():
501502
default=AccessMode.UNRESTRICTED.value,
502503
help="Set SQL access mode: unrestricted (unrestricted) or restricted (read-only with protections)",
503504
)
505+
parser.add_argument(
506+
"--transport",
507+
type=str,
508+
choices=["stdio", "sse"],
509+
default="stdio",
510+
help="Select MCP transport: stdio (default) or sse",
511+
)
512+
parser.add_argument(
513+
"--sse-host",
514+
type=str,
515+
default="localhost",
516+
help="Host to bind SSE server to (default: localhost)",
517+
)
518+
parser.add_argument(
519+
"--sse-port",
520+
type=int,
521+
default=8000,
522+
help="Port for SSE server (default: 8000)",
523+
)
504524

505525
args = parser.parse_args()
506526

@@ -547,7 +567,14 @@ async def main():
547567
logger.warning("Signal handling not supported on Windows")
548568
pass
549569

550-
await mcp.run_stdio_async()
570+
# Run the server with the selected transport (always async)
571+
if args.transport == "stdio":
572+
await mcp.run_stdio_async()
573+
else:
574+
# Update FastMCP settings for SSE transport
575+
mcp.settings.host = args.sse_host
576+
mcp.settings.port = args.sse_port
577+
await mcp.run_sse_async()
551578

552579

553580
async def shutdown(sig=None):

0 commit comments

Comments
 (0)