Tutorial MCP Server untuk AI Agent: Panduan Lengkap 2026

Apa Itu MCP dan Kenapa Lo Harus Tahu?

Oke, jadi gini ceritanya. Tahun 2026 ini, dunia AI agent makin gila perkembangannya. Salah satu teknologi yang lagi hot banget adalah MCP (Model Context Protocol). Kalau lo belum dengar tentang MCP, tenang aja—gue bakal jelasin dari nol sampe lo bisa bikin MCP server sendiri.

MCP itu basically protokol yang dikembangin sama Anthropic buat ngasih AI model (kayak Claude) kemampuan buat connect ke external tools dan data sources. Bayangin lo punya AI assistant yang bisa ngakses database lo, baca file di komputer, atau bahkan kontrol smart home lo—semua itu lewat satu protokol standar. Itulah inti dari MCP.

Kenapa ini penting? Karena sebelum MCP, integrasi AI dengan tools itu ribet banget. Setiap tools punya cara connect yang beda-beda, dan developer harus nulis custom integration buat masing-masing. MCP hadir sebagai solusi universal yang bikin semua jadi lebih gampang dan terstandarisasi.

Kenapa MCP Server Penting untuk AI Agent di 2026

Masalah Lama yang MCP Selesaikan

Dulu, waktu lo mau bikin AI agent yang bisa ngelakuin banyak hal, lo harus:

  • Nulis API wrapper buat setiap tools
  • Handle authentication masing-masing service
  • Maintain integrasi yang fragile dan gampang break
  • Debug masalah yang muncul dari kombinasi tools yang berbeda

Dengan MCP, semua masalah itu bisa diminimalisir. Lo cukup bikin satu MCP server yang expose capabilities tertentu, dan AI agent bisa langsung pake. Simple, clean, maintainable.

Ekosistem yang Makin Mateng

Sekarang di 2026, udah banyak banget MCP server yang ready-to-use. Mulai dari yang handle filesystem, database, web browsing, sampe integrasi sama SaaS tools kayak Slack, Notion, GitHub, dan banyak lagi. Komunitasnya juga aktif, jadi lo bisa nemuin banyak resource dan contoh implementasi.

Kalau lo udah familiar sama tools development kayak yang gue bahas di artikel Claude Code vs Codex, lo bakal appreciate gimana MCP bikin workflow development AI agent jadi lebih smooth.

Arsitektur MCP: Gimana Cara Kerjanya

Sebelum kita masuk ke coding, penting buat ngerti arsitektur MCP dulu.

Komponen Utama

MCP punya tiga komponen utama:

  1. MCP Host: Ini adalah aplikasi yang pengen pake MCP—contohnya Claude Desktop, Cursor IDE, atau app lo sendiri
  2. MCP Client: Komponen di dalam host yang handle komunikasi ke MCP server
  3. MCP Server: Program yang expose tools, resources, dan prompts ke AI model

Komunikasi MCP

MCP pake JSON-RPC 2.0 sebagai format pesannya. Ada dua cara komunikasi:

  • stdio: Komunikasi lewat stdin/stdout (paling umum buat local tools)
  • SSE (Server-Sent Events): Komunikasi lewat HTTP (cocok buat remote services)

Flow-nya kurang lebih begini:

AI Model → MCP Host → MCP Client → [transport] → MCP Server → External Tools/Data

Setup MCP Server dari Nol

Prerequisites

Sebelum mulai, pastiin lo punya:

  • Node.js v18 atau lebih baru
  • npm atau yarn
  • Claude Desktop atau IDE yang support MCP (kayak Cursor—cek perbandingannya di artikel Cursor vs Copilot)
  • Text editor favorit lo

Install MCP SDK

Pertama, bikin project baru dan install MCP SDK:

mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod

Hello World MCP Server

Oke, kita mulai dari yang paling basic dulu. Bikin file index.js:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

// Bikin instance MCP server
const server = new McpServer({
  name: "hello-world-mcp",
  version: "1.0.0",
});

