← Kembali ke Blog

Bikin MCP Server Pertama: Kasih LLM Tool Beneran dalam 10 Menit

Setiap aplikasi AI ujung-ujungnya nulis glue code yang sama. Model mau manggil sebuah fungsi, kamu bikin fungsi-calling schema manual, tulis handler per vendor, dan begitu ganti model, semuanya auto rusak. Model Context Protocol (MCP) adalah standar terbuka dari Anthropic yang mengubah tumpukan wiring custom itu jadi satu soket yang bisa dipakai ulang model dan client mana pun.

Tutorial ini bikin MCP server yang jalan dalam beberapa menit dan menghubungkannya ke host beneran. Hasilnya bukan mainan, sesuatu yang bisa langsung kamu pakai.

Prerequisites

  • Python 3.10 atau lebih baru
  • uv terinstall (manajer package Python yang cepat, curl -LsSf https://astral.sh/uv/install.sh | sh)
  • Client host MCP: Claude Desktop atau Claude Code
  • Akun GitHub (API yang kita panggil publik, baca data nggak butuh token)

Sebenernya MCP kasih kamu apa

MCP mendefinisikan tiga blok, dan anggap aja kayak verb HTTP biar gampang:

  • Tools mirip endpoint POST. Model manggil mereka untuk ngejalanin kode atau bikin side effect. Ini inti yang paling sering kamu pakai.
  • Resources mirip endpoint GET. Mereka memuat data ke context model tanpa model harus memutuskan memanggl apa-apa.
  • Prompts adalah template yang bisa dipakai ulang, memberi tahu model gimana merespon sebuah tugas.

Sebuah server expose campuran dari tiga hal ini. Host (Claude, atau aplikasi yang kamu bangun) connect ke server itu lewat stdio atau HTTP dan ngasih model akses ke apa yang sudah di-expose.

Langkah 1: siapin project

mkdir mcp-demo && cd mcp-demo
uv init --app
uv add "mcp[cli]" httpx

mcp[cli] narik Python SDK resmi plus tool command-line mcp buat ngejalanin dan ngetes server. Kamu butuh MCP SDK 2.0.0 atau lebih baru; uv add otomatis ambil versi terbaru.

Langkah 2: tulis server pertama kamu

Bikin file server.py. Ini expose satu tool untuk nampilin repo publik milik user GitHub:

# server.py
from mcp.server.fastmcp import FastMCP
import httpx

mcp = FastMCP("GitHub Helper")

@mcp.tool()
async def get_user_repos(username: str) -> str:
    """List public repos for a GitHub user with star counts."""
    url = f"https://api.github.com/users/{username}/repos"
    async with httpx.AsyncClient() as client:
        resp = await client.get(url, headers={"Accept": "application/vnd.github+json"})
        resp.raise_for_status()
    repos = resp.json()
    if not repos:
        return "No public repos found."
    lines = [
        f"{r['name']} ({r['stargazers_count']} stars) - {r['description'] or 'no description'}"
        for r in repos
    ]
    return "
".join(lines)

if __name__ == "__main__":
    mcp.run()

Docstring dan type hint username: str itu bukan hiasan. SDK mengubahnya jadi JSON schema yang dipakai model, jadi model tahu argumen apa yang harus dikasih. Tulis deskripsi tool di docstring seperti kamu jelasin ke rekan kerja, karena teks itu yang dibaca model saat memutuskan mau manggil tool atau nggak.

Langkah 3: tes lokal dulu

mcp run server.py

Ini menjalankan server lewat stdio dan nampilin tool yang terdaftar. Buat manggil tool tanpa host, pakai dev client:

mcp dev server.py

Ini membuka REPL interaktif di mana kamu bisa manggil get_user_repos langsung dan liat output tool sebelum model terlibat. Ngetes tool sendirian sekarang lebih enak daripada debug model dan tool sekaligus nanti.

Langkah 4: hubungkan ke host

Claude Desktop baca file config di ~/Library/Application Support/Claude/claude_desktop_config.json. Arahkan ke server kamu:

{
  "mcpServers": {
    "github-helper": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/mcp-demo", "server.py"]
    }
  }
}

Restart Claude Desktop. Model sekarang harusnya bisa manggil get_user_repos setiap pertanyaan yang menyangkut GitHub.

Claude Code (CLI-nya) pakai command sendiri, bukan edit config:

claude mcp add github-helper -- uv run --directory /absolute/path/to/mcp-demo server.py

Verifikasi dengan claude mcp list. Coba suruh Claude "list the top repos for localhost94" dan lihat dia pakai tool-nya.

Langkah 5: tambah resource dan prompt

Tools aja sudah cukup jauh, tapi dua blok lain itu murah dan bikin server terasa lebih berguna. Tambah satu resource yang nyuntikin konfigurasi, dan satu prompt yang menstrukturin tugas umum:

@mcp.resource("config://app")
def get_config() -> str:
    return """app_name: GitHub Helper MCP
version: 0.1.0
default_owner: localhost94
"""

@mcp.prompt()
def repo_roundup(username: str) -> str:
    return f"Give a short profile of GitHub user {username}, then list their three most-starred repos."

Sekarang host bisa memuat config://app ke context tanpa disuruh, dan prompt ngasih model template buat request yang berulang. Satu server, tiga cara ngasih model apa yang dia butuhin.

MCP vs bikin tool-calling loop sendiri

Kalau aplikasi kamu cuma ngobrol sama satu model dan tool-nya cuma dua fungsi internal, plain function-calling loop lebih ringan. Skip protocol ini sampai salah satu kondisi di bawah bener:

  • Lebih dari satu client atau model harus pakai tool yang sama. MCP bikin batas tool jadi sebuah kontrak, bukan kode yang di-copy-paste.
  • Kamu mau resources dan prompts, bukan cuma calls. Loop biasa cuma ngasih bagian calls.
  • Kamu berencana nge-ship tool yang orang lain bisa colokin ke agent mereka sendiri. MCP adalah format yang udah dipahami Claude Desktop, Claude Code, dan kebanyakan framework agent.

Reach for MCP ketika soketnya yang penting, bukan saat satu call langsung sudah cukup.

Langkah selanjutnya

  • Kalau API yang kamu panggil kayak GitHub punya rate limit, tambah caching di dalam tool biar call berulang tetap murah.
  • Amankan server. Untuk HTTP transport, tambah pengecekan token sebelum mcp.run(), dan pertimbangkan streaming mode buat job panjang.
  • Serve lewat HTTP (streamable transport) daripada stdio supaya yang connect bukan cuma client desktop, tapi juga web app.
  • Baca typescript-sdk kalau stack kamu Node, bukan Python.

Pola yang perlu kamu ingat itu kecil: schema muncul dari type hints dan docstring, tool-nya async Python biasa, dan host yang memutuskan cara manggil. Cuma itu triknya.

Referensi

Butuh Bantuan Implementasi?

Saya membantu tim mendesain dan membangun infrastruktur cloud scalable, pipeline DevOps, dan sistem production-grade.

Konsultasi Gratis