Apa yang dibutuhkan untuk membangun server MCP DynamoDB yang aman
membuat penyerahan database Anda ke sebuah menjadi sepele. Itulah masalahnya. Sebagian besar server MCP DynamoDB adalah sebuah proses tipis yang memegang kredensial AWS mentah Anda dengan jalur tulis dan tanpa langkah tinjauan — kami telah menulis tentang mengapa pola itu berisiko dan bagaimana memilih dengan aman dari sisi pengguna.
Postingan ini adalah sisi lainnya: apa yang sebenarnya dibutuhkan untuk membangun versi yang aman. DynoTable adalah klien DynamoDB desktop yang server MCP-nya mengekspos toolkit AI bergerbang miliknya ke agen eksternal — Claude Code, Cursor, Codex — tanpa agen tersebut pernah menyentuh kredensial AWS. Mencapai titik itu berarti merilis sebuah server otorisasi di dalam sebuah aplikasi Electron, merancang tipe identitas yang membuat kekeliruan kredensial tidak dapat direpresentasikan, dan memutuskan, lebih dari sekali, bahwa default yang nyaman adalah pilihan yang salah.
Jika Anda membangun sebuah server MCP di sekitar apa pun yang sensitif, inilah keputusan-keputusan yang akan Anda temui juga.
HTTP loopback tidak otomatis aman
Server mengikat 127.0.0.1, yang terdengar aman tetapi tidak cukup. Setiap
halaman web yang Anda kunjungi dapat mencoba mengirim permintaan ke localhost, dan DNS
rebinding memungkinkan halaman jahat mendandani permintaan itu dengan Host yang tampak masuk akal. Jadi
lapisan pertama adalah origin guard: tolak setiap permintaan yang membawa Origin
halaman web nyata, tolak header Host non-loopback — tetapi izinkan
permintaan yang sama sekali tanpa Origin, karena klien CLI yang sah seperti
Claude Code tidak mengirimkannya.
Klausa terakhir itu adalah bagian yang jujur: sebuah origin guard hanya memblokir kelas serangan browser. Ia tidak bisa mengautentikasi siapa pun. Bearer token adalah gerbang yang sebenarnya, yang memunculkan pertanyaan dari mana token berasal.
Kami merilis server otorisasi OAuth 2.1 di dalam aplikasi
Kisah autentikasi remote-server MCP adalah OAuth 2.1, dan untuk server desktop lokal tidak ada penyedia identitas hulu untuk diandalkan. Jadi aplikasilah yang menjadi server otorisasi: pendaftaran klien dinamis, (S256), authorization code, refresh token, pencabutan, dan dokumen metadata RFC 8414 / RFC 9728 yang memungkinkan klien menemukan semuanya.
Aturan yang kami tetapkan sejak awal dan kami pertahankan:
- Jangan membuat protokol sendiri secara manual. MCP SDK menyediakan seluruh permukaan AS sebagai sebuah router; kami hanya mengimplementasikan penyedia penyimpanan/kebijakan di bawahnya. Satu konsekuensi yang kami terima: framework MCP kami menggunakan satu HTTP stack secara internal dan router SDK menggunakan yang lain, sehingga AS berjalan sebagai listener loopback kedua, dengan resource server mengarahkan klien ke sana melalui metadata protected-resource. Dua listener adalah biaya yang tercakup dan eksplisit; menurunkan ulang PKCE dan tata bahasa token secara manual adalah biaya yang tak terbatas.
- Redirect hanya loopback (sesuai RFC 8252 untuk aplikasi native), dan sebuah redirect yang tidak valid tak pernah mendapat error redirect — ia mendapat 400 langsung, sehingga URI penyerang tak pernah menjadi tujuan.
- Authorization code hanya sekali pakai — code yang diputar ulang adalah grant yang tidak valid, titik.
- Refresh dapat mempersempit scope tetapi tak pernah memperluasnya, dan ia menerbitkan ulang payload identitas yang sama persis — token yang di-refresh tak bisa diam-diam memperoleh region yang berbeda.
- Pencabutan diperiksa ulang pada setiap permintaan, tidak di-cache saat koneksi — mengeklik "Revoke" di Pengaturan mematikan panggilan klien berikutnya.
Build pengembangan memakai jalur autentikasi yang lebih sederhana, yang dibangun agar tidak bisa ada dalam biner rilis — token full-scope tanpa autentikasi dalam perangkat lunak yang dirilis akan menjadi backdoor lokal di balik origin guard yang sengaja menerima permintaan tanpa Origin.
Satu koneksi, satu identitas AWS — dibawa utuh, tak pernah ditebak
Properti keamanan inti: sebuah agen eksternal terhubung ke sebuah profil, bukan ke "DynoTable". Setiap koneksi terikat pada satu profil AWS dan satu region, didukung oleh klien DynamoDB-nya sendiri yang tidak dibagikan, sehingga dua agen pada profil berbeda tak bisa saling merembes.
Binding tersebut awalnya berupa field-field lepas — awsProfile, region,
profileId, dan port lokal opsional — yang dideklarasikan ulang di setiap record pada
jalur itu. Kini ia menjadi satu tipe identitas discriminated-union dengan dua
cabang: online (profil + region + id) dan offline (port lokal + id,
untuk profil DynamoDB Local). Sifat offline adalah
diskriminannya sendiri, sehingga identitas online tanpa kredensial atau identitas
offline yang membawa region adalah sebuah type error, bukan kejutan saat runtime.
Satu tipe itu berjalan utuh melalui consent → token → grant → setiap
permintaan.
Dua konsekuensi yang kami anggap menahan beban:
- Region dibekukan saat consent. Pengguna menyetujui "profil X di
region Y", dan tuple itu disematkan pada token — bertahan melewati refresh,
tak pernah diselesaikan ulang dari state yang bisa berubah di hot path. Menyunting
region profil memerlukan consent ulang. Alternatifnya — menyelesaikan
region per permintaan atau kembali ke default — adalah bagaimana sebuah agen
diam-diam berakhir melakukan query pada
us-east-1. - Token yang cacat adalah 401, tak pernah dipaksakan. Jika klaim identitas sebuah token
tidak terurai menjadi cabang yang valid, permintaan tersebut tidak diotorisasi. Tanpa
profil
'default', tanpa region default, tanpa string kosong. Setiap tempat yang dulu ditebak oleh kode lama kini menjadi kegagalan keras.
Consent adalah permukaan produk, bukan kotak dialog
Prompt consent pertama adalah kotak pesan native platform. Ia membekukan proses utama Electron selama terbuka, tak bisa menyesuaikan design system aplikasi, dan bahkan tak bisa di-screenshot untuk dokumentasi. Kini ia menjadi modal di dalam aplikasi: nama klien yang terhubung, sebuah pemilih profil atas tepat profil-profil yang dipilih pengguna untuk diekspos, dan tiga scope yang ditawarkan dari yang paling sempit dahulu — read-only, read + stage, penuh. Permintaan consent yang kedaluwarsa atau duplikat berakhir sebagai ditolak alih-alih menggantung alur OAuth.

