---
title: "MCP atau CLI adalah pertanyaan yang keliru. Tanyakan di mana state disimpan."
description: "Tobi Lütke mengatakan perdebatan MCP versus CLI terjadi di lapisan yang salah: keduanya berjalan baik selama state bertahan di antara langkah. Kami setuju. Untuk sebuah sinkronisasi, state itu adalah catatan milik integrasi itu sendiri, bukan heap sebuah REPL, dan itulah sebabnya tool MCP Tajo tidak menyimpan apa pun di dalam sesi."
url: https://tajo.io/in/blog/mcp-or-cli-is-the-wrong-question/
markdown: https://tajo.io/in/blog/mcp-or-cli-is-the-wrong-question.md
lang: id-ID
author: "Set Noa"
author_url: https://tajo.io/in/set-noa/
published: 2026-11-04
updated: 2026-11-05
alternates: {en-US: /blog/mcp-or-cli-is-the-wrong-question.md, bg-BG: /bg/blog/mcp-or-cli-is-the-wrong-question.md, cs-CZ: /cz/blog/mcp-or-cli-is-the-wrong-question.md, de-DE: /de/blog/mcp-or-cli-is-the-wrong-question.md, da-DK: /dk/blog/mcp-or-cli-is-the-wrong-question.md, es-ES: /es/blog/mcp-or-cli-is-the-wrong-question.md, fr-FR: /fr/blog/mcp-or-cli-is-the-wrong-question.md, el-GR: /gr/blog/mcp-or-cli-is-the-wrong-question.md, hi-IN: /hi/blog/mcp-or-cli-is-the-wrong-question.md, hr-HR: /hr/blog/mcp-or-cli-is-the-wrong-question.md, hu-HU: /hu/blog/mcp-or-cli-is-the-wrong-question.md, it-IT: /it/blog/mcp-or-cli-is-the-wrong-question.md, ja-JP: /jp/blog/mcp-or-cli-is-the-wrong-question.md, ko-KR: /kr/blog/mcp-or-cli-is-the-wrong-question.md, ar-SA: /ar/blog/mcp-or-cli-is-the-wrong-question.md, nl-NL: /nl/blog/mcp-or-cli-is-the-wrong-question.md, no-NO: /no/blog/mcp-or-cli-is-the-wrong-question.md, pl-PL: /pl/blog/mcp-or-cli-is-the-wrong-question.md, pt-BR: /pt/blog/mcp-or-cli-is-the-wrong-question.md, ro-RO: /ro/blog/mcp-or-cli-is-the-wrong-question.md, ru-RU: /ru/blog/mcp-or-cli-is-the-wrong-question.md, sv-SE: /se/blog/mcp-or-cli-is-the-wrong-question.md, zh-CN: /zh-cn/blog/mcp-or-cli-is-the-wrong-question.md, sl-SI: /sl/blog/mcp-or-cli-is-the-wrong-question.md, sr-Latn-RS: /sr/blog/mcp-or-cli-is-the-wrong-question.md, th-TH: /th/blog/mcp-or-cli-is-the-wrong-question.md, tr-TR: /tr/blog/mcp-or-cli-is-the-wrong-question.md, ur-PK: /ur/blog/mcp-or-cli-is-the-wrong-question.md, vi-VN: /vi/blog/mcp-or-cli-is-the-wrong-question.md, sk-SK: /sk/blog/mcp-or-cli-is-the-wrong-question.md}
---

