Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions hips/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ restricted markdown format and can be found in the
- [hip-0024: Improve the Helm Documentation](hip-0024.md)
- [hip-0025: Better Support for Resource Creation Sequencing](hip-0025.md)
- [hip:0026: H4HIP: Wasm plugin system](hip-0026.md)
- [hip-0028: Add MCP Server to Helm CLI](hip-0028.md)
369 changes: 369 additions & 0 deletions hips/hip-0028.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,369 @@
---
hip: "0028"
title: "Add MCP Server to Helm CLI"
authors: [ "nick powell <[email protected]>" ]
created: "2025-09-03"
type: "feature"
status: "draft"
---

## Abstract

This HIP adds MCP (Model Context Protocol) support to Helm, letting AI assistants like Claude safely run read-only Helm commands. It's completely opt-in, only exposes read operations, and requires minimal implementation effort. The integration automatically converts Helm's Cobra commands into MCP tools, with command flags and arguments becoming the tool's input schema.

## Motivation

Developers are increasingly using AI assistants in their workflows. Currently, if an AI assistant needs to help with Helm operations, users must manually copy and paste terminal output. With MCP support, AI assistants can directly query Helm releases, check status, and explore charts without manual intervention.

## Specification

This HIP adds `helm mcp` commands that enable AI assistants to run safe, read-only Helm operations. Each allowed Helm command becomes an MCP tool, with the command's flags (like `--namespace`, `--all-namespaces`, `--output`) and arguments becoming the tool's input parameters that the AI assistant can use. Convenience commands, like `helm mcp claude enable`, provide a fast and easy opt-in user experience.

### MCP Command Tree

The integration adds the following command hierarchy under `helm mcp`:

```
helm mcp
├── start # Start MCP server on stdio
├── tools # Export available MCP tools as JSON
├── claude
│ ├── enable # Enable Helm MCP in Claude Desktop
│ ├── disable # Disable Helm MCP in Claude Desktop
│ └── list # List MCP configurations in Claude Desktop
└── vscode
├── enable # Enable Helm MCP in VS Code
├── disable # Disable Helm MCP in VS Code
└── list # List MCP configurations in VS Code
```

### Available MCP Tools

Once enabled, AI assistants will have access to the following Helm operations as MCP tools. This list is subject to change with the command tree. Each Helm command becomes an MCP tool, with its flags and arguments automatically converted to the tool's input schema:

| Tool Name | Helm Command | Description |
|-----------|--------------|-------------|
| `helm_list` | `helm list` | List releases in current namespace |
| `helm_status` | `helm status` | Show the status of a named release |
| `helm_history` | `helm history` | Fetch release history |
| `helm_get_all` | `helm get all` | Download all information for a named release |
| `helm_get_hooks` | `helm get hooks` | Download hooks for a named release |
| `helm_get_manifest` | `helm get manifest` | Download the manifest for a named release |
| `helm_get_metadata` | `helm get metadata` | Download metadata for a named release |
| `helm_get_notes` | `helm get notes` | Download notes for a named release |
| `helm_get_values` | `helm get values` | Download values for a named release |
| `helm_show_all` | `helm show all` | Show all information of a chart |
| `helm_show_chart` | `helm show chart` | Show the chart's metadata |
| `helm_show_crds` | `helm show crds` | Show the chart's CRDs |
| `helm_show_readme` | `helm show readme` | Show the chart's README |
| `helm_show_values` | `helm show values` | Show the chart's default values |

The complete tool definitions with their schemas can be exported by running `helm mcp tools`.

## Rationale

The proposed design leverages Helm's existing Cobra command structure to automatically generate MCP tools. Each Cobra command becomes an MCP tool, with the command's flags and arguments becoming the tool's input schema - meaning Helm's existing CLI structure directly maps to the MCP interface without additional configuration. This approach minimizes code changes and maintenance burden while providing a natural mapping between CLI commands and MCP tools.

## Backwards compatibility

Helm will continue to function exactly as before for users who do not enable MCP support. The MCP feature is entirely opt-in and does not modify any existing Helm commands or behaviors.

## How to teach this