// Definisi tool pertama: greeting
server.tool(
  "greet",
  "Kasih salam ke user dengan nama tertentu",
  {
    name: z.string().describe("Nama orang yang mau disapa"),
  },
  async ({ name }) => {
    return {
      content: [
        {
          type: "text",
          text: `Halo, ${name}! Selamat datang di MCP server gue! 🚀`,
        },
      ],
    };
  }
);

// Definisi tool kedua: kalkulator sederhana
server.tool(
  "calculate",
  "Hitung operasi matematika sederhana",
  {
    a: z.number().describe("Angka pertama"),
    b: z.number().describe("Angka kedua"),
    operation: z.enum(["add", "subtract", "multiply", "divide"]).describe("Operasi yang dilakukan"),
  },
  async ({ a, b, operation }) => {
    let result;
    switch (operation) {
      case "add":
        result = a + b;
        break;
      case "subtract":
        result = a - b;
        break;
      case "multiply":
        result = a * b;
        break;
      case "divide":
        result = b !== 0 ? a / b : "Error: Division by zero";
        break;
    }
    return {
      content: [
        {
          type: "text",
          text: `Hasil ${operation} dari ${a} dan ${b} = ${result}`,
        },
      ],
    };
  }
);

// Jalankan server
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP Server running on stdio");
}

main().catch(console.error);

Update package.json

Jangan lupa tambahin type: "module" di package.json:

{
  "name": "my-mcp-server",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "zod": "^3.22.0"
  }
}

Implementasi MCP Server yang Lebih Real-World

Filesystem MCP Server

Sekarang kita bikin yang lebih berguna—MCP server yang bisa baca dan nulis file di sistem lo:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import fs from "fs/promises";
import path from "path";

const server = new McpServer({
  name: "filesystem-mcp",
  version: "1.0.0",
});

// Base directory buat keamanan
const BASE_DIR = process.env.BASE_DIR || "/tmp/mcp-fs";

// Tool: Baca file
server.tool(
  "read_file",
  "Baca isi dari sebuah file",
  {
    path: z.string().describe("Path relatif ke file yang mau dibaca"),
  },
  async ({ path: filePath }) => {
    try {
      const fullPath = path.join(BASE_DIR, filePath);
      // Security check
      if (!fullPath.startsWith(BASE_DIR)) {
        throw new Error("Access denied: path traversal detected");
      }
      const content = await fs.readFile(fullPath, "utf-8");
      return {
        content: [{ type: "text", text: content }],
      };
    } catch (error) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }],
        isError: true,
      };
    }
  }
);

// Tool: Tulis file
server.tool(
  "write_file",
  "Tulis konten ke sebuah file",
  {
    path: z.string().describe("Path relatif ke file tujuan"),
    content: z.string().describe("Konten yang mau ditulis"),
  },
  async ({ path: filePath, content }) => {
    try {
      const fullPath = path.join(BASE_DIR, filePath);
      if (!fullPath.startsWith(BASE_DIR)) {
        throw new Error("Access denied: path traversal detected");
      }
      // Bikin directory kalau belum ada
      await fs.mkdir(path.dirname(fullPath), { recursive: true });
      await fs.writeFile(fullPath, content, "utf-8");
      return {
        content: [{ type: "text", text: `File berhasil ditulis: ${filePath}` }],
      };
    } catch (error) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }],
        isError: true,
      };
    }
  }
);

// Tool: List directory
server.tool(
  "list_directory",
  "Lihat isi dari sebuah directory",
  {
    path: z.string().optional().describe("Path directory (default: root)").default("."),
  },
  async ({ path: dirPath }) => {
    try {
      const fullPath = path.join(BASE_DIR, dirPath);
      if (!fullPath.startsWith(BASE_DIR)) {
        throw new Error("Access denied: path traversal detected");
      }
      const entries = await fs.readdir(fullPath, { withFileTypes: true });
      const listing = entries.map((entry) => {
        const type = entry.isDirectory() ? "📁" : "📄";
        return `${type} ${entry.name}`;
      });
      return {
        content: [{ type: "text", text: listing.join("\n") }],
      };
    } catch (error) {
      return {
        content: [{ type: "text", text: `Error: ${error.message}` }],
        isError: true,
      };
    }
  }
);

