Skip to content

Conversation

@onematchfox
Copy link
Contributor

@onematchfox onematchfox commented Aug 28, 2025

This PR decouples the kmcp integration, ensuring that kmcp is a separate, optional component that can be deployed alongside, and independently of, kagent.

The kmcp integration remains fully in place and, by default, is enabled as is the case in the current version. The main difference being that, instead of the hard-coupling that is in place today, where the kagent-controller runs the kmcp controller, the kmcp controller is deployed as a separate, standalone component/pod. This is important for numerous reasons... not least of which is the fact that these are separate projects with separate lifecycles and one should be able to manage them independently if desired.

Notes:

  • The KMCP_ENABLED flag (and associated Helm setting) merely determines whether the kmcp controller and associated CRDs are installed as part of the kagent and kagent-crds. Users can set this to false and install kmcp independently of the kagent Helm chart, and the controller will still work with any additional configuration. The controller simply enables/disables reconciliation of MCPServer resources based on whether or not the CRD is present in the cluster. If desired, in the future, a flag could be added to the controller to disable/enable the integration manually, but for now, I think that's overkill - the (automatic) integration is great 💌
  • The default setup will currently break if KMCP_ENABLED is set to false. This is due to the use of the MCPServer for the grafana MCP as part of the observability agent. This is addressed as part of feat(helm): extract Helm chart for Grafana MCP #812, which switches to using RemoteMCPServer, ensuring that all built-in components/agents/tools work regardless of whether KMCP is enabled.

--set providers.anthropic.apiKey=$(ANTHROPIC_API_KEY) \
--set providers.default=$(KAGENT_DEFAULT_MODEL_PROVIDER) \
--set kmcp.enabled=$(KMCP_ENABLED) \
--set kmcp.image.tag=$(KMCP_VERSION) \
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only required due to kagent-dev/kmcp#74

# ==============================================================================

