Documentation
¶
Overview ¶
Package mcptools wires Coremetry's telemetry surfaces as MCP tools (v0.6.5). Lives in its own package — not inside `mcp` — so the protocol layer stays storage-agnostic and we don't risk a chstore↔mcp import dance.
Each tool closes over a Deps struct containing the chstore + logstore handles. Register(srv, deps) is called once at boot after the MCP server is constructed, before SetMCP is called on the api.Server.
Design choices:
Args are decoded into a typed struct per tool. JSON Schema in the registration matches that struct field-for-field so a Claude Desktop-style inspector renders the right form.
Time windows are expressed as `range_s` (seconds back from now) instead of from/to nanoseconds. LLMs are notoriously bad at constructing big nanosecond integers; "give me the last 30 minutes" → range_s=1800 is a much more reliable prompt for them than two unix-nano timestamps.
Every tool caps Limit at a tool-specific sane default. The LLM can ask for 10 or 100 but not 10000 — context windows are precious and an oversized list_problems response trashes downstream reasoning. Server-side cap is the backstop.
Errors are returned as Go errors; the mcp package wraps them into MCP isError=true content. No need to format them here.
Yetki (v0.9.1136, AI Faz 3.1): her tool mcp.Tool.MinRole taşır ve BUGÜN 24'ünün tamamı "" (viewer tabanı) — hepsi salt-okunur ve hepsinin REST eşi viewer'a açık. Tek sapma list_anomalies↔GET /api/anomalies/active idi (REST editor, tool kapısız); A7 kararıyla REST viewer'a indi, tool "" kaldı — sapma sıfır. YENİ TOOL EKLERKEN: REST eşinin kapısına bak. auth.RequireRole /RequireAnyRole ile sarılıysa MinRole'ü aynı role AYARLA; yazma tool'u eklenirse (bu tasarımda yok) MinRole en az "editor" + audit satırı şart. Zorlama api/mcp_gate.go'daki kapıdadır; buradaki alan tek gerçek kaynak olduğu için MCP dispatch'i ve in-app sohbet spec listesi ayrışamaz.
Kompakt görünüm (v0.9.1230): her tool AYRICA bir mcp.Tool.ShortDescription taşır — 2-3 cümlelik TÜRKÇE sözleşme. Aynı kayıt defterinin iki tüketicisinin bağlam bütçesi zıt: dış MCP istemcisi kataloğu bir kez okur (tam İngilizce metni görür, tools/list DEĞİŞMEDİ), in-app sohbetteki gemma4 ise onu HER TUR yeniden yutuyordu — ölçüm: 33 tool = 24.268 B açıklama + 17.672 B şema, döngü 5 tura kadar. Sohbet yolu artık ChatDescription()'ı okur (kompakt toplam 5.671 B). YENİ TOOL EKLERKEN: kompakt metni de yaz — ikisi aynı literal'de yan yana durur ve short_desc_test.go boş bırakılmasına izin vermez. Şemalar bilinçli olarak KISALTILMAZ: arg adı/varsayılanı doğru çağrının koşulu, orada kazanılan bayt yanlış argümanla harcanan bir tura değmez.
Tool catalogue (34 tools; sayım v0.9.1050'de düzeltildi — blok v0.6.5'te kalmıştı, get_problem_root_cause/render_chart sayılmıyordu; v0.9.1227'de get_operation_health ile 33; v0.9.1233'te get_exception_samples ile 34; v0.9.1141'ta beş keşif tool'uyla 19 → 24; v0.9.1142'de find_trace_by_request_id ile 25; v0.9.1146'da üç analiz tool'uyla 28; v0.9.1147'de dört guided-parite tool'uyla 32):
- list_services
- get_service_health
- get_operation_health (v0.9.1227 — endpoint-bazlı RED, spanmetrics_1m)
- list_problems
- get_problem_root_cause (v0.9.160)
- list_anomalies
- search_logs
- get_trace
- search_traces (v0.9.1087 — id'siz giriş, zincirin ilk halkası)
- list_slo_status (v0.9.1089 — durum + deterministik yörünge)
- query_metric
- list_metric_names (v0.9.1090 — query_metric'in eşi)
- list_exception_groups (v0.9.1091 — Exceptions sayfasının okuması)
- get_exception_samples (v0.9.1233 — grubun stack'i + trace pivotu; zincirin ikinci yarısı, tarama penceresi GRUBUN kendi ömrü)
- get_correlated_changes (v0.9.1092 — MV'li "başka ne değişti")
- get_deploy_diff (v0.9.1092 — deploy önce/sonra RED kıyası)
- render_chart (v0.9.520)
Keşif tool'ları (v0.9.1141, AI Faz 3.2 — discovery.go). Hepsi bir ARG'ın eşi: arg'ı kabul edip listesini vermeyen tool = kimlik uydurmaya davet (v0.9.1087-1092 dalgasının aynı gerekçesi):
- list_operations (render_chart'ın `operation` arg'ı; katalog, pencere YOK)
- list_environments (list_services/get_service_health/list_problems `env`)
- list_clusters (search_logs'un `cluster` arg'ı; 1h sabit pencere)
- list_deploys ("dün gece ne çıktı" + get_deploy_diff'e sürüm)
- find_trace_by_span (yapıştırılan 16-hex span id → trace id)
Yapıştırılan KURUMSAL kimlik (v0.9.1142, find_trace_by_request_id.go):
- find_trace_by_request_id (sabit yapılı istek numarası → trace id; pencere kimliğin İÇİNDEKİ damgadan gelir, o yüzden range_s YOK)
Analiz tool'ları (v0.9.1146, AI Faz 3.3 — analysis.go). Bunlar bir ARG'ın değil bir SORUNUN eşi: model üçüne de cevap üretemiyordu ve üçü de olay anlatısının merkezinde. Hepsi mevcut okuyucuyu köprüler (yeni SQL yok):
- get_topology ("yukarımda/aşağımda ne var" — topology_edges_5m MV)
- get_blast_radius ("bu bozulursa kim bozulur" — service_callers_5m)
- get_log_histogram ("log hacmi zamanla nasıl" — severity kırılımı)
Guided-parite tool'ları (v0.9.1147, AI Faz 3.4 — guided_parity.go). D6: guided router 16 intent tanıyordu ve yedisinin MCP karşılığı YOKTU. Dördü indi ve guided AYNI veri katmanını çağırıyor (ReadX → yapısal veri; tool JSON'a, guided Türkçe metne çeviriyor — okumanın ikinci kopyası kalmadı):
- get_db_health ("hangi db yavaş" — db_summary_5m)
- get_messaging_health ("kuyruk tarafı nasıl" — messaging_summary_5m)
- get_pod_health ("hangi pod'un heap'i dolu" — OTel runtime)
- list_problem_window_events ("dün gece neler oldu" — açılan+ÇÖZÜLEN)
Cross-signal pivot tools (v0.8.333, pivots.go):
- get_logs_for_trace
- get_exemplar_traces
- get_linked_traces
- get_metrics_for_span
CoSRE Faz-2 (structured chart cards):
- render_chart — the model PICKS which live RED chart to show; the chat server emits the deterministic ```chart``` block (copilot_chat.go), the UI draws it from real telemetry.
Env-awareness (v0.8.398, AI audit): list_services, get_service_health and list_problems accept an OPTIONAL `env` arg (deployment environment, spans.deploy_env — int/uat/prep style values) because their underlying reads already support it (GetServicesFilteredIn's env conjunct v0.8.385; ProblemFilter.Env service-scoped semantics v0.8.387). Results echo the applied env. The other tools stay env-less ON PURPOSE: search_logs/list_anomalies/query_metric reads carry no env path yet (env-separation Phase 4 pending) and get_trace/pivot tools are id-anchored point lookups — no silent half-support.
v0.9.1141 — keşif tool'larında env kararı tool başına gözden geçirildi: list_environments/list_clusters env boyutunun KENDİSİNİ listeler (arg alamaz); list_operations'ın okuması operation_summary_5m'dir ve o MV'de deploy_env YOK (operationsUseMV env'i görünce MV'yi diskalifiye eder) → env arg'ı yok; list_deploys'un deploy işaretçileri env taşımıyor; find_trace_by_span id-çapalı. Gerekçeler discovery.go başlığında.
Index ¶
- func Register(srv *mcp.Server, d Deps)
- func ToolList(d Deps) []mcp.Tool
- type DBHealthData
- type DBHealthRow
- type Deps
- type ExceptionSampleRow
- type MessagingHealthData
- type MessagingHealthRow
- type MetricSource
- type OperationHealthRow
- type PodHealthData
- type PodHeapRow
- type PodInstanceRow
- type ProblemWindowData
- type ProblemWindowRow
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ToolList ¶ added in v0.6.53
Register installs every v0.6.5/v0.6.6 tool and resource on the given MCP server. Idempotent — calling twice overwrites with the latest closures, but that's a logic-error pattern the mcp package logs about. ToolList returns the full telemetry tool set as plain mcp.Tool values closed over the given Deps, WITHOUT registering them on an MCP server. v0.6.53 — the in-app chatbot reuses this exact set as its function-calling backend: it maps each tool's Name / Description / InputSchema into a copilot.ToolSpec for the LLM, and invokes Handler(ctx, args) directly (the handler signature is transport- agnostic — no JSON-RPC envelope needed). Register() delegates here so the MCP server and the chatbot can never drift to different tool sets.
Types ¶
type DBHealthData ¶ added in v0.9.1147
type DBHealthData struct {
Rows []DBHealthRow
Total int
Truncated bool
// StoreCapped — okuma STORE tavanına dayandı (liste eksik olabilir),
// StoreRowLimit tavanın kendisi. Guided bugüne dek bunu hiç
// söylemiyordu; artık ikisi de aynı bayrağı görüyor.
StoreCapped bool
StoreRowLimit int
}
DBHealthData — ortak katmanın çıktısı. Rows SIRALI (calls DESC, tam tiebreak) ve Limit'e kesik; Total kesme ÖNCESİ sayı.
func ReadDBHealth ¶ added in v0.9.1147
ReadDBHealth — ORTAK OKUMA. GetDatabases'in HAFİF çağrısı: çağıran turu ve receiver keşfi KAPALI (IncludeCallers/IncludeReceivers false), yani maliyet GetDatabasesRollup'ın birebir aynısı — üstüne yalnız zarfın RowsCapped bayrağı geliyor (guided o bayrağı görmüyordu).
type DBHealthRow ¶ added in v0.9.1147
type DBHealthRow struct {
System string `json:"system"`
Instance string `json:"instance"`
DBName string `json:"db_name,omitempty"`
Calls uint64 `json:"calls"`
Errors uint64 `json:"errors"`
// ErrorRatePct 0..100.
ErrorRatePct float64 `json:"error_rate_pct"`
AvgMs float64 `json:"avg_ms"`
P50Ms float64 `json:"p50_ms"`
P95Ms float64 `json:"p95_ms"`
P99Ms float64 `json:"p99_ms"`
}
DBHealthRow — bir (system, instance, db_name) satırı. Ondalıklar HAM: yuvarlama yalnız JSON tarafında (dbHealthPayload → sanitizeDBHealthRows). Guided metni %.1f/%.2f basıyor ve ön-yuvarlanmış bir değeri yeniden yuvarlamak kenar durumlarda BAŞKA bir dize üretir — ortak katman ham ölçümü taşır, biçim tüketicinin işi.
func DBHealthSlowestByP95 ¶ added in v0.9.1147
func DBHealthSlowestByP95(rows []DBHealthRow, n int) []DBHealthRow
DBHealthSlowestByP95 — verilen satırlardan p95'e göre en yavaş n. SAF. KAPSAM: girdi ne ise o — çağıran zaten kesilmiş bir liste verdiyse "en yavaş" o listenin içindedir. Guided bunu böyle kullanıyordu ve davranış korunuyor; tool gövdesi de aynı alt kümeden türetiliyor, yani iki yüzey aynı üç adı söylüyor.
type Deps ¶
type Deps struct {
Store *chstore.Store
LogStore logstore.Store
// Metrics — v0.9.1150. The METRIC read router (ClickHouse or an
// external VictoriaMetrics), for the two tools whose reads the
// operator can repoint from Settings: query_metric and
// list_metric_names.
//
// A narrow OPTIONAL field rather than turning Store into an
// interface: ~30 other tools read *chstore.Store for span-derived
// data that has no VM equivalent and never will, so widening Store
// would be a large mechanical change that buys nothing. See
// MetricSource for the nil contract.
Metrics MetricSource
}
Deps bundles the data-access handles concrete tools close over. Kept here (rather than passed through Register) so test setups can construct a Deps with mocks for just the surfaces under test instead of building a full chstore.
type ExceptionSampleRow ¶ added in v0.9.1233
type ExceptionSampleRow struct {
Service string `json:"service"`
ExType string `json:"ex_type"`
Message string `json:"message,omitempty"`
Stacktrace string `json:"stacktrace,omitempty"`
TraceID string `json:"trace_id,omitempty"`
SpanID string `json:"span_id,omitempty"`
SpanName string `json:"span_name,omitempty"`
TimeISO string `json:"time_iso"`
}
ExceptionSampleRow — bir istisna oluşumu. Service/ExType satır başına TEKRARLANIR (zarf da taşır) çünkü model satırı bağlamından kopararak alıntılıyor; stack'in hangi servise ait olduğu satırın kendisinde yazmazsa yanlış servise atfedilir.
type MessagingHealthData ¶ added in v0.9.1147
type MessagingHealthData struct {
Rows []MessagingHealthRow
Total int
Truncated bool
StoreCapped bool
StoreRowLimit int
}
MessagingHealthData — DBHealthData ikizi.
func ReadMessagingHealth ¶ added in v0.9.1147
func ReadMessagingHealth(ctx context.Context, d Deps, from, to time.Time, limit int) (MessagingHealthData, error)
ReadMessagingHealth — ORTAK OKUMA (GetMessaging; çağıran turu dahil, çünkü bu okuma onu zaten koşuyor — bkz. dosya başlığı sapma #2).
type MessagingHealthRow ¶ added in v0.9.1147
type MessagingHealthRow struct {
System string `json:"system"`
Cluster string `json:"cluster"`
Destination string `json:"destination"`
Calls uint64 `json:"calls"`
Errors uint64 `json:"errors"`
// ErrorRatePct 0..100.
ErrorRatePct float64 `json:"error_rate_pct"`
AvgMs float64 `json:"avg_ms"`
P50Ms float64 `json:"p50_ms"`
P95Ms float64 `json:"p95_ms"`
P99Ms float64 `json:"p99_ms"`
// Produce*/Consume* — kind kırılımı (messaging_caller_summary_5m).
// GECİKME AYRIŞMASI: publish (broker'a yazma) ile process (mesajı
// işleme) farklı işler; karışık p95 yavaş tüketiciyi hızlı üreticinin
// içinde saklar (v0.9.816). 0 ms bir ölçüm DEĞİL, ölçüm yokluğudur.
ProduceCalls uint64 `json:"produce_calls"`
ConsumeCalls uint64 `json:"consume_calls"`
ProduceErrors uint64 `json:"produce_errors"`
ConsumeErrors uint64 `json:"consume_errors"`
ProduceP95Ms float64 `json:"produce_p95_ms,omitempty"`
ConsumeP95Ms float64 `json:"consume_p95_ms,omitempty"`
// Callers — bu destination'a dokunan en yoğun servisler (grup başına
// 5, LIMIT n BY ile — v0.9.813). Mevcut okuma bunu zaten ödüyor.
Callers []string `json:"callers,omitempty"`
}
MessagingHealthRow — bir (system, cluster, destination) satırı. Ondalıklar HAM (bkz. DBHealthRow gerekçesi).
type MetricSource ¶ added in v0.9.1150
type MetricSource interface {
ListMetricNames(ctx context.Context, service, pattern string, limit, offset int) ([]chstore.MetricInfo, int, error)
QueryMetric(ctx context.Context, f chstore.MetricQueryFilter) ([]chstore.SpanMetricSeries, error)
}
MetricSource is the metric-read half of Deps, satisfied by *chstore.Store itself AND by internal/api's backend router. Declared HERE so the import direction stays api → mcptools (mcptools must never import api; that cycle is why /topology's hidden-pattern matcher could not move — see analysis.go).
type OperationHealthRow ¶ added in v0.9.1227
type OperationHealthRow struct {
Path string `json:"path"`
Method string `json:"method,omitempty"`
Calls uint64 `json:"calls"`
Errors uint64 `json:"errors"`
// ErrorRatePct 0..100.
ErrorRatePct float64 `json:"error_rate_pct"`
AvgMs float64 `json:"avg_ms"`
P50Ms float64 `json:"p50_ms"`
P95Ms float64 `json:"p95_ms"`
P99Ms float64 `json:"p99_ms"`
ReqPerMin float64 `json:"req_per_min"`
}
OperationHealthRow — bir (path, method) satırı. Ondalıklar HAM (DBHealthRow gerekçesi: biçim tüketicinin işi).
type PodHealthData ¶ added in v0.9.1147
type PodHealthData struct {
Service string
Instances []PodInstanceRow
InstanceTotal int
InstancesTruncated bool
UpCount int
Heap []PodHeapRow
HeapTotal int
HeapTruncated bool
// HeapWindowS — heap okumasının penceresi. DAİMA canlı
// chstore.RuntimePodWindow; çağıranın range_s'i buraya karışmaz.
HeapWindowS int
// ÖLÜMCÜL DEĞİL: envanter tek başına da cevap. Filo modunda heap tek
// veri olduğu için hata çağırana döner.
HeapUnavailable bool
}
PodHealthData — iki mod tek şekil. Service=="" → filo modu: envanter HİÇ okunmaz (Instances nil), Heap filo geneli sıralamadır.
func ReadPodHealth ¶ added in v0.9.1147
func ReadPodHealth(ctx context.Context, d Deps, service string, from, to time.Time, instLimit, heapLimit int) (PodHealthData, error)
ReadPodHealth — ORTAK OKUMA. İki okuma, iki PENCERE:
- heap: HER ZAMAN [now-RuntimePodWindow, now] (sustained 10dk ortalaması; v0.9.1053'te pencere parametre oldu ve "şimdi" semantiği çağıranda kuruluyor).
- envanter: çağıranın (from, to) penceresi, YALNIZ service != "" iken.
Hata sözleşmesi: filo modunda heap hatası çağırana döner (tek veri o); servis modunda envanter hatası döner, heap hatası HeapUnavailable ile işaretlenir (envanter tek başına da cevaptır — guided davranışı).
type PodHeapRow ¶ added in v0.9.1147
type PodHeapRow struct {
Service string `json:"service"`
Pod string `json:"pod"`
// HeapPct = used/limit. PostGCPct = used_after_last_gc/limit ve
// GERÇEK baskı sinyali odur (testere-dişi heap'te used/max sağlıklı
// pod'da bile %85+ görünür — v0.9.426 operatör raporu). PostGCPct 0 =
// metrik AKMIYOR, "GC sonrası boş" DEĞİL.
HeapPct float64 `json:"heap_pct"`
PostGCPct float64 `json:"post_gc_pct,omitempty"`
UsedBytes float64 `json:"used_bytes"`
LimitBytes float64 `json:"limit_bytes"`
PostGCBytes float64 `json:"post_gc_bytes,omitempty"`
}
PodHeapRow — bir pod'un JVM heap doygunluğu (10 dk ortalaması).
type PodInstanceRow ¶ added in v0.9.1147
type PodInstanceRow struct {
ID string `json:"id"`
Zone string `json:"zone,omitempty"`
CPUPct float64 `json:"cpu_pct"`
// MemBytes/MemPct — MemPct yalnız runtime bir bellek LİMİTİ
// bildirdiğinde dolu (JVM bildirir, Go bildirmez) — 0 = limit
// bilinmiyor, "bellek boş" DEĞİL.
MemBytes float64 `json:"mem_bytes"`
MemPct float64 `json:"mem_pct,omitempty"`
// Up — pencerenin SON 2 dakikasında örnek görüldü mü. false =
// "sessiz": düşmüş, drene olmuş ya da metrik yayınlamayı kesmiş.
Up bool `json:"up"`
LastSeenNs int64 `json:"last_seen_unix_ns"`
}
PodInstanceRow — bir pod/instance (OTel host.name kimliği).
type ProblemWindowData ¶ added in v0.9.1147
type ProblemWindowData struct {
Rows []ProblemWindowRow
Total int
Truncated bool
Opened int
Resolved int
StillOpen int
// StoreCapped — okuma store tavanına dayandı; sayaçlar LOWER BOUND.
StoreCapped bool
StoreRowLimit int
}
ProblemWindowData — sayaçlar + satırlar. Sayaçlar KESME ÖNCESİ tüm pencere üzerinden (satır listesi kırpılsa da "kaç açıldı" doğru kalır).
func ReadProblemWindowEvents ¶ added in v0.9.1147
func ReadProblemWindowEvents(ctx context.Context, d Deps, service string, from, to time.Time, limit int) (ProblemWindowData, error)
ReadProblemWindowEvents — ORTAK OKUMA. Zincir: pencere okuması → OKUMA zenginleştirmesi (deploy ÖNCE, öncelik SONRA — tek çağrılabilir kural, chstore.EnrichProblemsForRead) → yapısal veri.
Zenginleştirme atlanamaz: Priority bir CH kolonu değil okuma anı hesabıdır ve boş kalırsa tüketici tier'ı uydurur (v0.9.553/554).
type ProblemWindowRow ¶ added in v0.9.1147
type ProblemWindowRow struct {
ID string `json:"id"`
RuleID string `json:"rule_id,omitempty"`
RuleName string `json:"rule_name"`
Service string `json:"service,omitempty"`
Severity string `json:"severity"`
Status string `json:"status"`
// Priority — OKUMA ANI hesabı (deploy sonra öncelik zinciri;
// chstore.EnrichProblemsForRead). Boş kalırsa tüketici tier UYDURUR
// (v0.9.554'ün dersi).
Priority string `json:"priority,omitempty"`
StartedAtNs int64 `json:"started_at_unix_ns"`
ResolvedAtNs int64 `json:"resolved_at_unix_ns,omitempty"`
// OpenedInWindow / ResolvedInWindow — satırın pencereye NİYE girdiği.
// İkisi de false olabilir mi? Evet: pencereden ÖNCE açılmış ve hâlâ
// açık bir problem, resolved_at penceredeyse listeye girer; sınıflama
// bunu "hâlâ açık" sayar.
OpenedInWindow bool `json:"opened_in_window"`
ResolvedInWindow bool `json:"resolved_in_window"`
}
ProblemWindowRow — pencerede AÇILAN ya da ÇÖZÜLEN bir problem. chstore.Problem AYNEN geçmiyor: o şekil 25+ alan taşıyor ve bu odaklı okuma çoğunu (Value/Threshold/Reason/CoFiring…) HİÇ doldurmuyor — modelde "ölçüm 0" diye okunurdu.