Belajar MCP - Observability & Logging
Series/Belajar MCP/Episode 15
Episode 15 of 23

Belajar MCP - Observability & Logging

Episode ini membangun observability untuk server MCP: penggantian Logging protocol yang deprecated dengan OpenTelemetry tracing untuk request dan streaming, metrik seperti call rate, error rate, dan latency, serta structured logging dengan request IDs untuk melacak satu request dari awal sampai akhir.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 14 kalian memperkeras server MCP dengan mitigasi berlapis. Tapi benteng tanpa mata-mata buta: kalian tidak akan tahu serangan yang sudah tertahan, tool yang lambat, atau error yang menumpuk di balik satu endpoint. Episode 15 ini memasang mata-mata itu — observability. Kemampuan untuk menjawab tiga pertanyaan dalam lima menit saat produksi bermasalah: apa yang terjadi, request mana yang bermasalah, dan kenapa.

Roadmap episode ini: sejarah Logging protocol yang deprecated dan penggantinya, tracing OpenTelemetry untuk request dan streaming, metrik call rate, error rate, dan latency, lalu structured logging dengan request IDs yang menyatukan semuanya.

Dari Logging Protocol ke OpenTelemetry

Versi awal spec MCP menyediakan Logging sebagai method bawaan — server mengirim level log ke client. Masalahnya: setiap host menerapkan penyimpanan dan format lognya sendiri-sendiri, sehingga observability pecah dan tidak terstandardisasi. Di spec modern (2026-07-28), Logging protocol resmi deprecated dengan removal clock sekitar satu tahun — dan penggantinya bukan method baru, melainkan OpenTelemetry (OTel), standar industri yang sudah matang.

Kenapa OTel menang: ia memisahkan instrumentasi (di kode) dari backend (tempat data dikirim), mendukung tiga pilar — traces, metrics, logs — dalam satu ekosistem, dan sudah punya SDK serta eksporter untuk hampir semua bahasa. Server MCP kalian cukup menghasilkan telemetri standar; siapa pun bisa memilih backend mereka sendiri (Jaeger, Grafana Tempo, Prometheus, atau layanan SaaS) tanpa menyentuh kode.

Tracing dengan OpenTelemetry

Pilar pertama adalah tracing. Setiap request JSON-RPC yang masuk menjadi sebuah span — potongan waktu dengan nama, durasi, dan atribut. Satu request tools/call bisa membentuk pohon span: span HTTP untuk transport, span eksekusi tool, dan span request keluar yang dipicu tool tersebut.

Instrumentasi server MCP dengan SDK OTel terlihat seperti ini:

server.ts - span untuk tiap request JSON-RPC
import { trace } from "@opentelemetry/api";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
 
const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: "http://otel-collector:4318/v1/traces"
  }),
  serviceName: "mcp-server"
});
await sdk.start();
 
async function handleCall(req) {
  const span = trace.getTracer("mcp-server").startSpan("tools/call", {
    attributes: {
      "rpc.method": req.method,
      "rpc.system": "jsonrpc",
      "mcp.tool": req.params.name
    }
  });
  try {
    return await executeTool(req.params);
  } finally {
    span.end();
  }
}

Perhatikan atribut mcp.tool — atribut inilah yang membuat trace berguna: kalian bisa mencari semua panggilan ke tool tertentu dan melihat mana yang lambat. Praktik yang sama berlaku untuk streaming: span tidak berakhir saat response header terkirim, melainkan saat event SSE terakhir selesai atau koneksi ditutup. Kalau tidak, trace akan menunjukkan request "selesai" padahal streaming baru setengah jalan.

Metrik: Call Rate, Error Rate, Latency

Pilar kedua adalah metrik — angka agregat yang menjawab pertanyaan tren. Tiga yang wajib dipasang:

  • Call rate — berapa request per detik per method (tools/call, resources/read). Ini mengukur beban dan bisa menjadi alarm awal lonjakan aneh.
  • Error rate — proporsi request yang gagal, dipecah per tool dan per kode error JSON-RPC. Lonjakan error rate hampir selalu mendahului keluhan user.
  • Latency — durasi request, biasanya disimpan sebagai histogram dengan persentil (p50, p95, p99). Streaming request mengukur time-to-first-event dan total duration secara terpisah.

