Learn how to build a MongoDB MCP client using Embabel framework. Connect to MongoDB MCP server and execute database operations with AI agents using natural language commands.
1. Introduction
Welcome to the ninth installment of our Embabel Framework series! We’ve come a long way in our journey of building intelligent AI agents on the JVM. If you’ve been following along, you’ve seen how we can create powerful, goal-driven agents that interact with various systems using natural language.
Here’s a quick recap of our adventure so far:
- Embabel Framework: Create Goal-Driven AI Agents for the JVM: We covered the basics and built a shell-based meeting summarizer.:
- Embabel Framework: Build a REST API Based AI Agent: We learned how to expose agents over web endpoints.
- Embabel Framework Condition Annotation: Building Decision Making AI Agents: We added logic to our agents.
- Embabel Framework: How to Build MCP Server: We built a server that performs file operations.
- Build Confluence MCP Server Using Embabel Framework: We connected AI to the Confluence Cloud.
- Build MongoDB MCP Server Using Embabel Framework: We gave our agents database access.
- MCP Client: Build File Operations Agent with Embabel – We built our first MCP client for file operations
- Build Confluence MCP Client with Embabel Framework: We created our second MCP client for Confluence operations.
Today, we’re building our third MCP client—one that connects to the MongoDB MCP server we built earlier. This client will empower users to perform complex database operations using simple, conversational language like “Show me all databases” or “Find users older than 30 in the testdb database.”
2. What We’re Building – MongoDB MCP Client
We’ll create a Spring Boot application that acts as an intelligent MongoDB MCP client, connecting seamlessly to our previously built MongoDB MCP server. This client will enable users to:
- List all databases in your MongoDB instance
- List collections within a specific database
- Execute simple queries (field = value searches)
- Run complex queries with MongoDB operators like
$gt,$lt,$and,$or - List indexes for collections
- Create new collections
- Insert documents into collections
The game-changer? Users interact with all these database operations using natural language! No need to write MongoDB query syntax or remember collection names—just tell the agent what you want in plain English.
3. Prerequisites
Before we begin, make sure you have:
- Java 21 or higher installed
- Maven for dependency management
- Spring Boot knowledge (basic understanding is sufficient)
- A running instance of the MongoDB MCP Server (from our sixth article)
- An OpenRouter API key (for accessing free AI models)
4. Project Structure
Let’s understand how our MongoDB MCP client is organized before diving into the code
embabel-mongo-mcp-client
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── bootcamptoprod
│ │ ├── agents
│ │ │ └── SmartMongoAgent.java # AI Agent for MongoDB operations
│ │ ├── config
│ │ │ ├── ConfigureOpenRouterModels.java # Connects Embabel to LLMs via OpenRouter
│ │ │ └── MongoToolsConfig.java # MCP Server connection and tool setup
│ │ ├── controller
│ │ │ └── MongoOperationsController.java # REST API endpoint
│ │ ├── dto # Data Transfer Objects (Request/Response)
│ │ │ ├── MongoRequest.java # Natural language command input
│ │ │ └── MongoOperationResponse.java # Response containing MongoDB metadata and status
│ │ └── EmbabelMongoMcpClientApplication.java # The main Spring Boot application class
│ └── resources
│ └── application.yml # MCP server URL and LLM configurations
└── pom.xml # Project dependencies and Embabel BOM
Project StructureStructure Breakdown:
Here’s what each component does:
- SmartMongoAgent.java: The “Brain” of our application. It analyzes natural language commands (e.g., “Find all users where age is 25”) and uses the LLM to determine which MongoDB operation to execute.
- ConfigureOpenRouterModels.java: Configures the connection to our LLM (Large Language Model). We use OpenRouter to access free models like DeepSeek that provide the “reasoning” capabilities for our agent.
- MongoToolsConfig.java: The “Bridge” between our client and the MongoDB MCP server. It discovers available MongoDB tools and makes them accessible to the AI agent.
- MongoOperationsController.java: A standard Spring REST controller that receives HTTP requests and delegates them to our Embabel agent for processing.
- dto package: Contains simple Java Records that define the data contracts for requests and responses flowing through our application.
- application.yml: The configuration hub where we define the MCP server’s URL and the default LLM to use.
- pom.xml: Manages project dependencies, including the Embabel framework and OpenAI compatibility libraries.
5. Diving Into the Code
Let’s break down each component step by step.
Step 1: Setting Up Maven Dependencies
First, let’s set up our Maven project with all necessary dependencies. The pom.xml file defines our project configuration and required libraries:
<properties>
<java.version>21</java.version>
<embabel-agent.version>0.3.2-SNAPSHOT</embabel-agent.version>
</properties>
<dependencies>
<!-- Spring Boot Web for REST endpoints -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Actuator for health checks -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Embabel Agent Starter - Core framework -->
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-starter</artifactId>
</dependency>
<!-- OpenAI Compatible Model Support -->
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-starter-openai</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-dependencies</artifactId>
<version>${embabel-agent.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>embabel-releases</id>
<url>https://repo.embabel.com/artifactory/libs-release</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>embabel-snapshots</id>
<url>https://repo.embabel.com/artifactory/libs-snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
pom.xmlWhat’s Important Here:
- embabel-agent-starter: This is the core engine that provides the framework for building goal-driven AI agents. It handles task planning and action execution based on available tools.
- embabel-agent-starter-openai: Since this is an MCP Client, we need an LLM (the “brain”) for reasoning. This dependency enables communication with OpenAI-compatible providers like OpenRouter.
- spring-boot-starter-web: Essential for exposing our AI agent through REST endpoints, allowing external tools (like Postman or frontend applications) to trigger MongoDB operations.
- Custom repositories: Required to fetch Embabel framework artifacts from Embabel’s hosted repository.
- Actuator: Provides production-ready features like health checks and metrics monitoring.
Step 2: Configure Application Properties
Next, let’s configure our application settings in application.yml:
spring:
application:
name: embabel-mongo-mcp-client
ai:
mcp:
client:
enabled: true
name: embabel-mongo-mcp-client
version: 1.0.0
type: SYNC
sse:
connections:
# Connection to the MongoDB MCP Server
embabel-mongo-mcp-server:
url: http://localhost:8080/sse # The URL of your MCP server
server:
port: 8081
embabel:
models:
defaultLlm: nex-agi/deepseek-v3.1-nex-n1:free
application.yaml📄 Configuration Overview
- spring.ai.mcp.client.enabled: Enables MCP client functionality in our application
- spring.ai.mcp.client.type: Set to
SYNCfor synchronous communication with the MCP server - sse.connections: Defines our MongoDB MCP server connection
- embabel-mongo-mcp-server: A unique identifier for our MongoDB server
- url: The SSE (Server-Sent Events) endpoint where our MCP server is running (port 8080)
- server.port: Our client runs on port 8081 to avoid conflicts with the MCP server
- embabel.models.defaultLlm: The AI model we’ll use (DeepSeek v3.1 via OpenRouter, which is free)
Step 3: Application Entry Point
This is the main class that bootstraps our entire application.
package com.bootcamptoprod;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class EmbabelMongoMcpClientApplication {
public static void main(String[] args) {
SpringApplication.run(EmbabelMongoMcpClientApplication.class, args);
}
}EmbabelMongoMcpClientApplication.javaExplanation:
- This is our Spring Boot application entry point. The
@SpringBootApplicationannotation tells Spring to bootstrap both Spring Boot and the Embabel framework simultaneously, setting up all necessary components for our MongoDB MCP client.
Step 4: Configuring LLM Models
This configuration class sets up multiple LLM models via OpenRouter, a unified API gateway for various AI models. Here’s what’s happening:
package com.bootcamptoprod.config;
import com.embabel.agent.openai.OpenAiCompatibleModelFactory;
import com.embabel.common.ai.model.Llm;
import com.embabel.common.ai.model.PerTokenPricingModel;
import io.micrometer.observation.ObservationRegistry;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDate;
@Configuration
public class ConfigureOpenRouterModels extends OpenAiCompatibleModelFactory {
public ConfigureOpenRouterModels(@NotNull ObservationRegistry observationRegistry,
@Value("${OPENAI_API_KEY}") String apiKey) {
super(
"https://openrouter.ai",
apiKey,
"/api/v1/chat/completions",
null,
observationRegistry
);
}
@Bean
public Llm mistral7b_free() {
return openAiCompatibleLlm(
"mistralai/mistral-7b-instruct:free",
new PerTokenPricingModel(0.0, 0.0),
"OpenRouter",
LocalDate.of(2024, 10, 1)
);
}
@Bean
public Llm deepseek_r1_t2() {
return openAiCompatibleLlm(
"tngtech/deepseek-r1t2-chimera:free",
new PerTokenPricingModel(0.0, 0.0),
"OpenRouter",
LocalDate.of(2025, 5, 28)
);
}
@Bean
public Llm deepseek_3_1() {
return openAiCompatibleLlm(
"nex-agi/deepseek-v3.1-nex-n1:free",
new PerTokenPricingModel(0.0, 0.0),
"OpenRouter",
LocalDate.of(2025, 1, 28)
);
}
@Bean
public Llm glm_4_5_air() {
return openAiCompatibleLlm(
"z-ai/glm-4.5-air:free",
new PerTokenPricingModel(0.0, 0.0),
"OpenRouter",
LocalDate.of(2025, 5, 28)
);
}
}ConfigureOpenRouterModels.javaExplanation:
- This configuration class registers OpenRouter as an AI model provider.
- By extending
OpenAiCompatibleModelFactory, we leverage OpenRouter’s OpenAI-compatible API. - The constructor configures the base URL and endpoint for OpenRouter API.
- The
@Value("${OPENAI_API_KEY}")annotation injects your API key, which you must provide as an environment variable when running the application. - The LLM beans methods create different model instances with zero pricing (useful for free tier or internal tracking) and metadata about the model.
- The
PerTokenPricingModel(0.0, 0.0)indicates these are free-tier models with no cost per token. - The
ObservationRegistryintegration enables automatic metrics collection for model usage.
Why Multiple Models? Having multiple models configured gives you flexibility to switch between them without code changes
Step 5: Configuring MCP Tool Groups
This is where the magic happens! We need to tell our application which tools from the MCP server our agents can use.
package com.bootcamptoprod.config;
import com.embabel.agent.core.ToolGroup;
import com.embabel.agent.core.ToolGroupDescription;
import com.embabel.agent.core.ToolGroupPermission;
import com.embabel.agent.tools.mcp.McpToolGroup;
import io.modelcontextprotocol.client.McpSyncClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Set;
@Configuration
public class MongoToolsConfig {
private final List<McpSyncClient> mcpSyncClients;
@Autowired
public MongoToolsConfig(@Lazy List<McpSyncClient> mcpSyncClients) {
Assert.notNull(mcpSyncClients, "McpSyncClients must not be null");
this.mcpSyncClients = mcpSyncClients;
}
@Bean
public ToolGroup mongoMcpToolGroup() {
return new McpToolGroup(
ToolGroupDescription.Companion.invoke(
"MongoDB operations including list databases, list collections, query documents, create collections, insert documents, and list indexes via MCP",
"mongo-mcp-tool-group" // MUST match toolGroups in SmartMongoAgent
),
"MongoDB Provider",
"mongo-tool-group",
Set.of(),
mcpSyncClients,
toolCallback -> {
String toolName = toolCallback.getToolDefinition().name().toLowerCase();
return toolName.contains("database") ||
toolName.contains("collection") ||
toolName.contains("document") ||
toolName.contains("query") ||
toolName.contains("index");
}
);
}
}MongoToolsConfig.javaWhat’s Important Here:
- The Bridge: This class serves as the bridge between the external MongoDB MCP server and our AI agent, discovering available tools and organizing them for the agent’s use.
- McpSyncClient Injection: These clients are automatically created based on the connection details we provided in
application.yml. - Tool Group Identifier: The ID
"mongo-mcp-tool-group"is critical—it must exactly match thetoolGroupsname used in ourSmartMongoAgent. This is the “handshake” that connects the agent to its toolbox. - Permissions: We use Set.of() to provide an empty set. Since these specific tools don’t require any special permissions, we leave it empty. We use an empty set because the framework requires a value and doesn’t allow this to be null.
- Smart Filtering: The tool filter ensures our agent only sees MongoDB-related tools by checking if tool names contain keywords like “database”, “collection”, “document”, “query”, or “index”. This keeps the agent focused and prevents confusion with unrelated tools.
Step 6: Create Data Transfer Object (DTOs)
Our DTOs define the structure of data flowing through the application.
package com.bootcamptoprod.dto;
public record MongoRequest(
String command
) {}
MongoRequest.javaPurpose: A simple record that holds the user’s natural language command (e.g., “Show me all collections in the testdb database”). This is the only input our smart agent needs to begin interpreting and executing your request.
package com.bootcamptoprod.dto;
import java.util.Map;
public record MongoOperationResponse(
Map<String, Object> mongoMetadata,
String message,
boolean success,
String operationType,
String operationDetails
) {}
MongoOperationResponse.javaPurpose: This response record contains the results of a MongoDB operation:
- mongoMetadata: A flexible map holding MongoDB-specific information (database names, collection names, document counts, query results, inserted IDs, etc.)
- message: A human-readable message explaining what happened
- success: Boolean flag indicating operation success/failure
- operationType: The type of operation performed (e.g., “LIST_DATABASES”, “SIMPLE_QUERY”, “INSERT_DOCUMENT”)
- operationDetails: Additional details about parameters used and execution specifics
Step 7: Building the MongoDB Agent
This is where the magic happens! Our agent understands natural language and executes appropriate MongoDB operations:
package com.bootcamptoprod.agents;
import com.bootcamptoprod.dto.MongoOperationResponse;
import com.bootcamptoprod.dto.MongoRequest;
import com.embabel.agent.api.annotation.AchievesGoal;
import com.embabel.agent.api.annotation.Action;
import com.embabel.agent.api.annotation.Agent;
import com.embabel.agent.api.common.OperationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Agent(
name = "smart-mongo-agent",
description = "Intelligent agent that understands natural language commands and performs MongoDB operations via MCP",
version = "1.0.0"
)
public class SmartMongoAgent {
private static final Logger log = LoggerFactory.getLogger(SmartMongoAgent.class);
@Action(
description = "Process natural language MongoDB operation requests and execute appropriate database operations",
toolGroups = {"mongo-mcp-tool-group"}
)
@AchievesGoal(description = "Understand user's natural language command and execute the appropriate MongoDB operation")
public MongoOperationResponse processMongoOperation(MongoRequest request, OperationContext context) {
log.info("[ACTION] processMongoOperation START - user command: {}", request.command());
String prompt = String.format("""
You are a MongoDB operations assistant. The user has given you a command in natural language.
Analyze the command and perform the appropriate MongoDB operation using the available tools.
User Command: "%s"
Available MongoDB Operations:
1. LIST DATABASES - List all databases in the MongoDB instance
2. LIST COLLECTIONS - List all collections in a specific database
3. SIMPLE QUERY - Execute a simple equality query (field = value) on a collection
4. COMPLEX QUERY - Execute a complex JSON query with operators like $gt, $lt, $and, $or, etc.
5. LIST INDEXES - List all indexes for a specific collection
6. CREATE COLLECTION - Create a new collection in a database
7. INSERT DOCUMENT - Insert a JSON document into a collection
Your Task:
1. Analyze the user's command to determine which MongoDB operation they want to perform
2. Extract any required parameters from the command:
- dbName: The name of the MongoDB database (e.g., "testdb", "production")
- collectionName: The name of the collection (e.g., "users", "orders")
- field: The field name for simple queries (e.g., "age", "status")
- value: The value to match in simple queries (e.g., 25, "active")
- jsonQuery: A JSON string for complex queries (e.g., {"age": {"$gt": 30}})
- jsonDocument: A JSON string for document insertion (e.g., {"name": "John", "age": 30})
3. Use the appropriate MCP tool to execute the operation
4. Draft a user-friendly response that includes:
- A clear success/failure message
- Relevant MongoDB metadata (database names, collection counts, document counts, etc.)
- The operation type that was performed
- Any additional helpful information from the response (e.g., number of results, document IDs)
- Operation details showing what parameters were used
5. If parameters are missing or unclear:
- For listing operations (databases/collections), proceed without additional parameters
- For other operations, use available tools to fetch missing information if possible
- If critical information cannot be determined, ask for clarification in your response
Important Guidelines:
- Always include relevant MongoDB metadata in your response
- Make the response conversational and easy to understand
- When returning query results, summarize the key information rather than dumping raw JSON
- Include operation details (parameters used, query executed) for transparency
- Format technical details in a user-friendly way
- For queries, mention the number of results returned and provide a brief summary
- For insert operations, confirm success and mention any generated IDs
- For create operations, confirm the collection/database was created successfully
- If an error occurs, explain what went wrong in simple terms and suggest corrective actions
Execute the MongoDB operation and provide a comprehensive response.
""", request.command());
MongoOperationResponse response = context.ai()
.withDefaultLlm()
.createObject(prompt, MongoOperationResponse.class);
log.info("[ACTION] processMongoOperation END - success: {}, operation: {}",
response.success(), response.operationType());
return response;
}
}SmartMongoAgent.javaWhat’s Important Here:
- The Brain: While our MCP server acts as the “Hands” that physically interact with MongoDB, this Agent is the “Brain” that understands what users want and decides which tools to use.
- @Agent Annotation: Tells the Embabel framework this is an intelligent agent capable of understanding human language, not just a regular Java class.
- Single Action Approach: We have one action handling all MongoDB operations—no need for separate methods for each operation type. This keeps our code clean and maintainable.
- @Action with toolGroups: By specifying
toolGroups = {"mongo-mcp-tool-group"}, we’re giving the agent access to all MongoDB operations discovered from our MCP server. - @AchievesGoal: Clearly defines the agent’s mission: transform natural language commands into successful MongoDB operations.
- The Comprehensive Prompt: This acts as the agent’s “instruction manual,” telling the AI:
- Its role (MongoDB operations assistant)
- The available operations
- How to extract parameters from natural language
- How to format responses for users
- How to handle missing information
- context.ai().withDefaultLlm(): Uses our configured LLM (like DeepSeek) as the reasoning engine.
- createObject(): This is where the magic happens! The AI:
- Analyzes the command (e.g., “Find users older than 30”)
- Determines the required tool (complex_query)
- Extracts parameters automatically (dbName, collectionName, query with $gt operator)
- Calls the MCP tool on the server
- Parses the MongoDB response
- Returns a structured
MongoOperationResponseobject
The beauty of this approach: No complex if-else logic or manual parameter mapping needed. Just give the AI a goal and a toolbox, and it figures out the rest!
Step 8: Creating the REST Controller
Finally, let’s expose our agent’s capabilities through REST API:
package com.bootcamptoprod.controller;
import com.bootcamptoprod.dto.MongoOperationResponse;
import com.bootcamptoprod.dto.MongoRequest;
import com.embabel.agent.api.invocation.AgentInvocation;
import com.embabel.agent.core.AgentPlatform;
import com.embabel.agent.core.ProcessOptions;
import com.embabel.agent.core.Verbosity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/mongo")
public class MongoOperationsController {
private static final Logger log = LoggerFactory.getLogger(MongoOperationsController.class);
private final AgentPlatform agentPlatform;
private final ProcessOptions processOptions;
public MongoOperationsController(AgentPlatform agentPlatform) {
this.agentPlatform = agentPlatform;
Verbosity verbosity = Verbosity.DEFAULT
.showLlmResponses()
.showPrompts()
.showPlanning();
this.processOptions = ProcessOptions.DEFAULT.withVerbosity(verbosity);
}
@PostMapping
public MongoOperationResponse executeMongoOperation(@RequestBody MongoRequest request) {
log.info("MongoDB operation request received: {}", request.command());
var agentInvocation = AgentInvocation
.builder(agentPlatform)
.options(processOptions)
.build(MongoOperationResponse.class);
MongoOperationResponse response = agentInvocation.invoke(request);
log.info("MongoDB operation completed");
return response;
}
}MongoOperationsController.javaExplanation:
- The Front Door: This controller provides the REST API endpoint that allows external tools (Postman, frontend apps, Slack bots) to trigger MongoDB operations through our AI agent.
- Single Endpoint: Just one endpoint (
POST /api/v1/mongo) handles all MongoDB operations. Whether listing databases or inserting documents, the AI figures out what to do. - AgentPlatform: Injected by Spring, this serves as the “Command Center” that tracks all registered agents, tools from the MCP server, and active connections.
- Verbosity Settings: Configured in the constructor for detailed logging. This lets us see:
- LLM responses
- Prompts being sent
- Internal planning steps
- AgentInvocation: The “Mission Launcher” that executes our agent:
.builder(agentPlatform): Initialize with the platform.options(processOptions): Configure execution options.build(MongoOperationResponse.class): Specify expected response type.invoke(request): Execute the agent with the request
This controller acts as a thin layer between HTTP requests and our intelligent agent, making it incredibly easy to integrate MongoDB automation into any external tool!
6. Testing the Application
Now let’s test our MongoDB MCP client! Follow these steps carefully:
Step 1: Start the MongoDB MCP Server
First, ensure your MongoDB MCP Server is running on port 8080:
cd /path/to/embabel-mongo-mcp-server
mvn clean install
export OPENAI_API_KEY="your-openrouter-api-key"
export MONGODB_CONNECTION_STRING="mongodb://localhost:27017"
mvn spring-boot:runTerminalWait until you see logs confirming the server is running successfully on port 8080.
Step 2: Start the MCP Client Application
In a new terminal window, navigate to your MCP client project and run:
cd /path/to/embabel-mongo-mcp-client
mvn clean install
export OPENAI_API_KEY=your_openrouter_api_key_here
mvn spring-boot:runTerminalYour MCP client should start on port 8081. You’ll see logs showing the MCP connection being established.
Step 3: Test with Natural Language Commands
Use a tool like Postman, Insomnia, or curl to send POST requests to http://localhost:8081/api/v1/mongo:
- List Databases: {“command”: “List all databases”}
- List Collections: {“command”: “Show me all collections in the mcp database”}
- Simple Query: {“command”: “Find users where name is Test Record in employees collection of mcp database”}
- Complex Query: {“command”: “Find employess where salary is greater than 80000 in employees collection of mcp database. Also, list down details of all these records”}
- Create Collection: {“command”: “Create a new collection with name ‘demo’ inside the ‘mcp’ database”}
- Insert Document: {“command”: “Insert a document with name ‘John Doe’ and age 30 into ‘demo’ collection inside the ‘mcp’ database”}
- List Indexes: {“command”: “Show all indexes for the employees collection in the mcp database”}
6. Understanding the Agent Workflow
Let’s trace exactly what happens when you send the natural language command: “List all databases”:
- Request Reception: The REST controller receives your POST request containing the command.
- Agent Invocation: The
AgentInvocationroutes the command to theSmartMongoAgent. - Prompt Construction: Embabel builds a detailed prompt explaining the task and user intent to the LLM.
- LLM Analysis: The “Brain” (DeepSeek v3.1) analyzes “List all databases” and identifies it as a LIST_DATABASES intent.
- Tool Discovery: The LLM looks into the
mongo-mcp-tool-groupto find available tools. - Tool Selection: The LLM selects the specific MCP tool (e.g.,
list_databases) from the server. - MCP Communication: The MCP client sends the tool execution request to our MongoDB MCP Server via the SSE connection.
- Server Execution: The MongoDB MCP Server executes the actual database operation against MongoDB.
- Result Processing: MongoDB returns data to the MCP server, which passes it back to our client.
- Response Formatting: The LLM transforms the raw technical data into a conversational, user-friendly response.
- Object Mapping: Embabel automatically maps the AI’s response into our
MongoOperationResponseJava record. - JSON Response: The controller sends the structured JSON response back to you.
Note: This intelligent flow applies to every MongoDB operation—whether listing collections, executing complex queries, or inserting documents!
7. Video Tutorial
For a complete step-by-step walkthrough, check out our video tutorial where we build the Smart MongoDB MCP Client from scratch. We demonstrate how natural language commands can manage your MongoDB instance through the seamless integration of Embabel and the Model Context Protocol!
📺 Watch on YouTube:
8. Source Code
The full source code for our Smart MongoDB MCP Client is available on GitHub. Clone the repo, set your OPENAI_API_KEY as an environment variable, and launch the Spring Boot application.
Important: Remember to have your MongoDB MCP Server running on port 8080 before starting this client.
🔗 Embabel Mongo MCP Client: https://github.com/BootcampToProd/embabel-mongo-mcp-client
9. Things to Consider
As you build and deploy your MongoDB AI Agent, keep these points in mind:
- Sequential Startup: Always start your MongoDB MCP Server (Port 8080) before the Client (Port 8081). The client performs a “handshake” upon startup to discover available tools.
- LLM Connection & API Keys: Ensure your
OPENAI_API_KEYfor OpenRouter is correctly set. Without it, the agent’s “brain” won’t function. - AI Model Selection: Choose models that explicitly support Function Calling (like DeepSeek v3). This specialized capability allows the AI to translate sentences into technical tool executions.
- MongoDB Connection: Verify your MongoDB MCP server has proper credentials and can connect to your MongoDB instance before testing the client.
- Port Management: Avoid conflicts by using separate ports (8080 for server, 8081 for client).
- Query Complexity: Start with simple queries and gradually move to complex ones. Test various natural language phrasings to see how the agent interprets them.
- Error Handling: In production, implement proper error handling to inform users if the MCP server or MongoDB becomes unreachable.
- Security: Never hardcode credentials. Use environment variables or secure secret management systems.
- Prompt Injection Prevention: Validate user inputs to prevent malicious commands that could manipulate your database.
- Testing Variations: Build a test suite checking if the agent understands different phrasings of the same request (e.g., “Show databases”, “List all DBs”, “What databases exist”).
- Collection/Database Names: If users provide ambiguous names, configure the agent’s prompt to ask for clarification or list available options first.
10. FAQs
What if my MongoDB MCP server is on a different host
Simply update the spring.ai.mcp.client.sse.connections.embabel-mongo-mcp-server.url in application.yml to point to your server’s address.
Can I connect to multiple MCP servers simultaneously?
Yes! Add multiple connections in application.yml and create corresponding tool groups. Each agent can reference the appropriate tool group. You could have one “Super Agent” connecting to MongoDB, Confluence, and File Operations servers simultaneously!
How do I customize the response format?
Modify the MongoOperationResponse record and update the prompt instructions in SmartMongoAgent to match your desired format.
Does this client need MongoDB credentials?
No. Only the MCP Server needs MongoDB connection credentials. Your MCP Client only needs the server’s URL and an LLM API key (like OpenRouter) for reasoning.
Can I use this pattern for other databases like PostgreSQL?
Yes, the same pattern works for any system with an MCP server. Just create appropriate tool groups and configure the MCP connection. You could build similar clients for PostgreSQL, Redis, or any other database!
How does the agent handle complex queries with multiple conditions?
The agent’s prompt instructs it to recognize complex query patterns. When you say “Find users older than 30 AND status is active”, the AI automatically translates this into a MongoDB query with $and operator and appropriate conditions.
11. Conclusion
Building our third MCP client for MongoDB operations demonstrates the true power and flexibility of the Embabel framework combined with the Model Context Protocol. Through this MongoDB MCP client, we have successfully bridged the gap between human language and complex database operations. The Embabel framework allows us to keep our code modular: the server handles the “how” (database connectivity), while the client handles the “what” (intelligence and user intent). This architecture makes it incredibly easy to build powerful, database-aware AI agents for any JVM-based enterprise application.
12. Learn More
Interested in learning more?
Build Confluence MCP Client with Embabel Framework









Add a Comment