mcptools

package
v0.9.1233 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 13 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func Register

func Register(srv *mcp.Server, d Deps)

func ToolList added in v0.6.53

func ToolList(d Deps) []mcp.Tool

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

func ReadDBHealth(ctx context.Context, d Deps, from, to time.Time, limit int) (DBHealthData, error)

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
	// HeapUnavailable — heap okuması başarısız oldu ama servis modunda bu
	// Ö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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL