じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

tfmcp 🦀: A Rust-Implemented Tool to Operate Terraform from LLMs

Introduction

Hello! Today, I'd like to introduce a tool I recently developed called tfmcp. This tool allows you to operate Terraform from LLMs (Large Language Models) by utilizing the Model Context Protocol (MCP).

github.com

If you like this project, please consider giving a Star to the GitHub repository to encourage development. Feedback is always welcome!

What is MCP?

Before diving in, let me briefly explain MCP (Model Context Protocol). For more detailed information, refer to the official documentation at modelcontextprotocol.io.

MCP Overview

Note: The image above is in Japanese but illustrates the MCP concept.

MCP is a protocol that allows LLM clients like Cline or Cursor to connect with external services. Traditionally, LLMs could only "think" based on learned data, but with MCP, they gain the ability to "act" by connecting with external systems.

MCP enables capabilities like:

  • Editing files in Notion
  • Querying databases
  • Checking service status
  • Editing and operating local files

MCP is fundamentally a JSON-RPC-based protocol with three main components:

  1. Resources: Provide access to data (equivalent to REST API GET)
  2. Tools: Enable execution of actions (equivalent to REST API POST)
  3. Prompts: Guidance on how LLMs should use the service

tfmcp: Operating Terraform from LLMs

Now, let me introduce tfmcp. It's a tool that utilizes MCP to enable operation of Terraform from LLMs (particularly Claude Desktop).

tfmcp Overview

Note: The image above is in Japanese but illustrates the tfmcp architecture.

Main Features of tfmcp

With tfmcp, you can:

  1. Read and analyze Terraform configuration files
  2. Parse and explain Terraform plans
  3. Apply Terraform configurations
  4. Manage Terraform state
  5. Create and modify configuration files

Demo

Here's a demo of tfmcp working with Claude Desktop:

tfmcp Demo with Claude Desktop

In this demo, Claude operates a Terraform project through natural language commands.

Installation and Setup

tfmcp is written in Rust and can be easily installed using Cargo:

cargo install tfmcp

To connect with Claude Desktop, find the path to the installed tfmcp executable and add it to Claude Desktop's configuration file:

{
     "mcpServers": {
       "tfmcp": {
         "command": "/path/to/your/tfmcp",
         "args": ["mcp"],
         "env": {
           "HOME": "/Users/yourusername",
           "PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin",
           "TERRAFORM_DIR": "/path/to/your/terraform/project"
      }
    }
  }
}

Technical Implementation in Rust

tfmcp consists of these main components:

tfmcp
├── config      - Configuration management
├── core        - Core logic
├── mcp         - MCP protocol implementation
├── shared      - Common utilities
└── terraform   - Terraform integration

tfmcp Architecture

Note: The image above is in Japanese but illustrates the internal architecture of tfmcp.

MCP Server Implementation

The core of the MCP server is the McpHandler struct, which processes requests and executes appropriate Terraform commands:

pub struct McpHandler<'a> {
    tfmcp: &'a mut TfMcp,
    initialized: bool,
}

impl<'a> McpHandler<'a> {
    async fn handle_tools_call(
        &mut self,
        transport: &StdioTransport,
        id: u64,
        params_val: serde_json::Value,
    ) -> anyhow::Result<()> {
        let name = params_val
            .get("name")
            .and_then(|v| v.as_str())
            .unwrap_or("");

        match name {
            "list_terraform_resources" => {
                self.handle_list_terraform_resources(transport, id).await?;
            }
            "analyze_terraform" => {
                self.handle_analyze_terraform(transport, id, &params_val).await?;
            }
            "get_terraform_plan" => {
                self.handle_get_terraform_plan(transport, id).await?;
            }
            // Other tool handlers...
        }
        Ok(())
    }
}

The MCP request/response flow:

MCP Flow

Note: The image above is in Japanese but illustrates the MCP request/response flow.

Terraform Service

The Terraform service handles the actual integration with Terraform:

pub struct TerraformService {
    terraform_path: PathBuf,
    project_directory: PathBuf,
}

impl TerraformService {
    pub async fn apply(&self, auto_approve: bool) -> anyhow::Result<String> {
        let mut args = vec!["apply", "-no-color"];
        if auto_approve {
            args.push("-auto-approve");
        }

        let output = Command::new(&self.terraform_path)
            .args(&args)
            .current_dir(&self.project_directory)
            .output()?;

        // Output processing
        // ...
    }
    
    // Other methods for Terraform operations
}

JSON-RPC Implementation

tfmcp uses Rust to implement the JSON-RPC 2.0 protocol:

JSON-RPC Implementation

Note: The image above is in Japanese but illustrates the JSON-RPC implementation.

The message types and transport are defined as follows:

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Message {
    Request {
        #[serde(rename = "jsonrpc")]
        jsonrpc: String,
        #[serde(rename = "method")]
        method: String,
        #[serde(rename = "id")]
        id: u64,
        #[serde(rename = "params")]
        #[serde(skip_serializing_if = "Option::is_none")]
        params: Option<serde_json::Value>,
    },
    Notification { /* ... */ },
    Response { /* ... */ },
}

#[async_trait]
pub trait Transport: Send + Sync {
    async fn send(&self, message: Message) -> Result<(), Error>;
    fn receive(&self) -> Pin<Box<dyn Stream<Item = Result<Message, Error>> + Send>>;
    async fn close(&self) -> Result<(), Error>;
}

Security Considerations

When using MCP tools like tfmcp, be aware that:

  • They can create, modify, and delete infrastructure
  • They have access to local files and potentially sensitive information
  • Untrusted MCP servers could pose security risks

Implement these safety measures:

  1. Only install MCP servers from trusted sources
  2. Grant minimum required permissions
  3. Run in sandboxed environments when possible
  4. Enable audit logging
  5. Filter sensitive information

Conclusion

tfmcp represents a step forward in integrating Terraform with LLMs. By leveraging the Model Context Protocol, it provides a natural language interface to infrastructure management, simplifying complex IaC (Infrastructure as Code) tasks.

MCP itself acts as a bridge allowing AI models to safely access local resources and tools. The implementation is based on a simple JSON-RPC protocol, making it accessible for developers to create their own MCP servers for specific domains.

The Rust implementation provides benefits like type safety, robust error handling, and efficient asynchronous processing, creating a reliable foundation for smooth interaction between AI and tools.