Skip to content

Commit 26bfd8e

Browse files
jiaenrenclaude
andcommitted
Derive the MCP proxy configuration and share OSMO's Redis
Three reductions to what a deployer must state, none of which changes what the deployment does. **Values the chart already knew.** accessTokenAudience had to equal resourceUrl, scope had to equal resourceUrl plus the scope name, and the issuer had to be resourceUrl minus /mcp -- and the chart refused to render unless each matched what it had already computed. A deployer was asked for an answer the chart held, then rejected for giving a different one. They are derived now, so the 30-line cross-checking block in MCPAuthConfig, the matching Helm fail blocks, the three environment variables carrying the restated values, and the three CI cases that existed only to prove the cross-checks fired all go. This also drops trustedHttpsRedirectOrigins, which no deployment sets and which cost a CSV environment variable, two properties, a validator branch and a Helm regex loop. Native clients use loopback redirects, still allowed. **A URL discovery publishes.** accessTokenJwksUrl is jwks_uri in every OIDC discovery document, which FastMCP already fetches at startup. OSMO hand-built a JWTVerifier only to pin it, and carried a process-lifetime httpx client to serve it. OIDCProxy builds the verifier now, and OSMO overrides only what discovery cannot supply: an Entra resource application configured for v1 access tokens issues them from https://sts.windows.net/<tenant>/ even when its discovery document advertises the v2.0 issuer, so accessTokenIssuer stays configured. The audience is applied inside that override rather than through OIDCProxy's own audience argument, because that argument is forwarded to the provider's authorize and token endpoints (oidc_proxy.py:432-434), which Entra does not accept. An existing test asserting that no extra token parameters are sent caught this. **Redis that every sibling already shares.** MCP carried its own host, port and TLS settings. serviceName and port fell back to services.redis but tlsEnabled did not, so a deployment whose Redis requires TLS could satisfy every other service and still CrashLoop MCP. All three come from services.redis now; only dbNumber stays, to isolate proxy state from OSMO's other Redis users, and its default moves off 0 for that reason. The chart also refused more than one MCP replica, on the premise that FastMCP serializes token refresh within a process. FastMCP says the opposite -- "All state is stored in the configured client_storage backend (Redis, disk, etc.) enabling horizontal scaling across multiple instances" (oauth_proxy/proxy.py:212-213), with :1903-1912 handling the distributed refresh race explicitly. The rule also contradicted itself, since sharing state through Redis only matters across replicas it forbade. The negative test asserting the ban is replaced by a positive one that two replicas render, negative-tested by reintroducing a ban. Required OIDC proxy values: 10 -> 6. Note for anyone using --config rather than environment variables: a stale file carrying issuer_url, auth_scope, oidc_access_token_audience or oidc_access_token_jwks_url now fails at startup with an unrecognized-key error rather than being ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 81f9c92 commit 26bfd8e

9 files changed

Lines changed: 151 additions & 257 deletions

File tree