[Agen AI](https://tajo.io/in/blog/?category=ai-agents)

# MCP atau CLI adalah pertanyaan yang keliru. Tanyakan di mana state disimpan.

Tobi Lütke mengatakan perdebatan MCP versus CLI terjadi di lapisan yang salah: keduanya berjalan baik selama state bertahan di antara langkah. Kami setuju. Untuk sebuah sinkronisasi, state itu adalah catatan milik integrasi itu sendiri, bukan heap sebuah REPL, dan itulah sebabnya tool MCP Tajo tidak menyimpan apa pun di dalam sesi.

mcp vs cli

Haruskah agen AI memakai MCP atau CLI?

Lütke benar bahwa MCP versus CLI adalah lapisan yang salah: keduanya berjalan baik selama state bertahan di antara langkah, dan bash menang hanya karena sistem berkas adalah state tersebut. Namun untuk sebuah sinkronisasi, state bukanlah heap sebuah REPL. State adalah catatan milik integrasi itu sendiri: kursor, proposal yang tertunda, lease, rencana. Itulah sebabnya tool MCP Tajo tidak menyimpan apa pun di dalam sesi: agen mana pun, dari klien mana pun, melanjutkan dari catatan tersebut. Saat ini Tajo tidak menjalankan kode pelanggan dan tidak memiliki REPL, dan kami menyatakannya secara terbuka di bawah.

[Pelajari selengkapnya](https://tajo.io/in/blog/mcp-or-cli-is-the-wrong-question/#lapisan-yang-ia-maksud)

Pada 21 September 2026, pukul 00.33 UTC, Tobi Lütke menulis: “MCP vs CLI untuk LLM adalah diskusi yang keliru. Orang-orang berdebat di lapisan yang salah.” Lalu, [pada 23 Oktober](https://x.com/tobi/status/2113596638899974567), ia menunjuk sebuah repositori baru bernama [dquickts](https://github.com/stencil-hq/dquickts). Ini adalah fork dari QuickJS yang dapat menjeda program di tengah loop `for`, menulis seluruh heap-nya menjadi byte, lalu melanjutkannya di proses lain. “Lingkungan code mode yang luar biasa,” tulisnya.

Ia benar soal lapisannya. Saya ingin menyetujuinya lebih dulu, dengan kata-katanya sendiri, lalu mempersempit klaimnya sampai klaim itu menyatakan sesuatu yang bisa dipakai oleh sebuah sinkronisasi.

## Lapisan yang ia maksud

Berikut argumennya sebagaimana ia sampaikan, karena itulah satu-satunya cara yang adil untuk mengutip argumen yang hendak Anda belokkan:

> Keduanya bekerja luar biasa baik selama dijalankan melalui lingkungan mirip REPL yang dapat mempertahankan state. Yang lucu dari CLI adalah bahwa tool CLI biasanya diakses melalui BASH, yang kebetulan merupakan REPL dengan state persisten (sistem berkas), sehingga CLI bekerja jauh lebih baik daripada MCP. Tetapi ini sama sekali bukan sifat intrinsik MCP. Artinya hanya bahwa kita membutuhkan harness yang lebih baik.

Itu benar, dan itu menjelaskan pengamatan yang sudah dibuat banyak orang tanpa penjelasan. Agen yang diberi CLI menulis berkas, membacanya kembali tiga langkah kemudian, mencarinya dengan grep, dan mengalirkannya lewat pipe. Agen yang diberi server MCP polos mendapat satu hasil per pemanggilan dan harus membawa semua hal lain di jendela konteksnya. CLI tidak menang karena protokolnya. CLI menang karena bash datang bersama tempat untuk menaruh sesuatu.

Taruhannya mengikuti dari situ. Seseorang akan membangun mesin yang dapat disematkan, bergaya SQLite, yang mengubah bash, TypeScript, atau pemanggilan tool menjadi satu rencana, diperiksa sebelum dijalankan dan dibangun untuk eksekusi tahan lama. dquickts adalah satu langkah ke arah itu. [README-nya](https://github.com/stencil-hq/dquickts) menggambarkan REPL yang “fungsi dan variabelnya bertahan setelah restart”. README itu juga menggambarkan pemanggilan host yang tahan lama: “sebuah skrip memanggil fungsi host yang jawabannya datang berjam-jam kemudian. Proses menyimpan skrip itu lalu keluar.”

Sampai di sini, kami sepenuhnya setuju. Sekarang penyempitannya.

## State yang mana, untuk pekerjaan apa

“Mempertahankan state” menyembunyikan sebuah pertanyaan: state milik siapa, dan dalam bentuk apa? Bagi agen pemrograman, state-nya adalah repositori dan shell, dan REPL yang bertahan setelah restart adalah jawaban yang baik. Bagi agen yang membangun sinkronisasi antara dua sistem SaaS, state yang dibutuhkannya di antara langkah sudah ditentukan oleh pekerjaan itu sendiri. Empat catatan membawanya, dan tidak satu pun dari catatan itu adalah variabel di dalam skrip.

**Kursor.** Sebuah sinkronisasi membaca sumber dalam jendela-jendela dan harus tahu di mana jendela terakhir berakhir. Di mesin sinkronisasi Tajo, itu adalah [kursor yang disimpan](https://tajo.io/in/resources/help/troubleshooting/recover-a-stuck-or-failed-sync/#cursor) per sinkronisasi dan per cakupan, ditulis setelah setiap batch tanpa record yang gagal, dan run berikutnya melanjutkan dari sana. Run terjadwal menyimpan titik awalnya sebelum melakukan hal lain, sehingga run pertama yang gagal membuat run berikutnya membaca dari titik yang sama. Prinsip di baliknya, kirim delta dan jangan pernah seluruh tabel, ada di [penjelasan reverse ETL](https://tajo.io/in/blog/what-is-reverse-etl/). Saya cukupkan pembahasan kursor di sana.

**Proposal yang tertunda.** Pada tool MCP konektor Tajo, sebuah penulisan terdiri dari dua pemanggilan. `brevo_propose` memvalidasi input terhadap aksi yang dideklarasikan dan mencatat sebuah proposal. Tidak ada yang dikirim. Hasilnya membawa ID proposal dan, ketika seseorang harus memutuskan, halaman tempat ia menyetujuinya. `brevo_apply` menjalankan penulisan yang sudah disetujui pada koneksi itu secara berurutan dan berhenti pada penulisan pertama yang masih menunggu seseorang. Catatan di antaranya adalah state-nya. Catatan itu menyimpan input beserta digest-nya, sehingga penulisan yang sudah disetujui tidak dapat diubah di antara keputusan dan apply. Catatan itu tidak menyimpan nilai respons penyedia, karena catatan persetujuan yang hanya bisa ditambah tidak boleh berubah menjadi tempat penyimpanan data pribadi.

**Lease.** Setiap run sinkronisasi memegang satu [lease eksklusif](https://tajo.io/in/resources/help/troubleshooting/recover-a-stuck-or-failed-sync/#lease) sepanjang hidupnya, dengan token pemilik, batas waktu lima belas menit secara bawaan, dan pembaruan. Pemilik yang sudah usang tidak dapat melepaskan lease yang lebih baru. Jika penyimpanan lease tidak dapat dijangkau, run menolak untuk dimulai alih-alih menebak. Worker mana yang memegang run adalah fakta di dalam lease, bukan di memori proses mana pun.

**Rencana.** `syncs.dryRun` membaca jendela berikutnya dari kursor, menentukan sisipkan, perbarui, hapus, atau tidak berubah untuk setiap catatan, dan menulis tepat satu baris: rencana itu, yang disimpan selama satu jam. Ia tidak menggeser kursor dan tidak menulis apa pun ke sistem mana pun. `syncs.apply` menulis rencana itu satu kali. Ia menolak jika kursor sudah bergeser, atau jika lebih dari porsi yang ditoleransi dari catatan berubah dalam rentang waktu itu. Pengulangan mengembalikan hasil pertama alih-alih menulis lagi.

Itulah state di antara langkah: empat catatan dengan ID, yang dapat dibaca oleh agen mana pun yang diizinkan melihatnya.

## Mengapa sisi MCP tidak menyimpan apa pun di dalam sesi

Begitu state berada di dalam catatan, tidak ada lagi yang perlu disimpan oleh sesi. Karena itu endpoint MCP Tajo tidak menyimpan sesi. Setiap permintaan mendapat server baru dan transport tanpa ID sesi. Pembacaan adalah satu permintaan per pemanggilan, dengan hasil yang dibatasi agar satu jawaban tidak membanjiri satu giliran. Penulisan adalah propose, lalu apply, dan ID proposal itulah yang Anda bawa.

Protokolnya bergerak ke arah yang sama. [Revisi 2026-07-28 dari spesifikasi MCP](https://modelcontextprotocol.io/specification/2026-07-28/changelog) menghapus sesi tingkat protokol dan header `Mcp-Session-Id` dari transport Streamable HTTP. Server yang membutuhkan kesinambungan kini membuat handle-nya sendiri dan menerimanya kembali sebagai argumen biasa. Itulah sebuah ID proposal. [Apa itu server MCP](https://tajo.io/in/blog/what-is-an-mcp-server/) membahas revisi tersebut dan bagaimana pemanggilan tool berbeda dari sinkronisasi yang tahan lama; tulisan ini hanya membahas ke mana state pergi.

Konsekuensinya adalah yang penting bagi pekerjaan integrasi. Misalkan sebuah agen di Claude Code mengajukan penulisan lalu sesinya berakhir. Seseorang menyetujuinya satu jam kemudian. Agen di klien lain, atau agen yang sama keesokan harinya, memanggil apply dengan ID tersebut dan penulisan itu terjadi, satu kali. Agen yang crash kehilangan jendela konteksnya dan tidak ada yang lain. Tidak ada yang ditangguhkan, jadi tidak ada yang perlu dilanjutkan.

## Apa yang tidak kami miliki, dan berapa harganya

Keberatan yang jujur datang dari sisi REPL dan bunyinya begini: “Baik, catatan Anda bertahan. Tetapi setiap pemanggilan membaca ulang apa yang sudah dimiliki pemanggilan sebelumnya. Sebuah skrip akan mengambil kontak sekali, menggabungkannya, memfilternya, dan mengembalikan sebuah angka. Agen Anda melakukan lima pemanggilan dan membayar masing-masing.” Keberatan itu benar soal mekanismenya, dan kami belum mengukur harganya. Evaluasi yang akan menghitung jumlah pemanggilan per tugas, dengan dan tanpa state yang dibawa, belum dibangun. Sampai evaluasi itu ada, klaim bahwa mode pemanggilan menghabiskan lebih banyak token tetap belum terjawab.

Tiga hal lagi harus dinyatakan secara terbuka, karena pembaca yang menyelesaikan artikel ini tidak boleh membayangkan hal-hal tersebut ada:

- **Saat ini tidak ada kode tulisan pelanggan yang berjalan.** Pembacaan konektor adalah satu permintaan per pemanggilan, tanpa sandbox di jalurnya. Sebuah code runner memang ada di stack kami, dan itu adalah tool internal. Di produksi, code runner itu mati kecuali dua flag terpisah diaktifkan, dan hanya melayani administrator. Setiap pemanggilan mendapat konteks baru, binding yang hanya mengizinkan pembacaan, dan anggaran dua detik untuk kode sinkron. Header-nya sendiri menyatakan dengan huruf kapital bahwa itu adalah batas kebenaran, bukan batas keamanan.
- **Tidak ada REPL.** Tidak ada hasil komputasi agen dalam satu pemanggilan yang tersedia untuk pemanggilan berikutnya, kecuali jika ditulis sebagai catatan dengan ID.
- **Tidak ada sesi agen yang persisten.** Klien menyimpan percakapannya. Tajo menyimpan proposal, rencana, kursor, dan lease. Tidak ada hal ketiga.

## Untuk apa mesin yang tahan lama

Semua ini bukan argumen melawan dquickts. README-nya mencantumkan kegunaan snapshot, dan daftarnya bagus. Menidurkan skrip yang menganggur dan membebaskan memorinya. Menjalankan komputasi panjang dalam potongan-potongan di worker mana pun yang sedang bebas. Memulai setiap instans dengan cepat dari snapshot alih-alih mengulang penyiapan. Memarkir skrip pada pemanggilan host yang jawabannya datang belakangan. Untuk ruang kerja agen pemrograman, atau notebook yang harus bertahan setelah restart, itulah tool yang tepat.

Namun sinkronisasi tetap tidak boleh bergantung padanya, karena tiga alasan yang justru diberikan oleh README itu sendiri. Pertama: “File sesi hanya dapat dimuat ke build qjs yang menulisnya.” Heap yang ditulis oleh satu versi mesin menjadi berkas mati setelah upgrade; kursor hanyalah sebuah string. Kedua: “Snapshot adalah input tepercaya, seperti bytecode,” dan “snapshot berbahaya tidak terdeteksi.” Heap yang tersimpan adalah sesuatu yang harus Anda lindungi, bukan sesuatu yang bisa Anda tinjau; proposal adalah baris yang dibaca seseorang sebelum menyetujuinya. Ketiga, snapshot menyimpan apa pun yang telah dibaca skrip, termasuk catatan pelanggan. Catatan-catatan di atas dibangun dengan cara sebaliknya: rencana menyimpan digest, bukan nilai, dan catatan proposal tidak pernah menyimpan respons penyedia.

Salah satu aturan yang kami pegang dalam membangun adalah bahwa yang deterministik mengalahkan yang cerdik. Heap yang melanjutkan dari tengah loop itu cerdik. Kursor, proposal, lease, dan rencana itu membosankan, dapat diperiksa, dan sama di setiap mesin, di setiap klien, setelah setiap crash.

Lütke mengajukan pertanyaan yang tepat. Di mana state disimpan? Untuk sebuah sinkronisasi, jawabannya memang tidak akan pernah berada di dalam proses. Jawabannya selalu berada di dalam catatan, karena di sanalah orang yang menyetujui penulisan harus dapat membacanya.

## Pertanyaan yang sering diajukan

**Mana yang lebih baik untuk agen AI, MCP atau CLI?**

Tidak satu pun, jika berdiri sendiri. Poin Tobi Lütke pada 21 September 2026 tetap berlaku: keduanya berjalan baik selama pemanggilan berjalan melalui sesuatu yang menyimpan state di antara langkah. CLI terasa lebih baik saat ini karena bash menyimpan state di sistem berkas. Yang membedakan bukan protokolnya, melainkan harness-nya.

**State apa yang dibutuhkan agen di antara langkah-langkah sebuah sinkronisasi?**

Catatan milik integrasi itu sendiri: kursor yang menunjukkan di mana run terakhir berhenti, proposal yang menunggu persetujuan seseorang, lease yang menunjukkan worker mana yang memegang run, dan rencana dry-run yang harus dicocoki oleh apply. Tidak satu pun dari itu adalah variabel di dalam skrip. Semuanya adalah baris dengan ID.

**Mengapa server MCP Tajo tidak menyimpan apa pun di dalam sesi?**

Setiap permintaan mendapat server baru dan transport tanpa ID sesi. Apa pun yang dibutuhkan pemanggilan berikutnya adalah sebuah catatan: ID proposal, ID rencana, kursor. Jadi agen kedua, di klien yang berbeda, dapat melanjutkan dari titik agen pertama berhenti, dan agen yang crash tidak kehilangan apa pun selain jendela konteksnya sendiri.

**Apakah Tajo menjalankan kode yang ditulis agen?**

Tidak untuk pelanggan. Pembacaan pada tool konektor adalah satu permintaan per pemanggilan, tanpa sandbox. Code runner yang ada adalah tool internal di balik dua flag, hanya dapat dijangkau administrator, dengan binding hanya-baca dan konteks baru di setiap pemanggilan. Code runner itu sendiri menyatakan bahwa ia bukan batas keamanan. Tidak ada REPL dan tidak ada sesi persisten.

**Untuk apa mesin JavaScript tahan lama seperti dquickts?**

README-nya menyebutkan kegunaannya: menidurkan skrip yang menganggur, membagi komputasi panjang ke beberapa worker, memulai dengan cepat dari snapshot, dan memarkir skrip pada pemanggilan host yang jawabannya datang berjam-jam kemudian. Semuanya nyata. Namun sinkronisasi tetap tidak boleh bergantung padanya: snapshot hanya bisa dimuat ke build mesin yang menulisnya, tidak transparan bagi peninjau, dan menyimpan data pelanggan apa pun yang dibaca skrip.

## Artikel terkait

### [Jawabannya benar. Jalurnya salah.](https://tajo.io/in/blog/the-answer-is-right-the-path-is-wrong/)

8 Okt 2026 · 4 menit baca

3 bagian

### [Apa yang perlu dicatat untuk setiap panggilan tool MCP](https://tajo.io/in/blog/what-to-log-for-every-mcp-tool-call/)

6 Nov 2026 · 7 menit baca

6 bagian

### [Apa itu server MCP? Cara kerja MCP dan MCP UI di 2026](https://tajo.io/in/blog/what-is-an-mcp-server/)

3 Okt 2026 · 13 menit baca

Langkah 1 → Langkah 6
