Skip to content

[BFA-130] Default MCP public origin from BASE_DOMAIN - #392

Draft
arnold-retool wants to merge 2 commits into
arnold/mcp-routing-modefrom
arnold/mcp-public-origin-defaults
Draft

arnold-retool wants to merge 2 commits into
arnold/mcp-routing-modefrom
arnold/mcp-public-origin-defaults

Conversation

@arnold-retool

Copy link
Copy Markdown
Contributor

Summary

BFA-130: Use env.BASE_DOMAIN as the MCP public origin fallback in a single-host Retool installation. The chart passes it to the MCP process, derives OAUTH_MAIN_DOMAIN when it can resolve the value, and passes trusted-proxy CIDRs when configured. An explicit mcp.config.mcpServiceExternalUrl (or mcp.environmentVariables entry) is copied to the backend unless the backend has its own explicit value, keeping OAuth discovery, Bearer challenges, resource metadata, and upload links aligned. Existing explicit values are preserved.

Render-time validation rejects malformed public origin values and clear mismatches with chart-managed Ingress hosts and HTTPRoute hostnames. Multiple managed hosts, externally managed ingress, and secret-backed values that cannot be resolved during templating remain supported. Tests cover both backendRelay and direct routing modes. The chart version moves to 6.12.4 and both values files remain synchronized.

Companion server PR: https://github.com/tryretool/retool_development/pull/86710

This PR is stacked on routing PR #391 (itself stacked on #390) and targets arnold/mcp-routing-mode so the diff contains only the public-origin change.

Migration

For one public host, set env.BASE_DOMAIN: https://retool.example.com and serve that host via the configured Ingress or HTTPRoute. Remove mcp.config.mcpServiceExternalUrl when custom Space domains should be advertised per request; the existing explicit override continues to pin every MCP response to one origin. If a proxy rewrites Host or terminates TLS, set env.MCP_TRUSTED_PROXY_CIDRS to the immediate proxy peer CIDRs. The server PR consumes this contract. With external ingress, disable chart-managed routing and provide the public path mappings documented in the README.

Validation

  • python3 .github/test_mcp_routing.py: 16 render tests passed, including defaults, overrides, mismatches, secret-backed values, custom hosts, and both routing modes.
  • python3 .github/test_mcp_helm_test.py: 14 render and localhost HTTP smoke tests passed.
  • helm lint charts/retool --values charts/retool/ci/test-install-values.yaml --values charts/retool/ci/test-mcp-enabled-option.yaml: passed.
  • helm template ... | kubeconform -strict -ignore-missing-schemas -summary: 18 valid resources, zero invalid, one skipped.
  • git diff --check: passed.

No deployment was performed.

@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 3/5

[High risk] Changes how the MCP service discovers its public origin in Kubernetes.

The PR is not ready to merge because valid route setups can fail rendering and the backend can receive an origin without a scheme.

Findings

  1. P1 Valid route blocks rendering ▶
  2. P1 Backend gets bare hostname ▶
  3. P2 MCP diagnostics lose their host ▶

Reviews (1) · Last reviewed commit: "[BFA-130] Default MCP public origin from..."

Comment on lines +36 to +41
{{- if and $.Values.httpRoute.enabled $.Values.httpRoute.hostnames -}}
{{- $matched := false -}}
{{- range $routeHost := $.Values.httpRoute.hostnames -}}
{{- if or (eq (lower $routeHost) $host) (and (hasPrefix "*." $routeHost) (hasSuffix (trimPrefix "*" (lower $routeHost)) $host)) -}}{{- $matched = true -}}{{- end -}}
{{- end -}}
{{- if not $matched -}}{{- fail (printf "%s host %q does not match a chart-managed HTTPRoute hostname (%s)" $source $host (join ", " $.Values.httpRoute.hostnames)) -}}{{- end -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Valid route blocks rendering

If both chart-managed Ingress and HTTPRoute are enabled with different hostnames, BASE_DOMAIN must match both. The chart fails to render even when one route serves the public origin. Accept a match on either enabled route.

Comment on lines +87 to +88
{{- if $mcpExternalEnv -}}
{{- toYaml (list $mcpExternalEnv) }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Backend gets bare hostname

If MCP_SERVICE_EXTERNAL_URL in mcp.environmentVariables has no scheme, the new check adds https:// to validate it, but this copy sends the unchanged value to the backend. The backend can then produce bad discovery or upload links. Reject the bare hostname or normalize it before copying it.

{{- end }}
{{- end }}
{{- if not (or $mcpOAuthMainDomain $hasOAuthMainDomainEnv) }}
{{- if not (or $mcpOAuthMainDomain $hasOAuthMainDomainEnv $mcpBaseDomain $hasBaseDomainEnv) }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 MCP diagnostics lose their host

A secret-backed env.BASE_DOMAIN, or a BASE_DOMAIN set only in mcp.environmentVariables, now passes this check. But the chart cannot derive OAUTH_MAIN_DOMAIN from either value, so it leaves that variable out of the MCP pod. Require an explicit OAuth domain in these cases, or derive it when the server starts.

@arnold-retool
arnold-retool added this pull request to stack #393 September 30, 2026 21:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant