Skip to main content
Glama

Convex MCP server

Official
by get-convex
beacon.rs4.65 kB
//! Beacon coroutine for collecting anonymous usage metrics to help improve //! the self-hosted product. //! //! This module implements a beacon that periodically logs basic system //! information like database version. The beacon is disabled by default //! but can be enabled by setting CONVEX_ENABLE_BEACON=1. //! //! No personally identifiable information is collected. The data helps Convex //! understand how self-hosted instances are being used to improve the product. //! This is similar to Sentry's self-hosted telemetry approach, focusing on //! anonymous and privacy-preserving metrics. use std::time::{ Duration, SystemTime, }; use common::{ backoff::Backoff, errors::report_error, runtime::Runtime, }; use database::Database; use model::database_globals::DatabaseGlobalsModel; use reqwest::Client; use runtime::prod::ProdRuntime; use serde::Deserialize; use serde_json::Value as JsonValue; const COMPILED_REVISION: &str = env!("VERGEN_GIT_SHA"); const COMMIT_TIMESTAMP: &str = env!("VERGEN_GIT_COMMIT_TIMESTAMP"); const INITIAL_BACKOFF: Duration = Duration::from_secs(1); const MAX_BACKOFF: Duration = Duration::from_secs(900); // 15 minutes // Allow sending in overrides for the UUID when there's a better concept of // "unique user" than the database UUID, and also allow sending arbitrary // extra fields. #[derive(Deserialize)] struct BeaconFields { override_uuid: Option<String>, fields: Option<JsonValue>, } pub async fn start_beacon( runtime: ProdRuntime, database: Database<ProdRuntime>, beacon_tag: String, beacon_fields: Option<JsonValue>, ) { tracing::info!("Starting beacon coroutine..."); let start_time = SystemTime::now(); let mut backoff = Backoff::new(INITIAL_BACKOFF, MAX_BACKOFF); loop { let result = async { let mut tx = database.begin_system().await?; let mut db_model = DatabaseGlobalsModel::new(&mut tx); let globals = db_model.database_globals().await?; let client = Client::new(); let migration_version = globals.version; let compiled_revision = COMPILED_REVISION.to_string(); let commit_timestamp = COMMIT_TIMESTAMP.to_string(); let uptime = SystemTime::now() .duration_since(start_time) .unwrap_or_default() .as_secs(); let mut uuid = globals.id().to_string(); let mut extra_fields = JsonValue::Null; if let Some(fields) = beacon_fields.clone() { if let Ok(parsed_fields) = serde_json::from_value::<BeaconFields>(fields) { if let Some(override_uuid) = parsed_fields.override_uuid { uuid = override_uuid; } if let Some(f) = parsed_fields.fields { extra_fields = f; } } } let sent_json = serde_json::json!({ "database_uuid": uuid, "migration_version": migration_version, "compiled_revision": compiled_revision, "commit_timestamp": commit_timestamp, "uptime": uptime, "beacon_tag": beacon_tag, "beacon_fields": extra_fields, }); let url = "https://api.convex.dev/api/self_host_beacon"; let response = client.post(url).json(&sent_json).send().await?; if response.status().is_success() { tracing::info!( "Beacon request with json {sent_json} sent successfully to {url}. This \ anonymized data is used to help Convex understand and improve the product. \ You can disable this telemetry by setting the --disable-beacon flag or the \ DISABLE_BEACON environment variable." ); } else { tracing::warn!("Beacon request failed with status: {}", response.status()); } Ok::<(), anyhow::Error>(()) } .await; match result { Ok(()) => { backoff.reset(); // Sleep for one hour before next heartbeat runtime.wait(Duration::from_secs(3600)).await; }, Err(e) => { report_error(&mut e.context("Beacon coroutine error")).await; let delay = backoff.fail(&mut runtime.rng()); tracing::error!("Beacon failed, retrying in {delay:?}"); runtime.wait(delay).await; }, } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server