Skip to content

Conversation

@lyarwood
Copy link
Contributor

@lyarwood lyarwood commented Oct 21, 2025

Summary

This PR introduces an initial KubeVirt toolset for the kubernetes-mcp-server, enabling AI agents to create virtual machines through MCP tools.

New Tools

vm_create

Provides VM creation with automatic resource resolution:

  • Workload Matching: Auto-resolves OS names (fedora, ubuntu, rhel, etc.) to container disks or DataSources
  • Resource Selection:
    • Auto-selects instancetypes based on size/performance hints
    • Auto-matches preferences based on workload names
    • Supports DataSource defaults
  • Flexible Configuration: Supports both cluster-scoped and namespaced instancetypes/preferences
  • Configurable Storage: Customizable root disk size (default: 30Gi)

Example Usage

Basic VM with auto-selected resources

  {
    "name": "vm_create",
    "arguments": {
      "namespace": "vms",
      "name": "my-vm",
      "workload": "fedora"
    }
  }

VM with specific size and performance hints

  {
    "name": "vm_create",
    "arguments": {
      "namespace": "vms",
      "name": "my-vm",
      "workload": "rhel",
      "size": "large",
      "performance": "compute-optimized",
      "storage": "100Gi"
    }
  }

VM with explicit instancetype and preference

  {
    "name": "vm_create",
    "arguments": {
      "namespace": "vms",
      "name": "my-vm",
      "workload": "ubuntu",
      "instancetype": "u1.medium",
      "preference": "ubuntu",
      "autostart": true
    }
  }

VM with custom container disk image

  {
    "name": "vm_create",
    "arguments": {
      "namespace": "vms",
      "name": "my-vm",
      "workload": "quay.io/myrepo/custom-os:v1.0",
      "size": "xlarge",
      "storage": "200Gi"
    }
  }

@lyarwood lyarwood force-pushed the kubevirt branch 2 times, most recently from 9aa2732 to 4eac816 Compare November 3, 2025 20:27
@lyarwood lyarwood force-pushed the kubevirt branch 2 times, most recently from a135353 to 24ad072 Compare November 4, 2025 19:02
@lyarwood

This comment was marked as outdated.

@Cali0707
Copy link
Collaborator

Cali0707 commented Nov 5, 2025

it would be nice if gevals included /cost and /context data allowing us to assert against it potentially.

@lyarwood +1 from my side on that being nice, the reason we haven't been able to add it there is that we use claude code in the non-interactive setup in gevals, and we haven't been able to figure out how to get that information in the non interactive setup. If you have any ideas, let me know and/or open a PR!

@lyarwood lyarwood force-pushed the kubevirt branch 2 times, most recently from 30c0ec0 to c01fe35 Compare November 7, 2025 15:19
@lyarwood lyarwood marked this pull request as ready for review November 7, 2025 15:23
@lyarwood lyarwood changed the title WIP feat(kubevirt): Add VM management toolset feat(kubevirt): Add VM management toolset Nov 7, 2025
@lyarwood lyarwood changed the title feat(kubevirt): Add VM management toolset feat(kubevirt): Add basic VM management toolset Nov 7, 2025
Copy link

@codingben codingben left a comment

Choose a reason for hiding this comment

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

Good work Lee. Please consider creating a single VM package with tool.go that will have all VM's actions in one single place, it would help to avoid duplications and will be much better in terms of readablity and maintainability.

Copy link

@codingben codingben left a comment

Choose a reason for hiding this comment

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

Thanks Lee.

Just an opinion: For the beginning I see too many folders and scripts to achieve a few VM's actions via MCP tooling. I'd ask the project's maintainers opinion about this, eventually this repository's codebase can be very huge.

@lyarwood
Copy link
Contributor Author

Thanks Lee.

Just an opinion: For the beginning I see too many folders and scripts to achieve a few VM's actions via MCP tooling. I'd ask the project's maintainers opinion about this, eventually this repository's codebase can be very huge.

Assuming you are talking about the test directory, I agree it is indeed pretty large at the moment but I've already spoken to folks about improvements to the gevals framework that would help reduce that. I plan on working on introducing builtin agent support and configurable models for the openai-agent this week but until that is merged we will need to carry the extra scripts and config for now.

Comment on lines 34 to 40
// RESTConfig returns the Kubernetes REST configuration
func (k *Kubernetes) RESTConfig() *rest.Config {
if k.manager == nil {
return nil
}
return k.manager.cfg
}
Copy link
Member

Choose a reason for hiding this comment

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

There's already a ToRESTConfig method to cover this functionality and implement the RESTClientGetter interface required for Helm:

// ToRESTConfig returns the rest.Config object (genericclioptions.RESTClientGetter)
func (m *Manager) ToRESTConfig() (*rest.Config, error) {
return m.cfg, nil
}

Similarly, there's already a ToDiscoveryClient method too (I think you're creating it at some point in the toolset).

Nonetheless, we need to prevent accessing any kubernetes API without checking if the resource is allowed by configuration:

// isAllowed checks the resource is in denied list or not.
// If it is in denied list, this function returns false.
func isAllowed(
staticConfig *config.StaticConfig, // TODO: maybe just use the denied resource slice
gvk *schema.GroupVersionKind,
) bool {
if staticConfig == nil {
return true
}
for _, val := range staticConfig.DeniedResources {
// If kind is empty, that means Group/Version pair is denied entirely
if val.Kind == "" {
if gvk.Group == val.Group && gvk.Version == val.Version {
return false
}
}
if gvk.Group == val.Group &&
gvk.Version == val.Version &&
gvk.Kind == val.Kind {
return false
}
}
return true
}

