Resource Tracking for Dynamic Data Retrieval in the MCP Kubernetes Server

The MCP server implements resource tracking through an in-memory registry in KubernetesManager that records every created Kubernetes object, enabling dynamic data exposure via MCP resource URIs and automatic cleanup when sessions end.

The flux159/mcp-server-kubernetes repository provides a Model Context Protocol (MCP) server that enables AI assistants to interact with Kubernetes clusters programmatically. At the foundation of its dynamic data retrieval capabilities lies a lightweight resource tracking system that maintains authoritative state across pods, deployments, services, and other objects created during a session.

The Core Resource Tracking Architecture

Internal Collections in KubernetesManager

The KubernetesManager class serves as the central authority for resource tracking, maintaining three distinct internal collections defined in src/utils/kubernetes-manager.ts (lines 10-13):

private resources: ResourceTracker[] = [];      // created k8s objects
private portForwards: PortForwardTracker[] = []; // active port-forwards
private watches: WatchTracker[] = [];           // active watches

These arrays constitute the in-memory state that enables the server to track every interaction with the Kubernetes API throughout the session lifecycle.

The ResourceTracker Interface

The structure of tracked resources is formally defined in src/models/resource-models.ts (lines 26-32):

export interface ResourceTracker {
  kind: string;      // Kubernetes resource type (pod, deployment, etc.)
  name: string;      // Object name
  namespace: string; // Kubernetes namespace
  createdAt: Date;   // Timestamp for lifecycle management
}

This interface ensures type safety while providing the metadata necessary for dynamic data retrieval and cleanup operations.

How Resources Are Tracked

Recording New Resources with trackResource

Whenever a tool creates a Kubernetes object, it invokes the trackResource method in KubernetesManager (lines 76-78 in src/utils/kubernetes-manager.ts):

trackResource(kind: string, name: string, namespace: string) {
  this.resources.push({ kind, name, namespace, createdAt: new Date() });
}

This lightweight operation appends a plain object to the resources array, creating an immutable record of the creation event without impacting API performance.

Resource Creation Flow in Tool Handlers

The resource tracking system integrates with tool implementations in src/tools/ (such as kubectl-apply.ts and kubectl-delete.ts). After successfully creating an object via the Kubernetes API, tools call trackResource to register the new entity:

// Example flow in kubectl-apply.ts
await k8sManager.getAppsApi().createNamespacedDeployment({
  metadata: { name: "demo", namespace: "default" },
  spec: { replicas: 1, template: {/* … */} }
});
k8sManager.trackResource("deployment", "demo", "default");

This pattern ensures that every created resource is accounted for in the tracking system, enabling subsequent dynamic retrieval and guaranteed cleanup.

Dynamic Data Retrieval and Resource Exposure

Resource Handlers and Live URIs

The resource tracking system enables dynamic data retrieval through the resource handlers implemented in src/resources/handlers.ts. These handlers expose MCP-compatible listResources and readResource methods that allow AI assistants to access Kubernetes objects via structured URIs such as k8s://default/pods.

When a client requests a resource, the handler queries the live Kubernetes API through the KubernetesManager (using methods like getCoreApi(), getAppsApi(), etc.) and returns JSON payloads. Because every creation call records the object via trackResource, the server maintains an authoritative registry that ensures resource URIs remain valid and accessible throughout the session.

Reading Tracked Resources

While the resource handlers provide read access to the Kubernetes API, the tracking system itself serves as the single source of truth for session state. The resources array contains the metadata necessary to locate and identify objects, enabling operations such as:

  • Validating that a requested resource exists before attempting retrieval
  • Mapping generic resource requests to specific Kubernetes API calls
  • Ensuring that dynamically created objects remain accessible via MCP resource URIs

This integration between tracking and retrieval ensures that the MCP server can serve dynamic, real-time Kubernetes data while maintaining referential integrity across the session.

Automatic Cleanup and Resource Lifecycle

The cleanup Method

The cleanup method in KubernetesManager (lines 54-73 in src/utils/kubernetes-manager.ts) serves as the primary entry point for resource reclamation. This method ensures that all tracked resources are properly removed from the cluster when the session ends or when explicit cleanup is requested:

async cleanup() {
  // Stop watches first to prevent new events during deletion
  for (const watch of this.watches) { 
    watch.abort.abort(); 
  }

  // Delete tracked resources in reverse order
  for (const resource of [...this.resources].reverse()) {
    try {
      await this.deleteResource(resource.kind, resource.name, resource.namespace);
    } catch (error) {
      process.stderr.write(
        `Failed to delete ${resource.kind} ${resource.name}: ${error}\n`
      );
    }
  }
}

This implementation ensures graceful teardown by first terminating active watches, then systematically removing created resources while logging errors to stderr without aborting the cleanup run.

Deleting Resources in Reverse Order

The deleteResource method (lines 80-98 in src/utils/kubernetes-manager.ts) implements the actual deletion logic, mapping generic resource types to their respective API clients:

