Tutorial Build MCP Server Go: Automasi Linux Sysadmin Pakai AI Agent
Poin Kunci Artikel Ini:
- [ ] Sudoers diisolasi hanya untuk perintah dan argumen yang terdaftar mutlak.
- Namun, model AI membutuhkan protokol terstruktur untuk berinteraksi langsung dengan sistem operasi.
- MCP adalah standar terbuka berbasis JSON-RPC 2.0 yang dikembangkan oleh Anthropic.
Script Manual Lambat: AI Butuh Protokol Standar Akses OS
Eksekusi script Bash manual untuk mengelola infrastruktur Linux lambat, tidak terstruktur, dan rentan human error. Sysadmin sering membuat script ad-hoc tanpa standarisasi skema input-output, tanpa penanganan error yang konsisten, serta tanpa mekanisme rate-limiting atau pembatasan akses yang jelas. Ketika insiden terjadi di lingkungan produksi, mengeksekusi perintah satu per satu via SSH memperpanjang Mean Time to Resolution (MTTR).
AI Agent seperti Claude Desktop, Claude Code, atau LLM lokal (Ollama) memiliki kemampuan analisis log dan diagnostik sistem yang cepat. Namun, model AI membutuhkan protokol terstruktur untuk berinteraksi langsung dengan sistem operasi. Tanpa protokol standar, AI hanya bisa memberikan saran teks yang harus disalin-tempel secara manual oleh manusia.
Model Context Protocol (MCP) memecahkan masalah ini. MCP adalah standar terbuka berbasis JSON-RPC 2.0 yang dikembangkan oleh Anthropic. MCP mendefinisikan cara AI Agent (client) menemukan data (resources), mengeksekusi fungsi (tools), dan membaca instruksi konteks (prompts) dari server eksternal. Menggunakan Go (Golang) untuk membangun MCP Server memberikan tiga keuntungan utama: performa tinggi dengan pemakaian memori minimal, biner tunggal (single static binary) tanpa dependensi runtime eksternal seperti Node.js atau Python, serta model konkuensi murni bawaan language runtime.
Arsitektur & Protokol Transport MCP: Stdio vs HTTP/SSE
Spesifikasi MCP mendukung dua mekanisme transport utama untuk pertukaran pesan JSON-RPC 2.0:
- Standard I/O (stdio): Client menjalankan proses biner MCP Server sebagai child process dan berkomunikasi melalui stream
stdindanstdout. Transport ini ideal untuk pengoperasian lokal atau di dalam kontainer terisolasi karena tidak membuka port jaringan eksternal. - HTTP dengan Server-Sent Events (SSE): Digunakan untuk arsitektur terdistribusi di mana MCP Server berjalan pada remote host dan diakses oleh client melalui koneksi HTTP terenkripsi (TLS).
Aturan kritis dalam transport stdio: seluruh output log aplikasi wajib diarahkan ke stderr. Jika biner mencetak teks biasa atau pesan debug ke stdout, format JSON-RPC akan terdistorsi (corrupted), menyebabkan client gagal melakukan parsing respons.
Build MCP Server Go: Ekspos Metric CPU, RAM, dan Systemd
Tahap berikut menjelaskan pembuatan MCP Server di Go menggunakan SDK resmi github.com/mark3labs/mcp-go untuk mengekspos metrics memori dan kontrol service systemd.
1. Inisialisasi Proyek Go
Eksekusi perintah berikut untuk membuat direktori proyek dan mengunduh dependensi SDK:
mkdir mcp-linux-server && cd mcp-linux-server
go mod init mcp-linux-server
go get github.com/mark3labs/mcp-go2. Implementasi Kode Server Go
Buat file main.go dan masukkan kode berikut. Kode ini mendaftarkan dua tool: get_memory_usage untuk membaca statistik RAM dan check_service_status untuk mengecek status service Linux.
package main
import (
"context"
"fmt"
"os"
"os/exec"
"regexp"
"strings"
"time"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
s := server.NewMCPServer("linux-sysadmin-mcp", "1.0.0")
// Tool 1: Cek RAM
memTool := mcp.NewTool("get_memory_usage",
mcp.WithDescription("Mengambil statistik penggunaan RAM sistem Linux menggunakan perintah free"),
)
s.AddTool(memTool, handleMemoryUsage)
// Tool 2: Cek Service Systemd
serviceTool := mcp.NewTool("check_service_status",
mcp.WithDescription("Memeriksa status operasional service systemd"),
mcp.WithString("service_name", mcp.Required(), mcp.Description("Nama service target (contoh: nginx, docker, sshd)")),
)
s.AddTool(serviceTool, handleServiceStatus)
// Jalankan server menggunakan transport Stdio
if err := server.ServeStdio(s); err != nil {
fmt.Fprintf(os.Stderr, "[ERROR] MCP Server crash: %v\
", err)
os.Exit(1)
}
}
func handleMemoryUsage(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
logAudit("get_memory_usage", "N/A", "system")
out, err := exec.CommandContext(ctx, "free", "-h").Output()
if err != nil {
return mcp.NewToolResultError(fmt.Sprintf("Gagal membaca statistik RAM: %v", err)), nil
}
return mcp.NewToolResultText(string(out)), nil
}
func handleServiceStatus(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
service, ok := request.Params.Arguments["service_name"].(string)
if !ok || strings.TrimSpace(service) == "" {
return mcp.NewToolResultError("Argument service_name wajib diisi dan harus berupa string"), nil
}
// Validasi Strict: cegah command injection
matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", service)
if !matched {
return mcp.NewToolResultError("Format nama service tidak valid! Hanya karakter alfanumerik, dash, dan underscore diperbolehkan."), nil
}
logAudit("check_service_status", service, "system")
out, err := exec.CommandContext(ctx, "systemctl", "is-active", service).Output()
status := strings.TrimSpace(string(out))
if err != nil && status == "" {
status = "unknown/inactive"
}
return mcp.NewToolResultText(fmt.Sprintf("Service '%s' status: %s", service, status)), nil
}
func logAudit(action string, input string, user string) {
f, err := os.OpenFile("/var/log/mcp-audit.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
fmt.Fprintf(os.Stderr, "[WARN] Gagal menulis audit log: %v\
", err)
return
}
defer f.Close()
entry := fmt.Sprintf("[%s] USER=%s ACTION=%s INPUT=%s\
", time.Now().Format(time.RFC3339), user, action, input)
f.WriteString(entry)
}Integrasi Claude Desktop & Ollama Framework
Setelah kode dikompilasi, biner MCP Server dihubungkan ke client AI (Claude Desktop atau LLM Agent lokal).
- Kompilasi source code Go menjadi file biner biner executable:
go build -ldflags="-s -w" -o /usr/local/bin/mcp-linux-server main.go - Buka file konfigurasi client JSON:
- Linux:
~/.config/Claude/claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
- Linux:
- Tambahkan entri server ke dalam bagian
mcpServers:{ "mcpServers": { "linux_admin": { "command": "/usr/local/bin/mcp-linux-server" } } } - Restart Claude Desktop. AI Agent akan mendeteksi tool
get_memory_usagedancheck_service_statussecara otomatis saat sesi percakapan dimulai.
Vulnerability Vectors & Mitigasi Security: Mencegah RCE
Memberikan akses eksekusi sistem ke AI Agent tanpa batas keamanan adalah celah bahaya. LLM dapat mengalami prompt injection dari teks eksternal yang dianalisis, mengarahkan Agent mengeksekusi instruksi destruktif.
1. Hindari Shell Execution Evaluator
Jangan pernah menjalankan perintah via shell evaluator seperti exec.Command("sh", "-c", input) atau exec.Command("bash", "-c", input). Pendekatan ini memungkinkan penyerang menyisipkan karakter metacharacter shell seperti ;, |, atau && untuk mengeksekusi perintah tambahan (Arbitrary Command Execution).
Gunakan format pemisahan argumen eksplisit pada exec.CommandContext(ctx, "binary", "arg1", "arg2").
2. Sanitasi Input Berbasis Sanitization/Regex Whitelist
Setiap input parameter dari AI Client wajib difilter dengan ekspresi reguler ketat sebelum diproses oleh sistem operasi. Hanya karakter aman yang diizinkan masuk ke proses:
matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", inputParam)
if !matched {
return errors.New("Input ditolak: terdeteksi karakter ilegal")
}3. Whitelisting Service Target
Untuk membatasi cakupan aksinya, buat daftarkan izin (allowlist) perintah atau service yang boleh diakses oleh MCP Server:
var allowedServices = map[string]bool{
"nginx": true,
"docker": true,
"sshd": true,
}
if !allowedServices[serviceName] {
return mcp.NewToolResultError("Akses ditolak: service tidak terdaftar dalam allowlist security policy"), nil
}Prinsip Least Privilege & Implementasi Audit Logging
Menjalankan proses MCP Server menggunakan akun root melanggar prinsip dasar keamanan sistem. Jika terjadi exploit pada biner server, penyerang mendapatkan kendali penuh atas sistem operasi.
1. Konfigurasi User Sistem Tanpa Shell
Buat akun user dedicated berhak akses rendah khusus untuk menjalankan service MCP:
sudo useradd -r -s /sbin/nologin mcp-agent2. Konfigurasi Sudoers Terbatas
Jika server memerlukan perintah berhak akses tinggi (seperti merestart service), berikan izin spesifik pada file /etc/sudoers.d/mcp-agent tanpa akses password:
mcp-agent ALL=(ALL) NOPASSWD: /usr/bin/systemctl status nginx, /usr/bin/systemctl restart nginx3. Centralized Audit Log
Setiap eksekusi tool wajib dicatat ke file log yang terproteksi (/var/log/mcp-audit.log). Format log harus mencakup timestamp ISO-8601, nama tool, parameter yang dikirim, serta status keberhasilan eksekusi. Data ini krusial untuk analisis forensik keamanan digital.
Checklist Keamanan Produksi
- [ ] Biner MCP Server tidak dijalankan oleh user
root. - [ ] Seluruh parameter string difilter menggunakan regex
^[a-zA-Z0-9_-]+$. - [ ] Pemanggilan sistem menggunakan
exec.CommandContextdengan argumen terpisah (tanpash -c). - [ ] Sudoers diisolasi hanya untuk perintah dan argumen yang terdaftar mutlak.
- [ ] File log audit di-set dengan hak akses terbatas (
chmod 0600). - [ ] Proses dipasang di dalam ekosistem terisolasi seperti Docker/Podman container atau systemd isolation jail (
ProtectSystem=strict).
Kesimpulan
Mengintegrasikan AI Agent ke infrastruktur Linux dengan MCP Server Go memberikan efisiensi tinggi tanpa mengorbankan keamanan. Protokol terstandar JSON-RPC 2.0, validasi input yang ketat, serta penerapan principle of least privilege memastikan server tetap aman dari risiko Remote Code Execution (RCE). Bangun MCP Tool modular Anda sekarang untuk mengotomatisasi pekerjaan sysadmin secara presisi dan aman.


