← Kembali ke Blog

Bikin MCP Server Pertamamu di Python

Setiap aplikasi AI yang kamu sambungkan butuh lem perekat sendiri-sendiri. Wrapper buat Claude, wrapper lain buat ChatGPT, satu lagi buat agent internal kamu. Masing-masing mendefinisikan ulang tool yang sama, parse argumen yang sama, dan rusak kalau API modelnya berubah. MCP (Model Context Protocol) menghapus lapisan itu: server dibangun sekali, dan host mana pun yang mendukung MCP bisa menemukan tool kamu, membaca resource, dan memanggil semuanya lewat satu antarmuka standar.

MCP adalah protokol open source yang dirilis Anthropic bulan November 2024 dan sekarang dikembangkan bareng working group yang lebih luas. Di bawahnya ada JSON-RPC 2.0 biasa. Ada tiga primitif yang dia definisikan:

  • Tools: fungsi yang bisa dipanggil model dengan argumen bertipe
  • Resources: data read-only yang kamu expose lewat URI
  • Prompts: template siap pakai buat tugas yang berulang

Ada dua transport yang penting di praktik. stdio jalanin server sebagai subprocess lokal, cara host desktop meluncurkannya. Streamable HTTP nyajiin lewat port HTTP beneran buat yang remote. Spesifikasinya pakai versi berbasis tanggal; revisi sekarang adalah 2026-07-28, dan SDK Python v2 menargetkan versi itu.

Prasyarat

  • Python 3.10+
  • uv atau pip
  • Node.js dengan npx buat MCP Inspector (cuma dibutuhkan di Langkah 4)

Kamu nggak butuh API key atau aplikasi chat tertentu. Semua di tutorial ini jalan di lokal.

Langkah 1: Install SDK

pip install "mcp[cli]"

atau pakai uv:

uv add "mcp[cli]"

Extra [cli] nambahin tool baris perintah mcp (mcp dev, mcp run, mcp install) di atas SDK.

Satu peringatan sebelum kamu copy kode dari tutorial lama: pip install mcp sekarang nginstall v2, dan class server-nya diubah nama. Import lama, from mcp.server.fastmcp import FastMCP, dihapus total, bukan sekadar deprecated. Artikel ini pakai v2 dari awal sampai akhir.

Langkah 2: Tulis server.py

Buat file bernama server.py dengan ketiga primitif sekaligus biar keliatan bedanya:

from mcp.server import MCPServer