// Resource: Expose file sebagai resource
server.resource(
  "file://{path}",
  "Baca konten file dari path tertentu",
  async (uri) => {
    try {
      const filePath = uri.href.replace("file://", "");
      const fullPath = path.join(BASE_DIR, filePath);
      if (!fullPath.startsWith(BASE_DIR)) {
        throw new Error("Access denied");
      }
      const content = await fs.readFile(fullPath, "utf-8");
      return {
        contents: [
          {
            uri: uri.href,
            mimeType: "text/plain",
            text: content,
          },
        ],
      };
    } catch (error) {
      throw new Error(`Failed to read resource: ${error.message}`);
    }
  }
);

async function main() {
  await fs.mkdir(BASE_DIR, { recursive: true });
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error(`Filesystem MCP Server running (base: ${BASE_DIR})`);
}

main().catch(console.error);

Konfigurasi MCP di Claude Desktop

Edit Config File

Setelah server siap, lo perlu daftarin di Claude Desktop. Edit file config-nya:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "hello-world": {
      "command": "node",
      "args": ["/path/to/my-mcp-server/index.js"],
      "env": {}
    },
    "filesystem": {
      "command": "node",
      "args": ["/path/to/filesystem-mcp/index.js"],
      "env": {
        "BASE_DIR": "/Users/yourname/Documents/mcp-data"
      }
    }
  }
}

Test Koneksi

Restart Claude Desktop, dan lo harusnya bisa liat icon 🔨 di bagian bawah chat. Klik itu buat liat tools yang tersedia dari MCP server lo.

MCP dengan Python

Buat lo yang lebih prefer Python, tenang—MCP juga support Python. Malah cocok banget buat automation tasks. Kalau lo suka automation, cek juga artikel gue tentang Python Automation.

pip install mcp
import asyncio
import json
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types

# Bikin server instance
server = Server("python-mcp-demo")