Pemilih itu memiliki batas kepercayaannya sendiri yang kecil: sebuah klien boleh memberi petunjuk sebuah profil di authorize URL, tetapi grant dicetak dari apa yang pengguna benar-benar pilih, divalidasi terhadap snapshot yang ditampilkan kepada mereka — sebuah petunjuk yang dipalsukan tak bisa mengikat profil yang tak pernah ada di layar.
Kami sama eksplisitnya tentang apa yang tidak diberikan consent kepada Anda: otorisasi hanya soal scope, disetujui sekali per koneksi. Prompt izin per-panggilan dari asisten di dalam aplikasi tidak berlaku untuk lalu lintas MCP — sebuah token full-scope yang bocor bisa menulis (ke staging) tanpa manusia melihat setiap panggilan. Masa hidup token yang singkat, pencabutan per-klien, sebuah jejak audit yang selalu aktif menandai setiap tindakan yang berasal dari MCP, dan read-only sebagai tawaran default adalah mitigasinya. Menuliskan itu sebagai risiko sisa lebih berguna daripada berpura-pura bahwa modal consent telah menutupnya.
Pagar pengaman untuk kerja headless
Sebuah agen eksternal tak punya renderer, tak punya popup konfirmasi, tak ada pengguna yang mengawasi. Segala hal yang interaktif memerlukan padanan headless-nya:
- Pembatasan lisensi langsung, per panggilan. Grant menyimpan scope yang disetujui pengguna; scope efektif diturunkan pada setiap panggilan tool dari state lisensi aplikasi saat ini — lisensi read-only membatasi grant penuh ke bawah, state signed-out menolak dengan 401 sebelum cabang token mana pun (sehingga token dev tak bisa melewatinya), dan reaktivasi di tengah sesi memperluas kembali tanpa consent ulang. Satu asimetri yang disengaja: ekspor di dalam aplikasi tetap tersedia di bawah lisensi read-only (data Anda adalah data Anda), tetapi ekspor massal headless melalui MCP dibatasi mati — sebuah hak portabilitas interaktif dan sebuah kanal egress yang digerakkan agen adalah permukaan kepercayaan yang berbeda.
- Anggaran Scan alih-alih popup konfirmasi. Di dalam aplikasi, sebuah pembacaan seluruh tabel bertanya lebih dulu. Secara headless, anggaran item/byte/durasi membatasi setiap scan, dan SQL atas tabel dialirkan melalui engine berbasis disk alih-alih batas dalam memori.
- Pemutusan koneksi membatalkan dengan jujur. Jika klien terputus di tengah scan, server membatalkan pada batas halaman berikutnya — tak pernah di tengah statement — dan membuang state sementaranya.
- diselesaikan melalui koneksi. Ketika kredensial AWS memerlukan kode MFA dan klien mendukung elisitasi MCP, server memunculkan kode 6 digit itu melalui UI agen itu sendiri — Claude Code meminta manusia — lalu mencoba lagi. SSO sengaja dikecualikan dari jalur ini: ia memerlukan sebuah browser device flow, dan berpura-pura sebaliknya hanya akan menjadi pesan error yang lebih buruk. Panggilan bersamaan yang memerlukan kredensial yang sama disatukan menjadi satu prompt.
Apakah mengekspos database melalui MCP aman sama sekali?
Jawaban jujur kami: hanya jika server dirancang berdasarkan asumsi bahwa agen paling baik sedang kebingungan dan paling buruk bersifat adversarial. membuat niat sebuah agen tak bisa dipercaya, itulah sebabnya arsitektur tak pernah mengandalkan agen berperilaku baik: kredensial tetap di dalam aplikasi, penulisan hanya pernah masuk ke staging area yang dapat ditinjau, scope membatasi apa yang bisa dilakukan sebuah panggilan terlepas dari apa yang diminta model, dan setiap tindakan diaudit. Panduan sisi koneksi membahas apa artinya itu dalam praktik untuk setiap klien.
Apa yang harus dituntut dari server MCP mana pun yang menyentuh database Anda
- Di mana kredensial berada — di dalam proses agen, atau di balik server?
- Adakah consent per-koneksi dengan scope yang nyata, atau satu file konfigurasi memberi semuanya?
- Bisakah sebuah penulisan dieksekusi tanpa langkah tinjauan manusia?
- Apakah identitas (profil, region) disematkan saat consent, atau diselesaikan dari default saat panggilan?
- Apa yang terjadi pada token yang cacat atau dicabut — kegagalan keras, atau sebuah fallback?
- Adakah jejak audit yang membedakan tindakan yang berasal dari agen?
- Apa yang membatasi scan yang lepas kendali, dan apa yang terjadi ketika klien terputus di tengah operasi?
Jika sebuah server tak bisa menjawab pertanyaan-pertanyaan itu, integrasi yang nyaman adalah yang berisiko. Untuk memperkirakan berapa sebenarnya biaya sebuah scan tanpa batas bagi Anda, kalkulator harga cukup mencerahkan — dan jika Anda lebih suka melihat versi yang aman berjalan daripada membacanya, unduh DynoTable, aktifkan server MCP, dan hubungkan sebuah klien pada scope read-only dalam waktu kurang dari satu menit.


