From c419717e169fbad5c54a7198e89f88105d5c77d6 Mon Sep 17 00:00:00 2001 From: popagruia Date: Mon, 29 Sep 2025 11:50:04 +0300 Subject: [PATCH 1/8] Initial version Signed-off-by: popagruia --- .../templates/deployment-mcpgateway.yaml | 16 + charts/mcp-stack/values.schema.json | 4 + charts/mcp-stack/values.yaml | 397 +++++++++++++++++- deployment/k8s/postgres-pv.yaml | 16 +- deployment/k8s/postgres-pvc.yaml | 14 +- 5 files changed, 417 insertions(+), 30 deletions(-) diff --git a/charts/mcp-stack/templates/deployment-mcpgateway.yaml b/charts/mcp-stack/templates/deployment-mcpgateway.yaml index bdc2832f0..5e975f85f 100644 --- a/charts/mcp-stack/templates/deployment-mcpgateway.yaml +++ b/charts/mcp-stack/templates/deployment-mcpgateway.yaml @@ -152,3 +152,19 @@ spec: # Resource requests / limits resources: {{- toYaml .Values.mcpContextForge.resources | nindent 12 }} + {{- /* Plugins enabled need the plugins configuration */}} + {{- if .Values.mcpContextForge.config.PLUGINS_ENABLED }} + volumeMounts: + - name: plugin-config-volume + mountPath: {{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE | default "/app/mcpgateway/plugins/config.yaml" }} + subPath: config.yaml + {{- end }} +{{- if .Values.mcpContextForge.config.PLUGINS_ENABLED }} + volumes: + - name: plugin-config-volume + configMap: + name: {{ include "mcp-stack.fullname" . }}-gateway-plugins + items: + - key: config.yaml + path: config.yaml +{{- end }} diff --git a/charts/mcp-stack/values.schema.json b/charts/mcp-stack/values.schema.json index 09f396d2c..aad1be1be 100644 --- a/charts/mcp-stack/values.schema.json +++ b/charts/mcp-stack/values.schema.json @@ -251,6 +251,10 @@ }, "additionalProperties": false }, + "pluginConfig": { + "type": "string", + "description": "Content of the plugin file" + }, "env": { "type": "object", "description": "Environment configuration", diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 89d750f51..2c656b1f5 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -121,6 +121,7 @@ mcpContextForge: # host: redis # uncomment to override the generated name port: 6379 + #################################################################### # PLAIN-TEXT (NON-SECRET) SETTINGS # Rendered into a ConfigMap; readable by anyone with GET access. @@ -283,8 +284,8 @@ mcpContextForge: User-agent: * Disallow: / - # MCP Gateway is a private API gateway - # Public crawling is disabled by default + # MCP Gateway is a private API gateway + # Public crawling is disabled by default WELL_KNOWN_SECURITY_TXT: "" # security.txt content (RFC 9116) WELL_KNOWN_CUSTOM_FILES: "{}" # additional custom well-known files (JSON) WELL_KNOWN_CACHE_MAX_AGE: "3600" # cache control for well-known files (seconds) @@ -499,6 +500,398 @@ mcpContextForge: # ─ Documentation & UI Settings (Sensitive) ─ DOCS_ALLOW_BASIC_AUTH: "false" # allow basic auth for docs endpoints + # Plugin Configuration + PLUGINS_ENABLED: false + PLUGIN_CONFIG_FILE: "/app/plugins/config_vault.yaml" + + # (derived URLs are defined in deployment-mcp.yaml) + + # ─ Optional database / redis overrides ─ + # DATABASE_URL: "postgresql://admin:s3cr3t@db.acme.com:5432/prod" # override the auto-generated URL + # REDIS_URL: "redis://cache.acme.com:6379/0" # override the auto-generated URL + + #################################################################### + # Names of ConfigMap / Secret are resolved by templates; leave as-is. + #################################################################### + envFrom: + - secretRef: + name: mcp-gateway-secret + - configMapRef: + name: mcp-gateway-config + +######################################################################## +# DATABASE MIGRATION (Alembic) +# Runs as a Job before mcpgateway deployment +######################################################################## +migration: + enabled: true # Set to false to skip migrations + + # Job configuration + restartPolicy: Never # Job should not restart on failure + backoffLimit: 3 # Retry up to 3 times before giving up + activeDeadlineSeconds: 600 # Kill job after 10 minutes + + # Use same image as mcpgateway + image: + repository: ghcr.io/ibm/mcp-context-forge + tag: latest # Should match mcpContextForge.image.tag + #pullPolicy: IfNotPresent + pullPolicy: Always # always pull the latest image; useful for dev/testing + + # Resource limits for the migration job + resources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + + # Migration command configuration + command: + waitForDb: "python3 /app/mcpgateway/utils/db_isready.py --max-tries 30 --interval 2 --timeout 5" + migrate: "alembic upgrade head || echo '⚠️ Migration check failed'" + +######################################################################## +# POSTGRES DATABASE +######################################################################## +postgres: + enabled: true + + image: + repository: postgres + tag: "17" + pullPolicy: IfNotPresent + + service: + type: ClusterIP + port: 5432 + + # PersistentVolumeClaim for data durability + persistence: + enabled: true + storageClassName: manual # pick a StorageClass (e.g. gp2, standard) + accessModes: [ReadWriteMany] + size: 5Gi + + # Leave blank to autogenerate -mcp-stack-postgres-secret. + existingSecret: "" + + credentials: # used only when existingSecret is blank + database: postgresdb + user: admin + password: test123 # CHANGE ME in production! + + # ─── Resource limits & requests ─── + resources: + limits: + cpu: 1000m # 1 core hard cap + memory: 1Gi + requests: + cpu: 500m # guaranteed half-core + memory: 64Mi + + # ─── Health & readiness probes ─── + probes: + readiness: + type: exec + command: ["pg_isready", "-U", "$(POSTGRES_USER)"] + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 3 + + liveness: + type: exec + command: ["pg_isready", "-U", "$(POSTGRES_USER)"] + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 3 + successThreshold: 1 + failureThreshold: 5 + +######################################################################## +# REDIS CACHE +######################################################################## +redis: + enabled: true + + image: + repository: redis + tag: latest + pullPolicy: IfNotPresent + + service: + type: ClusterIP + port: 6379 + + # ─── Resource limits & requests ─── + resources: + limits: + cpu: 100m # cap at 0.1 core, 256 MiB + memory: 256Mi + requests: + cpu: 50m # reserve 0.05 core, 128 MiB + memory: 16Mi + + # ─── Health & readiness probes ─── + probes: + readiness: + type: exec + command: ["redis-cli", "PING"] + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + + liveness: + type: exec + command: ["redis-cli", "PING"] + initialDelaySeconds: 5 + periodSeconds: 15 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 5 + +######################################################################## +# PGADMIN - Web UI for Postgres +######################################################################## +pgadmin: + enabled: true + + image: + repository: dpage/pgadmin4 + tag: latest + pullPolicy: IfNotPresent + + service: + type: ClusterIP + port: 80 + + env: + email: admin@example.com + password: admin123 # CHANGE ME in production! + + # ─── Resource limits & requests ─── + resources: + limits: + cpu: 200m # cap at 0.2 core, 256 MiB + memory: 256Mi + requests: + cpu: 100m # reserve 0.1 core, 128 MiB + memory: 128Mi + + # ─── Health & readiness probes ─── + probes: + readiness: + type: http + path: /misc/ping # lightweight endpoint + port: 80 + initialDelaySeconds: 60 # pgAdmin needs more time to initialize + periodSeconds: 10 + timeoutSeconds: 5 # increased timeout + successThreshold: 1 + failureThreshold: 5 # more tolerance for failures + + liveness: + type: http + path: /misc/ping + port: 80 + initialDelaySeconds: 90 # even longer for liveness + periodSeconds: 20 # check less frequently + timeoutSeconds: 5 # increased timeout + successThreshold: 1 + failureThreshold: 3 # less aggressive killing + +######################################################################## +# REDIS-COMMANDER - Web UI for Redis +######################################################################## +redisCommander: + enabled: true + + image: + repository: rediscommander/redis-commander + tag: latest + pullPolicy: IfNotPresent + + service: + type: ClusterIP + port: 8081 + + # ─── Resource limits & requests ─── + resources: + limits: + cpu: 100m # cap at 0.1 core, 256 MiB + memory: 256Mi + requests: + cpu: 50m # reserve 0.05 core, 128 MiB + memory: 128Mi + + # ─── Health & readiness probes ─── + probes: + readiness: + type: http + path: / # root returns 200 OK + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + + liveness: + type: http + path: / + port: 8081 + initialDelaySeconds: 10 + periodSeconds: 15 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 5 + +######################################################################## +# MCP-FAST-TIME-SERVER - optional high-performance time server for MCP (go) +# Provides a fast implementation including SSE and Streamable HTTP +######################################################################## +mcpFastTimeServer: + enabled: true # switch to true to deploy + replicaCount: 2 + image: + repository: ghcr.io/ibm/fast-time-server + tag: "0.7.0" + pullPolicy: IfNotPresent + port: 8080 + + # Ingress example (leave as-is if you already have it) + ingress: + enabled: true + path: /fast-time + pathType: Prefix + servicePort: 80 + + # ─── Health & readiness probes ─── + probes: + readiness: + type: http + path: /health + port: 8080 + initialDelaySeconds: 3 + periodSeconds: 10 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + + liveness: + type: http + path: /health + port: 8080 + initialDelaySeconds: 3 + periodSeconds: 15 + timeoutSeconds: 2 + successThreshold: 1 + failureThreshold: 3 + + # Tiny Go process: ~10 MB runtime footprint + resources: + limits: + cpu: 50m # ~5 % of a core + memory: 64Mi + requests: + cpu: 25m + memory: 10Mi + #################################################################### + secret: + # ─ Admin & auth ─ + BASIC_AUTH_USER: admin # username for basic-auth login + BASIC_AUTH_PASSWORD: changeme # password for basic-auth (CHANGE IN PROD!) + AUTH_REQUIRED: "true" # enforce authentication globally (true/false) + JWT_SECRET_KEY: my-test-key # secret key used to sign JWT tokens + JWT_ALGORITHM: HS256 # signing algorithm for JWT tokens + JWT_AUDIENCE: mcpgateway-api # JWT audience claim for token validation + JWT_ISSUER: mcpgateway # JWT issuer claim for token validation + TOKEN_EXPIRY: "10080" # JWT validity (minutes); 10080 = 7 days + REQUIRE_TOKEN_EXPIRATION: "false" # require all JWT tokens to have expiration claims + AUTH_ENCRYPTION_SECRET: my-test-salt # passphrase to derive AES key for secure storage + + # ─ Email-Based Authentication ─ + EMAIL_AUTH_ENABLED: "true" # enable email-based authentication system + PLATFORM_ADMIN_EMAIL: admin@example.com # email for bootstrap platform admin user + PLATFORM_ADMIN_PASSWORD: changeme # password for bootstrap platform admin user + PLATFORM_ADMIN_FULL_NAME: Platform Administrator # full name for bootstrap platform admin + + # ─ Password Hashing & Security ─ + ARGON2ID_TIME_COST: "3" # Argon2id time cost (iterations) + ARGON2ID_MEMORY_COST: "65536" # Argon2id memory cost in KiB + ARGON2ID_PARALLELISM: "1" # Argon2id parallelism (threads) + PASSWORD_MIN_LENGTH: "8" # minimum password length + PASSWORD_REQUIRE_UPPERCASE: "false" # require uppercase letters in passwords + PASSWORD_REQUIRE_LOWERCASE: "false" # require lowercase letters in passwords + PASSWORD_REQUIRE_NUMBERS: "false" # require numbers in passwords + PASSWORD_REQUIRE_SPECIAL: "false" # require special characters in passwords + MAX_FAILED_LOGIN_ATTEMPTS: "5" # maximum failed login attempts before lockout + ACCOUNT_LOCKOUT_DURATION_MINUTES: "30" # account lockout duration in minutes + + # ─ MCP Client Authentication ─ + MCP_CLIENT_AUTH_ENABLED: "true" # enable JWT authentication for MCP client operations + TRUST_PROXY_AUTH: "false" # trust proxy authentication headers + PROXY_USER_HEADER: X-Authenticated-User # header containing authenticated username from proxy + + # ─ OAuth Configuration ─ + OAUTH_REQUEST_TIMEOUT: "30" # OAuth request timeout in seconds + OAUTH_MAX_RETRIES: "3" # maximum retries for OAuth token requests + + # ─ SSO (Single Sign-On) Configuration ─ + SSO_ENABLED: "false" # master switch for Single Sign-On authentication + SSO_AUTO_CREATE_USERS: "true" # automatically create users from SSO providers + SSO_TRUSTED_DOMAINS: "[]" # trusted email domains (JSON array) + SSO_PRESERVE_ADMIN_AUTH: "true" # preserve local admin authentication when SSO enabled + SSO_REQUIRE_ADMIN_APPROVAL: "false" # require admin approval for new SSO registrations + SSO_AUTO_ADMIN_DOMAINS: "[]" # email domains that automatically get admin privileges + + # ─ GitHub OAuth ─ + SSO_GITHUB_ENABLED: "false" # enable GitHub OAuth authentication + SSO_GITHUB_CLIENT_ID: "" # GitHub OAuth client ID + SSO_GITHUB_CLIENT_SECRET: "" # GitHub OAuth client secret + SSO_GITHUB_ADMIN_ORGS: "[]" # GitHub orgs granting admin privileges (JSON) + + # ─ Google OAuth ─ + SSO_GOOGLE_ENABLED: "false" # enable Google OAuth authentication + SSO_GOOGLE_CLIENT_ID: "" # Google OAuth client ID + SSO_GOOGLE_CLIENT_SECRET: "" # Google OAuth client secret + SSO_GOOGLE_ADMIN_DOMAINS: "[]" # Google admin domains (JSON) + + # ─ IBM Security Verify OIDC ─ + SSO_IBM_VERIFY_ENABLED: "false" # enable IBM Security Verify OIDC authentication + SSO_IBM_VERIFY_CLIENT_ID: "" # IBM Security Verify client ID + SSO_IBM_VERIFY_CLIENT_SECRET: "" # IBM Security Verify client secret + SSO_IBM_VERIFY_ISSUER: "" # IBM Security Verify OIDC issuer URL + + # ─ Okta OIDC ─ + SSO_OKTA_ENABLED: "false" # enable Okta OIDC authentication + SSO_OKTA_CLIENT_ID: "" # Okta client ID + SSO_OKTA_CLIENT_SECRET: "" # Okta client secret + SSO_OKTA_ISSUER: "" # Okta issuer URL + + # ─ Personal Teams Configuration ─ + AUTO_CREATE_PERSONAL_TEAMS: "true" # enable automatic personal team creation for new users + PERSONAL_TEAM_PREFIX: personal # personal team naming prefix + MAX_TEAMS_PER_USER: "50" # maximum number of teams a user can belong to + MAX_MEMBERS_PER_TEAM: "100" # maximum number of members per team + INVITATION_EXPIRY_DAYS: "7" # number of days before team invitations expire + REQUIRE_EMAIL_VERIFICATION_FOR_INVITES: "true" # require email verification for team invitations + + # ─ OpenTelemetry Endpoints (Optional/Sensitive) ─ + OTEL_EXPORTER_OTLP_ENDPOINT: "" # OTLP endpoint (e.g., http://localhost:4317) + OTEL_EXPORTER_OTLP_HEADERS: "" # OTLP headers (comma-separated key=value) + OTEL_EXPORTER_JAEGER_ENDPOINT: "" # Jaeger endpoint + OTEL_EXPORTER_ZIPKIN_ENDPOINT: "" # Zipkin endpoint + OTEL_RESOURCE_ATTRIBUTES: "" # resource attributes (comma-separated key=value) + + # ─ Documentation & UI Settings (Sensitive) ─ + DOCS_ALLOW_BASIC_AUTH: "false" # allow basic auth for docs endpoints + # (derived URLs are defined in deployment-mcp.yaml) # ─ Optional database / redis overrides ─ diff --git a/deployment/k8s/postgres-pv.yaml b/deployment/k8s/postgres-pv.yaml index 4264b3458..8b1378917 100644 --- a/deployment/k8s/postgres-pv.yaml +++ b/deployment/k8s/postgres-pv.yaml @@ -1,15 +1 @@ -apiVersion: v1 -kind: PersistentVolume -metadata: - name: postgres-pv-volume - labels: - type: local - app: postgres -spec: - storageClassName: manual - capacity: - storage: 5Gi - accessModes: - - ReadWriteMany - hostPath: - path: "/mnt/data" + diff --git a/deployment/k8s/postgres-pvc.yaml b/deployment/k8s/postgres-pvc.yaml index cc995e0ae..8b1378917 100644 --- a/deployment/k8s/postgres-pvc.yaml +++ b/deployment/k8s/postgres-pvc.yaml @@ -1,13 +1 @@ -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-pv-claim - labels: - app: postgres -spec: - storageClassName: manual - accessModes: - - ReadWriteMany - resources: - requests: - storage: 5Gi + From e28edd11e9f2d5dd62281b360cce32a9d8735e41 Mon Sep 17 00:00:00 2001 From: popagruia Date: Wed, 8 Oct 2025 11:27:45 +0300 Subject: [PATCH 2/8] Fixed dependency of plugins enable Signed-off-by: popagruia --- .../templates/configmap-gateway-plugin.yaml | 12 ++++++++++++ .../mcp-stack/templates/deployment-mcpgateway.yaml | 4 ++-- charts/mcp-stack/values.schema.json | 14 ++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 charts/mcp-stack/templates/configmap-gateway-plugin.yaml diff --git a/charts/mcp-stack/templates/configmap-gateway-plugin.yaml b/charts/mcp-stack/templates/configmap-gateway-plugin.yaml new file mode 100644 index 000000000..be94512d2 --- /dev/null +++ b/charts/mcp-stack/templates/configmap-gateway-plugin.yaml @@ -0,0 +1,12 @@ +{{- if .Values.mcpContextForge.pluginConfig.enabled}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "mcp-stack.fullname" . }}-gateway-plugins + labels: + {{- include "mcp-stack.labels" . | nindent 4 }} + app.kubernetes.io/component: gateway +data: + config.yaml: | + {{- .Values.mcpContextForge.pluginConfig.plugins | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/charts/mcp-stack/templates/deployment-mcpgateway.yaml b/charts/mcp-stack/templates/deployment-mcpgateway.yaml index 5e975f85f..e412c4608 100644 --- a/charts/mcp-stack/templates/deployment-mcpgateway.yaml +++ b/charts/mcp-stack/templates/deployment-mcpgateway.yaml @@ -153,13 +153,13 @@ spec: resources: {{- toYaml .Values.mcpContextForge.resources | nindent 12 }} {{- /* Plugins enabled need the plugins configuration */}} - {{- if .Values.mcpContextForge.config.PLUGINS_ENABLED }} + {{- if .Values.mcpContextForge.pluginConfig.enabled }} volumeMounts: - name: plugin-config-volume mountPath: {{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE | default "/app/mcpgateway/plugins/config.yaml" }} subPath: config.yaml {{- end }} -{{- if .Values.mcpContextForge.config.PLUGINS_ENABLED }} +{{- if .Values.mcpContextForge.pluginConfig.enabled }} volumes: - name: plugin-config-volume configMap: diff --git a/charts/mcp-stack/values.schema.json b/charts/mcp-stack/values.schema.json index aad1be1be..3803e73cd 100644 --- a/charts/mcp-stack/values.schema.json +++ b/charts/mcp-stack/values.schema.json @@ -251,9 +251,19 @@ }, "additionalProperties": false }, + "pluginConfig": { - "type": "string", - "description": "Content of the plugin file" + "type": "object", + "description": "Content of the plugin file", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable pluginConfig loading for ingress", + "default": false + }, + "plugins": { + "type": "string", + "description": "contents of plugin file" }, "env": { "type": "object", From 402c71488be9318ded5e662ec696227ae7b8cc01 Mon Sep 17 00:00:00 2001 From: popagruia Date: Wed, 8 Oct 2025 12:19:34 +0300 Subject: [PATCH 3/8] Changed schema/defaults Signed-off-by: popagruia --- charts/mcp-stack/values.schema.json | 2 ++ charts/mcp-stack/values.yaml | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/charts/mcp-stack/values.schema.json b/charts/mcp-stack/values.schema.json index 3803e73cd..7dbc42d56 100644 --- a/charts/mcp-stack/values.schema.json +++ b/charts/mcp-stack/values.schema.json @@ -264,6 +264,8 @@ "plugins": { "type": "string", "description": "contents of plugin file" + } + } }, "env": { "type": "object", diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 2c656b1f5..2f5d2df05 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -11,6 +11,12 @@ global: # MCP CONTEXT-FORGE (Gateway / API tier) ######################################################################## mcpContextForge: + # --- Specific plugin file ----# + pluginConfig: + enabled: false + plugins: | + # plugin file + replicaCount: 2 # horizontal scaling for the gateway # --- HORIZONTAL POD AUTOSCALER -------------------------------------- From d13f5d040ba19d5d15830dcd3176f98808319d8f Mon Sep 17 00:00:00 2001 From: popagruia Date: Wed, 8 Oct 2025 13:28:46 +0300 Subject: [PATCH 4/8] Fixed plugin path Signed-off-by: popagruia --- charts/mcp-stack/templates/deployment-mcpgateway.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/mcp-stack/templates/deployment-mcpgateway.yaml b/charts/mcp-stack/templates/deployment-mcpgateway.yaml index e412c4608..c9af75a65 100644 --- a/charts/mcp-stack/templates/deployment-mcpgateway.yaml +++ b/charts/mcp-stack/templates/deployment-mcpgateway.yaml @@ -156,7 +156,7 @@ spec: {{- if .Values.mcpContextForge.pluginConfig.enabled }} volumeMounts: - name: plugin-config-volume - mountPath: {{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE | default "/app/mcpgateway/plugins/config.yaml" }} + mountPath: /app/{{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE }} subPath: config.yaml {{- end }} {{- if .Values.mcpContextForge.pluginConfig.enabled }} From f2dc93420a350c86d62efe973233909b2484a5fe Mon Sep 17 00:00:00 2001 From: popagruia Date: Wed, 8 Oct 2025 14:12:00 +0300 Subject: [PATCH 5/8] bring files from main Signed-off-by: popagruia --- deployment/k8s/postgres-pv.yaml | 16 +++++++++++++++- deployment/k8s/postgres-pvc.yaml | 14 +++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/deployment/k8s/postgres-pv.yaml b/deployment/k8s/postgres-pv.yaml index 8b1378917..4264b3458 100644 --- a/deployment/k8s/postgres-pv.yaml +++ b/deployment/k8s/postgres-pv.yaml @@ -1 +1,15 @@ - +apiVersion: v1 +kind: PersistentVolume +metadata: + name: postgres-pv-volume + labels: + type: local + app: postgres +spec: + storageClassName: manual + capacity: + storage: 5Gi + accessModes: + - ReadWriteMany + hostPath: + path: "/mnt/data" diff --git a/deployment/k8s/postgres-pvc.yaml b/deployment/k8s/postgres-pvc.yaml index 8b1378917..cc995e0ae 100644 --- a/deployment/k8s/postgres-pvc.yaml +++ b/deployment/k8s/postgres-pvc.yaml @@ -1 +1,13 @@ - +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-pv-claim + labels: + app: postgres +spec: + storageClassName: manual + accessModes: + - ReadWriteMany + resources: + requests: + storage: 5Gi From 802223cdd3d01288af962908551cf0aabb100720 Mon Sep 17 00:00:00 2001 From: popagruia Date: Thu, 9 Oct 2025 10:32:46 +0300 Subject: [PATCH 6/8] Fixed rebase Signed-off-by: popagruia --- charts/mcp-stack/values.yaml | 407 +---------------------------------- 1 file changed, 7 insertions(+), 400 deletions(-) diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 2f5d2df05..26bb8906e 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -11,12 +11,12 @@ global: # MCP CONTEXT-FORGE (Gateway / API tier) ######################################################################## mcpContextForge: - # --- Specific plugin file ----# + # --- Specific plugin file ----# pluginConfig: - enabled: false - plugins: | - # plugin file - + enabled: false + plugins: | + # plugin file + replicaCount: 2 # horizontal scaling for the gateway # --- HORIZONTAL POD AUTOSCALER -------------------------------------- @@ -127,7 +127,6 @@ mcpContextForge: # host: redis # uncomment to override the generated name port: 6379 - #################################################################### # PLAIN-TEXT (NON-SECRET) SETTINGS # Rendered into a ConfigMap; readable by anyone with GET access. @@ -290,8 +289,8 @@ mcpContextForge: User-agent: * Disallow: / - # MCP Gateway is a private API gateway - # Public crawling is disabled by default + # MCP Gateway is a private API gateway + # Public crawling is disabled by default WELL_KNOWN_SECURITY_TXT: "" # security.txt content (RFC 9116) WELL_KNOWN_CUSTOM_FILES: "{}" # additional custom well-known files (JSON) WELL_KNOWN_CACHE_MAX_AGE: "3600" # cache control for well-known files (seconds) @@ -506,398 +505,6 @@ mcpContextForge: # ─ Documentation & UI Settings (Sensitive) ─ DOCS_ALLOW_BASIC_AUTH: "false" # allow basic auth for docs endpoints - # Plugin Configuration - PLUGINS_ENABLED: false - PLUGIN_CONFIG_FILE: "/app/plugins/config_vault.yaml" - - # (derived URLs are defined in deployment-mcp.yaml) - - # ─ Optional database / redis overrides ─ - # DATABASE_URL: "postgresql://admin:s3cr3t@db.acme.com:5432/prod" # override the auto-generated URL - # REDIS_URL: "redis://cache.acme.com:6379/0" # override the auto-generated URL - - #################################################################### - # Names of ConfigMap / Secret are resolved by templates; leave as-is. - #################################################################### - envFrom: - - secretRef: - name: mcp-gateway-secret - - configMapRef: - name: mcp-gateway-config - -######################################################################## -# DATABASE MIGRATION (Alembic) -# Runs as a Job before mcpgateway deployment -######################################################################## -migration: - enabled: true # Set to false to skip migrations - - # Job configuration - restartPolicy: Never # Job should not restart on failure - backoffLimit: 3 # Retry up to 3 times before giving up - activeDeadlineSeconds: 600 # Kill job after 10 minutes - - # Use same image as mcpgateway - image: - repository: ghcr.io/ibm/mcp-context-forge - tag: latest # Should match mcpContextForge.image.tag - #pullPolicy: IfNotPresent - pullPolicy: Always # always pull the latest image; useful for dev/testing - - # Resource limits for the migration job - resources: - limits: - cpu: 200m - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi - - # Migration command configuration - command: - waitForDb: "python3 /app/mcpgateway/utils/db_isready.py --max-tries 30 --interval 2 --timeout 5" - migrate: "alembic upgrade head || echo '⚠️ Migration check failed'" - -######################################################################## -# POSTGRES DATABASE -######################################################################## -postgres: - enabled: true - - image: - repository: postgres - tag: "17" - pullPolicy: IfNotPresent - - service: - type: ClusterIP - port: 5432 - - # PersistentVolumeClaim for data durability - persistence: - enabled: true - storageClassName: manual # pick a StorageClass (e.g. gp2, standard) - accessModes: [ReadWriteMany] - size: 5Gi - - # Leave blank to autogenerate -mcp-stack-postgres-secret. - existingSecret: "" - - credentials: # used only when existingSecret is blank - database: postgresdb - user: admin - password: test123 # CHANGE ME in production! - - # ─── Resource limits & requests ─── - resources: - limits: - cpu: 1000m # 1 core hard cap - memory: 1Gi - requests: - cpu: 500m # guaranteed half-core - memory: 64Mi - - # ─── Health & readiness probes ─── - probes: - readiness: - type: exec - command: ["pg_isready", "-U", "$(POSTGRES_USER)"] - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 3 - successThreshold: 1 - failureThreshold: 3 - - liveness: - type: exec - command: ["pg_isready", "-U", "$(POSTGRES_USER)"] - initialDelaySeconds: 10 - periodSeconds: 15 - timeoutSeconds: 3 - successThreshold: 1 - failureThreshold: 5 - -######################################################################## -# REDIS CACHE -######################################################################## -redis: - enabled: true - - image: - repository: redis - tag: latest - pullPolicy: IfNotPresent - - service: - type: ClusterIP - port: 6379 - - # ─── Resource limits & requests ─── - resources: - limits: - cpu: 100m # cap at 0.1 core, 256 MiB - memory: 256Mi - requests: - cpu: 50m # reserve 0.05 core, 128 MiB - memory: 16Mi - - # ─── Health & readiness probes ─── - probes: - readiness: - type: exec - command: ["redis-cli", "PING"] - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 3 - - liveness: - type: exec - command: ["redis-cli", "PING"] - initialDelaySeconds: 5 - periodSeconds: 15 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 5 - -######################################################################## -# PGADMIN - Web UI for Postgres -######################################################################## -pgadmin: - enabled: true - - image: - repository: dpage/pgadmin4 - tag: latest - pullPolicy: IfNotPresent - - service: - type: ClusterIP - port: 80 - - env: - email: admin@example.com - password: admin123 # CHANGE ME in production! - - # ─── Resource limits & requests ─── - resources: - limits: - cpu: 200m # cap at 0.2 core, 256 MiB - memory: 256Mi - requests: - cpu: 100m # reserve 0.1 core, 128 MiB - memory: 128Mi - - # ─── Health & readiness probes ─── - probes: - readiness: - type: http - path: /misc/ping # lightweight endpoint - port: 80 - initialDelaySeconds: 60 # pgAdmin needs more time to initialize - periodSeconds: 10 - timeoutSeconds: 5 # increased timeout - successThreshold: 1 - failureThreshold: 5 # more tolerance for failures - - liveness: - type: http - path: /misc/ping - port: 80 - initialDelaySeconds: 90 # even longer for liveness - periodSeconds: 20 # check less frequently - timeoutSeconds: 5 # increased timeout - successThreshold: 1 - failureThreshold: 3 # less aggressive killing - -######################################################################## -# REDIS-COMMANDER - Web UI for Redis -######################################################################## -redisCommander: - enabled: true - - image: - repository: rediscommander/redis-commander - tag: latest - pullPolicy: IfNotPresent - - service: - type: ClusterIP - port: 8081 - - # ─── Resource limits & requests ─── - resources: - limits: - cpu: 100m # cap at 0.1 core, 256 MiB - memory: 256Mi - requests: - cpu: 50m # reserve 0.05 core, 128 MiB - memory: 128Mi - - # ─── Health & readiness probes ─── - probes: - readiness: - type: http - path: / # root returns 200 OK - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 10 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 3 - - liveness: - type: http - path: / - port: 8081 - initialDelaySeconds: 10 - periodSeconds: 15 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 5 - -######################################################################## -# MCP-FAST-TIME-SERVER - optional high-performance time server for MCP (go) -# Provides a fast implementation including SSE and Streamable HTTP -######################################################################## -mcpFastTimeServer: - enabled: true # switch to true to deploy - replicaCount: 2 - image: - repository: ghcr.io/ibm/fast-time-server - tag: "0.7.0" - pullPolicy: IfNotPresent - port: 8080 - - # Ingress example (leave as-is if you already have it) - ingress: - enabled: true - path: /fast-time - pathType: Prefix - servicePort: 80 - - # ─── Health & readiness probes ─── - probes: - readiness: - type: http - path: /health - port: 8080 - initialDelaySeconds: 3 - periodSeconds: 10 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 3 - - liveness: - type: http - path: /health - port: 8080 - initialDelaySeconds: 3 - periodSeconds: 15 - timeoutSeconds: 2 - successThreshold: 1 - failureThreshold: 3 - - # Tiny Go process: ~10 MB runtime footprint - resources: - limits: - cpu: 50m # ~5 % of a core - memory: 64Mi - requests: - cpu: 25m - memory: 10Mi - #################################################################### - secret: - # ─ Admin & auth ─ - BASIC_AUTH_USER: admin # username for basic-auth login - BASIC_AUTH_PASSWORD: changeme # password for basic-auth (CHANGE IN PROD!) - AUTH_REQUIRED: "true" # enforce authentication globally (true/false) - JWT_SECRET_KEY: my-test-key # secret key used to sign JWT tokens - JWT_ALGORITHM: HS256 # signing algorithm for JWT tokens - JWT_AUDIENCE: mcpgateway-api # JWT audience claim for token validation - JWT_ISSUER: mcpgateway # JWT issuer claim for token validation - TOKEN_EXPIRY: "10080" # JWT validity (minutes); 10080 = 7 days - REQUIRE_TOKEN_EXPIRATION: "false" # require all JWT tokens to have expiration claims - AUTH_ENCRYPTION_SECRET: my-test-salt # passphrase to derive AES key for secure storage - - # ─ Email-Based Authentication ─ - EMAIL_AUTH_ENABLED: "true" # enable email-based authentication system - PLATFORM_ADMIN_EMAIL: admin@example.com # email for bootstrap platform admin user - PLATFORM_ADMIN_PASSWORD: changeme # password for bootstrap platform admin user - PLATFORM_ADMIN_FULL_NAME: Platform Administrator # full name for bootstrap platform admin - - # ─ Password Hashing & Security ─ - ARGON2ID_TIME_COST: "3" # Argon2id time cost (iterations) - ARGON2ID_MEMORY_COST: "65536" # Argon2id memory cost in KiB - ARGON2ID_PARALLELISM: "1" # Argon2id parallelism (threads) - PASSWORD_MIN_LENGTH: "8" # minimum password length - PASSWORD_REQUIRE_UPPERCASE: "false" # require uppercase letters in passwords - PASSWORD_REQUIRE_LOWERCASE: "false" # require lowercase letters in passwords - PASSWORD_REQUIRE_NUMBERS: "false" # require numbers in passwords - PASSWORD_REQUIRE_SPECIAL: "false" # require special characters in passwords - MAX_FAILED_LOGIN_ATTEMPTS: "5" # maximum failed login attempts before lockout - ACCOUNT_LOCKOUT_DURATION_MINUTES: "30" # account lockout duration in minutes - - # ─ MCP Client Authentication ─ - MCP_CLIENT_AUTH_ENABLED: "true" # enable JWT authentication for MCP client operations - TRUST_PROXY_AUTH: "false" # trust proxy authentication headers - PROXY_USER_HEADER: X-Authenticated-User # header containing authenticated username from proxy - - # ─ OAuth Configuration ─ - OAUTH_REQUEST_TIMEOUT: "30" # OAuth request timeout in seconds - OAUTH_MAX_RETRIES: "3" # maximum retries for OAuth token requests - - # ─ SSO (Single Sign-On) Configuration ─ - SSO_ENABLED: "false" # master switch for Single Sign-On authentication - SSO_AUTO_CREATE_USERS: "true" # automatically create users from SSO providers - SSO_TRUSTED_DOMAINS: "[]" # trusted email domains (JSON array) - SSO_PRESERVE_ADMIN_AUTH: "true" # preserve local admin authentication when SSO enabled - SSO_REQUIRE_ADMIN_APPROVAL: "false" # require admin approval for new SSO registrations - SSO_AUTO_ADMIN_DOMAINS: "[]" # email domains that automatically get admin privileges - - # ─ GitHub OAuth ─ - SSO_GITHUB_ENABLED: "false" # enable GitHub OAuth authentication - SSO_GITHUB_CLIENT_ID: "" # GitHub OAuth client ID - SSO_GITHUB_CLIENT_SECRET: "" # GitHub OAuth client secret - SSO_GITHUB_ADMIN_ORGS: "[]" # GitHub orgs granting admin privileges (JSON) - - # ─ Google OAuth ─ - SSO_GOOGLE_ENABLED: "false" # enable Google OAuth authentication - SSO_GOOGLE_CLIENT_ID: "" # Google OAuth client ID - SSO_GOOGLE_CLIENT_SECRET: "" # Google OAuth client secret - SSO_GOOGLE_ADMIN_DOMAINS: "[]" # Google admin domains (JSON) - - # ─ IBM Security Verify OIDC ─ - SSO_IBM_VERIFY_ENABLED: "false" # enable IBM Security Verify OIDC authentication - SSO_IBM_VERIFY_CLIENT_ID: "" # IBM Security Verify client ID - SSO_IBM_VERIFY_CLIENT_SECRET: "" # IBM Security Verify client secret - SSO_IBM_VERIFY_ISSUER: "" # IBM Security Verify OIDC issuer URL - - # ─ Okta OIDC ─ - SSO_OKTA_ENABLED: "false" # enable Okta OIDC authentication - SSO_OKTA_CLIENT_ID: "" # Okta client ID - SSO_OKTA_CLIENT_SECRET: "" # Okta client secret - SSO_OKTA_ISSUER: "" # Okta issuer URL - - # ─ Personal Teams Configuration ─ - AUTO_CREATE_PERSONAL_TEAMS: "true" # enable automatic personal team creation for new users - PERSONAL_TEAM_PREFIX: personal # personal team naming prefix - MAX_TEAMS_PER_USER: "50" # maximum number of teams a user can belong to - MAX_MEMBERS_PER_TEAM: "100" # maximum number of members per team - INVITATION_EXPIRY_DAYS: "7" # number of days before team invitations expire - REQUIRE_EMAIL_VERIFICATION_FOR_INVITES: "true" # require email verification for team invitations - - # ─ OpenTelemetry Endpoints (Optional/Sensitive) ─ - OTEL_EXPORTER_OTLP_ENDPOINT: "" # OTLP endpoint (e.g., http://localhost:4317) - OTEL_EXPORTER_OTLP_HEADERS: "" # OTLP headers (comma-separated key=value) - OTEL_EXPORTER_JAEGER_ENDPOINT: "" # Jaeger endpoint - OTEL_EXPORTER_ZIPKIN_ENDPOINT: "" # Zipkin endpoint - OTEL_RESOURCE_ATTRIBUTES: "" # resource attributes (comma-separated key=value) - - # ─ Documentation & UI Settings (Sensitive) ─ - DOCS_ALLOW_BASIC_AUTH: "false" # allow basic auth for docs endpoints - # (derived URLs are defined in deployment-mcp.yaml) # ─ Optional database / redis overrides ─ From 452f612eca11794fdf37376b32e50c8f2c077303 Mon Sep 17 00:00:00 2001 From: popagruia Date: Mon, 3 Nov 2025 12:28:34 +0200 Subject: [PATCH 7/8] Remove uwanted default value Signed-off-by: popagruia --- charts/mcp-stack/values.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 26bb8906e..1d98c56e6 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -99,9 +99,6 @@ mcpContextForge: host: gateway.local # CHANGE to your FQDN (e.g. api.example.com) path: / pathType: Prefix - annotations: - nginx.ingress.kubernetes.io/rewrite-target: / - # cert-manager.io/cluster-issuer: letsencrypt-prod # Uncomment to enable automatic TLS cert generation tls: enabled: false # Set to true to enable TLS secretName: "" # Name of the TLS secret (auto-generated if empty) From edd393d612f9ffddb14a8ff4b726b38a03d549d9 Mon Sep 17 00:00:00 2001 From: Mihai Criveti Date: Wed, 5 Nov 2025 01:58:26 +0000 Subject: [PATCH 8/8] fix: improve plugin config chart implementation - Add newline at end of configmap-gateway-plugin.yaml - Improve schema descriptions for pluginConfig - Restore ingress annotations field (as empty object) - Fix volumeMounts indentation in deployment - Ensure backward compatibility with existing deployments Signed-off-by: Mihai Criveti --- charts/mcp-stack/templates/configmap-gateway-plugin.yaml | 2 +- charts/mcp-stack/templates/deployment-mcpgateway.yaml | 7 ++++--- charts/mcp-stack/values.schema.json | 6 +++--- charts/mcp-stack/values.yaml | 3 +++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/charts/mcp-stack/templates/configmap-gateway-plugin.yaml b/charts/mcp-stack/templates/configmap-gateway-plugin.yaml index be94512d2..831e0fa6e 100644 --- a/charts/mcp-stack/templates/configmap-gateway-plugin.yaml +++ b/charts/mcp-stack/templates/configmap-gateway-plugin.yaml @@ -9,4 +9,4 @@ metadata: data: config.yaml: | {{- .Values.mcpContextForge.pluginConfig.plugins | nindent 4 }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/mcp-stack/templates/deployment-mcpgateway.yaml b/charts/mcp-stack/templates/deployment-mcpgateway.yaml index c9af75a65..2529dd31d 100644 --- a/charts/mcp-stack/templates/deployment-mcpgateway.yaml +++ b/charts/mcp-stack/templates/deployment-mcpgateway.yaml @@ -152,12 +152,13 @@ spec: # Resource requests / limits resources: {{- toYaml .Values.mcpContextForge.resources | nindent 12 }} + {{- /* Plugins enabled need the plugins configuration */}} {{- if .Values.mcpContextForge.pluginConfig.enabled }} volumeMounts: - - name: plugin-config-volume - mountPath: /app/{{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE }} - subPath: config.yaml + - name: plugin-config-volume + mountPath: /app/{{ .Values.mcpContextForge.config.PLUGIN_CONFIG_FILE }} + subPath: config.yaml {{- end }} {{- if .Values.mcpContextForge.pluginConfig.enabled }} volumes: diff --git a/charts/mcp-stack/values.schema.json b/charts/mcp-stack/values.schema.json index 7dbc42d56..d986cd186 100644 --- a/charts/mcp-stack/values.schema.json +++ b/charts/mcp-stack/values.schema.json @@ -254,16 +254,16 @@ "pluginConfig": { "type": "object", - "description": "Content of the plugin file", + "description": "Plugin configuration via ConfigMap", "properties": { "enabled": { "type": "boolean", - "description": "Enable pluginConfig loading for ingress", + "description": "Enable plugin configuration loading via ConfigMap", "default": false }, "plugins": { "type": "string", - "description": "contents of plugin file" + "description": "Plugin configuration file contents (YAML)" } } }, diff --git a/charts/mcp-stack/values.yaml b/charts/mcp-stack/values.yaml index 1d98c56e6..958c7507e 100644 --- a/charts/mcp-stack/values.yaml +++ b/charts/mcp-stack/values.yaml @@ -99,6 +99,9 @@ mcpContextForge: host: gateway.local # CHANGE to your FQDN (e.g. api.example.com) path: / pathType: Prefix + annotations: {} # Custom ingress annotations (optional) + # nginx.ingress.kubernetes.io/rewrite-target: / + # cert-manager.io/cluster-issuer: letsencrypt-prod tls: enabled: false # Set to true to enable TLS secretName: "" # Name of the TLS secret (auto-generated if empty)