async deleteResource(kind: string, name: string, namespace: string) {
  switch (kind.toLowerCase()) {
    case "pod":      
      await this.k8sApi.deleteNamespacedPod({ name, namespace }); 
      break;
    case "deployment": 
      await this.k8sAppsApi.deleteNamespacedDeployment({ name, namespace }); 
      break;
    case "service":   
      await this.k8sApi.deleteNamespacedService({ name, namespace }); 
      break;
    case "cronjob":  
      await this.k8sBatchApi.deleteNamespacedCronJob({ name, namespace }); 
      break;
  }
  
  // Remove from the in-memory list
  this.resources = this.resources.filter(
    r => !(r.kind === kind && r.name === name && r.namespace === namespace)
  );
}

The reverse iteration in cleanup ensures that dependent resources (such as pods owned by deployments) are removed after their parent objects, preventing orphaned objects and dependency conflicts during teardown.

Auxiliary Tracking: Port Forwards and Watches

Beyond static Kubernetes objects, the resource tracking system extends to ephemeral connections through PortForwardTracker and WatchTracker interfaces defined in src/models/resource-models.ts (lines 34-48).

The KubernetesManager maintains separate collections for these active sessions:

// From kubernetes-manager.ts (lines 30-34, 36-38)
trackPortForward(portForward: PortForwardTracker) {
  this.portForwards.push(portForward);
}

trackWatch(watch: WatchTracker) {
  this.watches.push(watch);
}

These trackers enable real-time streaming capabilities—such as tailing logs, exec sessions, or watch events—while ensuring that all network connections and API watches are properly terminated when cleanup() runs. The abort controllers stored in these trackers allow immediate cancellation of long-running connections, preventing resource leaks in the Kubernetes API server.

Summary

  • Resource tracking in the MCP server relies on three in-memory arrays (resources, portForwards, watches) maintained by the KubernetesManager class in src/utils/kubernetes-manager.ts.
  • The trackResource method records every created Kubernetes object with metadata (kind, name, namespace, timestamp), enabling the server to maintain an authoritative registry of session objects.
  • Dynamic data retrieval is powered by resource handlers in src/resources/handlers.ts that query live Kubernetes APIs and expose objects via MCP resource URIs like k8s://default/pods.
  • The cleanup method ensures deterministic teardown by iterating through tracked resources in reverse order, calling deleteResource to map generic kinds to specific Kubernetes API deletion calls, and filtering completed deletions from the in-memory tracker.
  • Port forwards and watches are tracked separately via PortForwardTracker and WatchTracker, enabling real-time streaming while ensuring proper connection termination during cleanup.

Frequently Asked Questions

How does resource tracking prevent resource leaks in the MCP server?

Resource tracking prevents leaks by maintaining an authoritative registry of every created object in the resources array within KubernetesManager. When a session ends or cleanup is triggered, the cleanup() method iterates through this registry in reverse chronological order, invoking deleteResource for each entry to ensure complete removal from the cluster. This guarantees that even if a tool crashes or a client disconnects unexpectedly, the tracking system retains the knowledge necessary to clean up all created objects, preventing orphaned pods, services, and deployments from accumulating in the Kubernetes cluster.

What types of resources can be tracked by the KubernetesManager?

The KubernetesManager tracks three distinct categories of resources through separate collections. First, Kubernetes objects (pods, deployments, services, cronjobs) are stored in the resources array as ResourceTracker objects. Second, port forwards are tracked in portForwards as PortForwardTracker objects, maintaining active network tunnels for pod access. Third, API watches are stored in watches as WatchTracker objects, enabling real-time monitoring of resource changes. This comprehensive tracking ensures that ephemeral connections and long-running observations receive the same lifecycle management as static cluster resources.

How does the cleanup method handle dependencies between resources?

The cleanup method handles dependencies by iterating through the resources array in reverse order using [...this.resources].reverse(). This reverse chronological approach ensures that resources created later—which often depend on earlier resources—are deleted first. For example, if a deployment was created (generating pods) and then a service was created to expose it, the reverse iteration removes the service before the deployment, preventing orphaned endpoints and ensuring clean dependency resolution. The method also wraps each deletion in a try-catch block, logging failures to stderr without aborting the cleanup run, ensuring that partial failures do not leave the tracking registry in an inconsistent state.

Where is the resource tracking data stored during a session?

Resource tracking data is stored in-memory within the KubernetesManager class instance throughout the session lifecycle. The three tracking arrays (resources, portForwards, watches) are private class members that persist as long as the server process runs. This ephemeral storage design means that if the MCP server process crashes or restarts, the tracking state is lost; however, this is intentional for a session-based protocol where cleanup should occur at session boundaries. The in-memory approach provides O(1) insertion and O(n) cleanup performance, suitable for the typical scale of resources managed in a single AI assistant session.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →