Skip to content

Commit c605477

Browse files
authored
feat: Merge KMCP crd and controller into Kagent (kagent-dev#939)
This PR contains the following changes and is the first in two PRs to migrate KMCP into Kagent. The second PR will focus on migrating the KMCP cli functionalities into the Kagent CLI. - Added KMCP's `mcpServer` CRD to Kagent. - Added a new controller that watches for the `mcpServer` CRD and handles the deployment lifecycle of the mcp server deployment. - Refactored existing mcp server controller into `mcp_server_tool_controller` to better reflect its responsibilities of managing tool discovery. - Added new e2e test for a declarative agent using tools derived from a mcp server deployed using the `mcpServer` CRD. Manual Testing: - Interacted with agent using tools derived from the deployed mcp server. - Tested deleting mcp tool server in the UI. (This is the only portion of the UI that was using kmcp resources) --------- Signed-off-by: JM Huibonhoa <jm.huibonhoa@solo.io>
1 parent a495681 commit c605477

49 files changed

Lines changed: 6725 additions & 311 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ jobs:
119119
- name: Run cmd/main.go tests
120120
working-directory: go
121121
run: |
122-
go test -skip 'TestInvokeInlineAgent|TestInvokeExternalAgent|TestE2E|TestAutogenClient' -v ./...
122+
go test -skip 'TestE2E.*|TestAutogenClient' -v ./...
123123
124124
helm-unit-tests:
125125
env:

Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ TOOLS_IMAGE_BUILD_ARGS += --build-arg TOOLS_BUN_VERSION=$(TOOLS_BUN_VERSION)
7171
TOOLS_IMAGE_BUILD_ARGS += --build-arg TOOLS_PYTHON_VERSION=$(TOOLS_PYTHON_VERSION)
7272
TOOLS_IMAGE_BUILD_ARGS += --build-arg TOOLS_NODE_VERSION=$(TOOLS_NODE_VERSION)
7373

74-
# kmcp version extraction from go.mod
75-
KMCP_VERSION ?= $(shell $(AWK) '/github\.com\/kagent-dev\/kmcp/ { print substr($$2, 2) }' go/go.mod)
76-
7774
HELM_ACTION=upgrade --install
7875

7976
# Helm chart variables
@@ -87,7 +84,6 @@ print-tools-versions:
8784
@echo "Tools Node : $(TOOLS_NODE_VERSION)"
8885
@echo "Tools Istio : $(TOOLS_ISTIO_VERSION)"
8986
@echo "Tools Argo CD: $(TOOLS_ARGO_CD_VERSION)"
90-
@echo "KMCP Version : $(KMCP_VERSION)"
9187

9288
# Check if the appropriate API key is set based on the model provider
9389
check-api-key:
@@ -278,7 +274,7 @@ helm-tools:
278274

279275
.PHONY: helm-version
280276
helm-version: helm-cleanup helm-agents helm-tools
281-
VERSION=$(VERSION) KMCP_VERSION=$(KMCP_VERSION) envsubst < helm/kagent-crds/Chart-template.yaml > helm/kagent-crds/Chart.yaml
277+
VERSION=$(VERSION) envsubst < helm/kagent-crds/Chart-template.yaml > helm/kagent-crds/Chart.yaml
282278
VERSION=$(VERSION) envsubst < helm/kagent/Chart-template.yaml > helm/kagent/Chart.yaml
283279
helm dependency update helm/kagent
284280
helm dependency update helm/kagent-crds

go/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ test:
104104

105105
.PHONY: e2e
106106
e2e:
107-
#UPDATE_GOLDEN=true go test -skip 'TestInvokeInlineAgent|TestE2E|TestAutogenClient' -v ./...
108-
go test -skip 'TestInvokeInlineAgent|TestE2E|TestAutogenClient' -v ./...
107+
#UPDATE_GOLDEN=true go test -skip 'TestE2E.*|TestAutogenClient' -v ./...
108+
go test -skip 'TestE2E.*|TestAutogenClient' -v ./...
109109

110110
.PHONY: install
111111
install: manifests

go/api/v1alpha1/mcpserver_types.go

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
/*
2+
Copyright 2025.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package v1alpha1
18+
19+
import (
20+
corev1 "k8s.io/api/core/v1"
21+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
)
23+
24+
// MCPServerTransportType defines the type of transport for the MCP server.
25+
type TransportType string
26+
27+
const (
28+
// TransportTypeStdio indicates that the MCP server uses standard input/output for communication.
29+
TransportTypeStdio TransportType = "stdio"
30+
31+
// TransportTypeHTTP indicates that the MCP server uses Streamable HTTP for communication.
32+
TransportTypeHTTP TransportType = "http"
33+
)
34+
35+
// MCPServerConditionType represents the condition types for MCPServer status.
36+
type MCPServerConditionType string
37+
38+
const (
39+
// MCPServerConditionAccepted indicates that the MCPServer has been accepted for processing.
40+
// This condition indicates that the MCPServer configuration is syntactically and semantically valid,
41+
// and the controller can generate some configuration for the underlying infrastructure.
42+
//
43+
// Possible reasons for this condition to be True are:
44+
//
45+
// * "Accepted"
46+
//
47+
// Possible reasons for this condition to be False are:
48+
//
49+
// * "InvalidConfig"
50+
// * "UnsupportedTransport"
51+
//
52+
// Controllers may raise this condition with other reasons,
53+
// but should prefer to use the reasons listed above to improve
54+
// interoperability.
55+
MCPServerConditionAccepted MCPServerConditionType = "Accepted"
56+
57+
// MCPServerConditionResolvedRefs indicates whether the controller was able to
58+
// resolve all the object references for the MCPServer.
59+
//
60+
// Possible reasons for this condition to be True are:
61+
//
62+
// * "ResolvedRefs"
63+
//
64+
// Possible reasons for this condition to be False are:
65+
//
66+
// * "ImageNotFound"
67+
//
68+
// Controllers may raise this condition with other reasons,
69+
// but should prefer to use the reasons listed above to improve
70+
// interoperability.
71+
MCPServerConditionResolvedRefs MCPServerConditionType = "ResolvedRefs"
72+
73+
// MCPServerConditionProgrammed indicates that the controller has successfully
74+
// programmed the underlying infrastructure with the MCPServer configuration.
75+
// This means that all required Kubernetes resources (Deployment, Service, ConfigMap)
76+
// have been created and configured.
77+
//
78+
// Possible reasons for this condition to be True are:
79+
//
80+
// * "Programmed"
81+
//
82+
// Possible reasons for this condition to be False are:
83+
//
84+
// * "DeploymentFailed"
85+
// * "ServiceFailed"
86+
// * "ConfigMapFailed"
87+
//
88+
// Controllers may raise this condition with other reasons,
89+
// but should prefer to use the reasons listed above to improve
90+
// interoperability.
91+
MCPServerConditionProgrammed MCPServerConditionType = "Programmed"
92+
93+
// MCPServerConditionReady indicates that the MCPServer is ready to serve traffic.
94+
// This condition indicates that the underlying Deployment has running pods
95+
// that are ready to accept connections.
96+
//
97+
// Possible reasons for this condition to be True are:
98+
//
99+
// * "Ready"
100+
//
101+
// Possible reasons for this condition to be False are:
102+
//
103+
// * "PodsNotReady"
104+
//
105+
// Controllers may raise this condition with other reasons,
106+
// but should prefer to use the reasons listed above to improve
107+
// interoperability.
108+
MCPServerConditionReady MCPServerConditionType = "Ready"
109+
)
110+
111+
// MCPServerConditionReason represents the reasons for MCPServer conditions.
112+
type MCPServerConditionReason string
113+
114+
const (
115+
// Accepted condition reasons
116+
MCPServerReasonAccepted MCPServerConditionReason = "Accepted"
117+
MCPServerReasonInvalidConfig MCPServerConditionReason = "InvalidConfig"
118+
MCPServerReasonUnsupportedTransport MCPServerConditionReason = "UnsupportedTransport"
119+
120+
// ResolvedRefs condition reasons
121+
MCPServerReasonResolvedRefs MCPServerConditionReason = "ResolvedRefs"
122+
MCPServerReasonImageNotFound MCPServerConditionReason = "ImageNotFound"
123+
124+
// Programmed condition reasons
125+
MCPServerReasonProgrammed MCPServerConditionReason = "Programmed"
126+
MCPServerReasonDeploymentFailed MCPServerConditionReason = "DeploymentFailed"
127+
MCPServerReasonServiceFailed MCPServerConditionReason = "ServiceFailed"
128+
MCPServerReasonConfigMapFailed MCPServerConditionReason = "ConfigMapFailed"
129+
130+
// Ready condition reasons
131+
MCPServerReasonReady MCPServerConditionReason = "Ready"
132+
MCPServerReasonPodsNotReady MCPServerConditionReason = "PodsNotReady"
133+
MCPServerReasonAvailable MCPServerConditionReason = "Available"
134+
MCPServerReasonNotAvailable MCPServerConditionReason = "NotAvailable"
135+
)
136+
137+
// MCPServerSpec defines the desired state of MCPServer.
138+
type MCPServerSpec struct {
139+
// Configuration to Deploy the MCP Server using a docker container
140+
Deployment MCPServerDeployment `json:"deployment"`
141+
142+
// TransportType defines the type of mcp server being run
143+
// +kubebuilder:validation:Enum=stdio;http
144+
TransportType TransportType `json:"transportType,omitempty"`
145+
146+
// StdioTransport defines the configuration for a standard input/output transport.
147+
StdioTransport *StdioTransport `json:"stdioTransport,omitempty"`
148+
149+
// HTTPTransport defines the configuration for a Streamable HTTP transport.
150+
HTTPTransport *HTTPTransport `json:"httpTransport,omitempty"`
151+
}
152+
153+
// StdioTransport defines the configuration for a standard input/output transport.
154+
type StdioTransport struct{}
155+
156+
// HTTPTransport defines the configuration for a Streamable HTTP transport.
157+
type HTTPTransport struct {
158+
// target port is the HTTP port that serves the MCP server.over HTTP
159+
TargetPort uint32 `json:"targetPort,omitempty"`
160+
161+
// the target path where MCP is served
162+
TargetPath string `json:"path,omitempty"`
163+
}
164+
165+
// MCPServerStatus defines the observed state of MCPServer.
166+
type MCPServerStatus struct {
167+
// Conditions describe the current conditions of the MCPServer.
168+
// Implementations should prefer to express MCPServer conditions
169+
// using the `MCPServerConditionType` and `MCPServerConditionReason`
170+
// constants so that operators and tools can converge on a common
171+
// vocabulary to describe MCPServer state.
172+
//
173+
// Known condition types are:
174+
//
175+
// * "Accepted"
176+
// * "ResolvedRefs"
177+
// * "Programmed"
178+
// * "Ready"
179+
//
180+
// +optional
181+
// +listType=map
182+
// +listMapKey=type
183+
// +kubebuilder:validation:MaxItems=8
184+
Conditions []metav1.Condition `json:"conditions,omitempty"`
185+
186+
// ObservedGeneration is the most recent generation observed for this MCPServer.
187+
// It corresponds to the MCPServer's generation, which is updated on mutation by the API Server.
188+
// +optional
189+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
190+
}
191+
192+
// MCPServerDeployment
193+
// TODO: consolidate with DeploymentSpec in agent_types.go
194+
type MCPServerDeployment struct {
195+
// Image defines the container image to to deploy the MCP server.
196+
// +optional
197+
Image string `json:"image,omitempty"`
198+
199+
// Port defines the port on which the MCP server will listen.
200+
// +optional
201+
// +kubebuilder:default=3000
202+
Port uint16 `json:"port,omitempty"`
203+
204+
// Cmd defines the command to run in the container to start the mcp server.
205+
// +optional
206+
Cmd string `json:"cmd,omitempty"`
207+
208+
// Args defines the arguments to pass to the command.
209+
// +optional
210+
Args []string `json:"args,omitempty"`
211+
212+
// Env defines the environment variables to set in the container.
213+
// +optional
214+
Env map[string]string `json:"env,omitempty"`
215+
216+
// SecretRefs defines the list of Kubernetes secrets to reference.
217+
// These secrets will be mounted as volumes to the MCP server container.
218+
// +optional
219+
SecretRefs []corev1.LocalObjectReference `json:"secretRefs,omitempty"`
220+
221+
// ConfigMapRefs defines the list of Kubernetes configmaps to reference.
222+
// These configmaps will be mounted as volumes to the MCP server container.
223+
// +optional
224+
ConfigMapRefs []corev1.LocalObjectReference `json:"configMapRefs,omitempty"`
225+
226+
// VolumeMounts defines the list of volume mounts for the MCP server container.
227+
// This allows for more flexible volume mounting configurations.
228+
// +optional
229+
VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"`
230+
231+
// Volumes defines the list of volumes that can be mounted by containers.
232+
// This allows for custom volume configurations beyond just secrets and configmaps.
233+
// +optional
234+
Volumes []corev1.Volume `json:"volumes,omitempty"`
235+
}
236+
237+
// +kubebuilder:object:root=true
238+
// +kubebuilder:subresource:status
239+
// +kubebuilder:resource:shortName=mcps;mcp
240+
// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status"
241+
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
242+
// +kubebuilder:resource:categories=kagent
243+
244+
// MCPServer is the Schema for the mcpservers API.
245+
type MCPServer struct {
246+
metav1.TypeMeta `json:",inline"`
247+
metav1.ObjectMeta `json:"metadata,omitempty"`
248+
249+
Spec MCPServerSpec `json:"spec,omitempty"`
250+
Status MCPServerStatus `json:"status,omitempty"`
251+
}
252+
253+
// +kubebuilder:object:root=true
254+
255+
// MCPServerList contains a list of MCPServer.
256+
type MCPServerList struct {
257+
metav1.TypeMeta `json:",inline"`
258+
metav1.ListMeta `json:"metadata,omitempty"`
259+
Items []MCPServer `json:"items"`
260+
}
261+
262+
func init() {
263+
SchemeBuilder.Register(&MCPServer{}, &MCPServerList{})
264+
}

0 commit comments

Comments
 (0)