deployments/charts/service/README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,21 +100,17 @@ destination, but it cannot validate external DNS.
100100
| `services.mcp.scopes` | OAuth scopes advertised in direct-provider mode; ignored when `oidcProxy.enabled` is true. | `[]` |
101101
| `services.mcp.allowedOrigins` | Exact browser origins permitted on `/mcp`; native clients normally omit `Origin`. | `[]` |
102102
| `services.mcp.requestTimeoutSeconds` | Total timeout for each MCP-initiated Gateway request, from 1 through 60 seconds. | `10` |
103-
| `services.mcp.replicas` | Number of MCP replicas. Must remain `1` with `oidcProxy.enabled` because FastMCP 3.4.7 refresh serialization is process-local. | `1` |
103+
| `services.mcp.replicas` | Number of MCP replicas. The OIDC proxy keeps its state in Redis, so it scales out. | `1` |
104104
| `services.mcp.extraEnv` | Additional non-managed environment variables. It cannot override MCP host, port, Gateway origin, or request timeout. | `[]` |
105105
| `services.mcp.extraVolumeMounts` | Additional MCP container volume mounts, including Vault-injected credential files. | `[]` |
106106
| `services.mcp.extraVolumes` | Additional MCP pod volumes. | `[]` |
107107
| `services.mcp.oidcProxy.enabled` | Enable FastMCP's built-in OIDC proxy inside the existing MCP process. It advertises CIMD and retains DCR as a compatibility fallback. | `false` |
108-
| `services.mcp.oidcProxy.scope` | Full delegated scope URI advertised to MCP clients and requested upstream, normally `<resourceUrl>/access_as_user`. | `""` |
109-
| `services.mcp.oidcProxy.trustedHttpsRedirectOrigins` | Exact HTTPS origins allowed for pre-registered web-client redirects; native clients use loopback redirects. | `[]` |
110108
| `services.mcp.oidcProxy.oidc.configUrl` | Upstream OIDC discovery URL. | `""` |
111109
| `services.mcp.oidcProxy.oidc.clientId` | Administrator-managed confidential OIDC application client ID. | `""` |
112110
| `services.mcp.oidcProxy.oidc.clientSecretFile` | Mounted file containing the upstream OIDC client secret. | `/etc/osmo/mcp-auth/client-secret` |
113111
| `services.mcp.oidcProxy.oidc.accessTokenIssuer` | Exact issuer required on upstream API access tokens. | `""` |
114-
| `services.mcp.oidcProxy.oidc.accessTokenAudience` | Exact OSMO MCP resource audience required on upstream API access tokens; must equal `resourceUrl`. | `""` |
115-
| `services.mcp.oidcProxy.oidc.accessTokenJwksUrl` | HTTPS JWKS URL used to verify upstream API access tokens. | `""` |
116112
| `services.mcp.oidcProxy.oidc.accessTokenRequiredScope` | Short scope value required in the upstream access token's `scp` claim. | `access_as_user` |
117-
| `services.mcp.oidcProxy.redis` | Redis connection used by FastMCP for registrations, authorization state, and encrypted upstream tokens; blank host/port inherit `services.redis`. | See `values.yaml` |
113+
| `services.mcp.oidcProxy.redis.dbNumber` | Logical Redis database for proxy state. Host, port and TLS come from `services.redis`. | `1` |
118114
| `services.mcp.oidcProxy.accessTokenTtlSeconds` | Lifetime of proxy access tokens, from 60 through 3600 seconds. | `600` |
119115
| `services.mcp.oidcProxy.refreshTokenTtlSeconds` | Lifetime of proxy refresh tokens, from 300 through 604800 seconds. | `28800` |
120116
| `services.mcp.oidcProxy.upstreamTimeoutSeconds` | Timeout for upstream OIDC requests, from 1 through 60 seconds. | `10` |
@@ -123,7 +119,7 @@ destination, but it cannot validate external DNS.
123119
The in-process proxy follows OSMO's OIDC profile: a full delegated scope URI is requested
124120
from the upstream provider while its short suffix is enforced in the verified
125121
API access token. Register the single stable upstream redirect URI
126-
`<resourceUrl origin>/auth/callback`. MCP clients still configure only `resourceUrl`.
122+
`<resourceUrl origin>/mcp/auth/callback`. MCP clients still configure only `resourceUrl`.
127123
CIMD-capable clients identify themselves with a hosted metadata document;
128124
older clients can use FastMCP's `/register` DCR endpoint. Both paths use
129125
authorization-code flow with PKCE and end in the same OSMO Gateway and semantic

deployments/charts/service/ci/mcp-oidc-proxy-values.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,13 @@ services:
2323
- http://localhost:6274
2424
oidcProxy:
2525
enabled: true
26-
scope: https://osmo.example.com/mcp/access_as_user
27-
trustedHttpsRedirectOrigins:
28-
- https://trusted-client.example.com
2926
oidc:
3027
configUrl: https://login.example.com/example-tenant/v2.0/.well-known/openid-configuration
3128
clientId: example-mcp-proxy-client
3229
accessTokenIssuer: https://sts.example.com/example-tenant/
33-
accessTokenAudience: https://osmo.example.com/mcp
34-
accessTokenJwksUrl: https://login.example.com/example-tenant/discovery/v2.0/keys
3530
accessTokenRequiredScope: access_as_user
3631
redis:
37-
serviceName: proxy-redis.example.internal
38-
port: 6380
3932
dbNumber: 14
40-
tlsEnabled: true
4133
passwordFile: /etc/osmo/mcp-auth/redis-password
4234
keyPrefix: test:mcp-auth
4335
existingSecret:

