-
Notifications
You must be signed in to change notification settings - Fork 2
HTTP Transport
- Build AI integrations instantly.
- Empower agents with secure database access.
- Execute complex logic via Code Mode.
- Scale operations with robust connection pooling.
- Leverage OAuth 2.1 for enterprise security.
This page explains how to run mysql-mcp as an HTTP server supporting two MCP transport protocols simultaneously — Streamable HTTP for modern clients and legacy SSE for backward compatibility.
Use HTTP mode when:
- Deploying the server to a remote location (cloud, Docker container)
- Multiple AI clients need to connect to the same database
- You need OAuth 2.1 authentication for enterprise security
- Running the server as a standalone network service
- Serverless/stateless deployments (
--stateless)
Use stdio mode (default) when:
- Running locally with Claude Desktop or Cursor IDE
- Single-user development environment
- Simplest setup with no network configuration needed
💡 Tip: Most users should use stdio mode. HTTP mode is for advanced deployments.
Important:
HTTP transport mode requires --allowed-io-roots to be set to explicitly authorize filesystem access boundaries. The server will fail to start without it.
# Build the project first
pnpm run build
# Start HTTP server on port 3001
npx @neverinfamous/mysql-mcp --transport http --port 3001 --server-host 0.0.0.0 --allowed-io-roots /data --mysql mysql://user:password@localhost:3306/database# Run with port mapping
docker run -p 3001:3001 writenotenow/mysql-mcp:latest \
--transport http \
--port 3001 \
--server-host 0.0.0.0 \
--allowed-io-roots /data \
--mysql mysql://user:password@host.docker.internal:3306/databasenpx @neverinfamous/mysql-mcp --transport http --port 3001 --allowed-io-roots /data --auth-token my-secret --mysql mysql://user:password@localhost:3306/databasenpx @neverinfamous/mysql-mcp --transport http --port 3001 --stateless --allowed-io-roots /data --mysql mysql://user:password@localhost:3306/databaseThe HTTP transport supports two MCP protocol versions simultaneously, allowing both modern and legacy clients to connect to the same server.
Modern protocol (MCP 2025-03-26) — single endpoint, session-based:
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/mcp |
JSON-RPC requests (initialize, tools/list, etc.) |
GET |
/mcp |
SSE stream for server notifications |
DELETE |
/mcp |
Session termination |
In stateless mode (--stateless): GET /mcp returns 405, DELETE /mcp returns 204, /sse and /messages return 404. Each POST /mcp creates a fresh transport with no session persistence, relying exclusively on synchronous HTTP request-response cycles.
Sessions are managed via the Mcp-Session-Id header. The server returns a session ID in the response to initialize, and clients must include it in subsequent requests.
Example — Initialize a session:
curl -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0.0"}}}'Example — List tools (with session):
curl -X POST http://localhost:3001/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Session-Id: <session-id-from-initialize>" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'Important:
Streamable HTTP requests must include Accept: application/json, text/event-stream — the server may respond with either format.
Legacy protocol (MCP 2024-11-05) — for older MCP clients:
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/sse |
Opens SSE stream, returns /messages?sessionId=<id> endpoint |
POST |
/messages?sessionId=<id> |
Send JSON-RPC messages to the session |
Example:
# Establish SSE connection (will stream events)
curl -N http://localhost:3001/sse
# Send a message (in another terminal, using the sessionId from the SSE stream)
curl -X POST "http://localhost:3001/messages?sessionId=<id>" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0.0"}}}'All HTTP responses include the following headers (6 base, 7 with HSTS):
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Cache-Control |
no-store, no-cache, must-revalidate |
Content-Security-Policy |
default-src 'none'; frame-ancestors 'none' |
Permissions-Policy |
camera=(), microphone=(), geolocation=() |
Referrer-Policy |
no-referrer |
Strict-Transport-Security |
Opt-in via enableHSTS (for HTTPS) |
The HTTP server applies three timeout layers to prevent slow-connection DoS attacks:
| Timeout | Value | Purpose |
|---|---|---|
requestTimeout |
120,000 ms | Maximum time for the entire request lifecycle |
keepAliveTimeout |
65,000 ms | Idle time before closing keep-alive connections |
headersTimeout |
66,000 ms | Maximum time to receive complete headers |
The HTTP transport enforces strict session lifecycle management to prevent memory leaks from disconnected clients:
- Idle TTL: 30 minutes. If a session receives no requests, it is terminated.
- Absolute TTL: 24 hours. Hard limit for any session duration.
- Reaper Interval: 1 minute. A background sweep cleans up orphaned sessions. Sessions with in-flight requests are protected from early termination.
CORS is currently hardcoded to allow all origins (*) to facilitate easy connections from web-based clients and inspectors. Restricting origins via CLI flags is not yet supported.
When running behind a reverse proxy (nginx, ALB, Cloudflare, etc.), enable trustProxy to read the client IP from X-Forwarded-For instead of the socket address. This ensures rate limiting and logging use the real client IP.
Per-IP request throttling is enabled by default to prevent abuse. The Transport Rate limiter (100 HTTP requests/min default) uses a sliding window approach with deterministic cleanup. Rate limiting is distributed across deployments via Redis if REDIS_URL is provided, with a graceful in-memory fallback. (Note: This is distinct from the 60 V8 Code Mode executions/min Execution Rate limit).
-
/healthbypass — Health check requests are served before rate limiting is checked, ensuring monitoring probes always succeed regardless of per-IP quotas -
Retry-Afterheader — Rate-limited responses (429 Too Many Requests) include aRetry-Afterheader indicating seconds until the window resets -
Environment override — Set
MCP_RATE_LIMIT_MAXto customize the per-IP request limit (default: 100 requests/minute)
Request body size is enforced with two layers:
- Content-Length header check — fast rejection for well-behaved clients
- Streaming byte tracking — catches missing/spoofed headers and chunked encoding
For production deployments, use a structured .env file following fleet groupings:
# Server
MCP_TRANSPORT=http
MYSQLMCP_PORT=3001
MCP_HOST=0.0.0.0
TRUST_PROXY=false
MCP_RATE_LIMIT_MAX=100
# Database
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=app_user
MYSQL_PASSWORD=secure_password
MYSQL_DATABASE=production| Argument | Environment Variable | Default | Description |
|---|---|---|---|
--transport, -t
|
MCP_TRANSPORT |
stdio |
Transport type (stdio, http, or sse) |
--port |
MYSQLMCP_PORT |
3001 |
HTTP server port |
--server-host |
MCP_HOST |
localhost |
Host to bind HTTP transport to |
--auth-token |
MCP_AUTH_TOKEN |
— | Simple bearer token for HTTP auth |
--stateless |
— | false |
Stateless HTTP mode (no sessions, no SSE) |
--trust-proxy |
TRUST_PROXY |
false |
Trust X-Forwarded-For for client IP |
--enable-hsts |
MCP_ENABLE_HSTS |
false |
Enable HTTP Strict Transport Security |
--metrics-export |
MCP_METRICS_EXPORT |
false |
Enable prometheus metrics endpoint /metrics
|
--allowed-io-roots |
ALLOWED_IO_ROOTS |
— | Explicitly authorize filesystem boundaries |
--oauth-enabled, -o
|
OAUTH_ENABLED |
false |
Enable OAuth 2.1 authentication |
--oauth-issuer |
OAUTH_ISSUER |
— | OAuth 2.1 issuer URL |
--oauth-audience |
OAUTH_AUDIENCE |
— | OAuth 2.1 audience |
--oauth-jwks-uri |
OAUTH_JWKS_URI |
— | JWKS URI (auto-discovered) |
--oauth-clock-tolerance |
OAUTH_CLOCK_TOLERANCE |
— | Clock tolerance in seconds |
--audit-log |
— | — | Enable JSONL forensic logging and tokens |
--audit-backup |
— | false |
Enable audit backups |
--audit-reads |
— | false |
Include read-scope tool calls in audit log |
--audit-redact |
— | false |
Redact sensitive arguments in audit log |
--audit-log-max-size |
— | — | Max file size before rotation (bytes) |
--audit-backup-data |
— | false |
Include sample data in pre-mutation snaps |
--audit-backup-max-size |
— | — | Max table size in bytes for data capture |
| — | CODE_MODE_MAX_RESULT_SIZE |
102400 |
Max Code Mode result payload in bytes |
HTTP mode supports OAuth 2.1 authentication for enterprise deployments:
npx @neverinfamous/mysql-mcp \
--transport http \
--port 3001 \
--allowed-io-roots /data \
--mysql mysql://user:password@localhost:3306/database \
--oauth-enabled \
--oauth-issuer https://your-keycloak.com/realms/mysql-mcp \
--oauth-audience mysql-mcpSee the OAuth page for complete setup instructions.
Test your HTTP server with MCP Inspector:
# Start the server
npx @neverinfamous/mysql-mcp --transport http --port 3001 --allowed-io-roots /data --mysql mysql://...
# In another terminal, connect Inspector
npx @modelcontextprotocol/inspector http://localhost:3001/ssecurl http://localhost:3001/health
# {"status":"healthy","timestamp":"2026-03-05T..."}# Build imagedocker build -t mysql-mcp .# Run container with port mappingdocker run -d \ --name mysql-mcp-server \ -p 3001:3001 \ mysql-mcp \ --transport http \ --port 3001 \ --server-host 0.0.0.0 \ --allowed-io-roots /data \ --mysql mysql://user:password@host.docker.internal:3306/databaseservices
: mysql-mcp: image: writenotenow/mysql-mcp:latest ports: - "3001:3001" command: - --transport - http - --port - "3001" - --allowed-io-roots - /data - --mysql - mysql://user:password@mysql:3306/database environment: - MYSQL_POOL_SIZE=20 depends_on: - mysql mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: database volumes: - mysql-data:/var/lib/mysqlvolumes: mysql-data:AWS ECS / Fargate1. Push Docker image to ECR2. Create ECS task definition with port 3001 exposed3. Configure ALB to route traffic to the container4. Set environment variables for MySQL connection
# Build and push to GCRgcloud builds submit --tag gcr.io/PROJECT_ID/mysql-mcp# Deploy to Cloud Rungcloud run deploy mysql-mcp \ --image gcr.io/PROJECT_ID/mysql-mcp \ --port 3001 \ --set-env-vars MYSQL_HOST=...,MYSQL_USER=...,MYSQL_PASSWORD=... \ --command "--transport,http,--port,3001,--allowed-io-roots,/data"az
container create \ --resource-group myResourceGroup \ --name mysql-mcp \ --image writenotenow/mysql-mcp:latest \ --ports 3001 \ --environment-variables \ MYSQL_HOST=... \ MYSQL_USER=... \ MYSQL_PASSWORD=... \ --command-line "--transport http --port 3001 --allowed-io-roots /data"Problem: Client cannot connect to the server
Solutions:- Verify server is running: curl http://localhost:3001/health- Check firewall rules allow port 3001- Ensure --server-host 0.0.0.0 if connecting from another machine- Check Docker port mapping: -p 3001:3001
Problem: POST /mcp returns 406
Solution: Include the required Accept header:
Accept: application/json, text/event-stream
The StreamableHTTPServerTransport requires clients to accept both JSON and SSE response formats.
Problem: Requests return 400 Bad Request or 404 Not Found with session-related errors
Solutions:- Ensure you're sending the Mcp-Session-Id header from the initialize response- SSE sessions cannot be used on /mcp and vice versa (cross-protocol guard)- Sessions expire when the client disconnects
Problem: Requests return 401 Unauthorized
Solutions:- Verify OAuth issuer URL is correct- Check token audience matches --oauth-audience- Ensure JWKS URI is accessible from the server- See OAuth troubleshooting section
Expand Your Knowledge (See Also)- Configuration - General configuration options- OAuth - OAuth 2.1 authentication setup- MCP-Inspector - Testing with MCP Inspector- MCP Protocol Specification - Official MCP docs
Unlock autonomous database orchestration with an enterprise-grade MySQL MCP server. Featuring blazing-fast sandboxed Code Mode, uncompromising schema enforcement, and seamless ecosystem integrations to power secure, intelligent AI workflows.
- Installation
- Configuration
- Architecture
- HTTP Transport
- Tool Filtering
- Code Mode
- Tools
- Prompts
- Resources
- Observability & Telemetry