Skip to main content
Glama
clpi

CLP MCP - DevOps Infrastructure Server

Official
by clpi
terraform.ts10.5 kB
import { z } from "zod"; export const terraformTools = { validateTerraform: { name: "validate_terraform", title: "Validate Terraform Configuration", description: "Validate Terraform configuration files for syntax and best practices", inputSchema: z.object({ content: z.string().describe("The Terraform configuration content to validate"), }), handler: async ({ content }: { content: string }) => { const issues: string[] = []; const warnings: string[] = []; // Basic structure checks if (!content.includes("terraform {") && !content.includes("resource ") && !content.includes("data ")) { issues.push("No Terraform configuration blocks found"); } // Best practices if (content.includes("terraform {") && !content.includes("required_version")) { warnings.push("Consider specifying required_version in terraform block"); } if (content.includes("terraform {") && !content.includes("backend")) { warnings.push("Consider configuring a backend for state management"); } // Security checks if (content.match(/password\s*=\s*"[^"]+"/)) { issues.push("CRITICAL: Hardcoded password detected - use variables or secrets manager"); } if (content.match(/access_key\s*=\s*"[^"]+"/)) { issues.push("CRITICAL: Hardcoded access key detected - use environment variables"); } // Resource naming if (!content.includes("tags") && content.includes("resource ")) { warnings.push("Resources should include tags for organization and cost tracking"); } // Variable validation if (content.includes("variable ") && !content.includes("description")) { warnings.push("Variables should include descriptions"); } return { content: [ { type: "text" as const, text: JSON.stringify({ valid: issues.length === 0, issues, warnings, recommendations: [ "Use terraform fmt to format configuration", "Use terraform validate for syntax checking", "Store sensitive values in terraform.tfvars (gitignored)", "Use remote state with locking", "Implement module versioning", ], }, null, 2), } ] }; }, }, generateTerraformModule: { name: "generate_terraform_module", title: "Generate Terraform Module", description: "Generate a Terraform module template", inputSchema: z.object({ moduleType: z.enum([ "vpc", "ec2", "rds", "s3", "lambda", "eks", "iam", "security_group", ]).describe("Type of module to generate"), provider: z.enum(["aws", "azure", "gcp"]).describe("Cloud provider"), includeVariables: z.boolean().default(true).describe("Include variables.tf"), includeOutputs: z.boolean().default(true).describe("Include outputs.tf"), }), handler: async ({ moduleType, provider, includeVariables, includeOutputs }: { moduleType: string; provider: string; includeVariables: boolean; includeOutputs: boolean; }) => { const mainTf = generateMainTf(moduleType, provider); const variablesTf = includeVariables ? generateVariablesTf(moduleType) : ""; const outputsTf = includeOutputs ? generateOutputsTf(moduleType) : ""; const files = { "main.tf": mainTf, ...(includeVariables && { "variables.tf": variablesTf }), ...(includeOutputs && { "outputs.tf": outputsTf }), "README.md": generateReadme(moduleType), }; return { content: [ { type: "text" as const, text: JSON.stringify(files, null, 2), } ] }; }, }, formatTerraform: { name: "format_terraform", title: "Format Terraform Configuration", description: "Format Terraform configuration to canonical style", inputSchema: z.object({ content: z.string().describe("The Terraform content to format"), }), handler: async ({ content }: { content: string }) => { // Basic formatting (simplified - real terraform fmt is more complex) let formatted = content .replace(/{\s+/g, "{\n ") .replace(/\s+}/g, "\n}") .replace(/=\s+/g, " = ") .split('\n') .map(line => line.trimEnd()) .join('\n'); return { content: [ { type: "text" as const, text: formatted, } ] }; }, }, analyzeTerraformState: { name: "analyze_terraform_state", title: "Analyze Terraform State", description: "Analyze Terraform state for insights and recommendations", inputSchema: z.object({ stateContent: z.string().describe("The Terraform state JSON content"), }), handler: async ({ stateContent }: { stateContent: string }) => { try { const state = JSON.parse(stateContent); const resources = state.resources || []; const analysis = { version: state.terraform_version, resourceCount: resources.length, resourceTypes: [...new Set(resources.map((r: any) => r.type))], modules: [...new Set(resources.map((r: any) => r.module).filter(Boolean))], providers: [...new Set(resources.map((r: any) => r.provider))], recommendations: [] as string[], }; if (resources.length > 50) { analysis.recommendations.push("Consider splitting into multiple modules"); } if (!state.backend) { analysis.recommendations.push("Configure remote backend for state management"); } return { content: [ { type: "text" as const, text: JSON.stringify(analysis, null, 2), } ] }; } catch (error) { return { content: [ { type: "text" as const, text: `Error parsing state: ${error}`, } ], isError: true, }; } }, }, generateTerraformBackend: { name: "generate_terraform_backend", title: "Generate Terraform Backend Configuration", description: "Generate backend configuration for state management", inputSchema: z.object({ backendType: z.enum(["s3", "azurerm", "gcs", "consul", "kubernetes"]).describe("Backend type"), config: z.record(z.string()).describe("Backend configuration parameters"), }), handler: async ({ backendType, config }: { backendType: string; config: Record<string, string> }) => { const configStr = Object.entries(config) .map(([key, value]) => ` ${key} = "${value}"`) .join('\n'); const backend = `terraform { backend "${backendType}" { ${configStr} } }`; return { content: [ { type: "text" as const, text: backend, } ] }; }, }, }; function generateMainTf(moduleType: string, provider: string): string { const templates: Record<string, Record<string, string>> = { aws: { vpc: `resource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true enable_dns_support = true tags = merge(var.tags, { Name = var.vpc_name }) } resource "aws_subnet" "public" { count = length(var.public_subnet_cidrs) vpc_id = aws_vpc.main.id cidr_block = var.public_subnet_cidrs[count.index] availability_zone = var.availability_zones[count.index] map_public_ip_on_launch = true tags = merge(var.tags, { Name = "\${var.vpc_name}-public-\${count.index + 1}" }) }`, ec2: `resource "aws_instance" "main" { ami = var.ami_id instance_type = var.instance_type subnet_id = var.subnet_id vpc_security_group_ids = var.security_group_ids root_block_device { volume_size = var.root_volume_size volume_type = "gp3" } tags = merge(var.tags, { Name = var.instance_name }) }`, rds: `resource "aws_db_instance" "main" { identifier = var.db_identifier engine = var.engine engine_version = var.engine_version instance_class = var.instance_class allocated_storage = var.allocated_storage storage_type = "gp3" storage_encrypted = true db_name = var.db_name username = var.db_username password = var.db_password vpc_security_group_ids = var.security_group_ids db_subnet_group_name = var.db_subnet_group_name backup_retention_period = var.backup_retention_period skip_final_snapshot = var.skip_final_snapshot tags = var.tags }`, s3: `resource "aws_s3_bucket" "main" { bucket = var.bucket_name tags = var.tags } resource "aws_s3_bucket_versioning" "main" { bucket = aws_s3_bucket.main.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_server_side_encryption_configuration" "main" { bucket = aws_s3_bucket.main.id rule { apply_server_side_encryption_by_default { sse_algorithm = "AES256" } } }`, }, }; return templates[provider]?.[moduleType] || `# ${moduleType} module for ${provider}\n`; } function generateVariablesTf(moduleType: string): string { return `variable "tags" { description = "A map of tags to add to all resources" type = map(string) default = {} } variable "name" { description = "Name to be used on all resources as prefix" type = string } # Add more variables specific to ${moduleType} `; } function generateOutputsTf(moduleType: string): string { return `output "id" { description = "The ID of the ${moduleType}" value = # TODO: Add appropriate resource reference } output "arn" { description = "The ARN of the ${moduleType}" value = # TODO: Add appropriate resource reference } `; } function generateReadme(moduleType: string): string { return `# ${moduleType.toUpperCase()} Terraform Module ## Usage \`\`\`hcl module "${moduleType}" { source = "./modules/${moduleType}" name = "example" tags = { Environment = "production" ManagedBy = "terraform" } } \`\`\` ## Requirements | Name | Version | |------|---------| | terraform | >= 1.0 | ## Inputs See variables.tf for all available inputs. ## Outputs See outputs.tf for all available outputs. `; }

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/clpi/clp-mcp'

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