· 9 menit baca

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.

MCP server (tools)User (consent modal)In-app OAuth ASClaude Code / CursorMCP server (tools)User (consent modal)In-app OAuth ASClaude Code / Cursorregister + authorize (PKCE)which profile? which scope?profile P, read-onlycode → token (identity {P, region}pinned)tool call + bearer tokenverify, re-check revocation,clamp scope to license, resolve P's credsresult (agent never sees AWS keys)

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.

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.

Modal consent MCP di dalam aplikasi: klien yang terhubung, pemilih profil, dan tiga scope dari yang paling sempit dahulu — read-only, read + stage, dan akses penuh.
Modal consent MCP di dalam aplikasi: klien yang terhubung, pemilih profil, dan tiga scope dari yang paling sempit dahulu — read-only, read + stage, dan akses penuh.

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.

Bekerja dengan DynamoDB tanpa Console

DynoTable adalah klien desktop yang cepat untuk DynamoDB — jelajahi tabel, jalankan query gaya SQL, dan edit Item secara lokal.