Contoh counter sederhana dengan OTel Metrics API:

metrics.ts - counter call dan error
import { metrics } from "@opentelemetry/api";
 
const meter = metrics.getMeter("mcp-server");
const calls = meter.createCounter("mcp.calls.total", {
  description: "Jumlah request JSON-RPC per method"
});
const errors = meter.createCounter("mcp.errors.total", {
  description: "Jumlah error per method"
});
 
calls.add(1, { "rpc.method": "tools/call" });
errors.add(1, { "rpc.method": "tools/call", "mcp.error_code": "-32603" });

Aturan penting: dekorasi atribut tidak boleh tinggi-kardinalitas. Memakai taskId atau userId sebagai atribut metrik akan meledakkan jumlah series di Prometheus. Identitas per-request masuk ke trace; metrik hanya memegang dimensi terbatas seperti method, tool, dan error code.

Structured Logging & Request IDs

Pilar ketiga — logs — adalah jaring pengaman terakhir saat trace tidak tertangkap. Log yang baik di era modern adalah structured: satu baris JSON per kejadian, bukan teks bebas yang sulit di-parse. Sebuah baris log request ideal terlihat seperti:

Satu baris log terstruktur
{
  "level": "error",
  "timestamp": "2026-08-03T07:12:04.582Z",
  "service": "mcp-server",
  "requestId": "req_9f2c71a4b8",
  "method": "tools/call",
  "tool": "send_email",
  "error": "upstream timeout after 5000ms",
  "durationMs": 5120
}

Perhatikan requestId di baris itu. Ini request IDs — identitas yang dibuat saat request masuk, diteruskan ke semua operasi turunan (tool call, request keluar, worker task), dan dikirim ulang ke client di response header. Dengan request ID, kalian bisa menggabungkan satu cerita: log error di server, trace di Jaeger, dan keluhan user di tiket — cukup satu string.

Info

Sambungkan ketiga pilar dengan konvensi ID: pakai request ID yang sama sebagai trace_id di OTel (bila memungkinkan) atau setidaknya simpan di atribut span dan di log. Standardisasi ID inilah yang mengubah observability dari tiga silo menjadi satu garis waktu yang bisa diceritakan ulang.

Menyatukan Semuanya

Ketiga pilar tidak berdiri sendiri. Alur debugging yang seharusnya menjadi kebiasaan:

  1. Dapatkan sinyal dari metrik — misalnya error rate send_email naik di dashboard.
  2. Klik ke trace tools/call yang gagal, lihat span mana yang menyimpang.
  3. Tarik log terstruktur untuk request ID tersebut untuk melihat pesan error mentahnya.
  4. Perbaiki, deploy, dan amati metrik turun kembali.

Untuk server stdio dari episode 13, ingat aturannya: telemetri dan log tidak boleh bocor ke stdout. Ekspor OTel ke collector via HTTP di dalam proses, dan tulis structured log ke stderr atau file — bukan ke kanal protokol.

Penutup

Episode 15 melengkapi server MCP kalian dengan mata: Logging protocol yang deprecated digantikan OpenTelemetry, tracing menghubungkan request tools/call hingga streaming dengan atribut seperti mcp.tool, metrik call rate, error rate, dan latency memberi sinyal tren, dan structured logging dengan request IDs menjadi jaring terakhir yang menyatukan seluruh cerita.

Inti yang harus dibawa pulang:

  • Logging protocol deprecated — arahkan investasi kalian ke OpenTelemetry sebagai standar pengganti.
  • Tracing menelusuri request: span per request JSON-RPC, dengan atribut mcp.tool, dan jangan menutup span streaming terlalu cepat.
  • Tiga metrik wajib: call rate, error rate, latency dengan histogram persentil.
  • Log harus structured JSON dan setiap baris membawa requestId untuk menghubungkan log, trace, dan tiket user.
  • Jaga kardinalitas atribut di metrik — identitas per-request masuk ke trace, bukan metrik.

Episode 16 berikutnya kita melebarkan pandangan dari satu server ke banyak: Proxy, Gateway & Fleet — membangun MCP gateway untuk banyak server, unified auth, routing, dan manajemen fleet dengan versioning serta rolling deployment. Sampai jumpa!

Belajar MCP - Observability & Logging | Belajar MCP