Skip to main content
Glama

Convex MCP server

Official
by get-convex
context.rs5.83 kB
use std::collections::BTreeMap; use anyhow::{ anyhow, Context as _, }; use common::types::UdfType; use deno_core::v8::{ self, }; use sync_types::CanonicalizedUdfPath; use value::ConvexArray; use super::{ callback_context::CallbackContext, client::{ Completions, EvaluateResult, }, context_state::ContextState, entered_context::EnteredContext, environment::Environment, session::Session, FunctionId, }; use crate::strings; // Each isolate session can have multiple contexts, which we'll eventually use // for subtransactions. Each context executes with a particular environment, // and note that we could have different environments for different contexts. pub struct Context { context: v8::Global<v8::Context>, next_function_id: FunctionId, pending_functions: BTreeMap<FunctionId, PendingFunction>, } impl Context { pub fn new(session: &mut Session, environment: Box<dyn Environment>) -> anyhow::Result<Self> { let context = { let context = v8::Context::new(&mut session.handle_scope, v8::ContextOptions::default()); let mut handle_scope = v8::HandleScope::new(&mut session.handle_scope); let mut scope = v8::ContextScope::new(&mut handle_scope, context); let state = ContextState::new(environment); // TODO: this uses isolate-global slots, ideally it should use context-keyed // slots scope.set_slot(state); let global = context.global(&mut scope); let convex_key = strings::Convex.create(&mut scope)?; let convex_value: v8::Local<v8::Object> = global .get(&mut scope, convex_key.into()) .context("Missing global.Convex")? .try_into() .context("Wrong type of global.Convex")?; let syscall_template = v8::FunctionTemplate::new(&mut scope, CallbackContext::syscall); let syscall_value = syscall_template .get_function(&mut scope) .ok_or_else(|| anyhow!("Failed to retrieve function from FunctionTemplate"))?; let syscall_key = strings::syscall.create(&mut scope)?; convex_value.set(&mut scope, syscall_key.into(), syscall_value.into()); let async_syscall_template = v8::FunctionTemplate::new(&mut scope, CallbackContext::async_syscall); let async_syscall_value = async_syscall_template .get_function(&mut scope) .ok_or_else(|| anyhow!("Failed to retrieve function from FunctionTemplate"))?; let async_syscall_key = strings::asyncSyscall.create(&mut scope)?; convex_value.set( &mut scope, async_syscall_key.into(), async_syscall_value.into(), ); let op_template = v8::FunctionTemplate::new(&mut scope, CallbackContext::op); let op_value = op_template .get_function(&mut scope) .ok_or_else(|| anyhow!("Failed to retrieve function from FunctionTemplate"))?; let op_key = strings::op.create(&mut scope)?; convex_value.set(&mut scope, op_key.into(), op_value.into()); let async_op_template = v8::FunctionTemplate::new(&mut scope, CallbackContext::start_async_op); let async_op_value = async_op_template .get_function(&mut scope) .ok_or_else(|| anyhow!("Failed to retrieve function from FunctionTemplate"))?; let async_op_key = strings::asyncOp.create(&mut scope)?; convex_value.set(&mut scope, async_op_key.into(), async_op_value.into()); v8::Global::new(&mut scope, context) }; Ok(Self { context, next_function_id: 0, pending_functions: BTreeMap::new(), }) } pub fn enter<R>(&mut self, session: &mut Session, f: impl FnOnce(EnteredContext) -> R) -> R { let mut handle_scope = v8::HandleScope::new(&mut session.handle_scope); let context = v8::Local::new(&mut handle_scope, self.context.clone()); let mut scope = v8::ContextScope::new(&mut handle_scope, context); let entered = EnteredContext::new(&mut scope, &session.heap_context, context); f(entered) } pub fn start_function( &mut self, session: &mut Session, udf_type: UdfType, udf_path: CanonicalizedUdfPath, arguments: ConvexArray, ) -> anyhow::Result<(FunctionId, EvaluateResult)> { let function_id = self.next_function_id; self.next_function_id += 1; let (promise, result) = self.enter(session, |mut ctx| { ctx.start_evaluate_function(udf_type, &udf_path, arguments) })?; if let EvaluateResult::Pending { .. } = result { self.pending_functions .insert(function_id, PendingFunction { udf_path, promise }); }; Ok((function_id, result)) } pub fn poll_function( &mut self, session: &mut Session, function_id: FunctionId, completions: Completions, ) -> anyhow::Result<EvaluateResult> { let Some(pending_function) = self.pending_functions.remove(&function_id) else { anyhow::bail!("Function {function_id} not found"); }; let result = self.enter(session, |mut ctx| { ctx.poll_function(&pending_function, completions) })?; if let EvaluateResult::Pending { .. } = result { self.pending_functions.insert(function_id, pending_function); } Ok(result) } } pub struct PendingFunction { pub udf_path: CanonicalizedUdfPath, pub promise: v8::Global<v8::Promise>, }

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