In general, we don't want to directly expose the Kuberentes API to the toolsets implementors and provide whatetever is needed in the kubernetes package.

Copy link
Contributor Author

@lyarwood lyarwood Nov 14, 2025

Choose a reason for hiding this comment

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

@manusa ACK apologies, pushed 9a977dc that should address this.


// ResourcesListByGVR lists resources using a GroupVersionResource directly.
// Access control is enforced through the RESTMapper.
// Use this when you need to query arbitrary resources not covered by ResourcesList.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@lyarwood what is the use case where the ResourcesList doesn't work?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah apologies, should be fixed by 9cd97b4

@lyarwood lyarwood force-pushed the kubevirt branch 2 times, most recently from aec49be to 9cd97b4 Compare November 17, 2025 16:59
@manusa manusa self-requested a review November 24, 2025 13:35
@lyarwood lyarwood changed the title feat(kubevirt): Add basic VM management toolset feat(kubevirt): Add basic VM creation toolset Nov 24, 2025
lyarwood and others added 8 commits November 27, 2025 11:19
Add framework support for using k8s.io/client-go/dynamic/fake in tests.
This enables unit tests to inject fake Kubernetes clients without
requiring a real cluster or envtest setup.

Changes:

1. Add NewAccessControlClientsetForTesting() constructor
   - Accepts pre-built fake clients (dynamic, discovery, REST mapper)
   - Returns AccessControlClientset for use in tests
   - Located in pkg/kubernetes/accesscontrol_clientset.go

2. Add NewForTesting() constructor for Kubernetes
   - Creates Kubernetes instance with fake AccessControlClientset
   - Minimal Manager setup suitable for testing
   - Located in pkg/kubernetes/kubernetes.go

3. Add Config() method to AccessControlClientset
   - Exposes rest.Config for use by other components
   - Fixes NewKiali() to use Config() instead of direct field access

4. Create pkg/kubernetes/testing package with helpers
   - NewFakeKubernetesClient() factory function
   - Accepts runtime.Scheme, GVR to ListKind mapping, and initial objects
   - Returns fully configured Kubernetes instance with fake clients
   - Includes FakeRESTMapper implementing meta.ResettableRESTMapper
   - Includes minimal fakeDiscoveryClient for cached discovery

These changes enable toolset tests (like kubevirt VM creation) to use
fake clients for unit testing without external dependencies.

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
Introduces a new KubeVirt toolset providing virtual machine management
capabilities through MCP tools.

Features:
  - Smart workload resolution: Matches user input against cluster
    DataSources or built-in OS mappings (fedora, ubuntu, centos, rhel,
    debian, opensuse)
  - Automatic instance type selection based on size/performance hints
  - Preference auto-selection matching workload names
  - Supports both DataSource-backed VMs and containerdisk VMs
  - Configurable runStrategy (Halted by default, Always with autostart
    flag)

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
…es/preferences

Previously, the VM template hardcoded instancetype and preference kinds to
always use VirtualMachineClusterInstancetype and VirtualMachineClusterPreference.
This prevented using namespaced VirtualMachineInstancetype and VirtualMachinePreference
resources.

This enables VMs to reference both cluster-wide and namespace-specific
instance types and preferences correctly.

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
Previously, the VM storage size was hardcoded to 30Gi in the template,
making it impossible to create VMs with different disk sizes without
manually editing the generated YAML.

Storage parameter only applies when using DataSources. Container disk
VMs don't create persistent volumes, so the parameter is ignored in
those cases (as noted in the parameter description).

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
Previously, errors encountered while listing DataSources, Preferences,
and Instancetypes were silently ignored, making it difficult to debug
issues when resources weren't being discovered properly.

This provides better observability for debugging while maintaining the
existing resilient behavior (failures don't block VM creation, they just
limit available resources for auto-selection).

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
Previously, public functions in pkg/kubevirt/resources.go lacked detailed
documentation explaining their parameters, return values, and behavior.
This made the code harder to understand and maintain.

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
Move tests to create_test package and access functionality only through
the Tools() function, ensuring tests are decoupled from internal
implementation details.

Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
@manusa manusa added this to the 0.1.0 milestone Nov 27, 2025
Copy link
Member

@manusa manusa left a comment

Choose a reason for hiding this comment

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

LGTM, thx!

I added an additional commit to move the toolset tests to the MCP layer.
We are now testing the behavior from the MCP client up to the Kube API layer at no cost.

Production code looks good; there are a few optimizations that can be done, but I suppose we can defer these to follow up PRs.

@manusa manusa requested a review from Cali0707 November 27, 2025 12:01
@ksimon1
Copy link

ksimon1 commented Nov 27, 2025

/lgtm

Copy link
Contributor Author

@lyarwood lyarwood left a comment

Choose a reason for hiding this comment

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

/lgtm

Copy link
Collaborator

@Cali0707 Cali0707 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for all the hard work on this @lyarwood @ksimon1 @manusa !

@Cali0707 Cali0707 merged commit d6a28d7 into containers:main Nov 27, 2025
6 checks passed
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.

5 participants