Skip to main content
Glama

Convex MCP server

Official
by get-convex
schema.rs11.7 kB
use common::{ object_validator, runtime::Runtime, schemas::{ validator::{ FieldValidator, LiteralValidator, Validator, }, DatabaseSchema, DocumentSchema, IndexSchema, TableDefinition, TextIndexSchema, }, types::{ IndexDescriptor, TableName, }, }; use keybroker::DEV_INSTANCE_NAME; use maplit::{ btreemap, btreeset, }; use rand::Rng; use runtime::testing::TestRuntime; use crate::test_helpers::UdfTest; #[convex_macro::test_runtime] async fn test_eval_schema(rt: TestRuntime) -> anyhow::Result<()> { // Document type is copied and pasted from // `npm-packages/convex/src/schema/index.test.ts` let source = r#" class SchemaDefinition { tables; constructor() { this.tables = { schemaValidation: true, tables: [ { tableName: "noIndexes", indexes: [], "documentType": { "type": "object", "value": { "ref": { "fieldType": { "type": "id", "tableName": "twoIndexTable" }, "optional": false }, "nullField": { "fieldType": { "type": "null" }, "optional": false }, "numberField": { "fieldType": { "type": "number" }, "optional": false }, "bigintField": { "fieldType": { "type": "bigint" }, "optional": false }, "booleanField": { "fieldType": { "type": "boolean" }, "optional": false }, "stringField": { "fieldType": { "type": "string" }, "optional": false }, "bytesField": { "fieldType": { "type": "bytes" }, "optional": false }, "arrayField": { "fieldType": { "type": "array", "value": { "type": "boolean" } }, "optional": false }, "setField": { "fieldType": { "type": "set", "value": { "type": "number" } }, "optional": false }, "mapField": { "fieldType": { "type": "map", "keys": { "type": "string" }, "values": { "type": "number" } }, "optional": false }, "anyField": { "fieldType": { "type": "any" }, "optional": false }, "literalBigint": { "fieldType": { "type": "literal", "value": { "$integer": "AQAAAAAAAAA=" } }, "optional": false }, "literalNumber": { "fieldType": { "type": "literal", "value": 0 }, "optional": false }, "literalString": { "fieldType": { "type": "literal", "value": "hello world" }, "optional": false }, "literalBoolean": { "fieldType": { "type": "literal", "value": true }, "optional": false }, "union": { "fieldType": { "type": "union", "value": [ { "type": "string" }, { "type": "number" } ] }, "optional": false }, "object": { "fieldType": { "type": "object", "value": { "a": { "fieldType": { "type": "any" }, "optional": true } } }, "optional": false } } } }, { tableName: "twoIndexTable", indexes: [ { indexDescriptor: "by_email", fields: ["email"], }, { indexDescriptor: "by_creation_deleted", fields: ["creation", "deleted"], }, ], }, { tableName: "searchIndexTable", indexes: [], searchIndexes: [ { indexDescriptor: "search_index", searchField: "title", filterFields: ["is_deleted", "workspace_id"], }, ], }, ], }; } export() { return JSON.stringify(this.tables); } } export default new SchemaDefinition(); "#; let rng_seed = rt.rng().random(); let unix_timestamp = rt.unix_timestamp(); let t = UdfTest::default_with_modules(vec![], rt).await??; let schema = t .isolate .evaluate_schema( source.into(), None, rng_seed, unix_timestamp, DEV_INSTANCE_NAME.to_string(), ) .await?; let name1: TableName = "noIndexes".parse()?; let name2: TableName = "twoIndexTable".parse()?; let name3: TableName = "searchIndexTable".parse()?; let by_email = IndexDescriptor::new("by_email")?; let by_creation_deleted = IndexDescriptor::new("by_creation_deleted")?; let search_index = IndexDescriptor::new("search_index")?; let expected = DatabaseSchema { tables: btreemap!( name1.clone() => TableDefinition { table_name: name1, indexes: btreemap!(), staged_db_indexes: btreemap!(), text_indexes: btreemap!(), staged_text_indexes: btreemap!(), vector_indexes: btreemap!(), staged_vector_indexes: btreemap!(), document_type: Some(DocumentSchema::Union(vec![ object_validator!( "ref" => FieldValidator::required_field_type(Validator::Id("twoIndexTable".parse()?)), "nullField" => FieldValidator::required_field_type(Validator::Null), "numberField" => FieldValidator::required_field_type(Validator::Float64), "bigintField" => FieldValidator::required_field_type(Validator::Int64), "booleanField" => FieldValidator::required_field_type(Validator::Boolean), "stringField" => FieldValidator::required_field_type(Validator::String), "bytesField" => FieldValidator::required_field_type(Validator::Bytes), "arrayField" => FieldValidator::required_field_type(Validator::Array(Box::new(Validator::Boolean))), "setField" => FieldValidator::required_field_type(Validator::Set(Box::new(Validator::Float64))), "mapField" => FieldValidator::required_field_type(Validator::Map(Box::new(Validator::String), Box::new(Validator::Float64))), "anyField" => FieldValidator::required_field_type(Validator::Any), "literalBigint" => FieldValidator::required_field_type(Validator::Literal(LiteralValidator::Int64(1))), "literalNumber" => FieldValidator::required_field_type(Validator::Literal(LiteralValidator::Float64((0.).into()))), "literalString" => FieldValidator::required_field_type(Validator::Literal(LiteralValidator::String("hello world".to_string().try_into()?))), "literalBoolean" => FieldValidator::required_field_type(Validator::Literal(LiteralValidator::Boolean(true))), "union" => FieldValidator::required_field_type(Validator::Union(vec![Validator::String, Validator::Float64])), "object" => FieldValidator::required_field_type(Validator::Object(object_validator!("a" => FieldValidator::optional_field_type(Validator::Any)))) ) ])) }, name2.clone() => TableDefinition { table_name: name2, indexes: btreemap!( by_email.clone() => IndexSchema { index_descriptor: by_email, fields: vec!["email".parse()?].try_into()?, }, by_creation_deleted.clone() => IndexSchema { index_descriptor: by_creation_deleted, fields: vec!["creation".parse()?, "deleted".parse()?].try_into()?, }, ), staged_db_indexes: btreemap!(), text_indexes: btreemap!(), staged_text_indexes: btreemap!(), vector_indexes: btreemap!(), staged_vector_indexes: btreemap!(), document_type: None, }, name3.clone() => TableDefinition { table_name: name3, indexes: btreemap!(), staged_db_indexes: btreemap!(), text_indexes: btreemap! { search_index.clone() => TextIndexSchema::new( search_index, "title".parse()?, btreeset!{"is_deleted".parse()?, "workspace_id".parse()?} )? }, staged_text_indexes: btreemap!(), vector_indexes: btreemap!(), staged_vector_indexes: btreemap!(), document_type: None, } ), schema_validation: true, }; assert_eq!(schema, expected); Ok(()) }

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