Reflow Gateway sits between your AI clients (Claude, Cursor, Windsurf…) and your upstream MCP servers (GitHub, Jira, Slack, filesystem…). Instead of giving each client direct access to each server, the gateway centralizes:
- Who can access which tools (authorization policies)
- Which credentials to use for each upstream (per-user, per-group, per-role)
- How to route requests (Streamable HTTP, SSE, STDIO, Kubernetes pods)
- What happened (audit logs, OpenTelemetry traces, Grafana dashboards)
AI Clients Reflow Gateway MCP Servers
────────── ────────────── ───────────
Claude ┐ ┌─▶ GitHub (HTTP)
Cursor ├──JWT Bearer──▶┌────────┐ ├─▶ Jira (STDIO · per-user)
Windsurf ┘ │JWT Auth│ ├─▶ Slack (STDIO · per-group)
Any MCP client │Policies│ └─▶ Custom (Kubernetes pod)
│Cred Inj│
└───┬────┘
│
PostgreSQL
(sessions · policies tokens · audit logs)
| 🔀 MCP Multiplexing | Aggregate tools from multiple servers into one endpoint |
| 🔐 JWT Authentication | Every request verified; API tokens for programmatic access |
| 🛡️ Default-deny Authorization | Fine-grained policies at target, tool, resource, and prompt level |
| 🔑 Credential Injection | Gateway resolves and injects upstream creds — clients never see them |
| 🚀 Four Transports | Streamable HTTP · SSE · STDIO processes · Kubernetes pods |
| 🔒 Encryption at rest | AES-256-GCM for all stored credentials |
| 📋 Audit Logging | Every MCP request logged with user, method, target, and duration |
| 📡 OpenTelemetry | Traces + metrics exported to any OTLP collector (Grafana included) |
| ♻️ Session Recycle | Auto-detects JWT claim changes and refreshes sessions mid-flight |
| 🐳 Docker & Helm ready | One command to run; Helm chart for Kubernetes deployments |
git clone https://github.com/JulianPedro/reflow-gateway.git
cd gateway
cp .env.example .env
cp config.yaml.example config.yamlEdit .env with secure secrets:
DB_PASSWORD=$(openssl rand -hex 16)
JWT_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -base64 24 | cut -c1-32)docker compose up -dGateway is running at http://localhost:3000. API docs at http://localhost:3000/docs.
curl -fsSL https://raw.githubusercontent.com/JulianPedro/reflow-gateway/main/install.sh | bashhelm install reflow-gateway ./chart \
--set secrets.jwtSecret="$(openssl rand -hex 32)" \
--set secrets.encryptionKey="$(openssl rand -base64 24 | cut -c1-32)" \
--set secrets.dbPassword="$(openssl rand -hex 16)" \
--set config.database.host=my-postgres.default.svc# First user gets admin role automatically
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com","password":"secure123"}'
TOKEN=$(curl -s -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com","password":"secure123"}' | jq -r .token)TARGET=$(curl -s -X POST http://localhost:3000/api/targets \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "github",
"transport_type": "stdio",
"command": "npx",
"args": ["@modelcontextprotocol/server-github"],
"statefulness": "stateful",
"isolation_boundary": "per_user"
}' | jq -r .id)
# Set the GitHub token for this user
curl -X POST http://localhost:3000/api/targets/$TARGET/env/user/$USER_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"GITHUB_PERSONAL_ACCESS_TOKEN","value":"ghp_xxxx"}'curl -X POST http://localhost:3000/api/policies \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Developers can use GitHub",
"target_id": "'$TARGET'",
"resource_type": "all",
"effect": "allow",
"priority": 10,
"subjects": [{"subject_type": "role", "subject_value": "developer"}]
}'Configure Claude Desktop, Cursor, or any MCP client:
{
"mcpServers": {
"reflow": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer <your-api-token>"
}
}
}
}Tools from all authorized targets are automatically available, prefixed by target name (github_list_repos, jira_create_issue, etc.).
backend/
cmd/server/main.go Entry point
internal/
api/ REST API (handlers, routes)
auth/ JWT validation, AES-256-GCM encryption
config/ YAML config with ${ENV_VAR} expansion
database/ PostgreSQL + single consolidated migration
gateway/ MCP handler, proxy, session manager, authorizer
mcp/ HTTP/SSE MCP client (auto-detect transport)
stdio/ STDIO process pool with GC
k8s/ Kubernetes MCPInstance CR manager
observability/ Real-time WebSocket dashboard
telemetry/ OpenTelemetry tracing and metrics
docs/ Embedded OpenAPI spec + Scalar UI
operator/ Kubernetes operator (separate Go module)
Reconciles MCPInstance CRDs → Pods + Services
website/ Docusaurus documentation site
chart/ Helm chart
# config.yaml — all values support ${ENV_VAR} expansion
server: { port: 3000, host: "0.0.0.0" }
database: { host: postgres, port: 5432, user: reflow, password: ${DB_PASSWORD} }
jwt: { secret: ${JWT_SECRET} }
encryption: { key: ${ENCRYPTION_KEY} } # exactly 32 chars
session: { timeout: 30m }
logging: { level: info, format: json }
kubernetes: { enabled: false, namespace: reflow }
telemetry: { enabled: false, endpoint: "otel-collector:4317" }See full configuration reference.
| Getting Started | Docker Compose setup in 5 minutes |
| Architecture | System design and request flow |
| Authentication | JWT, API tokens, user management |
| Authorization | Default-deny policies, evaluation order |
| Credential Management | Per-user/group/role credential injection |
| Transports | HTTP, SSE, STDIO, Kubernetes |
| Session Management | Recycle on identity changes |
| Kubernetes Operator | CRDs, Helm, pod lifecycle |
| Observability | OpenTelemetry, Grafana, audit logs |
| API Reference | Interactive Scalar UI at /docs |
| Transport | When to use | Isolation |
|---|---|---|
streamable-http |
Remote HTTP MCP servers | N/A (stateless proxy) |
sse |
Legacy SSE MCP servers | N/A |
stdio |
Local processes (npx, python…) | shared · per_role · per_group · per_user |
kubernetes |
Isolated pods in K8s clusters | same as stdio |
Contributions are welcome. Please open an issue before submitting a large PR.
# Backend
cd backend && go run cmd/server/main.go -config ../config.yaml
# Frontend
cd frontend && npm install && npm run dev
# Docs site
cd website && npm install && npm startMIT — see LICENSE.