Last9 MCP Server
resmiBawa konteks produksi real-time—log, metrik, dan trace—secara mulus ke lingkungan lokal Anda untuk memperbaiki kode secara otomatis lebih cepat.
Dokumentasi
Server MCP Last9

Agen AI Anda tidak tahu apa yang rusak di production. Ini memperbaikinya.
Server MCP Last9 menghubungkan Claude, Cursor, Windsurf, dan asisten AI berkemampuan MCP lainnya langsung ke data observabilitas production Anda — log, metrik, trace, exception, kueri database, alert, dan deployment. Agen berhenti menebak dan mulai membaca sinyal yang sebenarnya.
Mulai dalam 30 detik (Hosted)
Tidak ada binary untuk diinstal. Tidak ada token untuk dikelola. Satu URL, OAuth di browser Anda, selesai.
Temukan slug org Anda di URL Last9 Anda: app.last9.io/<org_slug>/...
Claude Code
claude mcp add --transport http last9 https://app.last9.io/api/v4/organizations/<org_slug>/mcp
Ketik /mcp, pilih last9, autentikasi. Selesai.
Cursor
Settings > MCP > Add New MCP Server:
{
"mcpServers": {
"last9": {
"type": "http",
"url": "https://app.last9.io/api/v4/organizations/<org_slug>/mcp"
}
}
}
Klik Connect, selesaikan OAuth.
VS Code
Membutuhkan v1.99+. Buka Command Palette → MCP: Add Server, tempel URL, autentikasi.
Atau langsung di settings.json:
{
"mcp": {
"servers": {
"last9": {
"type": "http",
"url": "https://app.last9.io/api/v4/organizations/<org_slug>/mcp"
}
}
}
}
Windsurf
Settings > Cascade > Open MCP Marketplace > ikon gear (mcp_config.json):
{
"mcpServers": {
"last9": {
"serverUrl": "https://app.last9.io/api/v4/organizations/<org_slug>/mcp"
}
}
}
Claude Web/Desktop
Settings > Connectors > Add custom connector. Beri nama last9, tempel URL, autentikasi.
Membutuhkan akses admin ke organisasi Claude Anda.
Self-Hosted (STDIO)
Gunakan ini ketika klien MCP Anda tidak mendukung transport HTTP, atau ketika Anda perlu server berjalan secara lokal.
Instal
Homebrew:
brew install last9/tap/last9-mcp
NPM:
npm install -g @last9/mcp-server@latest
# or directly:
npx -y @last9/mcp-server@latest
Rilis binary (Windows / manual):
Unduh dari GitHub Releases:
| Platform | Arsip |
|---|---|
| Windows (x64) | last9-mcp-server_Windows_x86_64.zip |
| Windows (ARM64) | last9-mcp-server_Windows_arm64.zip |
| Linux (x64) | last9-mcp-server_Linux_x86_64.tar.gz |
| Linux (ARM64) | last9-mcp-server_Linux_arm64.tar.gz |
| macOS (x64) | last9-mcp-server_Darwin_x86_64.tar.gz |
| macOS (ARM64) | last9-mcp-server_Darwin_arm64.tar.gz |
Dapatkan Refresh Token
Hanya admin yang dapat membuat token.
- Buka API Access
- Klik Generate Token dengan izin Write
- Salin token tersebut
Konfigurasi Klien
Homebrew:
{
"mcpServers": {
"last9": {
"command": "/opt/homebrew/bin/last9-mcp",
"env": {
"LAST9_REFRESH_TOKEN": "<your_refresh_token>"
}
}
}
}
NPM:
{
"mcpServers": {
"last9": {
"command": "npx",
"args": ["-y", "@last9/mcp-server@latest"],
"env": {
"LAST9_REFRESH_TOKEN": "<your_refresh_token>"
}
}
}
}
Tempat menempelkan ini:
| Klien | Lokasi |
|---|---|
| Claude Web/Desktop | Settings > Developer > Edit Config (claude_desktop_config.json) |
| Cursor | Settings > Cursor Settings > MCP > Add New Global MCP Server |
| Windsurf | Settings > Cascade > MCP Marketplace > ikon gear (mcp_config.json) |
| VS Code | Bungkus dalam { "mcp": { "servers": { ... } } } di settings.json — detail |
Konfigurasi STDIO VS Code
{
"mcp": {
"servers": {
"last9": {
"type": "stdio",
"command": "/opt/homebrew/bin/last9-mcp",
"env": {
"LAST9_REFRESH_TOKEN": "<your_refresh_token>"
}
}
}
}
}
Untuk NPM: gunakan "command": "npx" dan tambahkan "args": ["-y", "@last9/mcp-server@latest"].
Windows
Setelah mengunduh dari GitHub Releases, ekstrak dan arahkan ke path lengkap:
{
"mcpServers": {
"last9": {
"command": "C:\\Users\\<user>\\AppData\\Local\\Programs\\last9-mcp-server.exe",
"env": {
"LAST9_REFRESH_TOKEN": "<your_refresh_token>"
}
}
}
}
Rute NPM lebih mudah di Windows — tidak ada manajemen path.
Variabel Lingkungan
| Variabel | Default | Deskripsi |
|---|---|---|
LAST9_REFRESH_TOKEN | (wajib) | Refresh token dari API Access |
LAST9_DATASOURCE | default org | Nama sumber data/klaster — berguna ketika Anda memiliki beberapa klaster Levitate |
LAST9_API_HOST | app.last9.io | Timpa host API |
LAST9_MAX_GET_LOGS_ENTRIES | 5000 | Entri maksimum untuk permintaan get_logs yang dichunk |
LAST9_DEBUG_CHUNKING | false | Atur true untuk mencatat detail perencanaan chunk untuk get_logs, get_service_logs, get_traces |
LAST9_DISABLE_TELEMETRY | true | Atur false untuk mengaktifkan tracing OTel internal |
OTEL_SDK_DISABLED | — | Variabel env OTel standar. Menimpa LAST9_DISABLE_TELEMETRY |
OTEL_EXPORTER_OTLP_ENDPOINT | — | Endpoint kolektor OTLP (hanya ketika telemetri diaktifkan) |
OTEL_EXPORTER_OTLP_HEADERS | — | Header auth OTLP (hanya ketika telemetri diaktifkan) |
Apa yang Dapat Dilakukan
Kesehatan Layanan
get_service_summary— Throughput, tingkat error, waktu respons p95 di semua layananget_service_environments— Lingkungan yang tersedia untuk layanan Anda. Jalankan ini terlebih dahulu — alat APM lain memerlukanenvdari siniget_service_performance_details— Rincian lengkap: throughput, tingkat error, p50/p90/p95/rata-rata/maks, apdex, ketersediaanget_service_operations_summary— Operasi yang dikelompokkan berdasarkan endpoint HTTP, panggilan DB, messaging, klien HTTPget_service_dependency_graph— Peta dependensi dengan throughput, latensi, dan tingkat error untuk upstream/downstream/infraget_exceptions— Exception sisi server dengan filter layanan dan span
Observabilitas Database
Empat alat yang langsung menuju performa database Anda, berasal dari span trace OpenTelemetry. Tidak perlu instrumentasi tambahan jika Anda sudah menggunakan OTel.
get_databases— Temukan semua database di seluruh infrastruktur Anda: tipe DB, host, throughput (kueri/menit), latensi p95, tingkat error, jumlah layanan dependenget_database_slow_queries— Eksekusi kueri paling lambat yang sebenarnya, diurutkan berdasarkan durasi, dengan ID trace untuk menelusuri trace lengkapget_database_queries— Pola dan agregat kueri: seberapa sering kueri berjalan, durasi rata-rata/p95, tingkat errorget_database_server_metrics— Metrik sisi server dari host DB itu sendiri (CPU, koneksi, tingkat buffer hit — tergantung pada sistem DB Anda)
Mendukung PostgreSQL, MySQL, MongoDB, Redis, Aerospike, dan apa pun yang memiliki trace OTel dengan atribut db_system.
Prometheus / PromQL
prometheus_range_query— Kueri rentang PromQL pada metrik apa punprometheus_instant_query— Kueri instan; gunakan fungsi rollup sepertiavg_over_time,sum_over_timeprometheus_label_values— Nilai label untuk seri tertentuprometheus_labels— Semua label yang tersedia untuk suatu seri
Arahkan ini ke sumber data/klaster yang berbeda dari default dengan mengatur LAST9_DATASOURCE.
Log
get_logs— Kueri log pipeline JSON lengkap (agregasi, filter, ekstraksi field)get_service_logs— Baris log mentah untuk suatu layanan, dapat difilter berdasarkan tingkat keparahan dan konten bodyget_log_attributes— Katalog global atribut dalam skema log untuk jendela waktuget_log_attributes_for_pipeline— Field log yang benar-benar ada untuk pipeline yang sedang berjalan (penemuan terlingkup), masing-masing denganfilter_fieldyang tepatget_drop_rules— Aturan drop log dari Last9 Control Planeadd_drop_rule— Buat aturan drop baru untuk mengurangi volume log di sumbernya
Trace
get_traces— Kueri trace pipeline JSON untuk pencarian luas dan agregasiget_service_traces— Trace berdasarkan ID trace atau nama layanan yang tepat. Gunakan ini ketika Anda memiliki ID trace — ini lebih cepatget_trace_attributes— Katalog global atribut dalam skema traceget_trace_attributes_for_pipeline— Atribut yang benar-benar ada untuk pipeline yang sedang berjalan (penemuan terlingkup), masing-masing denganfilter_fieldyang tepatget_trace_attribute_values— Nilai berbeda untuk atribut trace, secara opsional terlingkup ke pipeline
Peristiwa Perubahan & Alert
get_change_events— Deployment, perubahan konfigurasi, rollback. Korelasikan insiden dengan apa yang berubahget_alert_config— Konfigurasi aturan alert — dapat dicari berdasarkan nama, tingkat keparahan, tipe, tagget_alerts— Alert yang sedang aktif dalam jendela waktuget_alert_rule_state— Status aktif historis (1/0) per aturan alert selama rentang waktu, dikelompokkan berdasarkanrule_id. Dapat difilter berdasarkan grup alert, nama aturan, filter label, dan status.get_notification_channels— Saluran notifikasi yang dikonfigurasi (Slack, PagerDuty, email, dll.)
Dasbor Kustom
list_dashboards— Semua dasbor kustom di org Anda: ID, nama, dan metadataget_dashboard— Definisi dasbor lengkap berdasarkan ID, termasuk panel dan kuericreate_dashboard— Buat dasbor kustom baru dengan panel, kueri, dan metadataupdate_dashboard— Perbarui dasbor yang ada berdasarkan ID (dasbor sistem readonly akan mengembalikan error)delete_dashboard— Hapus dasbor kustom berdasarkan ID
Resolusi Nama Fuzzy
did_you_mean— Ketika agen tidak yakin tentang nama entitas, ini mengembalikan kecocokan terdekat dari katalog Anda (layanan, lingkungan, host, database, deployment/namespace K8s, job). Hingga 3 saran dengan skor kemiripan. Server memanggil ini secara otomatis sebelum sebagian besar alat ketika pencarian nama mengembalikan kosong.
Cara Kerjanya
Tautan langsung di setiap respons. Setiap alat mengembalikan field deep_link — URL langsung ke dasbor Last9 untuk kueri dan rentang waktu yang tepat tersebut. Agen dapat memberikan tautan kepada Anda; Anda mengkliknya; Anda langsung di sana.
Caching atribut langsung. Saat startup, server mengambil nama atribut log dan trace yang sebenarnya dari data Anda dan menyematkannya ke dalam deskripsi alat. Ini berarti asisten AI mengetahui field apa yang ada di skema Anda, bukan hanya daftar generik. Cache diperbarui setiap 2 jam.
Hasil besar dichunk. get_logs dan get_traces menangani set hasil besar melalui chunking daripada pemotongan. Batas default adalah 5000 entri untuk log; dapat dikonfigurasi melalui LAST9_MAX_GET_LOGS_ENTRIES.
Pengembangan
Mode HTTP, pengujian curl, membangun dari sumber
Jalankan dalam Mode HTTP
export LAST9_REFRESH_TOKEN="your_refresh_token"
export LAST9_HTTP=true
export LAST9_PORT=8080
./last9-mcp-server
Server dimulai di http://localhost:8080/mcp.
Uji dengan curl
MCP Streamable HTTP memerlukan jabat tangan inisialisasi terlebih dahulu. Jangan atur Mcp-Session-Id pada permintaan pertama.
# Step 1: Initialize
SESSION_ID=$(curl -si -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "curl-test", "version": "1.0"}
}
}' | grep -i "^Mcp-Session-Id:" | awk '{print $2}' | tr -d '\r')
echo "Session: $SESSION_ID"
# Step 2: Send initialized notification
curl -s -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'
# Step 3: List tools
curl -s -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}'
# Step 4: Call a tool
curl -s -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_service_logs",
"arguments": {
"service": "your-service-name",
"lookback_minutes": 30,
"limit": 10
}
}
}'
Bangun dari Sumber
git clone https://github.com/last9/last9-mcp-server.git
cd last9-mcp-server
go build -o last9-mcp-server
LAST9_HTTP=true ./last9-mcp-server
LAST9_HTTP=true untuk pengembangan lokal. Untuk penggunaan sebenarnya, endpoint HTTP hosted lebih mudah.
Referensi Alat
Semua parameter, standar input waktu, dan detail
Input Waktu
- Waktu absolut (
start_time_iso/end_time_iso, atautime_iso) diutamakan daripadalookback_minutes. - Untuk jendela relatif: gunakan
lookback_minutes. - Untuk jendela absolut: gunakan RFC3339/ISO8601 —
2026-02-09T15:04:05Z. YYYY-MM-DD HH:MM:SSlawas diterima hanya untuk kompatibilitas.
get_exceptions
limit(integer, opsional): Maks exception. Default: 20.lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional): Rentang waktu absolut.service_name(string, opsional): Filter berdasarkan layanan.span_name(string, opsional): Filter berdasarkan nama span.deployment_environment(string, opsional): Filter berdasarkan lingkungan.
get_service_summary
start_time_iso/end_time_iso(string, opsional)env(string, opsional): Default keprod.
get_service_environments
start_time_iso/end_time_iso(string, opsional)
Semua alat APM lainnya memerlukan nilai
env. Gunakan""jika ini mengembalikan kosong.
get_service_performance_details
service_name(string, wajib)lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)env(string, opsional): Default keprod.
get_service_operations_summary
service_name(string, wajib)lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)env(string, opsional): Default keprod.
get_service_dependency_graph
service_name(string, opsional)lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)env(string, opsional): Default keprod.
get_databases
env(string, opsional): Filter berdasarkan environment. Default: all.lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)
get_database_slow_queries
db_system(string, opsional): mis.postgresql,mysql,mongodb,redis.host(string, opsional): Host database (net_peer_name).service_name(string, opsional): Nama layanan pemanggil.env(string, opsional)min_duration_ms(float, opsional): Durasi kueri minimum dalam ms.lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)limit(integer, opsional): Default: 20.
get_database_queries
db_system(string, opsional)host(string, opsional)service_name(string, opsional)env(string, opsional)lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)limit(integer, opsional): Default: 20.
get_database_server_metrics
db_system(string, wajib): mis.postgresql,mysql,mongodb,redis,aerospike.host(string, opsional)lookback_minutes(integer, opsional): Default: 60.start_time_iso/end_time_iso(string, opsional)
prometheus_range_query
query(string, wajib): Kueri PromQL.start_time_iso/end_time_iso(string, opsional): Default ke 60 menit terakhir.lookback_minutes(float, opsional): Default: 60.
prometheus_instant_query
query(string, wajib)time_iso(string, opsional): Default ke sekarang.lookback_minutes(float, opsional)
prometheus_label_values
match_query(string, opsional): Filter PromQL.label(string, wajib): Nama label.start_time_iso/end_time_iso(string, opsional)
prometheus_labels
match_query(string, opsional): Filter PromQL.start_time_iso/end_time_iso(string, opsional)
get_logs
logjson_query(array, wajib): Kueri pipeline JSON.lookback_minutes(integer, opsional): Default: 5.start_time_iso/end_time_iso(string, opsional)limit(integer, opsional): Default server: 5000.index(string, opsional):physical_index:<name>ataurehydration_index:<block_name>.
Untuk inventaris layanan berbasis log, kueri physical_index_service_count terlebih dahulu:
sum by (name, service_name, env) (physical_index_service_count{destination="logs"})
Gunakan service_name sebagai ServiceName, env sebagai environment jika ada, dan name sebagai nama indeks fisik. Jika name="default", hilangkan index; untuk indeks fisik non-default yang dipilih pengguna, berikan index: "physical_index:<name>". Jika backend menolak pemfilteran indeks fisik eksplisit, coba lagi tanpa index dan laporkan bahwa pemfilteran indeks fisik eksplisit tidak tersedia untuk backend tersebut.
get_service_logs
service(string, wajib)lookback_minutes(integer, opsional): Default: 60.limit(integer, opsional): Default: 20.env(string, opsional)severity_filters(array, opsional): mis.["error", "warn"]. Logika OR.body_filters(array, opsional): mis.["timeout", "failed"]. Logika OR.start_time_iso/end_time_iso(string, opsional)index(string, opsional)
Beberapa tipe filter digabungkan dengan AND. Setiap array menggunakan OR secara internal.
Gunakan get_logs untuk hitungan agregat luas terlebih dahulu; gunakan get_service_logs hanya setelah mempersempit ke layanan/env/indeks dan set sampel kecil.
get_log_attributes
lookback_minutes(integer, opsional): Default: 15.start_time_iso/end_time_iso(string, opsional)region(string, opsional)index(string, opsional)
get_log_attributes_for_pipeline
pipeline(array, wajib): Tahapan filter sebelumnya untuk membatasi cakupan penemuan, mis.[{"type":"filter","query":{"$eq":["ServiceName","<service>"]}}].lookback_minutes(integer, opsional): Default: 15.start_time_iso/end_time_iso(string, opsional)region(string, opsional)index(string, opsional)
get_drop_rules
Tidak ada parameter.
add_drop_rule
name(string, wajib)filters(array, wajib): Setiap filter:key,value,operator(equals/not_equals),conjunction(and).
get_traces
Gunakan untuk pencarian luas dan agregasi. Untuk pencarian trace ID yang tepat, gunakan get_service_traces.
tracejson_query(array, wajib)start_time_iso/end_time_iso(string, opsional)lookback_minutes(integer, opsional): Default: 60.limit(integer, opsional): Default: 5000.
get_service_traces
Tepat salah satu dari trace_id atau service_name wajib diisi.
trace_id(string, opsional): Lookback default: 72 jam.service_name(string, opsional): Lookback default: 60 menit.lookback_minutes(integer, opsional)start_time_iso/end_time_iso(string, opsional)limit(integer, opsional): Default: 10.env(string, opsional)
get_trace_attributes
lookback_minutes(integer, opsional): Default: 15.start_time_iso/end_time_iso(string, opsional)region(string, opsional)
get_trace_attributes_for_pipeline
pipeline(array, wajib): Tahapan filter sebelumnya untuk membatasi cakupan penemuan, mis.[{"type":"filter","query":{"$eq":["ServiceName","<service>"]}}].lookback_minutes(integer, opsional): Default: 15.start_time_iso/end_time_iso(string, opsional)region(string, opsional)
get_trace_attribute_values
tag_name(string, wajib): Nama atribut dariget_trace_attributes(mis.resource_departmentatauattributes['http.method']).pipeline(array, opsional): Tahapan filter sebelumnya untuk membatasi nilai; hilangkan untuk nilai global.region(string, opsional)
get_change_events
start_time_iso/end_time_iso(string, opsional)lookback_minutes(integer, opsional): Default: 60.service(string, opsional)environment(string, opsional)event_name(string, opsional): Panggil tanpa ini terlebih dahulu untuk mendapatkanavailable_event_names.
get_alert_config
search_term(string, opsional): Pencarian teks bebas di seluruh nama, grup, sumber data, tag.rule_name(string, opsional)severity(string, opsional)rule_type(string, opsional):staticatauanomaly.alert_group_name/alert_group_type/data_source_name(string, opsional)tags(array, opsional): Semua harus cocok (logika AND).
get_alerts
time_iso(string, opsional): Waktu evaluasi dalam RFC3339.window(integer, opsional): Lookback dalam detik. Default: 900. Rentang: 60–86400.lookback_minutes(integer, opsional): Rentang: 1–1440.
get_alert_rule_state
start_time(integer, wajib): Awal rentang epoch Unix (inklusif).end_time(integer, wajib): Akhir rentang epoch Unix (inklusif).step(integer, wajib): Resolusi dalam detik antar sampel. Jumlah sampel((end_time - start_time) / step + 1)dibatasi hingga 100.alert_group_id(string, opsional): Filter berdasarkan ID grup alert.rule_name(string, opsional): Filter regex pada nama aturan.alert_group_name(string, opsional): Filter regex pada nama grup alert.label_filters(string, opsional): Filter labelkey=valueyang dipisahkan koma.state(string, opsional): Filter berdasarkan state (mis.firing).
Mengembalikan peta JSON dari rule_id -> [{timestamp, is_firing}]. Timestamp di mana suatu aturan tidak ada dalam respons upstream dilaporkan sebagai is_firing=0 — ini berarti "tidak teramati sebagai firing", bukan status normal yang terkonfirmasi.
get_notification_channels
Tidak ada parameter. Mengembalikan semua saluran notifikasi yang dikonfigurasi (Slack, PagerDuty, email, webhook, dll.).
did_you_mean
query(string, wajib): Nama yang akan dicari — sebagian, salah eja, atau disingkat.type(string, opsional): Batasi ke tipe entitas:service,environment,host,database,k8s_deployment,k8s_namespace,job.
Mengembalikan hingga 3 kecocokan terdekat dengan skor kemiripan. Gunakan ini sebelum pemanggilan alat apa pun yang nama entitasnya tidak pasti. Jika panggilan sebelumnya mengembalikan hasil kosong, coba ini sebelum mencoba lagi.
list_dashboards
Tidak ada parameter. Mengembalikan semua dasbor kustom di organisasi sebagai array JSON dengan id, name, dan metadata.
get_dashboard
id(string, wajib): UUID Dasbor.region(string, opsional): Region untuk populasi kueri panel. Default ke region sumber data yang dikonfigurasi.
create_dashboard
dashboard(object, wajib): Definisi dasbor dengannamedanpanels[]. Setiap panel memerlukanname,version,layout(x,y,w,h),visualization.type, danqueries[].metadata(object, opsional): Metadata dasbor — field_categorydan_type(mis.{"_category":"custom","_type":"metrics"}).
update_dashboard
id(string, wajib): UUID dasbor yang akan diperbarui.dashboard(object, wajib): Body dasbor pengganti penuh (bentuk sama seperti create).metadata(object, opsional): Metadata pengganti. Dasbor sistem readonly akan mengembalikan error 403.
delete_dashboard
id(string, wajib): UUID dasbor yang akan dihapus. Dasbor sistem readonly tidak dapat dihapus.
Pengujian
Lihat TESTING.md untuk penyiapan dan instruksi pengujian integrasi.
