Default stdio mode requires no additional flags
#stdio vs streamable-http Transport Modes in MCP-PostgreSQL-Ops: 4 Key Differences Explained
The primary difference between stdio and streamable-http transport modes in MCP-PostgreSQL-Ops is that stdio uses local standard input/output streams for communication with no authentication, while streamable-http runs an HTTP server accessible over TCP/IP with optional Bearer token authentication.
MCP-PostgreSQL-Ops is a Model Context Protocol (MCP) server implementation for PostgreSQL operations that supports two distinct transport modes depending on your deployment architecture. Understanding the architectural and security differences between these modes is essential for choosing the right configuration for local development versus production network deployments.
Communication Architecture and Protocol Differences
The transport mode determines how MCP clients communicate with the PostgreSQL operations server.
Standard I/O (stdio) Transport
In stdio mode, the server communicates exclusively through the process's standard input and output streams. This mode is the default when no transport type is specified, implemented in [src/mcp_postgresql_ops/mcp_main.py](https://github.com/call518/mcp-postgresql-ops/blob/main/src/mcp_postgresql_ops/mcp_main.py) at line 3738 where the server executes mcp.run(transport='stdio'). This approach creates a bidirectional JSON-RPC communication channel over stdin/stdout, making it ideal for local CLI integrations and subprocess-based workflows where the client and server run on the same machine.
Streamable HTTP Transport
The streamable-http mode starts an HTTP server that accepts JSON-RPC requests over TCP/IP. According to the source code at line 3734 in mcp_main.py, this mode executes mcp.run(transport='streamable-http', host=host, port=port), binding to a configurable network interface. Unlike stdio, this transport supports remote clients connecting over the network, with the default binding address being 127.0.0.1:8000 unless overridden by command-line arguments or environment variables.
Configuration Requirements and Validation
Each transport mode enforces different configuration constraints during startup validation.
Network Binding and Port Configuration
The stdio mode requires no network configuration and ignores host or port settings entirely. In contrast, streamable-http mode performs strict validation of network parameters. The validate_config() function in mcp_main.py (lines 3595-3604) explicitly checks that the host is non-empty and the port falls within the valid range of 1-65535 before attempting to bind the HTTP server.
Authentication and Security Model
Stdio mode operates without any authentication layer, as it assumes a trusted local execution environment. This makes it unsuitable for exposed network interfaces but eliminates configuration overhead for local development.
Streamable-http mode offers optional Bearer token authentication controlled by the --auth-enable flag or REMOTE_AUTH_ENABLE environment variable. When authentication is enabled, the server validates the presence of a secret key (lines 3699-3705 in mcp_main.py), logging a fatal error if authentication is enabled without a corresponding REMOTE_SECRET_KEY or --secret-key argument. If authentication remains disabled, the server logs a security warning at startup (lines 3707-3710), alerting operators that the HTTP endpoint is exposed without credential protection.
Implementation Details in Source Code
The transport selection logic resides in the mcp_postgresql_ops package with clear branching based on the transport_type variable.
Transport Selection Logic
After parsing CLI arguments, the application checks the transport_type value to determine execution path:
- For
stdio: Callsmcp.run(transport='stdio')with no additional parameters - For
streamable-http: Extracts host/port fromFASTMCP_HOSTandFASTMCP_PORTenvironment variables or CLI arguments, then invokes the HTTP transport with authentication provider if enabled
Authentication Provider Integration
When streamable-http runs with --auth-enable, the code at lines 3713-3715 installs a static token authentication provider using mcp.auth = _build_static_token_auth(secret_key). This middleware intercepts incoming HTTP requests and validates the Authorization: Bearer <token> header before processing PostgreSQL operations.
Practical Usage Examples
Running Local Development with stdio
For local debugging or integration with CLI tools that spawn the server as a subprocess:
# Default stdio mode requires no additional flags
python -m mcp_postgresql_ops.mcp_main
# Or explicitly specify stdio transport
mcp-postgresql-ops --type stdio
Deploying Network-Accessible HTTP Server
For remote access or web UI integration with authentication:
# Start HTTP server on all interfaces with authentication
mcp-postgresql-ops \
--type streamable-http \
--host 0.0.0.0 \
--port 8080 \
--auth-enable \
--secret-key "secure-token-12345"
Python Client Connection Examples
Connecting to stdio mode (local subprocess):
from mcp_postgresql_ops.mcp_main import main
import subprocess
# Spawn server process and communicate via stdin/stdout
process = subprocess.Popen(
["python", "-m", "mcp_postgresql_ops.mcp_main", "--type", "stdio"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
text=True
)
# Send JSON-RPC request
process.stdin.write('{"jsonrpc": "2.0", "method": "list_databases", "id": 1}\n')
process.stdin.flush()
response = process.stdout.readline()
print(response)
Connecting to streamable-http mode with authentication:
import requests
import json
url = "http://localhost:8080/"
headers = {
"Authorization": "Bearer secure-token-12345",
"Content-Type": "application/json"
}
payload = {
"jsonrpc": "2.0",
"method": "execute_query",
"params": {"query": "SELECT version();"},
"id": 1
}
response = requests.post(url, headers=headers, json=payload)
result = response.json()
print(result["result"])
Summary
- stdio transport uses local standard input/output streams with no network exposure and no authentication requirements, ideal for local CLI integrations and development workflows.
- streamable-http transport creates an HTTP server accessible over TCP/IP, requires explicit host/port configuration, and supports optional Bearer token authentication for secure remote access.
- The
validate_config()function enforces port range validation (1-65535) and host presence checks exclusively for HTTP mode. - Authentication in HTTP mode is implemented through
_build_static_token_auth()when--auth-enableis specified, with mandatory secret key validation. - Stdio mode is the default and requires zero configuration, while streamable-http must be explicitly selected with the
--type streamable-httpargument.
Frequently Asked Questions
When should I use stdio mode versus streamable-http mode?
Use stdio mode for local development, CLI tooling, or when running the MCP server as a subprocess where the parent process manages communication through pipes. Use streamable-http mode when you need to expose PostgreSQL operations to remote clients, web dashboards, or microservices architectures that communicate over HTTP.
How do I secure the streamable-http transport in production?
Enable Bearer token authentication by setting --auth-enable and providing a strong secret key via --secret-key or the REMOTE_SECRET_KEY environment variable. The server validates this token against the Authorization header on every request. Never run streamable-http without authentication on public networks, as the server logs an explicit warning when starting without credential protection.
Can stdio mode handle concurrent connections from multiple clients?
No. The stdio transport supports only a single client communicating through the process's standard streams. For concurrent client support or multi-tenant scenarios, you must use streamable-http mode, which leverages the underlying HTTP server's connection handling capabilities to manage multiple simultaneous requests.
What environment variables configure each transport mode?
For stdio mode, only general MCP variables like MCP_LOG_LEVEL and PostgreSQL connection strings are relevant. For streamable-http, you must set FASTMCP_HOST (default: 127.0.0.1), FASTMCP_PORT (default: 8000), and optionally REMOTE_AUTH_ENABLE and REMOTE_SECRET_KEY when using authentication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →