Skip to content

Conversation

@onematchfox
Copy link
Contributor

Enables this to be deployed as a standalone component (i.e. without the observability-agent) and also upgrades to make use of Streamable HTTP as this is now supported.

Comment on lines -2 to -5
prometheus:
url: "prometheus.kagent:9090/api/v1"
username: ""
password: ""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of this was unused so cleaned up while I was at it. Same goes for grafana.username and grafana.password just below.

@@ -0,0 +1,14 @@
apiVersion: kagent.dev/v1alpha2
kind: RemoteMCPServer
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know I could have just used the Service, but I prefer this because, since the removal of the ToolServer, one has to look at controller logs to see if there are any issues with Service/McpServer-based tooling.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am cognisant that the original stdio implementation may have been used to dog-food the KMCP integration, but hopefully a different solution can be found for that.

- name: querydoc
version: ${VERSION}
repository: file://../tools/querydoc
condition: external-mcp.querydoc.enabled
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed this condition while I was here

@onematchfox onematchfox marked this pull request as ready for review August 26, 2025 15:58
Copilot AI review requested due to automatic review settings August 26, 2025 15:58
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 extracts the Grafana MCP server functionality into a standalone Helm chart while upgrading to use Streamable HTTP transport. Previously, the Grafana MCP server was tightly coupled with the observability agent, and this change enables independent deployment and improved connectivity through HTTP streaming.

  • Extracts Grafana MCP server into a standalone Helm chart in helm/tools/grafana-mcp/
  • Migrates from stdio transport to streamable-http transport protocol
  • Updates observability agent to reference the new standalone Grafana MCP server

Reviewed Changes

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

Show a summary per file
File Description
helm/tools/grafana-mcp/ New standalone Helm chart for Grafana MCP server with streamable-http transport
helm/kagent/values.yaml Adds configuration for new grafana-mcp tool dependency
helm/kagent/Chart-template.yaml Updates dependencies to include new grafana-mcp chart
helm/agents/observability/ Removes embedded Grafana MCP server and updates agent to reference standalone version
Makefile Adds build steps for new grafana-mcp Helm chart

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

