Skip to content

Commit fe957d9

Browse files
JAORMXclaude
andauthored
Add MCPRemoteProxy CRD definition and schema (#2240)
Introduces the MCPRemoteProxy custom resource definition for proxying remote MCP servers in Kubernetes with authentication, authorization, audit logging, and tool filtering capabilities. This CRD enables organizations to deploy centralized proxies for external SaaS MCP services (e.g., Salesforce MCP, GitHub MCP) with visibility, policy enforcement, and audit trails. Key features: - Remote URL configuration with HTTPS validation - Configurable transport (SSE or streamable-http) - Required OIDC authentication for incoming requests - Optional token exchange for remote service authentication - Authorization policy support (inline or ConfigMap) - Audit logging configuration - Tool filtering and renaming via MCPToolConfig references - OpenTelemetry telemetry integration - Resource requirements and overrides Includes: - CRD type definition with kubebuilder markers - Generated deepcopy methods - Generated CRD manifest with OpenAPI v3 schema - Operator-crds chart version bump (0.0.35 -> 0.0.36) - API documentation Note: RBAC permissions will be added when the controller is implemented. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1aea46a commit fe957d9

File tree

6 files changed

+1020
-2
lines changed

6 files changed

+1020
-2
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
package v1alpha1
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
)
6+
7+
// MCPRemoteProxySpec defines the desired state of MCPRemoteProxy
8+
type MCPRemoteProxySpec struct {
9+
// RemoteURL is the URL of the remote MCP server to proxy
10+
// +kubebuilder:validation:Required
11+
// +kubebuilder:validation:Pattern=`^https?://`
12+
RemoteURL string `json:"remoteURL"`
13+
14+
// Port is the port to expose the MCP proxy on
15+
// +kubebuilder:validation:Minimum=1
16+
// +kubebuilder:validation:Maximum=65535
17+
// +kubebuilder:default=8080
18+
Port int32 `json:"port,omitempty"`
19+
20+
// Transport is the transport method for the remote proxy (sse or streamable-http)
21+
// +kubebuilder:validation:Enum=sse;streamable-http
22+
// +kubebuilder:default=streamable-http
23+
Transport string `json:"transport,omitempty"`
24+
25+
// OIDCConfig defines OIDC authentication configuration for the proxy
26+
// This validates incoming tokens from clients. Required for proxy mode.
27+
// +kubebuilder:validation:Required
28+
OIDCConfig OIDCConfigRef `json:"oidcConfig"`
29+
30+
// ExternalAuthConfigRef references a MCPExternalAuthConfig resource for token exchange.
31+
// When specified, the proxy will exchange validated incoming tokens for remote service tokens.
32+
// The referenced MCPExternalAuthConfig must exist in the same namespace as this MCPRemoteProxy.
33+
// +optional
34+
ExternalAuthConfigRef *ExternalAuthConfigRef `json:"externalAuthConfigRef,omitempty"`
35+
36+
// AuthzConfig defines authorization policy configuration for the proxy
37+
// +optional
38+
AuthzConfig *AuthzConfigRef `json:"authzConfig,omitempty"`
39+
40+
// Audit defines audit logging configuration for the proxy
41+
// +optional
42+
Audit *AuditConfig `json:"audit,omitempty"`
43+
44+
// ToolConfigRef references a MCPToolConfig resource for tool filtering and renaming.
45+
// The referenced MCPToolConfig must exist in the same namespace as this MCPRemoteProxy.
46+
// Cross-namespace references are not supported for security and isolation reasons.
47+
// If specified, this allows filtering and overriding tools from the remote MCP server.
48+
// +optional
49+
ToolConfigRef *ToolConfigRef `json:"toolConfigRef,omitempty"`
50+
51+
// Telemetry defines observability configuration for the proxy
52+
// +optional
53+
Telemetry *TelemetryConfig `json:"telemetry,omitempty"`
54+
55+
// Resources defines the resource requirements for the proxy container
56+
// +optional
57+
Resources ResourceRequirements `json:"resources,omitempty"`
58+
59+
// TrustProxyHeaders indicates whether to trust X-Forwarded-* headers from reverse proxies
60+
// When enabled, the proxy will use X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port,
61+
// and X-Forwarded-Prefix headers to construct endpoint URLs
62+
// +kubebuilder:default=false
63+
// +optional
64+
TrustProxyHeaders bool `json:"trustProxyHeaders,omitempty"`
65+
66+
// ResourceOverrides allows overriding annotations and labels for resources created by the operator
67+
// +optional
68+
ResourceOverrides *ResourceOverrides `json:"resourceOverrides,omitempty"`
69+
}
70+
71+
// MCPRemoteProxyStatus defines the observed state of MCPRemoteProxy
72+
type MCPRemoteProxyStatus struct {
73+
// Phase is the current phase of the MCPRemoteProxy
74+
// +optional
75+
Phase MCPRemoteProxyPhase `json:"phase,omitempty"`
76+
77+
// URL is the internal cluster URL where the proxy can be accessed
78+
// +optional
79+
URL string `json:"url,omitempty"`
80+
81+
// ExternalURL is the external URL where the proxy can be accessed (if exposed externally)
82+
// +optional
83+
ExternalURL string `json:"externalURL,omitempty"`
84+
85+
// ObservedGeneration reflects the generation of the most recently observed MCPRemoteProxy
86+
// +optional
87+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
88+
89+
// Conditions represent the latest available observations of the MCPRemoteProxy's state
90+
// +optional
91+
Conditions []metav1.Condition `json:"conditions,omitempty"`
92+
93+
// ToolConfigHash stores the hash of the referenced ToolConfig for change detection
94+
// +optional
95+
ToolConfigHash string `json:"toolConfigHash,omitempty"`
96+
97+
// ExternalAuthConfigHash is the hash of the referenced MCPExternalAuthConfig spec
98+
// +optional
99+
ExternalAuthConfigHash string `json:"externalAuthConfigHash,omitempty"`
100+
101+
// Message provides additional information about the current phase
102+
// +optional
103+
Message string `json:"message,omitempty"`
104+
}
105+
106+
// MCPRemoteProxyPhase is a label for the condition of a MCPRemoteProxy at the current time
107+
// +kubebuilder:validation:Enum=Pending;Ready;Failed;Terminating
108+
type MCPRemoteProxyPhase string
109+
110+
const (
111+
// MCPRemoteProxyPhasePending means the proxy is being created
112+
MCPRemoteProxyPhasePending MCPRemoteProxyPhase = "Pending"
113+
114+
// MCPRemoteProxyPhaseReady means the proxy is ready and operational
115+
MCPRemoteProxyPhaseReady MCPRemoteProxyPhase = "Ready"
116+
117+
// MCPRemoteProxyPhaseFailed means the proxy failed to start or encountered an error
118+
MCPRemoteProxyPhaseFailed MCPRemoteProxyPhase = "Failed"
119+
120+
// MCPRemoteProxyPhaseTerminating means the proxy is being deleted
121+
MCPRemoteProxyPhaseTerminating MCPRemoteProxyPhase = "Terminating"
122+
)
123+
124+
// Condition types for MCPRemoteProxy
125+
const (
126+
// ConditionTypeReady indicates overall readiness of the proxy
127+
ConditionTypeReady = "Ready"
128+
129+
// ConditionTypeRemoteAvailable indicates whether the remote MCP server is reachable
130+
ConditionTypeRemoteAvailable = "RemoteAvailable"
131+
132+
// ConditionTypeAuthConfigured indicates whether authentication is properly configured
133+
ConditionTypeAuthConfigured = "AuthConfigured"
134+
)
135+
136+
// Condition reasons for MCPRemoteProxy
137+
const (
138+
// ConditionReasonDeploymentReady indicates the deployment is ready
139+
ConditionReasonDeploymentReady = "DeploymentReady"
140+
141+
// ConditionReasonDeploymentNotReady indicates the deployment is not ready
142+
ConditionReasonDeploymentNotReady = "DeploymentNotReady"
143+
144+
// ConditionReasonRemoteURLReachable indicates the remote URL is reachable
145+
ConditionReasonRemoteURLReachable = "RemoteURLReachable"
146+
147+
// ConditionReasonRemoteURLUnreachable indicates the remote URL is unreachable
148+
ConditionReasonRemoteURLUnreachable = "RemoteURLUnreachable"
149+
150+
// ConditionReasonAuthValid indicates authentication configuration is valid
151+
ConditionReasonAuthValid = "AuthValid"
152+
153+
// ConditionReasonAuthInvalid indicates authentication configuration is invalid
154+
ConditionReasonAuthInvalid = "AuthInvalid"
155+
156+
// ConditionReasonMissingOIDCConfig indicates OIDCConfig is not specified
157+
ConditionReasonMissingOIDCConfig = "MissingOIDCConfig"
158+
)
159+
160+
//+kubebuilder:object:root=true
161+
//+kubebuilder:subresource:status
162+
//+kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase"
163+
//+kubebuilder:printcolumn:name="Remote URL",type="string",JSONPath=".spec.remoteURL"
164+
//+kubebuilder:printcolumn:name="URL",type="string",JSONPath=".status.url"
165+
//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
166+
167+
// MCPRemoteProxy is the Schema for the mcpremoteproxies API
168+
// It enables proxying remote MCP servers with authentication, authorization, audit logging, and tool filtering
169+
type MCPRemoteProxy struct {
170+
metav1.TypeMeta `json:",inline"` // nolint:revive
171+
metav1.ObjectMeta `json:"metadata,omitempty"`
172+
173+
Spec MCPRemoteProxySpec `json:"spec,omitempty"`
174+
Status MCPRemoteProxyStatus `json:"status,omitempty"`
175+
}
176+
177+
//+kubebuilder:object:root=true
178+
179+
// MCPRemoteProxyList contains a list of MCPRemoteProxy
180+
type MCPRemoteProxyList struct {
181+
metav1.TypeMeta `json:",inline"` // nolint:revive
182+
metav1.ListMeta `json:"metadata,omitempty"`
183+
Items []MCPRemoteProxy `json:"items"`
184+
}
185+
186+
func init() {
187+
SchemeBuilder.Register(&MCPRemoteProxy{}, &MCPRemoteProxyList{})
188+
}
189+
190+
// GetName returns the name of the MCPRemoteProxy
191+
func (m *MCPRemoteProxy) GetName() string {
192+
return m.Name
193+
}
194+
195+
// GetNamespace returns the namespace of the MCPRemoteProxy
196+
func (m *MCPRemoteProxy) GetNamespace() string {
197+
return m.Namespace
198+
}
199+
200+
// GetOIDCConfig returns the OIDC configuration reference
201+
func (m *MCPRemoteProxy) GetOIDCConfig() *OIDCConfigRef {
202+
return &m.Spec.OIDCConfig
203+
}
204+
205+
// GetPort returns the port for the MCPRemoteProxy
206+
func (m *MCPRemoteProxy) GetPort() int32 {
207+
return m.Spec.Port
208+
}

cmd/thv-operator/api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 128 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

deploy/charts/operator-crds/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ apiVersion: v2
22
name: toolhive-operator-crds
33
description: A Helm chart for installing the ToolHive Operator CRDs into Kubernetes.
44
type: application
5-
version: 0.0.35
5+
version: 0.0.36
66
appVersion: "0.0.1"

deploy/charts/operator-crds/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# ToolHive Operator CRDs Helm Chart
33

4-
![Version: 0.0.35](https://img.shields.io/badge/Version-0.0.35-informational?style=flat-square)
4+
![Version: 0.0.36](https://img.shields.io/badge/Version-0.0.36-informational?style=flat-square)
55
![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square)
66

77
A Helm chart for installing the ToolHive Operator CRDs into Kubernetes.

0 commit comments

Comments
 (0)