deployments/charts/service/ci/validate-mcp-chart.sh

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -162,18 +162,14 @@ assert_env_value "$MCP_MANIFEST" OSMO_MCP_AUTH_ENABLED false
162162
assert_route_omits "$RENDERED_MANIFEST" osmo-mcp 'typed_per_filter_config:'
163163

164164
for expected in \
165-
'name: OSMO_MCP_AUTH_ISSUER_URL' \
166165
'name: OSMO_MCP_AUTH_RESOURCE_URL' \
167-
'name: OSMO_MCP_AUTH_SCOPE' \
168166
'name: OSMO_MCP_AUTH_REDIS_URL' \
169167
'name: OSMO_MCP_AUTH_REDIS_CONNECT_TIMEOUT_SECONDS' \
170168
'name: OSMO_MCP_AUTH_REDIS_OPERATION_TIMEOUT_SECONDS' \
171169
'name: OSMO_MCP_AUTH_OIDC_CONFIG_URL' \
172170
'name: OSMO_MCP_AUTH_OIDC_CLIENT_ID' \
173171
'name: OSMO_MCP_AUTH_OIDC_CLIENT_SECRET_FILE' \
174172
'name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_ISSUER' \
175-
'name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_AUDIENCE' \
176-
'name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_JWKS_URL' \
177173
'name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_REQUIRED_SCOPE' \
178174
'name: OSMO_MCP_AUTH_UPSTREAM_TIMEOUT_SECONDS' \
179175
'secretName: mcp-oidc-proxy-secrets'; do
@@ -208,10 +204,14 @@ assert_route_contains "$PROXY_RENDERED_MANIFEST" mcp-health-not-public \
208204
assert_route_contains "$PROXY_RENDERED_MANIFEST" mcp-health-not-public \
209205
'envoy.filters.http.ext_authz:'
210206
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_ENABLED true
211-
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_ISSUER_URL https://osmo.example.com
212207
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_RESOURCE_URL https://osmo.example.com/mcp
213-
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_SCOPE https://osmo.example.com/mcp/access_as_user
214-
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_REDIS_URL rediss://proxy-redis.example.internal:6380/14
208+
assert_env_value "$PROXY_MCP_MANIFEST" OSMO_MCP_AUTH_REDIS_URL rediss://redis:6379/14
209+
210+
# The proxy keeps all state in Redis, so scaling out must render.
211+
if ! helm template test-release "$CHART_DIR" -f "$PROXY_VALUES_FILE" \
212+
--set 'services.mcp.replicas=2' >/dev/null 2>&1; then
213+
fail "MCP OIDC proxy with two replicas failed to render"
214+
fi
215215

216216
# FastMCP advertises its endpoints under /mcp; the gateway publishes that
217217
# prefix and rewrites it off before forwarding to the root paths the MCP SDK
@@ -260,16 +260,6 @@ expect_render_failure "$PROXY_VALUES_FILE" \
260260
'services.mcp.oidcProxy.enabled requires services.mcp.enabled=true' \
261261
--set 'services.mcp.enabled=false'
262262

263-
expect_render_failure "$PROXY_VALUES_FILE" \
264-
'OIDC proxy with multiple replicas' \
265-
'services.mcp.replicas must be 1 when services.mcp.oidcProxy.enabled=true' \
266-
--set 'services.mcp.replicas=2'
267-
268-
expect_render_failure "$PROXY_VALUES_FILE" \
269-
'invalid OIDC proxy Redis port' \
270-
'services.mcp.oidcProxy.redis.port must be between 1 and 65535' \
271-
--set 'services.mcp.oidcProxy.redis.port=0'
272-
273263
expect_render_failure "$PROXY_VALUES_FILE" \
274264
'OIDC proxy Redis database below range' \
275265
'services.mcp.oidcProxy.redis.dbNumber must be between 0 and 15' \
@@ -315,16 +305,6 @@ expect_render_failure "$PROXY_VALUES_FILE" \
315305
'services.mcp.oidcProxy.upstreamTimeoutSeconds must be between 1 and 60' \
316306
--set 'services.mcp.oidcProxy.upstreamTimeoutSeconds=61'
317307

