Skip to content
Next Next commit
feat: add VoyageAI embeddings/rerank integration and MongoDB Atlas co…
…nnection string support

- Add VoyageAI tools: embeddings (voyage-3, voyage-3-large, etc.) and rerank (rerank-2, rerank-2-lite)
- Add VoyageAI block with operation dropdown (Generate Embeddings / Rerank)
- Add VoyageAI icon and register in tool/block registries
- Enhance MongoDB with connection string mode for Atlas (mongodb+srv://) support
- Add connection mode toggle to MongoDB block (Host & Port / Connection String)
- Update all 6 MongoDB API routes to accept optional connectionString
- Add 48 unit tests (VoyageAI tools, block config, MongoDB utils)
  • Loading branch information
fzowl committed Mar 23, 2026
commit 22662b3aa2a07401c611a80d9d24196b45ba26d3
10 changes: 6 additions & 4 deletions apps/sim/app/api/tools/mongodb/delete/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from
const logger = createLogger('MongoDBDeleteAPI')

const DeleteSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
username: z.string().default(''),
password: z.string().default(''),
authSource: z.string().optional(),
ssl: z.enum(['disabled', 'required', 'preferred']).default('preferred'),
collection: z.string().min(1, 'Collection name is required'),
Expand Down Expand Up @@ -75,6 +76,7 @@ export async function POST(request: NextRequest) {
}

client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database,
Expand Down
10 changes: 6 additions & 4 deletions apps/sim/app/api/tools/mongodb/execute/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { createMongoDBConnection, sanitizeCollectionName, validatePipeline } fro
const logger = createLogger('MongoDBExecuteAPI')

const ExecuteSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
username: z.string().default(''),
password: z.string().default(''),
authSource: z.string().optional(),
ssl: z.enum(['disabled', 'required', 'preferred']).default('preferred'),
collection: z.string().min(1, 'Collection name is required'),
Expand Down Expand Up @@ -61,6 +62,7 @@ export async function POST(request: NextRequest) {
const pipelineDoc = JSON.parse(params.pipeline)

client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database,
Expand Down
10 changes: 6 additions & 4 deletions apps/sim/app/api/tools/mongodb/insert/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { createMongoDBConnection, sanitizeCollectionName } from '../utils'
const logger = createLogger('MongoDBInsertAPI')

const InsertSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
username: z.string().default(''),
password: z.string().default(''),
authSource: z.string().optional(),
ssl: z.enum(['disabled', 'required', 'preferred']).default('preferred'),
collection: z.string().min(1, 'Collection name is required'),
Expand Down Expand Up @@ -54,6 +55,7 @@ export async function POST(request: NextRequest) {

const sanitizedCollection = sanitizeCollectionName(params.collection)
client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database,
Expand Down
6 changes: 4 additions & 2 deletions apps/sim/app/api/tools/mongodb/introspect/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { createMongoDBConnection, executeIntrospect } from '../utils'
const logger = createLogger('MongoDBIntrospectAPI')

const IntrospectSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
Expand All @@ -36,6 +37,7 @@ export async function POST(request: NextRequest) {
)

client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database || 'admin',
Expand Down
10 changes: 6 additions & 4 deletions apps/sim/app/api/tools/mongodb/query/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from
const logger = createLogger('MongoDBQueryAPI')

const QuerySchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
username: z.string().default(''),
password: z.string().default(''),
authSource: z.string().optional(),
ssl: z.enum(['disabled', 'required', 'preferred']).default('preferred'),
collection: z.string().min(1, 'Collection name is required'),
Expand Down Expand Up @@ -90,6 +91,7 @@ export async function POST(request: NextRequest) {
}

client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database,
Expand Down
10 changes: 6 additions & 4 deletions apps/sim/app/api/tools/mongodb/update/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { createMongoDBConnection, sanitizeCollectionName, validateFilter } from
const logger = createLogger('MongoDBUpdateAPI')

const UpdateSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
connectionString: z.string().optional(),
host: z.string().default(''),
port: z.coerce.number().int().nonnegative().default(27017),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
username: z.string().default(''),
password: z.string().default(''),
authSource: z.string().optional(),
ssl: z.enum(['disabled', 'required', 'preferred']).default('preferred'),
collection: z.string().min(1, 'Collection name is required'),
Expand Down Expand Up @@ -99,6 +100,7 @@ export async function POST(request: NextRequest) {
}

client = await createMongoDBConnection({
connectionString: params.connectionString,
host: params.host,
port: params.port,
database: params.database,
Expand Down
10 changes: 10 additions & 0 deletions apps/sim/app/api/tools/mongodb/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ import { validateDatabaseHost } from '@/lib/core/security/input-validation.serve
import type { MongoDBCollectionInfo, MongoDBConnectionConfig } from '@/tools/mongodb/types'

export async function createMongoDBConnection(config: MongoDBConnectionConfig) {
if (config.connectionString) {
const client = new MongoClient(config.connectionString, {
connectTimeoutMS: 10000,
socketTimeoutMS: 10000,
maxPoolSize: 1,
})
await client.connect()
return client
}

const hostValidation = await validateDatabaseHost(config.host, 'host')
if (!hostValidation.isValid) {
throw new Error(hostValidation.error)
Expand Down
41 changes: 35 additions & 6 deletions apps/sim/blocks/blocks/mongodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,41 @@ export const MongoDBBlock: BlockConfig<MongoDBResponse | MongoDBIntrospectRespon
],
value: () => 'query',
},
{
id: 'connectionMode',
title: 'Connection Mode',
type: 'dropdown',
options: [
{ label: 'Host & Port', id: 'host_port' },
{ label: 'Connection String (Atlas)', id: 'connection_string' },
],
value: () => 'host_port',
},
{
id: 'connectionString',
title: 'Connection String',
type: 'short-input',
placeholder: 'mongodb+srv://user:password@cluster.mongodb.net/mydb',
password: true,
condition: { field: 'connectionMode', value: 'connection_string' },
required: { field: 'connectionMode', value: 'connection_string' },
},
{
id: 'host',
title: 'Host',
type: 'short-input',
placeholder: 'localhost or your.mongodb.host',
required: true,
condition: { field: 'connectionMode', value: 'connection_string', not: true },
required: { field: 'connectionMode', value: 'connection_string', not: true },
},
{
id: 'port',
title: 'Port',
type: 'short-input',
placeholder: '27017',
value: () => '27017',
required: true,
condition: { field: 'connectionMode', value: 'connection_string', not: true },
required: { field: 'connectionMode', value: 'connection_string', not: true },
},
{
id: 'database',
Expand All @@ -57,15 +78,17 @@ export const MongoDBBlock: BlockConfig<MongoDBResponse | MongoDBIntrospectRespon
title: 'Username',
type: 'short-input',
placeholder: 'mongodb_user',
required: true,
condition: { field: 'connectionMode', value: 'connection_string', not: true },
required: { field: 'connectionMode', value: 'connection_string', not: true },
},
{
id: 'password',
title: 'Password',
type: 'short-input',
password: true,
placeholder: 'Your database password',
required: true,
condition: { field: 'connectionMode', value: 'connection_string', not: true },
required: { field: 'connectionMode', value: 'connection_string', not: true },
},
{
id: 'authSource',
Expand Down Expand Up @@ -837,7 +860,7 @@ Return ONLY the MongoDB query filter as valid JSON - no explanations, no markdow
}
},
params: (params) => {
const { operation, documents, ...rest } = params
const { operation, documents, connectionMode, ...rest } = params

let parsedDocuments
if (documents && typeof documents === 'string' && documents.trim()) {
Expand All @@ -853,7 +876,7 @@ Return ONLY the MongoDB query filter as valid JSON - no explanations, no markdow
parsedDocuments = documents
}

const connectionConfig = {
const connectionConfig: Record<string, unknown> = {
host: rest.host,
port: typeof rest.port === 'string' ? Number.parseInt(rest.port, 10) : rest.port || 27017,
database: rest.database,
Expand All @@ -863,6 +886,10 @@ Return ONLY the MongoDB query filter as valid JSON - no explanations, no markdow
ssl: rest.ssl || 'preferred',
}

if (rest.connectionString) {
connectionConfig.connectionString = rest.connectionString
}

const result: any = { ...connectionConfig }

if (rest.collection) result.collection = rest.collection
Expand Down Expand Up @@ -900,6 +927,8 @@ Return ONLY the MongoDB query filter as valid JSON - no explanations, no markdow
},
inputs: {
operation: { type: 'string', description: 'Database operation to perform' },
connectionMode: { type: 'string', description: 'Connection mode (host_port or connection_string)' },
connectionString: { type: 'string', description: 'Full MongoDB connection string' },
host: { type: 'string', description: 'MongoDB host' },
port: { type: 'string', description: 'MongoDB port' },
database: { type: 'string', description: 'Database name' },
Expand Down
Loading