Skip to main content
Glama
clpi

CLP MCP - DevOps Infrastructure Server

Official
by clpi
ansible.ts10.1 kB
import { z } from "zod"; export const ansibleTools = { validatePlaybook: { name: "validate_ansible_playbook", title: "Validate Ansible Playbook", description: "Validate an Ansible playbook for syntax and best practices", inputSchema: z.object({ content: z.string().describe("The playbook YAML content to validate"), }), handler: async ({ content }: { content: string }) => { const issues: string[] = []; const warnings: string[] = []; // Basic YAML structure checks if (!content.includes("hosts:")) { issues.push("Missing 'hosts' directive - playbook must specify target hosts"); } if (!content.includes("tasks:") && !content.includes("roles:")) { issues.push("Missing 'tasks' or 'roles' - playbook must define actions"); } // Best practices checks if (!content.includes("name:")) { warnings.push("Tasks should have descriptive names for better readability"); } if (!content.includes("become:") && !content.includes("sudo:")) { warnings.push("Consider if privilege escalation (become) is needed"); } if (content.includes("command:") || content.includes("shell:")) { warnings.push("Prefer native Ansible modules over command/shell when possible"); } // Security checks if (content.includes("password:") && !content.includes("vault")) { issues.push("CRITICAL: Potential plaintext password detected - use Ansible Vault"); } return { content: [ { type: "text" as const, text: JSON.stringify({ valid: issues.length === 0, issues, warnings, recommendations: [ "Use ansible-lint for comprehensive static analysis", "Store secrets in Ansible Vault", "Use tags for selective playbook execution", "Add handlers for service restarts", ], }, null, 2), } ] }; }, }, generatePlaybook: { name: "generate_ansible_playbook", title: "Generate Ansible Playbook", description: "Generate an Ansible playbook template based on requirements", inputSchema: z.object({ playbookType: z.enum([ "webserver", "database", "docker", "kubernetes", "security_hardening", "user_management", ]).describe("Type of playbook to generate"), hosts: z.string().describe("Target hosts or group"), variables: z.record(z.string()).optional().describe("Variables to include"), }), handler: async ({ playbookType, hosts, variables }: { playbookType: string; hosts: string; variables?: Record<string, string> }) => { const tasks = getPlaybookTasks(playbookType); const varsSection = variables && Object.keys(variables).length > 0 ? ` vars:\n${Object.entries(variables).map(([k, v]) => ` ${k}: ${v}`).join('\n')}\n` : ''; const playbook = `--- - name: ${capitalize(playbookType.replace(/_/g, ' '))} Configuration hosts: ${hosts} become: yes ${varsSection} tasks: ${tasks.map(task => ` - name: ${task.name} ${task.module}: ${task.params}`).join('\n\n')} handlers: - name: restart service service: name: "{{ service_name }}" state: restarted `; return { content: [ { type: "text" as const, text: playbook, } ] }; }, }, lintPlaybook: { name: "lint_ansible_playbook", title: "Lint Ansible Playbook", description: "Check Ansible playbook for common anti-patterns and style issues", inputSchema: z.object({ content: z.string().describe("The playbook content to lint"), }), handler: async ({ content }: { content: string }) => { const lintResults: Array<{ rule: string; severity: string; message: string }> = []; // Check for deprecated modules const deprecatedModules = ["include", "raw"]; deprecatedModules.forEach(mod => { if (content.includes(`${mod}:`)) { lintResults.push({ rule: "deprecated-module", severity: "warning", message: `Module '${mod}' is deprecated`, }); } }); // Check for command without changed_when if ((content.includes("command:") || content.includes("shell:")) && !content.includes("changed_when:")) { lintResults.push({ rule: "command-instead-of-module", severity: "warning", message: "command/shell should have 'changed_when' clause", }); } // Check for missing no_log on sensitive tasks if ((content.includes("password") || content.includes("secret")) && !content.includes("no_log:")) { lintResults.push({ rule: "no-log-password", severity: "error", message: "Tasks with passwords should use 'no_log: true'", }); } // Check for package without state if (content.includes("package:") && !content.includes("state:")) { lintResults.push({ rule: "package-latest", severity: "warning", message: "Package tasks should explicitly specify 'state'", }); } return { content: [ { type: "text" as const, text: JSON.stringify({ total_issues: lintResults.length, errors: lintResults.filter(r => r.severity === "error").length, warnings: lintResults.filter(r => r.severity === "warning").length, results: lintResults, }, null, 2), } ] }; }, }, generateInventory: { name: "generate_ansible_inventory", title: "Generate Ansible Inventory", description: "Generate an Ansible inventory file", inputSchema: z.object({ format: z.enum(["ini", "yaml"]).describe("Inventory format"), groups: z.record(z.array(z.string())).describe("Host groups and their hosts"), variables: z.record(z.record(z.string())).optional().describe("Group variables"), }), handler: async ({ format, groups, variables }: { format: string; groups: Record<string, string[]>; variables?: Record<string, Record<string, string>> }) => { let inventory = ""; if (format === "ini") { for (const [group, hosts] of Object.entries(groups)) { inventory += `[${group}]\n`; hosts.forEach(host => { inventory += `${host}\n`; }); inventory += "\n"; } if (variables) { for (const [group, vars] of Object.entries(variables)) { inventory += `[${group}:vars]\n`; for (const [key, value] of Object.entries(vars)) { inventory += `${key}=${value}\n`; } inventory += "\n"; } } } else { // YAML format const yamlObj: any = { all: { children: {} } }; for (const [group, hosts] of Object.entries(groups)) { yamlObj.all.children[group] = { hosts: {} }; hosts.forEach(host => { yamlObj.all.children[group].hosts[host] = {}; }); if (variables?.[group]) { yamlObj.all.children[group].vars = variables[group]; } } inventory = JSON.stringify(yamlObj, null, 2); } return { content: [ { type: "text" as const, text: inventory, } ] }; }, }, }; function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } function getPlaybookTasks(playbookType: string): Array<{ name: string; module: string; params: string }> { const taskTemplates: Record<string, Array<{ name: string; module: string; params: string }>> = { webserver: [ { name: "Install nginx", module: "apt", params: "name=nginx state=present update_cache=yes" }, { name: "Start nginx service", module: "service", params: "name=nginx state=started enabled=yes" }, { name: "Copy nginx config", module: "template", params: "src=nginx.conf.j2 dest=/etc/nginx/nginx.conf" }, ], database: [ { name: "Install PostgreSQL", module: "apt", params: "name=postgresql state=present" }, { name: "Start PostgreSQL", module: "service", params: "name=postgresql state=started enabled=yes" }, { name: "Create database", module: "postgresql_db", params: "name={{ db_name }} state=present" }, ], docker: [ { name: "Install Docker dependencies", module: "apt", params: "name={{ item }} state=present with_items: [apt-transport-https, ca-certificates, curl]" }, { name: "Add Docker GPG key", module: "apt_key", params: "url=https://download.docker.com/linux/ubuntu/gpg" }, { name: "Install Docker", module: "apt", params: "name=docker-ce state=present" }, ], kubernetes: [ { name: "Install kubectl", module: "get_url", params: "url=https://dl.k8s.io/release/stable.txt dest=/usr/local/bin/kubectl mode=0755" }, { name: "Install kubeadm", module: "apt", params: "name=kubeadm state=present" }, { name: "Initialize cluster", module: "command", params: "kubeadm init" }, ], security_hardening: [ { name: "Update all packages", module: "apt", params: "upgrade=dist update_cache=yes" }, { name: "Install fail2ban", module: "apt", params: "name=fail2ban state=present" }, { name: "Configure firewall", module: "ufw", params: "rule=allow port=22 proto=tcp" }, ], user_management: [ { name: "Create user group", module: "group", params: "name={{ group_name }} state=present" }, { name: "Create user", module: "user", params: "name={{ username }} groups={{ group_name }} state=present" }, { name: "Set up SSH keys", module: "authorized_key", params: "user={{ username }} key={{ ssh_key }}" }, ], }; return taskTemplates[playbookType] || []; }

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