mcp = MCPServer("Kitchen")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two integers."""
    return a + b

@mcp.tool()
def count_words(text: str) -> int:
    """Count the words in a piece of text."""
    return len(text.split())

@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"

@mcp.prompt()
def review(code: str) -> str:
    """Ask the model to review a code snippet."""
    return f"Review this code for bugs and style: {code}"

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

Perhatiin apa yang nggak kamu tulis: nggak ada JSON Schema, nggak ada parsing request, nggak ada penanganan protokol. Type hint kamu jadi input schema tool-nya, dan docstring jadi deskripsi yang dibaca model sebelum mutusin mau manggil tool yang mana. Ini inti SDK-nya: dua fungsi dan satu docstring udah jadi permukaan integrasi yang lengkap.

Langkah 3: Jalanin lewat stdio

python server.py

Nggak ada output apa pun, dan prosesnya nggak balik lagi. Itu perilaku yang bener. stdout adalah wire-nya: server ngomong pakai JSON-RPC lewat standard input dan output, dan dia nunggu host ngomong duluan. Kalau kamu print() di dalam tool, SDK mindahin output yang ter-flush ke stderr biar nggak ngerusak aliran data. Buat log yang emang mau kamu lihat, pakai module logging.

Langkah 4: Tes dengan MCP Inspector

uv run mcp dev server.py

Perintah ini meluncurkan file kamu sebagai subprocess lewat stdio dan buka UI di browser, persis cara host beneran meluncurkannya. Inspector butuh npx di PATH kamu. Dari situ kamu bisa lihat daftar tool, inspect schema yang di-generate, manggil add dengan argumen, dan baca resource greeting.

Kamu nggak pernah kasih port, karena emang nggak ada. stdio adalah transport-nya.

Langkah 5: Daftarkan ke host

Biar Claude Desktop meluncurkan server ini di tiap percakapan:

uv run mcp install server.py --name "Kitchen"

Host jalanin server di prosesnya sendiri, jadi environment shell kamu nggak diwariskan. Catat environment variable yang dibutuhkan server pakai -v KEY=VALUE atau -f .env. Host lain kayak Claude Code, Cursor, dan VS Code nerima command peluncuran yang sama di file konfigurasi MCP masing-masing; tiap project mendokumentasikan formatnya sendiri.

Langkah 6: Sajikan lewat HTTP

Server yang sama, tanpa diubah, bisa jawab lewat Streamable HTTP. Ganti bagian bawah file:

if __name__ == "__main__":
    mcp.run(transport="streamable-http", port=3001)

Client sekarang connect ke http://127.0.0.1:3001/mcp. Atau skip edit-nya dan biarin CLI yang jalanin:

uv run mcp run server.py --transport streamable-http

Satu jebakan di sini: opsi transport milik run(), bukan constructor. MCPServer("Kitchen", port=3001) bakal raise TypeError. Constructor mendeskripsikan server itu apa; run() mendeskripsikan gimana dia disajikan.

Langkah 7: Tulis test beneran

SDK-nya sekalian nyediain client, jadi kamu bisa tes server di memori tanpa subprocess atau port:

import pytest
from mcp import Client

from server import mcp

@pytest.mark.anyio
async def test_add() -> None:
    async with Client(mcp) as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        assert result.structured_content == {"result": 3}

Client(mcp) connect langsung ke object server, tanpa transport. Ini pola yang dipake dokumentasi resmi buat semua contoh di test suite mereka, dan ini cara tercepat buat mastiin tool kamu tetep beneran jalan pas makin banyak.

stdio vs Streamable HTTP

stdio Streamable HTTP
Cara jalan subprocess lokal lewat stdin/stdout HTTP server di port
Default ya nggak
Terbaik buat host desktop, satu mesin server deployed atau remote
Auth nggak perlu OAuth kalau dibutuhkan

Mulai dari stdio. Pindah ke Streamable HTTP kalau mesin lain, client browser, atau banyak host perlu akses server.

Jebakan yang sering muncul

  • Kebingungan FastMCP. Ada dua hal beda yang sama-sama dipanggil FastMCP. SDK v1 punya FastMCP dari mcp.server.fastmcp, diubah jadi MCPServer di v2, dan path import lamanya dihapus. Ada juga package pihak ketiga bernama fastmcp dengan sintaks decorator sendiri. Kalau snippet error ImportError, cek dulu dia nargetin yang mana sebelum ganti kode kamu.
  • Guard if __name__ == "__main__": itu wajib, bukan pemanis. mcp dev, mcp run, mcp install, dan test kamu semuanya import file-nya duluan. Tanpa guard, import file artinya jalanin server.
  • Pin dependency lama. Kalau project yang kamu andalkan masih nargetin v1, tahan mcp>=1.28,<2 di requirement-nya biar resolve yang nggak di-pin tetep di jalur 1.x, yang masih dapet patch keamanan.

Kapan MCP masuk akal (dan kapan nggak)

MCP pantas dipake kalau konsumennya adalah model atau host agent yang diuntungin discovery: host bisa list tool kamu, baca schema-nya, dan manggil tanpa kode integrasi per-host di sisi kamu. Satu server, semua host.

REST API biasa lebih tepat kalau konsumennya cuma satu dan lapisan protokol tambahan nggak ngasih apa-apa. Kabar baiknya, dua-duanya nggak saling ngusir: tool MCP bisa manggil fungsi yang nge-wrap API kamu yang udah ada. Banyak server produksi emang kayak gitu: lapisan MCP tipis di atas service internal.

Langkah selanjutnya

Dokumentasi SDK mencakup hal setelah basic: handler dependencies (pola Resolve buat nanya ke user di tengah pemanggilan), resource dengan opsi keamanan, dan tracing OpenTelemetry yang udah nyala default. Habis itu pilih masalah nyata buat di-expose. Project pertama yang paling pas adalah data kamu sendiri: server yang nge-expose notes, project board, atau API internal, terus sambungkan ke host yang emang kamu pake tiap hari.

Referensi:

Butuh Bantuan Implementasi?

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

Konsultasi Gratis