@server.list_tools()
async def list_tools():
    return [
        types.Tool(
            name="analyze_text",
            description="Analisis teks: hitung kata, karakter, dan kalimat",
            inputSchema={
                "type": "object",
                "properties": {
                    "text": {
                        "type": "string",
                        "description": "Teks yang mau dianalisis"
                    }
                },
                "required": ["text"]
            }
        ),
        types.Tool(
            name="generate_password",
            description="Generate random password",
            inputSchema={
                "type": "object",
                "properties": {
                    "length": {
                        "type": "integer",
                        "description": "Panjang password",
                        "default": 16
                    }
                }
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "analyze_text":
        text = arguments["text"]
        words = len(text.split())
        chars = len(text)
        sentences = text.count('.') + text.count('!') + text.count('?')
        
        result = {
            "word_count": words,
            "char_count": chars,
            "sentence_count": sentences,
            "avg_word_length": round(sum(len(w) for w in text.split()) / words, 2) if words > 0 else 0
        }
        return [types.TextContent(type="text", text=json.dumps(result, indent=2))]
    
    elif name == "generate_password":
        import string
        import secrets
        length = arguments.get("length", 16)
        chars = string.ascii_letters + string.digits + "!@#$%^&*"
        password = ''.join(secrets.choice(chars) for _ in range(length))
        return [types.TextContent(type="text", text=f"Generated password: {password}")]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream, server.create_initialization_options())

if __name__ == "__main__":
    asyncio.run(main())

Deploy MCP Server dengan Docker

Buat production deployment, gue recommend pake Docker. Lo bisa cek panduan lengkapnya di artikel Cara Pakai Docker Compose.

FROM node:20-slim

WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .

CMD ["node", "index.js"]

Kalau mau pake SSE transport buat remote access:

import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";

const app = express();
const server = new McpServer({
  name: "remote-mcp",
  version: "1.0.0",
});

// ... daftarin tools lo di sini ...

const sessions = new Map();

app.get("/sse", async (req, res) => {
  const transport = new SSEServerTransport("/messages", res);
  sessions.set(transport.sessionId, transport);
  
  transport.onclose = () => {
    sessions.delete(transport.sessionId);
  };
  
  await server.connect(transport);
});

app.post("/messages", async (req, res) => {
  const sessionId = req.query.sessionId;
  const transport = sessions.get(sessionId);
  if (transport) {
    await transport.handlePostMessage(req, res);
  } else {
    res.status(404).json({ error: "Session not found" });
  }
});

app.listen(3001, () => {
  console.log("MCP SSE Server running on port 3001");
});

Best Practices & Tips

1. Validasi Input

Selalu validasi input dari AI model. Jangan pernah trust input mentah-mentah—gunakan Zod atau Pydantic buat schema validation.

2. Security First

  • Implementasi path traversal protection
  • Limit akses ke resource tertentu
  • Jangan expose sensitive data lewat tools
  • Pake environment variables buat secrets

3. Error Handling

server.tool("risky_tool", "Tool yang bisa error", {}, async () => {
  try {
    // ... logic
    return { content: [{ type: "text", text: "Success!" }] };
  } catch (error) {
    return {
      content: [{ type: "text", text: `Gagal: ${error.message}` }],
      isError: true,
    };
  }
});

4. Deskripsi yang Jelas

AI model rely heavily on tool descriptions buat tau kapan dan gimana cara make tools lo. Tulis deskripsi yang jelas dan informatif.

5. Testing

Test MCP server lo secara independent sebelum integrate sama AI host. Lo bisa pake MCP Inspector buat debugging.


FAQ seputar MCP Server

Apa bedanya MCP sama REST API?

MCP itu protokol yang didesain khusus buat komunikasi AI-to-Tools. Bedanya sama REST API, MCP punya konsep tools, resources, dan prompts yang lebih rich. Plus, MCP handle discovery otomatis—AI model tau tools apa aja yang available tanpa perlu dokumentasi terpisah.

Bisa nggak MCP server diakses dari multiple AI clients?

Bisa banget! Kalau lo pake SSE transport, MCP server bisa handle multiple clients sekaligus. Setiap client bakal punya session sendiri. Cocok buat skenario di mana lo punya beberapa AI agent yang perlu akses tools yang sama.

MCP server gue kok nggak muncul di Claude Desktop?

Cek beberapa hal:

  1. Path di config JSON udah bener belum?
  2. File config-nya valid JSON nggak?
  3. Server bisa running tanpa error kalau dijalankan manual?
  4. Udah restart Claude Desktop belum setelah edit config?

Aman nggak sih pake MCP buat akses file sistem?

Keamanan tergantung implementasi lo. Selalu:

  • Set base directory yang spesifik
  • Validasi path supaya nggak ada traversal
  • Jangan kasih akses ke directory sensitif
  • Pake environment variables buat konfigurasi sensitif

Bisa bikin MCP server yang connect ke database?

Bisa banget! Lo tinggal bikin tools yang handle database queries. Contohnya tool query_database yang terima SQL query dan return hasilnya. Tapi ingat, ini perlu extra hati-hati soal security—jangan sampe AI bisa drop table lo! 😅


Mulai Eksplorasi MCP Sekarang!

Udah siap bikin MCP server sendiri? Mulai aja dari yang simple—hello world server yang gue kasih di atas. Dari situ, lo bisa expand pelan-pelan sesuai kebutuhan.

MCP ini game-changer banget buat development AI agent. Lo bisa bikin AI assistant yang bener-bener powerful dan terintegrasi sama tools yang lo pake sehari-hari.

Kalau lo punya pertanyaan, stuck di某个step, atau mau sharing hasil project MCP lo, feel free buat reach out ke gue:

📧 [email protected]

Gue seneng banget bisa bantu dan ngobrol soal AI development. Let’s build something awesome together! 🚀