318-
expect_render_failure "$PROXY_VALUES_FILE" \
319-
'OIDC access-token audience mismatch' \
320-
'services.mcp.oidcProxy.oidc.accessTokenAudience must equal services.mcp.resourceUrl' \
321-
--set 'services.mcp.oidcProxy.oidc.accessTokenAudience=https://other.example.com/mcp'
322-
323-
expect_render_failure "$PROXY_VALUES_FILE" \
324-
'OIDC full scope mismatch' \
325-
'services.mcp.oidcProxy.scope must equal services.mcp.resourceUrl followed by oidc.accessTokenRequiredScope' \
326-
--set 'services.mcp.oidcProxy.scope=https://other.example.com/access_as_user'
327-
328308
expect_render_failure "$PROXY_VALUES_FILE" \
329309
'relative OIDC client-secret path' \
330310
'services.mcp.oidcProxy.oidc.clientSecretFile must be an absolute path' \
@@ -345,14 +325,9 @@ expect_render_failure "$PROXY_VALUES_FILE" \
345325
'services.mcp.oidcProxy.redis.passwordFile must be <existingSecret.mountPath>/redis-password' \
346326
--set 'services.mcp.oidcProxy.redis.passwordFile=/other/redis-password'
347327

348-
expect_render_failure "$PROXY_VALUES_FILE" \
349-
'untrusted redirect origin with a path' \
350-
'trustedHttpsRedirectOrigins entries must be exact HTTPS origins' \
351-
--set 'services.mcp.oidcProxy.trustedHttpsRedirectOrigins[0]=https://trusted.example.com/callback'
352-
353328
expect_render_failure "$PROXY_VALUES_FILE" \
354329
'managed OIDC proxy issuer override' \
355-
'services.mcp.extraEnv must not override managed variable OSMO_MCP_AUTH_ISSUER_URL' \
356-
--set-json 'services.mcp.extraEnv=[{"name":"OSMO_MCP_AUTH_ISSUER_URL","value":"https://evil.example.com"}]'
330+
'services.mcp.extraEnv must not override managed variable OSMO_MCP_AUTH_OIDC_CLIENT_ID' \
331+
--set-json 'services.mcp.extraEnv=[{"name":"OSMO_MCP_AUTH_OIDC_CLIENT_ID","value":"evil-client"}]'
357332

358333
echo 'MCP chart validation passed'

