diff --git a/README.md b/README.md index 0e122ad..6f601af 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ services: # - DEMO_MODE=false # Enable demo mode (resets data hourly) # - ADMIN_EMAIL=admin@trek.local # Initial admin e-mail — only used on first boot when no users exist # - ADMIN_PASSWORD=changeme # Initial admin password — only used on first boot when no users exist + # - MCP_RATE_LIMIT=60 # Max MCP API requests per user per minute (default: 60) volumes: - ./data:/app/data - ./uploads:/app/uploads @@ -301,6 +302,7 @@ trek.yourdomain.com { | `ADMIN_PASSWORD` | Password for the first admin account created on initial boot. Must be set together with `ADMIN_EMAIL`. | random | | **Other** | | | | `DEMO_MODE` | Enable demo mode (hourly data resets) | `false` | +| `MCP_RATE_LIMIT` | Max MCP API requests per user per minute | `60` | ## Optional API Keys diff --git a/chart/templates/configmap.yaml b/chart/templates/configmap.yaml index 7322505..7f76e8b 100644 --- a/chart/templates/configmap.yaml +++ b/chart/templates/configmap.yaml @@ -22,3 +22,6 @@ data: {{- if .Values.env.OIDC_DISCOVERY_URL }} OIDC_DISCOVERY_URL: {{ .Values.env.OIDC_DISCOVERY_URL | quote }} {{- end }} + {{- if .Values.env.MCP_RATE_LIMIT }} + MCP_RATE_LIMIT: {{ .Values.env.MCP_RATE_LIMIT | quote }} + {{- end }} diff --git a/chart/values.yaml b/chart/values.yaml index 9501c60..c92d3bd 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -29,6 +29,8 @@ env: # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik). # OIDC_SCOPE: "openid email profile groups" # Space-separated OIDC scopes to request. Must include scopes for any claim used by OIDC_ADMIN_CLAIM. + # MCP_RATE_LIMIT: "60" + # Max MCP API requests per user per minute. Defaults to 60. # Secret environment variables stored in a Kubernetes Secret. diff --git a/docker-compose.yml b/docker-compose.yml index 4645f2d..2d141a9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,6 +38,7 @@ services: # - OIDC_DISCOVERY_URL= # Override the OIDC discovery endpoint for providers with non-standard paths (e.g. Authentik) # - ADMIN_EMAIL=admin@trek.local # Initial admin e-mail — only used on first boot when no users exist # - ADMIN_PASSWORD=changeme # Initial admin password — only used on first boot when no users exist +# - MCP_RATE_LIMIT=60 # Max MCP API requests per user per minute (default: 60) volumes: - ./data:/app/data - ./uploads:/app/uploads diff --git a/server/.env.example b/server/.env.example index 0e1f64d..2c606c5 100644 --- a/server/.env.example +++ b/server/.env.example @@ -28,6 +28,8 @@ OIDC_SCOPE=openid email profile groups # Space-separated OIDC scopes to request DEMO_MODE=false # Demo mode - resets data hourly +# MCP_RATE_LIMIT=60 # Max MCP API requests per user per minute (default: 60) + # Initial admin account — only used on first boot when no users exist yet. # If both are set the admin account is created with these credentials. # If either is omitted a random password is generated and printed to the server log. diff --git a/server/src/mcp/index.ts b/server/src/mcp/index.ts index 47c79f0..154eac5 100644 --- a/server/src/mcp/index.ts +++ b/server/src/mcp/index.ts @@ -21,7 +21,8 @@ const sessions = new Map(); const SESSION_TTL_MS = 60 * 60 * 1000; // 1 hour const MAX_SESSIONS_PER_USER = 5; const RATE_LIMIT_WINDOW_MS = 60 * 1000; // 1 minute -const RATE_LIMIT_MAX = 60; // requests per minute per user +const parsed = Number.parseInt(process.env.MCP_RATE_LIMIT ?? ""); +const RATE_LIMIT_MAX = Number.isFinite(parsed) && parsed > 0 ? parsed : 60; // requests per minute per user interface RateLimitEntry { count: number;