Skip to main content
Glama

Convex MCP server

Official
by get-convex
mod.rs3.75 kB
use std::{ collections::BTreeMap, sync::LazyLock, }; use anyhow::Context; use common::{ document::{ ParseDocument, ParsedDocument, }, query::{ IndexRange, Order, Query, }, runtime::Runtime, types::{ IndexName, NodeDependency, }, }; use database::{ ResolvedQuery, SystemMetadataModel, Transaction, }; use value::{ id_v6::DeveloperDocumentId, TableName, TableNamespace, }; use self::types::{ ExternalDepsPackage, ExternalDepsPackageId, }; use crate::{ SystemIndex, SystemTable, }; pub mod types; const NUM_EXTERNAL_DEPS_CACHE_ENTRIES: usize = 10; pub static EXTERNAL_PACKAGES_TABLE: LazyLock<TableName> = LazyLock::new(|| { "_external_deps_packages" .parse() .expect("invalid built-in _external_packages table") }); pub struct ExternalPackagesTable; impl SystemTable for ExternalPackagesTable { type Metadata = ExternalDepsPackage; fn table_name() -> &'static TableName { &EXTERNAL_PACKAGES_TABLE } fn indexes() -> Vec<SystemIndex<Self>> { vec![] } } pub struct ExternalPackagesModel<'a, RT: Runtime> { tx: &'a mut Transaction<RT>, } impl<'a, RT: Runtime> ExternalPackagesModel<'a, RT> { pub fn new(tx: &'a mut Transaction<RT>) -> Self { Self { tx } } #[fastrace::trace] pub async fn get( &mut self, external_deps_package_id: ExternalDepsPackageId, ) -> anyhow::Result<ParsedDocument<ExternalDepsPackage>> { let id: DeveloperDocumentId = external_deps_package_id.into(); let document_id = self.tx.resolve_developer_id(&id, TableNamespace::Global)?; self.tx .get(document_id) .await? .context("Couldn't find external package")? .parse() } pub async fn put( &mut self, external_deps_package: ExternalDepsPackage, ) -> anyhow::Result<ExternalDepsPackageId> { let id = SystemMetadataModel::new_global(self.tx) .insert(&EXTERNAL_PACKAGES_TABLE, external_deps_package.try_into()?) .await?; let doc_id: DeveloperDocumentId = id.into(); Ok(doc_id.into()) } #[fastrace::trace] pub async fn get_cached_package_match( &mut self, deps: Vec<NodeDependency>, ) -> anyhow::Result<Option<(ExternalDepsPackageId, ExternalDepsPackage)>> { let index_query = Query::index_range(IndexRange { index_name: IndexName::by_creation_time(EXTERNAL_PACKAGES_TABLE.clone()), range: vec![], order: Order::Desc, }); let mut query_stream = ResolvedQuery::new(self.tx, TableNamespace::Global, index_query)?; let deps_map: BTreeMap<String, String> = deps .into_iter() .map(|dep| (dep.package, dep.version)) .collect(); // Check at most NUM_EXTERNAL_DEPS_CACHE_ENTRIES entries for a match let mut cache_entries_checked = 0; while let Some(doc) = query_stream.next(self.tx, None).await? && cache_entries_checked < NUM_EXTERNAL_DEPS_CACHE_ENTRIES { let row: ParsedDocument<ExternalDepsPackage> = doc.parse()?; let (id, pkg) = row.into_id_and_value(); let pkg_deps_map: BTreeMap<String, String> = pkg .deps .clone() .into_iter() .map(|dep| (dep.package, dep.version)) .collect(); if pkg_deps_map.eq(&deps_map) { return Ok(Some((DeveloperDocumentId::from(id).into(), pkg))); } cache_entries_checked += 1; } Ok(None) } }

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