Skip to main content
Glama
yanmxa

OCM MCP Server

by yanmxa

kubectl

Execute Kubernetes cluster commands or apply YAML configurations through the OCM MCP Server to manage and operate Kubernetes resources across multiple clusters.

Instructions

Securely run a kubectl command or apply YAML. Provide either 'command' or 'yaml'.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
commandYesThe full kubectl command to execute. Must start with 'kubectl'.
yamlYesYAML configuration to apply, provided as a string.
clusterNoThe cluster name in a multi-cluster environment. Defaults to the hub cluster.default

Implementation Reference

  • Python MCP tool handler for 'kubectl': executes kubectl commands or applies YAML manifests with cluster-specific kubeconfig handling, validation, and error management.
    @mcp.tool(description="Securely run a kubectl command or apply YAML. Provide either 'command' or 'yaml'.")
    def kube_executor(
        cluster: Annotated[str, Field(description="The cluster name in a multi-cluster environment. Defaults to the hub cluster.")] = "default",
        command: Annotated[Optional[str], Field(description="The full kubectl command to execute. Must start with 'kubectl'.")] = None,
        yaml: Annotated[Optional[str], Field(description="YAML configuration to apply, provided as a string.")] = None,
    ) -> Annotated[str, Field(description="The execution result")]:
        try:
            if not command and not yaml:
                raise ValueError("Either 'command' or 'yaml' must be provided.")
            if command and yaml:
                raise ValueError("Provide only one of 'command' or 'yaml', not both.")
    
            kubeconfig_file = None
            if cluster and cluster != "default":
                kubeconfig_file = get_kubeconfig_file(cluster)
                if not validate_kubeconfig_file(kubeconfig_file):
                    kubeconfig_file = setup_cluster_access(cluster=cluster)
                    if not kubeconfig_file:
                        raise FileNotFoundError(f"KUBECONFIG for cluster '{cluster}' does not exist.")
    
            if command:
                if not isinstance(command, str) or not is_valid_kubectl_command(command):
                    raise ValueError("Invalid command: Only 'kubectl' commands are allowed.")
                final_command = command
            else:
                # Write YAML to a temp file
                if not isinstance(yaml, str) or not yaml.strip():
                    raise ValueError("Invalid YAML content.")
                with tempfile.NamedTemporaryFile("w", delete=False, suffix=".yaml") as temp_file:
                    temp_file.write(yaml)
                    temp_file_path = temp_file.name
                final_command = f"kubectl apply -f {temp_file_path}"
    
            # Add --kubeconfig if needed
            if kubeconfig_file:
                final_command = inject_kubeconfig(final_command, kubeconfig_file)
    
            print(f"[debug] Executing: {final_command}")
            result = subprocess.run(final_command, shell=True, capture_output=True, text=True, timeout=10)
    
            output = result.stdout or result.stderr or "Run kube executor successfully, but no output returned."
            return output
        except Exception as e:
            return f"Error running kube executor: {str(e)}"
  • TypeScript MCP tool handler for 'kubectl': executes kubectl commands or applies YAML via stdin with cluster kubeconfig injection and validation.
    export async function kubectl({
      command,
      cluster,
      yaml,
    }: {
      command?: string;
      yaml?: string;
      cluster?: string;
    }): Promise<CallToolResult> {
      try {
        if (!command && !yaml) {
          throw new Error("Either 'command' or 'yaml' must be provided.");
        }
        if (command && yaml) {
          throw new Error("Provide only one of 'command' or 'yaml', not both.");
        }
    
        const kubeConfigFile = await getKubeconfigFile(cluster);
    
        let stdout = "";
        let stderr = "";
    
        if (command) {
          if (typeof command !== "string" || !isValidKubectlCommand(command)) {
            throw new Error("Invalid command: Only 'kubectl' commands are allowed.");
          }
    
          const finalCommand = kubeConfigFile
            ? `${command} --kubeconfig=${kubeConfigFile}`
            : command;
    
          const result = await execPromise(finalCommand);
          stdout = result.stdout;
          stderr = result.stderr;
        } else if (yaml) {
          stdout = await applyYaml(yaml, kubeConfigFile)
        }
    
        return {
          content: [{
            type: "text",
            text: stdout?.trim() || stderr?.trim() || "Run kubectl successfully, but no output returned.",
          }],
        };
      } catch (err: any) {
        return {
          content: [{
            type: "text",
            text: `Error running kubectl: ${err.message || String(err)}`,
          }],
        };
      }
    }
  • src/index.ts:37-42 (registration)
    TypeScript MCP server registration of the 'kubectl' tool using McpServer.tool().
    server.tool(
      "kubectl",
      kubectlDesc,
      kubectlArgs,
      async (args, extra) => kubectl(args) // ensure connectCluster matches (args, extra) => ...
    )
  • TypeScript Zod schema definition for 'kubectl' tool arguments and description.
    export const kubectlDesc = "Securely run a kubectl command or apply YAML. Provide either 'command' or 'yaml'.";
    export const kubectlArgs = {
      command: z
        .string()
        .describe("The full kubectl command to execute. Must start with 'kubectl'."),
      yaml: z
        .string()
        .describe("YAML configuration to apply, provided as a string."),
      cluster: z
        .string()
        .describe("The cluster name in a multi-cluster environment. Defaults to the hub cluster.")
        .default("default"),
    };
  • Helper function to validate if a command is a valid kubectl command (shared pattern in both implementations).
    // Validate that the command starts with "kubectl"
    export function isValidKubectlCommand(command: string): boolean {
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions 'Securely' but doesn't elaborate on what that entails (e.g., authentication, encryption, permissions). It also doesn't describe potential side effects (e.g., resource creation/deletion), error handling, or output format, leaving significant gaps for a tool that interacts with Kubernetes clusters.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise and front-loaded: a single sentence that directly states the purpose and key usage rule. Every word serves a clear function, with no redundancy or unnecessary elaboration, making it efficient for an agent to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of Kubernetes operations (potentially destructive commands), lack of annotations, and no output schema, the description is incomplete. It doesn't address critical aspects like safety warnings, required permissions, response formats, or error conditions, which are essential for an agent to use this tool effectively in a production environment.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal value by reiterating the exclusive choice between 'command' and 'yaml,' but doesn't provide additional context like examples, constraints beyond the schema, or how parameters interact. Baseline 3 is appropriate given the comprehensive schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Securely run a kubectl command or apply YAML.' It specifies two distinct operations (run commands vs apply YAML) and mentions security, though it doesn't differentiate from sibling tools like 'clusters' or 'connect_cluster' which likely serve different Kubernetes-related functions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides basic guidance: 'Provide either 'command' or 'yaml',' indicating an exclusive choice between these two parameters. However, it doesn't explain when to use this tool versus the sibling tools (e.g., 'clusters' for cluster management) or specify prerequisites like authentication or cluster access.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/yanmxa/ocm-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server