- Provide a quick start guide showing how to enable MCP in Claude Desktop or VS Code
- Include examples demonstrating AI-assisted Helm workflows

### Example Usage

```bash
# Enable for Claude Desktop
helm mcp claude enable
```
```bash
# Enable for VS Code
helm mcp vscode enable
```

Users can then ask their AI assistant questions like "What Helm releases are deployed?" or "Show me the nginx values" and the assistant will execute the appropriate commands and provide explanations.

## Reference Implementation

[PR #31221](https://github.com/helm/helm/pull/31221)

The implementation uses [Ophis](https://github.com/njayp/ophis), a Go library that automatically converts Cobra CLI commands into MCP servers. Each allowed Cobra command becomes an MCP tool, with the command's flags and arguments automatically becoming the tool's input parameters. The integration is added to `pkg/cmd/root.go`:

```go
// mcp server commands
ophis.Command(&ophis.Config{
Filters: []ophis.Filter{
ophis.AllowFilter([]string{
"helm list",
"helm status",
"helm get",
"helm history",
"helm show",
"helm search",
}),
},
}),
```

### Under the Hood

Ophis works by automatically analyzing a Cobra CLI's command structure and converting each allowed command into an MCP tool with a corresponding JSON schema. Here's how the transformation process works:

#### Command Discovery and Filtering

When Ophis starts, it recursively traverses the entire Cobra command tree starting from the root command. For each command it encounters, it applies a series of filters to determine whether that command should be exposed as an MCP tool.

The default filters exclude:
- Commands without a `Run` or `PreRun` function (non-executable commands)
- Hidden commands (`cmd.Hidden = true`)
- Built-in utility commands like `mcp`, `help`, and `completion`

For Helm, the integration uses an `AllowFilter` to explicitly whitelist only safe, read-only operations:

```go
ophis.AllowFilter([]string{
"helm list",
"helm status",
"helm get",
"helm history",
"helm show",
"helm search",
})
```

#### Tool Name Generation

Each allowed command is assigned a unique tool name by flattening the command path with underscores. For example:
- `helm list` becomes `helm_list`
- `helm get values` becomes `helm_get_values`
- `helm search repo` becomes `helm_search_repo`

This naming scheme ensures each MCP tool has a unique, predictable identifier that maps directly back to the original CLI command.

#### Schema Generation

Ophis automatically generates a JSON schema for each tool by analyzing the command's flags and arguments:

**Input Schema Structure:**
```json
{
"type": "object",
"properties": {
"flags": {
"type": "object",
"properties": {
// Individual flag schemas generated from cobra.Command.Flags()
}
},
"args": {
"type": "array",
"items": {"type": "string"},
"description": "Positional command line arguments\nUsage pattern: <extracted from cmd.Use>"
}
}
}
```

**Flag Schema Generation:**
Ophis inspects each command's flag set and automatically generates appropriate JSON schema types:

- `bool` flags → `"type": "boolean"`
- `int`/`uint` flags → `"type": "integer"`
- `float` flags → `"type": "number"`
- `string` flags → `"type": "string"`
- `stringSlice` flags → `"type": "array", "items": {"type": "string"}`
- `duration` flags → `"type": "string"` with regex pattern validation
- `ip`/`ipNet` flags → `"type": "string"` with IP address patterns

Each flag's usage description becomes the schema's description field, and hidden flags are automatically excluded.

**Output Schema:**
All tools share a consistent output schema:
```json
{
"type": "object",
"properties": {
"stdout": {"type": "string"},
"stderr": {"type": "string"},
"exitCode": {"type": "integer"}
}
}
```

#### Command Execution

When an AI assistant invokes an MCP tool, Ophis handles the execution through a structured process:

1. **Argument Construction**: The MCP tool input is converted back to CLI arguments:
- Tool name `helm_get_manifest` → command path `["get", "manifest"]`
- Boolean flags: `{"all-namespaces": true}` → `["--all-namespaces"]`
- Value flags: `{"output": "json"}` → `["--output", "json"]`
- Array flags: `{"selector": ["app=web", "env=prod"]}` → `["--selector", "app=web", "--selector", "env=prod"]`
- Positional args are appended directly

2. **Subprocess Execution**: Ophis executes the original CLI binary as a subprocess:
```go
cmd := exec.CommandContext(ctx, executablePath, args...)
```

3. **Output Capture**: All stdout, stderr, and exit code information is captured and returned in the structured output format.

#### Configuration Management

Ophis provides convenience commands for integrating with AI assistants:

- **`helm mcp claude enable`**: Automatically updates Claude Desktop's configuration file (`~/.config/claude-desktop/config.json`) to include the Helm MCP server
- **`helm mcp vscode enable`**: Updates VS Code's settings to register the MCP server for Copilot integration
- **`helm mcp tools`**: Exports all available tools and their schemas to `mcp-tools.json` for inspection

## Appendix

### Example Tool Schema

For `helm_get_manifest`. Running `helm mcp tools` exports all tools.

```json
{
"description": "\nThis command fetches the generated manifest for a given release.\n\nA manifest is a YAML-encoded representation of the Kubernetes resources that\nwere generated from this release's chart(s). If a chart is dependent on other\ncharts, those resources will also be included in the manifest.\n",
"inputSchema": {
"type": "object",
"properties": {
"args": {
"type": "array",
"description": "Positional command line arguments\nUsage pattern: RELEASE_NAME",
"items": {
"type": "string"
}
},
"flags": {
"type": "object",
"description": "Command line flags",
"properties": {
"burst-limit": {
"type": "integer",
"description": "client-side default throttling limit"
},
"color": {
"type": "string",
"description": "use colored output (never, auto, always)"
},
"colour": {
"type": "string",
"description": "use colored output (never, auto, always)"
},
"content-cache": {
"type": "string",
"description": "path to the directory containing cached content (e.g. charts)"
},
"debug": {
"type": "boolean",
"description": "enable verbose output"
},
"kube-apiserver": {
"type": "string",
"description": "the address and the port for the Kubernetes API server"
},
"kube-as-group": {
"type": "array",
"description": "group to impersonate for the operation, this flag can be repeated to specify multiple groups.",
"items": {
"type": "string"
}
},
"kube-as-user": {
"type": "string",
"description": "username to impersonate for the operation"
},
"kube-ca-file": {
"type": "string",
"description": "the certificate authority file for the Kubernetes API server connection"
},
"kube-context": {
"type": "string",
"description": "name of the kubeconfig context to use"
},
"kube-insecure-skip-tls-verify": {
"type": "boolean",
"description": "if true, the Kubernetes API server's certificate will not be checked for validity. This will make your HTTPS connections insecure"
},
"kube-tls-server-name": {
"type": "string",
"description": "server name to use for Kubernetes API server certificate validation. If it is not provided, the hostname used to contact the server is used"
},
"kube-token": {
"type": "string",
"description": "bearer token used for authentication"
},
"kubeconfig": {
"type": "string",
"description": "path to the kubeconfig file"
},
"namespace": {
"type": "string",
"description": "namespace scope for this request"
},
"qps": {
"type": "number",
"description": "queries per second used when communicating with the Kubernetes API, not including bursting"
},
"registry-config": {
"type": "string",
"description": "path to the registry config file"
},
"repository-cache": {
"type": "string",
"description": "path to the directory containing cached repository indexes"
},
"repository-config": {
"type": "string",
"description": "path to the file containing repository names and URLs"
},
"revision": {
"type": "integer",
"description": "get the named release with revision"
}
},
"additionalProperties": true
}
},
"additionalProperties": false
},
"name": "helm_get_manifest",
"outputSchema": {
"type": "object",
"required": [
"exitCode"
],
"properties": {
"exitCode": {
"type": "integer",
"description": "Exit code"
},
"stderr": {
"type": "string",
"description": "Standard error"
},
"stdout": {
"type": "string",
"description": "Standard output"
}
},
"additionalProperties": false
}
},
```

### Example Claude Config Object

```json
"helm": {
"command": "/Users/nickpowell/forks/helm/bin/helm",
"args": [
"mcp",
"start"
]
},
```