kmcp:
enabled: true
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Related discussion here. Have used kmcp.enabled here instead of something like integrations.kmcp.enabled, but happy to rework things if desired.

}).
For(&v1alpha1.MCPServer{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Named("toolserver").
Named("mcpserver").
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change wasn't possible previously (see #757) because the code was already running a controller named mcpserver. I.e. this code was running 2 separate controllers reconciling the same resources. 😧

@onematchfox onematchfox marked this pull request as ready for review August 28, 2025 08:49
@onematchfox
Copy link
Contributor Author

onematchfox commented Aug 28, 2025

Just realised that I haven't even considered the UI implications of this change, and I'm going to go ahead and guess that there's stuff that needs to be handled there as well. Will try to take a look ASA,P but feel free to point me in the right direction if you like 🙏

@onematchfox onematchfox marked this pull request as draft August 28, 2025 09:13
@onematchfox onematchfox force-pushed the decouple-kmcp-integration branch 3 times, most recently from 8b203cb to 4c41c95 Compare August 28, 2025 13:37
}

// HandleListToolServerTypes handles GET /api/toolservertypes requests
func (h *ToolServerTypesHandler) HandleListToolServerTypes(w ErrorResponseWriter, r *http.Request) {
Copy link
Contributor Author

@onematchfox onematchfox Aug 28, 2025

Choose a reason for hiding this comment

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

Not 100% sure about this approach. I.e., adding an API endpoint and then calling that via the UI. But, it seemed to fit best with the current usage patterns between UI<->API vs. e.g., having the UI query the cluster directly. It may also prove a useful extension point if other "tool server" types/integrations are added later on. 🤷

More than happy to switch approach if anyone has any thoughts.

URL
</TabsTrigger>
{renderTabTrigger(
"command",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Left the tabs as "url" and "command" for now although I can't help but feel like this dialog/the tabs need a bit of an overhaul given that ultimately, url = RemoteMCPServer and command = MCPServer (which incidentally now needs to support a far broader range of cmd than just npx and uvx).

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree. As a start, it might make sense to rename them RemoteMCPServer and MCPServer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you want to do that as part of this PR or as a separate one?

Copy link
Collaborator

Choose a reason for hiding this comment

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

up to you

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's deal with it separately since it will be needed regardless of what happens with this PR.

@peterj
Copy link
Collaborator

peterj commented Aug 28, 2025

Just realised that I haven't even considered the UI implications of this change, and I'm going to go ahead and guess that there's stuff that needs to be handled there as well. Will try to take a look ASA,P but feel free to point me in the right direction if you like 🙏

In the UI, we'll have to block the creation of tools that use MCPServer resource (the stdio ones, the sse use the RemoteMCPServer crds).

@onematchfox
Copy link
Contributor Author

In the UI, we'll have to block the creation of tools that use MCPServer resource (the stdio ones, the sse use the RemoteMCPServer crds).

Done 🎉 Screenshot of what it looks like when MCPServer CRDs are not found. Moved URL to be the default/first tab so user's won't ever start on a disabled tab.

image

@onematchfox
Copy link
Contributor Author

Had a bit of a discussion with @EItanya on Discord regarding this PR, and I was made aware that there is some history as to why things were implemented the way they have been. We will discuss further at the next contributors meeting. In the meantime, I will open for review and try to address any comments/feedback that are received between now and then. That should also hopefully provide time for the comments here and here to be addressed.

@onematchfox onematchfox marked this pull request as ready for review August 28, 2025 14:14
Copilot AI review requested due to automatic review settings August 29, 2025 06:22
@onematchfox onematchfox force-pushed the decouple-kmcp-integration branch from 4c41c95 to 7d7f79a Compare August 29, 2025 06:22
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR decouples the KMCP (Kubernetes MCP) integration from kagent by making it an optional, standalone component. Instead of the hard-coupled approach where kagent-controller directly runs the kmcp controller, KMCP is now deployed as a separate pod that can be managed independently.

Key changes include:

  • Making KMCP an optional Helm dependency with configurable enablement
  • Adding dynamic tool server type detection based on available CRDs
  • Removing direct KMCP controller integration from kagent's main application

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ui/src/components/AddServerDialog.tsx Updates UI to conditionally show MCPServer tab based on KMCP availability
ui/src/app/servers/page.tsx Fetches supported tool server types to pass to the dialog
ui/src/app/actions/servers.ts Adds API call to retrieve available tool server types
helm/kagent/values.yaml Adds KMCP configuration section with enabled flag
helm/kagent/templates/NOTES.txt Conditionally displays KMCP controller in deployment notes
helm/kagent/Chart-template.yaml Adds KMCP as conditional Helm dependency
helm/kagent-crds/values.yaml Adds KMCP enabled configuration
helm/kagent-crds/Chart-template.yaml Makes KMCP CRDs conditional
go/pkg/app/app.go Removes direct KMCP controller initialization
go/internal/httpserver/server.go Adds route for tool server types endpoint
go/internal/httpserver/handlers/toolservertypes_test.go Tests for tool server types handler
go/internal/httpserver/handlers/toolservertypes.go Implements handler for listing supported tool server types
go/internal/httpserver/handlers/toolservers.go Updates to use shared tool server types and validation
go/internal/httpserver/handlers/handlers.go Registers tool server types handler
go/internal/controller/mcp_server_controller.go Adds CRD detection to conditionally enable controller
go/internal/controller/agent_controller.go Makes MCPServer watching conditional on CRD availability
Makefile Adds KMCP configuration variables and build parameters

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

export function AddServerDialog({ open, onOpenChange, onAddServer, onError }: AddServerDialogProps) {
const [activeTab, setActiveTab] = useState<"command" | "url">("command");
export function AddServerDialog({ open, supportedToolServerTypes, onOpenChange, onAddServer, onError }: AddServerDialogProps) {
const [activeTab, setActiveTab] = useState<"command" | "url">("url");
Copy link

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

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

The default tab has been changed from 'command' to 'url', but this change appears to be unrelated to the KMCP decoupling purpose of this PR. Consider whether this change should be in a separate commit or if it's intentional for this feature.

Suggested change
const [activeTab, setActiveTab] = useState<"command" | "url">("url");
const [activeTab, setActiveTab] = useState<"command" | "url">("command");

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was intentionally changed to ensure that the default tab is always enabled.

Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
onematchfox and others added 11 commits September 11, 2025 08:16
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
…not supported

Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
@onematchfox onematchfox force-pushed the decouple-kmcp-integration branch from d6a925b to fadb976 Compare September 11, 2025 06:18
@onematchfox
Copy link
Contributor Author

Superseded by #939

@EItanya EItanya reopened this Oct 17, 2025
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
@EItanya EItanya merged commit b7f8d32 into kagent-dev:main Oct 21, 2025
16 checks passed
@onematchfox onematchfox deleted the decouple-kmcp-integration branch October 24, 2025 15:15
killjoycircuit pushed a commit to killjoycircuit/kagent that referenced this pull request Nov 1, 2025
This PR decouples the kmcp integration, ensuring that kmcp is a
separate, optional component that can be deployed alongside, and
independently of, kagent.

The kmcp integration remains fully in place and, by default, is enabled
as is the case in the current version. The main difference being that,
instead of the hard-coupling that is in place today, where the
`kagent-controller` [runs the kmcp
controller](https://github.com/kagent-dev/kagent/blob/bdbde1109e7fd214a2536940043a6afef8e07c92/go/pkg/app/app.go#L323-L329),
the kmcp controller is deployed as a separate, standalone component/pod.
This is important for numerous reasons... not least of which is the fact
that these are separate projects with separate lifecycles and one should
be able to manage them independently if desired.

Notes:
- The `KMCP_ENABLED` flag (and associated Helm setting) merely
determines whether the kmcp controller and associated CRDs are installed
as part of the `kagent` and `kagent-crds`. Users can set this to false
and install kmcp independently of the `kagent` Helm chart, and the
controller will still work with any additional configuration. The
controller simply enables/disables reconciliation of `MCPServer`
resources based on whether or not the CRD is present in the cluster. If
desired, in the future, a flag could be added to the controller to
disable/enable the integration manually, but for now, I think that's
overkill - the (automatic) integration is great 💌
- The default setup will currently break if `KMCP_ENABLED` is set to
`false`. This is due to the use of the `MCPServer` for the [`grafana`
MCP](https://github.com/kagent-dev/kagent/blob/bdbde1109e7fd214a2536940043a6afef8e07c92/helm/agents/observability/templates/mcp-server.yaml#L12-L31)
as part of the `observability` agent. This is addressed as part of kagent-dev#812,
which switches to using `RemoteMCPServer`, ensuring that all built-in
components/agents/tools work regardless of whether KMCP is enabled.

---------

Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: killjoycircuit <rutujdhawale@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants