Skip to main content
Glama

kubectl_logs

Retrieve logs from Kubernetes resources including pods, deployments, jobs, and cronjobs to monitor application behavior and troubleshoot issues.

Instructions

Get logs from Kubernetes resources like pods, deployments, or jobs

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
resourceTypeYesType of resource to get logs from
nameYesName of the resource
namespaceYesKubernetes namespacedefault
containerNoContainer name (required when pod has multiple containers)
tailNoNumber of lines to show from end of logs
sinceNoShow logs since relative time (e.g. '5s', '2m', '3h')
sinceTimeNoShow logs since absolute time (RFC3339)
timestampsNoInclude timestamps in logs
previousNoInclude logs from previously terminated containers
followNoFollow logs output (not recommended, may cause timeouts)
labelSelectorNoFilter resources by label selector
contextNoKubeconfig Context to use for the command (optional - defaults to null)

Implementation Reference

  • Main handler function for the 'kubectl_logs' tool. Executes kubectl logs commands for pods, deployments, jobs, and cronjobs, supporting various options like tail, since, container selection, and label selectors. Handles multi-pod scenarios by fetching logs from all matching pods.
    export async function kubectlLogs( k8sManager: KubernetesManager, input: { resourceType: string; name: string; namespace: string; container?: string; tail?: number; since?: string; sinceTime?: string; timestamps?: boolean; previous?: boolean; follow?: boolean; labelSelector?: string; context?: string; } ) { try { const resourceType = input.resourceType.toLowerCase(); const name = input.name; const namespace = input.namespace || "default"; const context = input.context || ""; const command = "kubectl"; // Handle different resource types if (resourceType === "pod") { // Direct pod logs let args = ["-n", namespace, "logs", name]; // If container is specified, add it if (input.container) { args.push(`-c`, input.container); } // Add options args = addLogOptions(args, input); // Add context if provided if (context) { args.push("--context", context); } // Execute the command try { const result = execFileSync(command, args, { encoding: "utf8", maxBuffer: getSpawnMaxBuffer(), env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG }, }); return formatLogOutput(name, result); } catch (error: any) { return handleCommandError(error, `pod ${name}`); } } else if ( resourceType === "deployment" || resourceType === "job" || resourceType === "cronjob" ) { // For deployments, jobs and cronjobs we need to find the pods first let selectorArgs; if (resourceType === "deployment") { selectorArgs = [ "-n", namespace, "get", "deployment", name, "-o", "jsonpath='{.spec.selector.matchLabels}'", ]; } else if (resourceType === "job") { // For jobs, we use the job-name label return getLabelSelectorLogs(`job-name=${name}`, namespace, input); } else if (resourceType === "cronjob") { // For cronjobs, it's more complex - need to find the job first const jobsArgs = [ "-n", namespace, "get", "jobs", "--selector=job-name=" + name, "-o", "jsonpath='{.items[*].metadata.name}'", ]; try { const jobs = execFileSync(command, jobsArgs, { encoding: "utf8", maxBuffer: getSpawnMaxBuffer(), env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG }, }) .trim() .split(" "); if (jobs.length === 0 || (jobs.length === 1 && jobs[0] === "")) { return { content: [ { type: "text", text: JSON.stringify( { message: `No jobs found for cronjob ${name} in namespace ${namespace}`, }, null, 2 ), }, ], }; } // Get logs for all jobs const allJobLogs: Record<string, any> = {}; for (const job of jobs) { // Get logs for pods from this job const result = await getLabelSelectorLogs( `job-name=${job}`, namespace, input ); const jobLog = JSON.parse(result.content[0].text); allJobLogs[job] = jobLog.logs; } return { content: [ { type: "text", text: JSON.stringify( { cronjob: name, namespace: namespace, jobs: allJobLogs, }, null, 2 ), }, ], }; } catch (error: any) { return handleCommandError(error, `cronjob ${name}`); } } try { if (resourceType === "deployment") { // Get the deployment's selector if (!selectorArgs) { throw new Error("Selector command is undefined"); } const selectorJson = execFileSync(command, selectorArgs, { encoding: "utf8", maxBuffer: getSpawnMaxBuffer(), env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG }, }).trim(); const selector = JSON.parse(selectorJson.replace(/'/g, '"')); // Convert to label selector format const labelSelector = Object.entries(selector) .map(([key, value]) => `${key}=${value}`) .join(","); return getLabelSelectorLogs(labelSelector, namespace, input); } // For jobs and cronjobs, the logic is handled above return { content: [ { type: "text", text: JSON.stringify( { error: `Unexpected resource type: ${resourceType}`, }, null, 2 ), }, ], isError: true, }; } catch (error: any) { return handleCommandError(error, `${resourceType} ${name}`); } } else if (input.labelSelector) { // Handle logs by label selector return getLabelSelectorLogs(input.labelSelector, namespace, input); } else { throw new McpError( ErrorCode.InvalidRequest, `Unsupported resource type: ${resourceType}` ); } } catch (error: any) { if (error instanceof McpError) throw error; throw new McpError( ErrorCode.InternalError, `Failed to get logs: ${error.message}` ); } }
  • Input schema and metadata for the kubectl_logs tool, defining required and optional parameters.
    export const kubectlLogsSchema = { name: "kubectl_logs", description: "Get logs from Kubernetes resources like pods, deployments, or jobs", annotations: { readOnlyHint: true, }, inputSchema: { type: "object", properties: { resourceType: { type: "string", enum: ["pod", "deployment", "job", "cronjob"], description: "Type of resource to get logs from", }, name: { type: "string", description: "Name of the resource", }, namespace: namespaceParameter, container: { type: "string", description: "Container name (required when pod has multiple containers)", }, tail: { type: "number", description: "Number of lines to show from end of logs", }, since: { type: "string", description: "Show logs since relative time (e.g. '5s', '2m', '3h')", }, sinceTime: { type: "string", description: "Show logs since absolute time (RFC3339)", }, timestamps: { type: "boolean", description: "Include timestamps in logs", default: false, }, previous: { type: "boolean", description: "Include logs from previously terminated containers", default: false, }, follow: { type: "boolean", description: "Follow logs output (not recommended, may cause timeouts)", default: false, }, labelSelector: { type: "string", description: "Filter resources by label selector", }, context: contextParameter, }, required: ["resourceType", "name", "namespace"], }, } as const;
  • src/index.ts:292-310 (registration)
    Registration and dispatch logic in the main CallToolRequestSchema handler that routes 'kubectl_logs' tool calls to the kubectlLogs function.
    if (name === "kubectl_logs") { return await kubectlLogs( k8sManager, input as { resourceType: string; name: string; namespace: string; container?: string; tail?: number; since?: string; sinceTime?: string; timestamps?: boolean; previous?: boolean; follow?: boolean; labelSelector?: string; context?: string; } ); }
  • src/index.ts:100-140 (registration)
    Tool schema is included in the allTools array, which is used by ListToolsRequestSchema to expose the tool.
    const allTools = [ // Core operation tools cleanupSchema, // Unified kubectl-style tools - these replace many specific tools kubectlGetSchema, kubectlDescribeSchema, kubectlApplySchema, kubectlDeleteSchema, kubectlCreateSchema, kubectlLogsSchema, kubectlScaleSchema, kubectlPatchSchema, kubectlRolloutSchema, // Kubernetes context management kubectlContextSchema, // Special operations that aren't covered by simple kubectl commands explainResourceSchema, // Helm operations installHelmChartSchema, upgradeHelmChartSchema, uninstallHelmChartSchema, nodeManagementSchema, // Port forwarding PortForwardSchema, StopPortForwardSchema, execInPodSchema, // API resource operations listApiResourcesSchema, // Generic kubectl command kubectlGenericSchema, // Ping utility pingSchema, ];
  • Helper function to retrieve logs from multiple pods matching a label selector, used for deployments, jobs, etc.
    async function getLabelSelectorLogs( labelSelector: string, namespace: string, input: any ): Promise<{ content: Array<{ type: string; text: string }> }> { try { const command = "kubectl"; // First, find all pods matching the label selector const podsArgs = [ "-n", namespace, "get", "pods", `--selector=${labelSelector}`, "-o", "jsonpath='{.items[*].metadata.name}'", ]; const pods = execFileSync(command, podsArgs, { encoding: "utf8", maxBuffer: getSpawnMaxBuffer(), env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG }, }) .trim() .split(" "); if (pods.length === 0 || (pods.length === 1 && pods[0] === "")) { return { content: [ { type: "text", text: JSON.stringify( { message: `No pods found with label selector "${labelSelector}" in namespace ${namespace}`, }, null, 2 ), }, ], }; } // Get logs for each pod const logsMap: Record<string, string> = {}; for (const pod of pods) { // Skip empty pod names if (!pod) continue; let podArgs = ["-n", namespace, "logs", pod]; // Add container if specified if (input.container) { podArgs.push(`-c`, input.container); } // Add other options podArgs = addLogOptions(podArgs, input); try { const logs = execFileSync(command, podArgs, { encoding: "utf8", maxBuffer: getSpawnMaxBuffer(), env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG }, }); logsMap[pod] = logs; } catch (error: any) { logsMap[pod] = `Error: ${error.message}`; } } return { content: [ { type: "text", text: JSON.stringify( { selector: labelSelector, namespace: namespace, logs: logsMap, }, null, 2 ), }, ], }; } catch (error: any) { return handleCommandError(error, `pods with selector "${labelSelector}"`); } }

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/Flux159/mcp-server-kubernetes'

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