deployments/charts/service/templates/mcp-service.yaml

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -25,66 +25,30 @@
2525
{{- if not (regexMatch "^([1-9]|[1-5][0-9]|60)$" $requestTimeoutSeconds) }}
2626
{{- fail "services.mcp.requestTimeoutSeconds must be between 1 and 60" }}
2727
{{- end }}
28-
{{- $scope := "" }}
2928
{{- $oidcConfigUrl := "" }}
3029
{{- $oidcClientId := "" }}
3130
{{- $oidcClientSecretFile := "" }}
3231
{{- $oidcAccessTokenIssuer := "" }}
33-
{{- $oidcAccessTokenAudience := "" }}
34-
{{- $oidcAccessTokenJwksUrl := "" }}
3532
{{- $oidcAccessTokenRequiredScope := "" }}
3633
{{- $redisKeyPrefix := "" }}
3734
{{- $redisUrl := "" }}
3835
{{- if $oidcProxyEnabled }}
39-
{{- if ne (int $mcp.replicas) 1 }}
40-
{{- fail "services.mcp.replicas must be 1 when services.mcp.oidcProxy.enabled=true" }}
41-
{{- end }}
42-
{{- if not (kindIs "slice" $oidcProxy.trustedHttpsRedirectOrigins) }}
43-
{{- fail "services.mcp.oidcProxy.trustedHttpsRedirectOrigins must be a list" }}
44-
{{- end }}
45-
{{- range $origin := $oidcProxy.trustedHttpsRedirectOrigins }}
46-
{{- if or (not (kindIs "string" $origin)) (not (regexMatch "^https://[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?(:[0-9]{1,5})?$" $origin)) }}
47-
{{- fail "services.mcp.oidcProxy.trustedHttpsRedirectOrigins entries must be exact HTTPS origins" }}
48-
{{- end }}
49-
{{- $originPortSuffix := regexFind ":[0-9]+$" $origin }}
50-
{{- if $originPortSuffix }}
51-
{{- $originPort := trimPrefix ":" $originPortSuffix | int }}
52-
{{- if or (lt $originPort 1) (gt $originPort 65535) }}
53-
{{- fail "services.mcp.oidcProxy.trustedHttpsRedirectOrigins ports must be between 1 and 65535" }}
54-
{{- end }}
55-
{{- end }}
56-
{{- end }}
57-
{{- $scope = required "services.mcp.oidcProxy.scope is required when the OIDC proxy is enabled" $oidcProxy.scope }}
5836
{{- $oidcConfigUrl = required "services.mcp.oidcProxy.oidc.configUrl is required when the OIDC proxy is enabled" $oidcProxy.oidc.configUrl }}
5937
{{- $oidcClientId = required "services.mcp.oidcProxy.oidc.clientId is required when the OIDC proxy is enabled" $oidcProxy.oidc.clientId }}
6038
{{- $oidcClientSecretFile = required "services.mcp.oidcProxy.oidc.clientSecretFile is required when the OIDC proxy is enabled" $oidcProxy.oidc.clientSecretFile }}
6139
{{- $oidcAccessTokenIssuer = required "services.mcp.oidcProxy.oidc.accessTokenIssuer is required when the OIDC proxy is enabled" $oidcProxy.oidc.accessTokenIssuer }}
62-
{{- $oidcAccessTokenAudience = required "services.mcp.oidcProxy.oidc.accessTokenAudience is required when the OIDC proxy is enabled" $oidcProxy.oidc.accessTokenAudience }}
63-
{{- $oidcAccessTokenJwksUrl = required "services.mcp.oidcProxy.oidc.accessTokenJwksUrl is required when the OIDC proxy is enabled" $oidcProxy.oidc.accessTokenJwksUrl }}
6440
{{- $oidcAccessTokenRequiredScope = required "services.mcp.oidcProxy.oidc.accessTokenRequiredScope is required when the OIDC proxy is enabled" $oidcProxy.oidc.accessTokenRequiredScope }}
6541
{{- if not (regexMatch "^[A-Za-z0-9:._~-]{1,128}$" $oidcAccessTokenRequiredScope) }}
6642
{{- fail "services.mcp.oidcProxy.oidc.accessTokenRequiredScope must be one non-empty scope" }}
6743
{{- end }}
68-
{{- if or (gt (len $oidcAccessTokenAudience) 2048) (not (regexMatch "^[^[:space:][:cntrl:]]+$" $oidcAccessTokenAudience)) }}
69-
{{- fail "services.mcp.oidcProxy.oidc.accessTokenAudience must be one non-empty value without whitespace or control characters" }}
70-
{{- end }}
71-
{{- if ne $oidcAccessTokenAudience $mcpResourceUrl }}
72-
{{- fail "services.mcp.oidcProxy.oidc.accessTokenAudience must equal services.mcp.resourceUrl" }}
73-
{{- end }}
74-
{{- if ne $scope (printf "%s/%s" $mcpResourceUrl $oidcAccessTokenRequiredScope) }}
75-
{{- fail "services.mcp.oidcProxy.scope must equal services.mcp.resourceUrl followed by oidc.accessTokenRequiredScope" }}
76-
{{- end }}
7744
{{- $oidcHttpsUrlPattern := "^https://[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?(:[0-9]{1,5})?(/[A-Za-z0-9._~%!$&'()*+,;=:@/-]*)?$" }}
7845
{{- if not (regexMatch $oidcHttpsUrlPattern $oidcConfigUrl) }}
7946
{{- fail "services.mcp.oidcProxy.oidc.configUrl must be an absolute HTTPS URL without query or fragment" }}
8047
{{- end }}
8148
{{- if not (regexMatch $oidcHttpsUrlPattern $oidcAccessTokenIssuer) }}
8249
{{- fail "services.mcp.oidcProxy.oidc.accessTokenIssuer must be an absolute HTTPS issuer without query or fragment" }}
8350
{{- end }}
84-
{{- if not (regexMatch $oidcHttpsUrlPattern $oidcAccessTokenJwksUrl) }}
85-
{{- fail "services.mcp.oidcProxy.oidc.accessTokenJwksUrl must be an absolute HTTPS URL without query or fragment" }}
86-
{{- end }}
87-
{{- range $name, $url := dict "configUrl" $oidcConfigUrl "accessTokenIssuer" $oidcAccessTokenIssuer "accessTokenJwksUrl" $oidcAccessTokenJwksUrl }}
51+
{{- range $name, $url := dict "configUrl" $oidcConfigUrl "accessTokenIssuer" $oidcAccessTokenIssuer }}
8852
{{- $portMatch := regexFind ":[0-9]+(/|$)" $url }}
8953
{{- if $portMatch }}
9054
{{- $urlPort := trimSuffix "/" (trimPrefix ":" $portMatch) | int }}
@@ -96,14 +60,8 @@
9660
{{- if not (hasPrefix "/" $oidcClientSecretFile) }}
9761
{{- fail "services.mcp.oidcProxy.oidc.clientSecretFile must be an absolute path" }}
9862
{{- end }}
99-
{{- $redisHost := $oidcProxy.redis.serviceName | default .Values.services.redis.serviceName | required "services.mcp.oidcProxy.redis.serviceName or services.redis.serviceName is required" }}
63+
{{- $redisHost := .Values.services.redis.serviceName | required "services.redis.serviceName is required when the MCP OIDC proxy is enabled" }}
10064
{{- $redisPort := .Values.services.redis.port }}
101-
{{- if not (kindIs "invalid" $oidcProxy.redis.port) }}
102-
{{- $redisPort = $oidcProxy.redis.port }}
103-
{{- end }}
104-
{{- if or (lt (int $redisPort) 1) (gt (int $redisPort) 65535) }}
105-
{{- fail "services.mcp.oidcProxy.redis.port must be between 1 and 65535" }}
106-
{{- end }}
10765
{{- if or (lt (int $oidcProxy.redis.dbNumber) 0) (gt (int $oidcProxy.redis.dbNumber) 15) }}
10866
{{- fail "services.mcp.oidcProxy.redis.dbNumber must be between 0 and 15" }}
10967
{{- end }}
@@ -146,7 +104,7 @@
146104
{{- fail "services.mcp.oidcProxy.existingSecret.redisPasswordKey is required when redis.passwordFile is configured" }}
147105
{{- end }}
148106
{{- end }}
149-
{{- $redisScheme := ternary "rediss" "redis" $oidcProxy.redis.tlsEnabled }}
107+
{{- $redisScheme := ternary "rediss" "redis" .Values.services.redis.tlsEnabled }}
150108
{{- $redisUrl = printf "%s://%s:%v/%v" $redisScheme $redisHost $redisPort $oidcProxy.redis.dbNumber }}
151109
{{- end }}
152110
{{- if not (kindIs "slice" $mcp.allowedOrigins) }}
@@ -164,10 +122,7 @@
164122
"OSMO_MCP_REQUEST_TIMEOUT_SECONDS"
165123
"OSMO_MCP_ALLOWED_ORIGINS"
166124
"OSMO_MCP_AUTH_ENABLED"
167-
"OSMO_MCP_AUTH_ISSUER_URL"
168125
"OSMO_MCP_AUTH_RESOURCE_URL"
169-
"OSMO_MCP_AUTH_SCOPE"
170-
"OSMO_MCP_AUTH_TRUSTED_HTTPS_REDIRECT_ORIGINS"
171126
"OSMO_MCP_AUTH_REDIS_URL"
172127
"OSMO_MCP_AUTH_REDIS_PASSWORD_FILE"
173128
"OSMO_MCP_AUTH_REDIS_KEY_PREFIX"
@@ -177,8 +132,6 @@
177132
"OSMO_MCP_AUTH_OIDC_CLIENT_ID"
178133
"OSMO_MCP_AUTH_OIDC_CLIENT_SECRET_FILE"
179134
"OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_ISSUER"
180-
"OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_AUDIENCE"
181-
"OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_JWKS_URL"
182135
"OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_REQUIRED_SCOPE"
183136
"OSMO_MCP_AUTH_ACCESS_TOKEN_TTL_SECONDS"
184137
"OSMO_MCP_AUTH_REFRESH_TOKEN_TTL_SECONDS"
@@ -258,14 +211,8 @@ spec:
258211
- name: OSMO_MCP_AUTH_ENABLED
259212
value: {{ $oidcProxyEnabled | quote }}
260213
{{- if $oidcProxyEnabled }}
261-
- name: OSMO_MCP_AUTH_ISSUER_URL
262-
value: {{ $gatewayUrl | quote }}
263214
- name: OSMO_MCP_AUTH_RESOURCE_URL
264215
value: {{ $mcpResourceUrl | quote }}
265-
- name: OSMO_MCP_AUTH_SCOPE
266-
value: {{ $scope | quote }}
267-
- name: OSMO_MCP_AUTH_TRUSTED_HTTPS_REDIRECT_ORIGINS
268-
value: {{ join "," $oidcProxy.trustedHttpsRedirectOrigins | quote }}
269216
- name: OSMO_MCP_AUTH_REDIS_URL
270217
value: {{ $redisUrl | quote }}
271218
{{- if $oidcProxy.redis.passwordFile }}
@@ -286,10 +233,6 @@ spec:
286233
value: {{ $oidcClientSecretFile | quote }}
287234
- name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_ISSUER
288235
value: {{ $oidcAccessTokenIssuer | quote }}
289-
- name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_AUDIENCE
290-
value: {{ $oidcAccessTokenAudience | quote }}
291-
- name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_JWKS_URL
292-
value: {{ $oidcAccessTokenJwksUrl | quote }}
293236
- name: OSMO_MCP_AUTH_OIDC_ACCESS_TOKEN_REQUIRED_SCOPE
294237
value: {{ $oidcAccessTokenRequiredScope | quote }}
295238
- name: OSMO_MCP_AUTH_ACCESS_TOKEN_TTL_SECONDS

