A high-performance Model Context Protocol (MCP) server for executing read-only MongoDB queries. Built in Rust for speed and reliability.
This server enables LLMs to safely query MongoDB databases through the MCP protocol. It supports two connection types:
| Connection Type | Use Case | Speed |
|---|---|---|
| Direct URL | Local, Atlas, any network-accessible MongoDB | ~13ms |
| Kubernetes | MongoDB running in K8s pods | ~700ms |
- Read-only queries - Only
find,aggregate,countDocuments, anddistinctoperations - Query controls - Limit, sort, and projection parameters for find operations
- Dual connection support - Kubernetes pods and direct MongoDB URLs
- Saved queries with variables - Save reusable queries with
{{placeholder}}variables - Schema integration - Data model files help LLMs understand your collections
- Auto-discovery - Automatic K8s credential discovery from pod environment
- Timeout protection - 30-second query timeout prevents runaway queries
- Fast startup - ~4ms cold start, sub-millisecond for cached operations
cargo build --releaseCreate ~/.config/ro-mongodb-mcp-rs/config.yaml:
# Direct connection (simplest)
connections:
- name: local
mongodb_url: mongodb://localhost:27017
database_name: mydb
# data_model_file_path: /path/to/schema.md # optionalOr copy and customize the example:
cp config.example.yaml ~/.config/ro-mongodb-mcp-rs/config.yaml./target/release/ro-mongodb-mcp-rsThe server communicates via JSON-RPC 2.0 over stdin/stdout.
Configuration file: ~/.config/ro-mongodb-mcp-rs/config.yaml
For local development, MongoDB Atlas, or any network-accessible MongoDB:
connections:
- name: local-dev
mongodb_url: mongodb://localhost:27017
database_name: myapp
data_model_file_path: /path/to/schema.md
- name: atlas-prod
mongodb_url: mongodb+srv://user:pass@cluster.mongodb.net
database_name: production
data_model_file_path: /path/to/schema.mdFor MongoDB running in Kubernetes clusters:
# Optional: custom kubeconfig
# kubeconfig_path: /path/to/kubeconfig
namespaces:
- namespace_name: production # K8s namespace (also the connection name)
deployment_name: mongodb # Pod label: app=mongodb
database_name: myapp
data_model_file_path: /path/to/schema.mdK8s Credential Discovery: The server reads credentials from pod environment variables:
MONGO_INITDB_ROOT_USERNAME_FILE→ file path containing usernameMONGO_INITDB_ROOT_PASSWORD_FILE→ file path containing password
| Field | Description |
|---|---|
kubeconfig_path |
(optional) Custom kubeconfig file path (K8s only) |
name / namespace_name |
Unique connection identifier |
mongodb_url |
MongoDB connection string (direct connections only) |
deployment_name |
Pod label selector app=<value> (K8s only) |
database_name |
Default database for queries |
data_model_file_path |
(optional) Schema documentation file (any format) |
Path expansion: All path fields support environment variables ($HOME, ${VAR}) and tilde (~) expansion.
Important: Connection names must be unique across all connections.
The server provides 10 tools:
| Tool | Description |
|---|---|
list_connections |
List all configured connections |
list_collections |
List MongoDB collections (case-sensitive names) |
get_data_model |
Get schema documentation for a connection |
get_current_time |
Get current timestamp for time-based queries |
| Tool | Description |
|---|---|
query_mongodb |
Execute a read-only MongoDB query |
Supported operations:
// find - retrieve documents
{"status": "active"}
// aggregate - pipeline queries
[{"$match": {}}, {"$group": {"_id": "$status", "count": {"$sum": 1}}}]
// countDocuments - count matching documents
{"status": "active"}
// distinct - unique values (use distinct_field param)
{} // with distinct_field: "country"Optional parameters (find only):
| Parameter | Description | Example |
|---|---|---|
limit |
Maximum documents to return | 10 |
sort |
Sort order (JSON) | {"createdAt": -1} |
projection |
Fields to include/exclude | {"name": 1, "email": 1} |
distinct_field |
Field for distinct values | "country" |
| Tool | Description |
|---|---|
save_query |
Save a query for later reuse |
list_saved_queries |
List all saved queries for a connection |
get_saved_query |
Get details of a saved query |
run_saved_query |
Execute a saved query |
delete_saved_query |
Delete a saved query |
Placeholder Variables: Saved queries support {{placeholder}} syntax for runtime substitution:
// Save with placeholders - quotes in template control output type
{
"query": "{\"name\": \"{{name}}\", \"age\": {{age}}}"
}
// "{{name}}" → string {{age}} → number
// Run with variables (all values are strings)
{
"variables": {"name": "John", "age": "25"}
}
// Result: {"name": "John", "age": 25}Runtime Overrides: For find operations only, you can override limit, sort, and projection. These are ignored for other operations (with a warning).
Storage: Queries are persisted per connection in ~/.local/share/ro-mongodb-mcp-rs/<connection>.queries.yaml
{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "users",
"operation": "find",
"query": "{\"status\": \"active\"}",
"limit": 10,
"sort": "{\"createdAt\": -1}",
"projection": "{\"name\": 1, \"email\": 1}"
}
}{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "orders",
"operation": "aggregate",
"query": "[{\"$match\": {\"status\": \"completed\"}}, {\"$group\": {\"_id\": \"$userId\", \"total\": {\"$sum\": \"$amount\"}}}]"
}
}{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "users",
"operation": "countDocuments",
"query": "{}"
}
}{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "users",
"operation": "distinct",
"query": "{}",
"distinct_field": "country"
}
}{
"name": "save_query",
"arguments": {
"connection_name": "local",
"query_name": "user_activity",
"description": "Get user activity after a date",
"collection_name": "events",
"operation": "find",
"query": "{\"userId\": \"{{userId}}\", \"createdAt\": {\"$gte\": \"{{startDate}}\"}}"
}
}{
"name": "run_saved_query",
"arguments": {
"connection_name": "local",
"query_name": "user_activity",
"variables": {"userId": "12345", "startDate": "2024-01-01T00:00:00Z"},
"limit": 100
}
}Benchmarks on typical hardware:
| Metric | Time |
|---|---|
| Binary startup | 4ms |
get_current_time |
<1ms |
list_connections |
<1ms |
| Direct MongoDB query | ~13ms |
| K8s MongoDB query | ~700ms |
| 10 sequential direct queries | 5ms (connection reused) |
Binary size: ~21MB (release build)
Add to your Claude Desktop config:
{
"mcpServers": {
"mongodb": {
"command": "/path/to/ro-mongodb-mcp-rs"
}
}
}Add to ~/.config/goose/config.yaml:
extensions:
mongodb:
bundled: false
display_name: "MongoDB"
enabled: true
name: "mongodb"
timeout: 300
type: "stdio"
cmd: "/path/to/ro-mongodb-mcp-rs"
args: []Or add it interactively with goose configure and select "Command-line Extension".
The server uses JSON-RPC 2.0 over stdin/stdout:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | ./ro-mongodb-mcp-rs- Rust 1.85 or later (edition 2024)
- For K8s connections: valid kubeconfig with cluster access
- For direct connections: network access to MongoDB
cargo build --releasecargo testRUST_LOG=ro_mongodb_mcp_rs=debug ./target/release/ro-mongodb-mcp-rscargo clippy --all-targetsCheck version:
./ro-mongodb-mcp-rs --versionRelease new version:
./set-version.sh 1.2.3
git push origin main --follow-tags# Check pods exist and are running
kubectl get pods -n <namespace> -l app=<deployment_name>
# Verify pod is healthy
kubectl describe pod <pod-name> -n <namespace># Check pod environment variables
kubectl exec -n <namespace> <pod-name> -- env | grep MONGORequired variables:
MONGO_INITDB_ROOT_USERNAME_FILEMONGO_INITDB_ROOT_PASSWORD_FILE
- Verify the file exists:
ls -la /path/to/schema.md - Paths support
$HOME,${VAR}, and~expansion
- Verify MongoDB is running:
mongosh mongodb://localhost:27017 - Check network connectivity
- Verify credentials in URL are correct
Queries timeout after 30 seconds. For large datasets:
- Add filters to reduce result size
- Use
$limitin aggregation pipelines - Use
countDocumentsfirst to check data size
src/
├── main.rs # Entry point, CLI, initialization
├── config.rs # Configuration loading and validation
├── connection.rs # MongoConnection trait and registry
├── direct_connection.rs # Direct MongoDB URL connections
├── k8s_connection.rs # Kubernetes namespace connections
├── k8s_client.rs # Kubernetes API interactions
├── mcp.rs # MCP server and tool implementations
├── mongodb.rs # Query operations and mongosh execution
├── saved_queries.rs # Query persistence
└── tools.rs # MCP tool parameter types
- Read-only by design - Only read operations are supported
- No query injection - Operations are validated before execution
- Credential isolation - K8s credentials stay in the cluster
- Timeout protection - 30-second limit prevents resource exhaustion
Note: Direct connection URLs may contain credentials. Keep your config file secure:
chmod 600 ~/.config/ro-mongodb-mcp-rs/config.yamlMIT License. See LICENSE for details.