labels:
{{- include "grafana-mcp.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicas }}
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

The template references .Values.replicas but the values.yaml file defines replicaCount. This will cause the deployment to fail. Change this to {{ .Values.replicaCount }}.

Suggested change
replicas: {{ .Values.replicas }}
replicas: {{ .Values.replicaCount }}

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.

Addressed


resources: {}

# Deployment configuration
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

[nitpick] The config: section is empty but referenced in the ConfigMap template. Consider either providing a default value (e.g., config: {}) or adding a comment explaining its purpose.

Suggested change
# Deployment configuration
# Deployment configuration
# The 'config:' section is used to populate the ConfigMap template.
# Add custom configuration values here as needed.

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.

Addressed

Comment on lines +64 to +69
{{/*
Create the grafana server URL
*/}}
{{- define "grafana-mcp.serverUrl" -}}
{{- printf "http://%s.%s:%d/mcp" (include "grafana-mcp.fullname" .) .Release.Namespace (.Values.service.port | int) }}
{{- end }}
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

The helper function grafana-mcp.serverUrl is defined but not used anywhere in the templates. Consider removing it or using it in the RemoteMCPServer template where the URL is currently hardcoded.

Suggested change
{{/*
Create the grafana server URL
*/}}
{{- define "grafana-mcp.serverUrl" -}}
{{- printf "http://%s.%s:%d/mcp" (include "grafana-mcp.fullname" .) .Release.Namespace (.Values.service.port | int) }}
{{- end }}

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.

Addressed

- name: grafana-mcp
version: ${VERSION}
repository: file://../tools/grafana-mcp
condition: tools.grafana-mcp.enabled, agents.observability-agent.enabled
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

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

The condition uses agents.observability-agent.enabled but this should be agents.observability.enabled based on the values structure. Also, using multiple conditions with comma separation creates an AND condition - verify this is the intended behavior.

Suggested change
condition: tools.grafana-mcp.enabled, agents.observability-agent.enabled
condition: tools.grafana-mcp.enabled, agents.observability.enabled

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.

observability-agent is correct - see here.

@EItanya
Copy link
Contributor

EItanya commented Aug 26, 2025

Just out of curiosity why did you move from the MCPServer towards a full deployment/service/configmap approach. We originally had this, but then we added kmcp support into kagent for exactly this purpose.

@onematchfox
Copy link
Contributor Author

Just out of curiosity why did you move from the MCPServer towards a full deployment/service/configmap approach. We originally had this, but then we added kmcp support into kagent for exactly this purpose.

The main reason at this point is that I think that using a native CRD, RemoteMCPServer, provides a better, more idiomatic UX than is possible using either Service or MCPServer. Neither of the other objects provides any form of feedback regarding reconciliation, which means that, in the event of issues, a user is left to trawl through the controller logs to find out why things aren't working. Whereas when using a RemoteMCPServer, one can simply look at the Status of the object to see what went wrong.

Also, whilst I think the KMCP integration is great, I do, however, also disagree with the current implementation, which couples the two projects - but that's a bigger discussion that I was hoping to save for another time 😅.

@EItanya
Copy link
Contributor

EItanya commented Aug 27, 2025

Just out of curiosity why did you move from the MCPServer towards a full deployment/service/configmap approach. We originally had this, but then we added kmcp support into kagent for exactly this purpose.

The main reason at this point is that I think that using a native CRD, RemoteMCPServer, provides a better, more idiomatic UX than is possible using either Service or MCPServer. Neither of the other objects provides any form of feedback regarding reconciliation, which means that, in the event of issues, a user is left to trawl through the controller logs to find out why things aren't working. Whereas when using a RemoteMCPServer, one can simply look at the Status of the object to see what went wrong.

Also, whilst I think the KMCP integration is great, I do, however, also disagree with the current implementation, which couples the two projects - but that's a bigger discussion that I was hoping to save for another time 😅.

Leaving aside the larger architecture question for one moment. I think the fact that the status is not useful is a bug rather than an inherent feature. If the MCPServer status is not properly indicative of what’s happening that’s something we can absolutely fix. In terms of the service, I think we can pretty easily expose a status via the kagent CLI.

@onematchfox
Copy link
Contributor Author

Leaving aside the larger architecture question for one moment. I think the fact that the status is not useful is a bug rather than an inherent feature. If the MCPServer status is not properly indicative of what’s happening that’s something we can absolutely fix. In terms of the service, I think we can pretty easily expose a status via the kagent CLI.

Absolutely. This should be addressed at some point, and was something else I was going to bring up at another point. IMO the correct way to do this is to ensure that all tool servers are reflected in the cluster and not only stored in the database 😅

ToolServer

Enables this to be deployed as a standalone component (i.e. without the observability-agent) and also, incidentally, 😉, without the need for KMCP to be deployed to the cluster since this now supports Streamable HTTP.

Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
@onematchfox
Copy link
Contributor Author

FWIW - I have tried using the grafana-mcp in its current form (using MCPServer with transportType: "stdio") but have been unable to get it to work. I suspect that it's related to the way env vars are populated when running via agentgateway. Needless to say, this isn't an issue when using a Deployment and hosting via streamable HTTP 🤷

image

Comment on lines +216 to +220
tools:
grafana-mcp:
enabled: true
querydoc:
enabled: true
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we have a separate block for this, and not just nest it in the individual blocks below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The tools.x block has a slightly different semantic meaning from the individual blocks below. The tools.x block is used to enable the subcharts for the various tools, whereas the individual querydoc and grafana-mcp blocks are used to configure the subcharts themselves. I.e., any values/directives within the individual blocks themselves will be passed through/sent to the subchart. Were we to specify enabled: true within the individual blocks, this would also be passed through to the subcharts' values. Now, neither of the charts actually defines/makes use of enabled: true at present, so there is no real harm in doing that, but this sort of thing can lead to weird/unexpected behaviour, so generally I prefer maintaining a distinction between the two use-cases. I also noticed that the agents themselves are enabled/disabled/configured in a similar manner, and so I thought I'd be consistent with that for tools. That said, I don't have a hard opinion here, so if you'd prefer enabled to be part of the individual blocks, then I'll happily make it so.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just define these in the deployment. Personally I much prefer an env block in the values file, and then fill them directly into the deployment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't have a strong opinion here either - both work. I did it this way to be consistent with how things are done in querydoc. Happy to refactor as per your desire.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm fine with keeping it here, but can we change the values.yaml field to env to better reflect where these values end up, config is a little too generic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you sure about just changing the name? IMO it would be confusing to specify env as key/values. config is currently a key/value map. env on the other hand implies a list of objects like

 - name: FOO
   value: bar

... or at least that is how env is used on a Deployment. I honestly don't mind the use of either, but would recommend keeping to commonly expected formats.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok fine, we can always change later if we need

Signed-off-by: Brian Fox <878612+onematchfox@users.noreply.github.com>
@EItanya EItanya merged commit c99a3af into kagent-dev:main Aug 28, 2025
13 of 14 checks passed
@onematchfox onematchfox deleted the bf/grafana-mcp branch August 29, 2025 06:28
EItanya added a commit that referenced this pull request Oct 21, 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 #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>
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.

2 participants