deployments/charts/service/values.yaml

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ services:
120120
##
121121
enabled: false
122122

123-
## Number of MCP replicas. Keep this at 1 while oidcProxy is enabled;
124-
## FastMCP 3.4.7 serializes refreshes within one process.
123+
## Number of MCP replicas. The OIDC proxy keeps all of its state in Redis,
124+
## so more than one replica is supported.
125125
##
126126
replicas: 1
127127

@@ -176,36 +176,23 @@ services:
176176
oidcProxy:
177177
enabled: false
178178

179-
## Full delegated scope URI advertised to MCP clients and requested from
180-
## the upstream provider, normally <resourceUrl>/access_as_user.
181-
##
182-
scope: ""
183-
184-
## Public HTTPS redirect origins allowed for pre-registered web clients.
185-
## Native clients use dynamically allocated loopback redirects.
186-
##
187-
trustedHttpsRedirectOrigins: []
188-
189179
## Upstream OpenID Connect provider. Register the fixed redirect URL
190-
## <resourceUrl origin>/auth/callback on this confidential application.
180+
## <resourceUrl origin>/mcp/auth/callback on this confidential application.
191181
##
192182
oidc:
193183
configUrl: ""
194184
clientId: ""
195185
clientSecretFile: /etc/osmo/mcp-auth/client-secret
196186
accessTokenIssuer: ""
197-
accessTokenAudience: ""
198-
accessTokenJwksUrl: ""
199187
accessTokenRequiredScope: access_as_user
200188

201189
## Redis stores proxy registrations, authorization state, and encrypted
202-
## upstream tokens. Empty serviceName/port inherit services.redis.
190+
## upstream tokens. Host, port and TLS come from services.redis; only the
191+
## logical database is chosen here, so proxy state stays isolated from
192+
## OSMO's other Redis users.
203193
##
204194
redis:
205-
serviceName: ""
206-
port: null
207-
dbNumber: 0
208-
tlsEnabled: true
195+
dbNumber: 1
209196
passwordFile: ""
210197
keyPrefix: osmo:mcp-fastmcp
211198
connectTimeoutSeconds: 3

0 commit comments

Comments
 (0)