Metabase
resmiServer MCP resmi Metabase untuk mencari data, membangun kueri pada lapisan semantik, dan memvisualisasikan hasil melalui klien MCP.
Apa yang bisa Anda lakukan dengan Metabase MCP?
- Mencari dan mengambil konten — Minta asisten Anda untuk menemukan pertanyaan, dasbor, atau model di seluruh Metabase menggunakan alat
search, lalu ambil detailnya denganget_content. - Menjalankan kueri dan memvisualisasikan hasil — Minta asisten Anda untuk menjalankan kueri terstruktur melalui
execute_queryatau SQL mentah denganexecute_sql, lalu render hasilnya sebagai bagan interaktif menggunakanvisualize_query. - Membuat dan mengelola dasbor — Instruksikan asisten Anda untuk membuat atau memperbarui dasbor beserta tata letaknya dengan
dashboard_write, atau duplikat konten yang ada ke dalam koleksi melaluiduplicate_content. - Menyiapkan pemberitahuan dan langganan — Minta asisten Anda untuk membuat pemberitahuan terjadwal untuk pertanyaan tersimpan dengan
alert_writeatau konfigurasikan langganan email dasbor menggunakansubscription_write. - Menjelajahi hierarki data — Arahkan asisten Anda untuk menelusuri basis data, skema, tabel, dan kolom melalui
browse_data, atau navigasikan koleksi secara struktural denganbrowse_collection.
Dokumentasi
Server MCP Metabase
Metabase menyertakan server Model Context Protocol (MCP) bawaan yang memungkinkan klien AI terhubung langsung ke instance Metabase. Server ini menggunakan https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http dan dibangun di atas Agent API Metabase untuk mengekspos alat untuk mencari, menavigasi, membuat kueri, memvisualisasikan, dan membuat/memperbarui konten - semuanya dibatasi oleh izin pengguna yang terhubung.
Endpoint
Server MCP tersedia di:
https://{your-metabase.example.com}/api/metabase-mcp
Jalur /api/mcp lama masih berfungsi sebagai alias untuk klien yang sudah ada, tetapi /api/metabase-mcp adalah
URL kanonik yang perlu diiklankan.
Menghubungkan klien
Arahkan klien yang kompatibel dengan MCP ke endpoint /api/metabase-mcp. Misalnya, dengan Claude Code:
claude mcp add metabase https://{your-metabase.example.com}/api/metabase-mcp --transport streamable-http
Untuk Claude Desktop, buat konektor khusus menggunakan URL yang sama.
Untuk Cursor, buka Settings > MCP dan tambahkan server baru dengan tipe diatur ke streamable-http dan URL:
https://{your-metabase.example.com}/api/metabase-mcp
Autentikasi
Klien MCP melakukan autentikasi melalui OAuth 2.0. Metabase menjalankan server OAuth tertanamnya sendiri - tidak diperlukan penyedia eksternal.
Alur untuk koneksi pertama kali:
- Klien menemukan endpoint OAuth Metabase.
- Klien mendaftarkan dirinya ke Metabase.
- Pengguna diarahkan ke Metabase untuk masuk dan menyetujui koneksi.
- Klien menerima token akses yang dibatasi oleh izin Metabase pengguna.
Sesi berbasis browser (autentikasi cookie), kunci API, dan token mb:full tidak memiliki cakupan MCP, sehingga mereka dapat terhubung tetapi
tidak dapat memanggil alat yang dibatasi cakupan.
Cakupan
Token akses dibatasi untuk membatasi alat apa yang dapat digunakan klien:
| Cakupan | Alat yang diberikan |
|---|---|
agent:content:read | browse_collection, browse_data, get_content, get_parameter_values, glossary, learn, search, dan sumber daya data catalog://metabase/fields (lihat Sumber Daya) |
agent:content:write | bookmark_content, collection_write, dashboard_write, document_write, duplicate_content, measure_write, metric_write, question_write, segment_write |
agent:delivery:write | alert_write, subscription_write |
agent:query:run | execute_query, refresh_ui_credential, render_drill_through, run_saved_question, visualize_query |
agent:sql:run | execute_sql |
Sebuah alat hanya cocok dengan cakupan yang tepat di tabel. Wildcard seperti * atau agent:*, dan sentinel ::unrestricted,
bukanlah cakupan MCP, sehingga mereka tidak memberikan alat apa pun.
Cakupan ini hanya menggerbang permukaan MCP. Tidak ada endpoint REST yang boleh mendeklarasikan salah satunya sebagai :scope-nya, sehingga token baru yang diterbitkan ke
klien MCP tidak memberikan apa pun pada REST API.
scopes_supported dari metadata sumber daya yang dilindungi dan scope dari tantangan 401 keduanya mencantumkan setiap cakupan di
tabel, sehingga koneksi baru meminta semuanya. Beberapa klien tidak melakukan step-up setelah 403: koneksi ulang manual
dari pengaturan konektor Claude mendaftarkan klien baru dan meminta persis apa yang tercantum. Ketika mereka hanya mencantumkan
baseline, koneksi ulang itu tidak pernah menawarkan penulisan, SQL mentah, atau pengiriman, dan pengguna tidak memiliki cara untuk memberikannya
(ENG-11089). Metadata server otorisasi juga mengiklankan semuanya.
Baseline (agent:content:read agent:query:run) terkunci di layar persetujuan: ketika klien meminta salah satunya,
pengguna tidak dapat menghapus centangnya. agent:query:run ada di baseline sehingga bagan tidak pernah memerlukan step-up. Claude
Desktop mencoba ulang alat setelah step-up melalui sesi yang tidak mendeklarasikan dukungan MCP Apps, sehingga
visualize_query yang di-step-up ditolak dan bagannya tidak pernah disematkan.
Panggilan alat atau pembacaan sumber daya data yang tokennya tidak memiliki cakupan ditolak dengan HTTP 403 dan
tantangan WWW-Authenticate: Bearer error="insufficient_scope" yang scope-nya mencantumkan cakupan v2 yang sudah dimiliki token
ditambah yang diperlukan, sehingga klien dapat melakukan step-up. Setiap alat juga mendeklarasikan cakupannya di securitySchemes, yang merupakan
draf SEP-1488, didukung oleh ChatGPT. Ini
bukan bagian dari MCP 2025-03-26 (versi yang dilaporkan server ini) atau spesifikasi alat final 2026-07-28, sehingga klien lain
menemukan cakupan yang hilang dari 403 sebagai gantinya. Di dalam batch JSON-RPC, penolakan adalah kesalahan -32600 in-band
sebagai gantinya. Pembacaan shell UI tidak pernah ditantang: lihat Sumber Daya.
Metadata sumber daya yang dilindungi OAuth tersedia di:
/.well-known/oauth-protected-resource/api/metabase-mcp
Di layar persetujuan, setiap cakupan yang diminta klien mulai dicentang, dan cakupan baseline juga terkunci. Hanya
cakupan yang tetap dicentang yang diberikan, dan hanya untuk token yang dicetak oleh otorisasi ini. Penghapusan centang tidak pernah menyentuh token
yang sudah dimiliki aplikasi. Cakupan yang tidak dicentang tidak diingat oleh Metabase. 403 berikutnya dapat memicu step-up lain di
klien yang mendukungnya. Klien lain mungkin memerlukan otorisasi ulang manual. error_description setiap tantangan diakhiri
dengan catatan bahwa pengguna harus memberikan izin di layar persetujuan.
Beberapa klien mengganti error_description dari 403 dengan teks mereka sendiri, sehingga hasil initialize instructions-nya
menjelaskan kegagalan cakupan ke model juga: kesalahan autentikasi biasanya berarti izin yang hilang daripada
login yang kedaluwarsa, model harus menyebutkan alat atau sumber daya yang gagal dan izin yang diperlukan, dan pengguna memberikannya dengan
menghubungkan ulang dan membiarkan izin dicentang di layar persetujuan. Instruksinya adalah satu string statis, sama
untuk setiap pemanggil: tidak ada daftar izin per koneksi.
Akses alat per grup
Pada instance Enterprise dengan fitur ai_controls, admin dapat mempersempit permukaan per grup izin di Admin > AI > Kontrol penggunaan > Akses alat MCP (ditampilkan setiap kali server MCP aktif, dengan atau tanpa penyedia LLM). Setiap grup memiliki baris di mcp_group_permission yang menyatakan apakah anggotanya dapat terhubung sama sekali dan, per nama alat, "yes" atau "no" eksplisit admin; alat tanpa entri mengambil default yang dideklarasikan pembuatnya, sehingga setiap deftool membawa :default-access wajib dari :allowed atau :denied dan alat yang dirilis kemudian mendapatkan default itu persis di setiap grup sampai admin menimpanya. Entri dikunci oleh nama alat, sehingga mengganti nama alat memerlukan :renamed-from dengan nama lamanya (entri tersimpan di bawah nama lama masih berlaku dan API admin menyajikannya di bawah nama saat ini), atau pembuat menerima bahwa pilihan setiap admin untuk itu dibuang; metabase.mcp.v2.tool-names-test mengunci nama langsung sehingga keduanya tidak terjadi secara tidak sengaja. Kebijakan efektif pengguna adalah tool_access dari setiap grup mereka yang barisnya mengaktifkan MCP: MCP aktif ketika grup semacam itu ada, dan alat diizinkan ketika salah satu grup tersebut menyelesaikannya menjadi ya. Baris-baris itu sendiri yang memutuskannya, dan mereka juga mencatat mode izin: mode sederhana (Administrator, Semua Pengguna, dan Semua pengguna penyewa) atau mode tingkat grup (setiap grup lainnya), yang merupakan keadaan di mana Semua Pengguna tidak memiliki baris. Sakelar menghapus baris grup yang disembunyikan mode baru dan mengisi grup yang diaktifkannya pada entri yang tidak memiliki baris (Analis Data saat memasuki mode tingkat grup, Semua Pengguna dan Semua pengguna penyewa saat meninggalkannya), dan PUT menolak grup yang disembunyikan mode saat ini, sehingga tidak ada permintaan yang membaca mode cache. Kebijakan diterapkan di atas cakupan OAuth di tools/list dan tools/call (v2/registry.clj), dan pengguna yang grupnya tidak memberikan akses ditolak di initialize dan di resources/read (untuk sesi yang dibuka sebelum MCP dimatikan) dengan kesalahan yang menyebutkan perbaikannya. Alat khusus aplikasi (_meta {:ui {:visibility ["app"]}}, yaitu refresh_ui_credential) tidak ada di halaman admin: mereka diizinkan selama kebijakan mengizinkan alat MCP Apps apa pun. Superuser dan pemanggil internal tidak pernah dipersempit; OSS mengizinkan semuanya. Di Enterprise, baris tersimpan ditegakkan bahkan tanpa fitur ai_controls (token yang kedaluwarsa atau tidak dapat diverifikasi tetap mempertahankan pembatasan yang dikonfigurasi admin); fitur hanya menggerbang halaman admin dan API. Resolver adalah permissions.clj (defenterprise, implementasi EE di metabase-enterprise.mcp.permissions) dan API admin adalah /api/ee/ai-controls/mcp-permissions.
Alat yang tersedia
Dihasilkan dari registri v2 (deftool). Cakupan yang disebutkan di sini adalah apa yang diperiksa registri sebelum alat
berjalan; beberapa penangan memeriksa cakupan lebih lanjut setelah mereka tahu apa yang dilakukan panggilan - agent:sql:run ketika sumber
diselesaikan ke SQL asli (question_write), dan agent:query:run untuk eksekusi yang ditunda oleh peringatan atau langganan
(alert_write, subscription_write). Penolakan tersebut membawa tantangan 403 insufficient_scope yang sama. tools/list
menunjukkan setiap alat apa pun yang dimiliki token, dan token yang tidak memiliki cakupan tidak boleh memanggilnya.
| Alat | Cakupan | Deskripsi |
|---|---|---|
alert_write | agent:delivery:write | Membuat atau memperbarui peringatan: notifikasi yang dikirim sesuai jadwal ketika hasil pertanyaan tersimpan memenuhi suatu kondisi. |
bookmark_content | agent:content:write | Menambah atau menghapus penanda pada konten untuk pengguna yang memanggil — daftar berbintang/favorit yang sama dengan yang ditampilkan sidebar Metabase. |
browse_collection | agent:content:read | Menjelajahi koleksi secara struktural — satu id seragam di setiap partisi: id numerik, entity_id 21 karakter, "root" (di-root ulang per namespace), atau "trash" (konten yang diarsipkan, hanya mode item). |
browse_data | agent:content:read | Menjelajahi hierarki data: database → skema → tabel → kolom. |
collection_write | agent:content:write | Membuat, mengganti nama, memindahkan, mengarsipkan, atau memulihkan koleksi — folder yang menampung pertanyaan, dasbor, model, dan dokumen. |
dashboard_write | agent:content:write | Membuat atau memperbarui dasbor dan mengedit tata letaknya dengan operasi terurut. |
document_write | agent:content:write | Membuat atau memperbarui dokumen. |
duplicate_content | agent:content:write | Menyalin pertanyaan, dasbor, atau dokumen ke dalam koleksi — lebih murah dan lebih aman daripada membaca yang asli lalu membuat ulang, dan ini mempertahankan semua yang tidak tercakup oleh proyeksi baca. |
execute_query | agent:query:run | Cara default untuk menjawab pertanyaan dari data: memvalidasi dan mengeksekusi kueri terstruktur (MBQL), mengembalikan baris plus query_handle. |
execute_sql | agent:sql:run | Jalur pelarian: mengeksekusi string SQL mentah terhadap database, mengembalikan baris plus query_handle. |
get_content | agent:content:read | Mengambil konten berdasarkan {type, id} — pembacaan bertipe untuk apa pun yang ditemukan melalui pencarian atau browse_collection. |
get_parameter_values | agent:content:read | Mengambil nilai valid untuk satu filter pada dasbor atau pertanyaan tersimpan, sehingga Anda memfilter dengan nilai nyata alih-alih menebak. |
glossary | agent:content:read | Mencari istilah bisnis sebagaimana didefinisikan oleh instance Metabase ini; nama istilah yang didefinisikan mengikuti deskripsi alat itu sendiri. |
learn | agent:content:read | Membaca dokumen tugas (keterampilan) server ini untuk dialek penulisan yang tidak dapat dijelaskan sepenuhnya oleh skema. |
measure_write | agent:content:write | Membuat atau memperbarui ukuran: agregasi MBQL bernama yang dapat digunakan ulang, dilampirkan ke satu tabel, direferensikan di dalam agregasi kueri lain sebagai ["measure", id]. |
metric_write | agent:content:write | Membuat atau memperbarui metrik: agregasi tersimpan yang dapat digunakan ulang, berada di koleksi, dan dapat dikueri sendiri atau direferensikan dari kueri lain. |
question_write | agent:content:write | Membuat, memperbarui, atau mengarsipkan pertanyaan atau model tersimpan. |
refresh_ui_credential | agent:query:run | Menyegarkan kredensial tercakup yang digunakan oleh Aplikasi MCP Metabase. |
render_drill_through | agent:query:run | Merender visualisasi drill-through yang baru saja dinavigasi pengguna. |
run_saved_question | agent:query:run | Menjalankan pertanyaan tersimpan (kartu) berdasarkan id numerik atau entity_id, mengembalikan baris secara inline. |
search | agent:content:read | Menemukan konten di seluruh instance Metabase berdasarkan relevansi. |
segment_write | agent:content:write | Membuat atau memperbarui segmen: filter MBQL bernama yang dapat digunakan ulang, dilampirkan ke satu tabel, direferensikan dari filter kueri lain. |
subscription_write | agent:delivery:write | Membuat atau memperbarui langganan dasbor — pengiriman terjadwal untuk seluruh dasbor, mis. |
visualize_query | agent:query:run | Memvisualisasikan kueri sebagai bagan atau tabel interaktif, dirender inline dalam percakapan. |
execute_query mengembalikan row_limit baris per panggilan (default 100, maks 2000) — ukuran halaman, bukan batas hasil.
Halaman yang terpotong melaporkan truncated: true dan, ketika kueri memiliki urutan total, next_cursor untuk diteruskan kembali sebagai
cursor untuk halaman berikutnya, hingga halaman tiba dengan truncated: false. Kueri yang hanya menginginkan N baris pertamanya
membawa limit: N di tahapnya (dengan order-by); server menghabiskan batas itu di seluruh halaman, sehingga halaman
terakhir kembali lengkap tanpa kursor dan paginasi berakhir dengan sendirinya.
Sumber Daya
Server mengekspos sumber daya MCP sehingga klien dapat mengambil konten tambahan berdasarkan URI tanpa memperbesar deskripsi alat.
| URI Sumber Daya | Cakupan | Deskripsi |
|---|---|---|
ui://metabase/visualize-query.html | agent:query:run (kredensial UI saja) | Shell iframe Aplikasi MCP visualize_query yang ditunjuk oleh klien yang mampu. |
ui://metabase/render-drill-through.html | agent:query:run (kredensial UI saja) | Shell yang render_drill_through tunjuk. |
catalog://metabase/fields | agent:content:read | Jalur titik yang diterima setiap jenis konten dalam argumen fields. |
Setiap sumber daya terdaftar apa pun cakupan tokennya. Sumber daya data, seperti katalog kolom, hanya dibaca oleh
token yang memegang cakupannya; jika tidak, pembacaan mendapatkan tantangan 403 insufficient_scope yang dijelaskan di bawah
Scopes. Shell UI dibaca oleh token apa pun, karena host Aplikasi MCP membaca shell alat
bersamaan dengan panggilan alat, dan jika pembacaan itu ditolak, host tidak akan naik setelah 403 panggilan alat. Shell
tidak membawa data. Shell yang dibaca oleh token tanpa cakupan shell tidak pernah mencetak kredensial UI. Data bagan
digerbang oleh panggilan alat dan oleh refresh_ui_credential (keduanya agent:query:run), yang dibutuhkan iframe sebelum dapat
membuat kueri apa pun. URI yang tidak dikenal adalah kesalahan -32602 "Resource not found".
Paket keterampilan dikirim melalui alat learn daripada sebagai sumber daya.
Navigasi entitas dilakukan dengan alat get_content dan browse_* daripada skema URI; sumber daya ui://
di atas ada hanya agar klien yang dapat merender iframe memiliki sesuatu untuk dipasang.
Metode JSON-RPC yang didukung
| Metode | Deskripsi |
|---|---|
initialize | Menginisialisasi koneksi MCP. Mengembalikan kemampuan server dan ID sesi. |
notifications/initialized | Notifikasi klien bahwa inisialisasi selesai. |
tools/list | Mencantumkan alat yang tersedia, apa pun cakupan tokennya. |
tools/call | Memanggil alat dengan argumen. |
resources/list | Mencantumkan sumber daya yang tersedia, apa pun cakupan tokennya. |
resources/read | Membaca sumber daya berdasarkan URI; sumber daya data memerlukan cakupannya. Memerlukan sesi. |
ping | Ping keepalive. |
Permintaan dapat dikirim secara individual atau sebagai batch JSON-RPC. Server merespons dengan JSON atau SSE tergantung pada
header Accept.
Arsitektur
Implementasi berada di file-file ini:
-
transport.clj- Transport HTTP. Mengurai permintaan JSON-RPC, memvalidasi autentikasi dan header sesi, menegakkan pemeriksaan asal (perlindungan DNS rebinding), dan mengirim ke metode yang sesuai. Mendukung format respons JSON dan SSE. -
v2/api.clj- Penangan permukaan alat. Menghubungkan transport ke registri alat + sumber daya v2 dan mendefinisikan pengiriman metode (tools/list,tools/call,resources/list,resources/read,ping). -
v2/registry.clj- Registri alat v2. Alat mendaftar sendiri melaluideftool; registri memeriksa cakupan, memvalidasi argumen, mengirim panggilan, dan mencatat penggunaan. -
scope.clj- Logika pencocokan cakupan. Hanya kecocokan tepat: wildcard, cakupan nil, dan sentinel::unrestrictedtidak cocok dengan apa pun.
Alur permintaan
MCP client
-> POST /api/metabase-mcp (JSON-RPC)
-> Origin + session validation
-> Auth: OAuth bearer token or browser session
-> Scope check against requested tool
-> Synthetic request to Agent API endpoint
-> Response materialized as MCP content
-> JSON or SSE back to client