You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Enable multi-upstream for MCPServer, MCPRemoteProxy, and proxy runner (#4322)
* Add explicit-name validation and proxy runner multi-upstream guard
Move multi-upstream restrictions from the authserver library to consumer
layers. The library now accepts multi-upstream configs but enforces name
semantics: single-upstream defaults empty names to "default", while
multi-upstream requires explicit non-"default" names with distinct error
messages for empty vs reserved names.
Validate upstream names against a DNS-label regex (no leading/trailing
hyphens, lowercase alphanumeric only) to prevent delimiter injection in
storage keys. Add test coverage for invalid name formats (uppercase,
underscores, leading/trailing hyphens).
Remove the GetUpstream() convenience method (no callers remain after
Phase 2). Add a cardinality guard in the proxy runner's Run() that
rejects len(Upstreams) > 1 with an actionable error pointing to
VirtualMCPServer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Move multi-upstream restriction from CRD to controller layers
Remove the len > 1 guard from MCPExternalAuthConfig.validateEmbeddedAuthServer()
so the CRD accepts multi-upstream configs. Add multi-upstream rejection to
MCPServer and MCPRemoteProxy controllers in handleExternalAuthConfig(), setting
a ConditionFalse status with reason MultiUpstreamNotSupported and an actionable
error directing users to VirtualMCPServer.
Add duplicate upstream name validation in the CRD webhook so conflicts
are caught at admission time rather than Pod startup. Tighten the Name
field pattern to disallow trailing hyphens and add MaxLength=63 for
RFC 1123 compliance.
VirtualMCPServer remains unrestricted as the intended multi-upstream consumer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Enable multi-upstream for MCPServer, MCPRemoteProxy, and proxy runner
The embedded auth server has supported sequential multi-upstream chains
since the Phase 2 work, but every consumer layer (MCPServer controller,
MCPRemoteProxy controller, proxy runner) blocked configs with more than
one upstream provider. This commit lifts all those restrictions and fixes
the two bugs that would have broken multi-upstream even without the guards.
Guard removal:
- MCPServer controller: remove len > 1 check in handleExternalAuthConfig
- MCPRemoteProxy controller: same removal
- Proxy runner Run(): remove len > 1 early-return
- Remove associated condition type/reason constants and rejection tests
Converter fix (authserver.go):
- GenerateAuthServerEnvVars now iterates all providers and emits
name-keyed env vars (TOOLHIVE_UPSTREAM_CLIENT_SECRET_OKTA, _GITHUB, …)
derived from each provider's Name field, instead of only reading
UpstreamProviders[0] into a single unindexed var. Name-keyed bindings
are position-independent, so reordering providers in the CRD does not
change the secret-to-provider mapping.
- buildEmbeddedAuthServerRunnerConfig now builds Upstreams from all
providers instead of only the first; buildUpstreamRunConfig gains an
envVarName parameter to match the env var naming
Middleware fix (middleware.go):
- Restore ProviderName auto-derivation in addUpstreamSwapMiddleware,
defaulting to the first upstream's name for single-upstream configs.
Multi-upstream ProviderName selection will be addressed when a CRD
field is added in a follow-up.
Observability (upstreamswap/middleware.go):
- Add provider field to all upstreamswap log lines (injection success,
empty-token warning, get-tokens error) to make confused-deputy
debugging tractable when multiple providers are in play.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix lint: reduce cyclomatic complexity and update stale comments
Extract validateUpstreamName and validateUpstreamType from
validateUpstreams to bring cyclomatic complexity under the limit.
Break long fmt.Errorf line that exceeded 130 characters.
Update stale godoc comments in controllerutil/authserver.go that
still referenced the old index-based env var naming scheme.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Downgrade client-attributable token errors to Debug log level
Client-attributable errors (session not found, no refresh token, refresh
failed, invalid binding) are expected conditions that trigger re-auth,
not server issues an operator needs to investigate. Log these at Debug
instead of Warn; keep Warn for unexpected server-side failures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Re-add multi-upstream guards for MCPServer and MCPRemoteProxy
The upstream swap middleware only injects one provider's token, and
there is no CRD field to control which provider. Until tokenInjection-
Provider is added and Cedar upstream claims extraction is implemented,
multi-upstream configs would silently inject only the first upstream's
token while the second is stored but unused.
Re-add controller-level guards (MCPServer, MCPRemoteProxy, proxy
runner) that reject len > 1 with actionable errors directing users to
VirtualMCPServer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* regen docs
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 commit comments