MongoDB Read-Only
FreeNot checkedProvides secure read-only access to MongoDB databases with support for Kubernetes deployments and direct connections.
About
Provides secure read-only access to MongoDB databases with support for Kubernetes deployments and direct connections.
README
A high-performance Model Context Protocol (MCP) server for executing read-only MongoDB queries. Built in Rust for speed and reliability.
Overview
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 |
Features
- 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
Quick Start
1. Build
cargo build --release
2. Configure
Create ~/.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 # optional
Or copy and customize the example:
cp config.example.yaml ~/.config/ro-mongodb-mcp-rs/config.yaml
3. Run
./target/release/ro-mongodb-mcp-rs
The server communicates via JSON-RPC 2.0 over stdin/stdout.
Configuration
Configuration file: ~/.config/ro-mongodb-mcp-rs/config.yaml
Direct MongoDB Connections
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:[email protected]
database_name: production
data_model_file_path: /path/to/schema.md
Kubernetes Namespace Connections
For 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.md
K8s 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
Configuration Fields
| 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.
MCP Tools
The server provides 10 tools:
Discovery 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 |
Query Tools
| 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" |
Saved Query Tools
| 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
Usage Examples
Basic Query
{
"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}"
}
}
Aggregation Pipeline
{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "orders",
"operation": "aggregate",
"query": "[{\"$match\": {\"status\": \"completed\"}}, {\"$group\": {\"_id\": \"$userId\", \"total\": {\"$sum\": \"$amount\"}}}]"
}
}
Count Documents
{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "users",
"operation": "countDocuments",
"query": "{}"
}
}
Distinct Values
{
"name": "query_mongodb",
"arguments": {
"connection_name": "local",
"collection_name": "users",
"operation": "distinct",
"query": "{}",
"distinct_field": "country"
}
}
Save a Query (with Variables)
{
"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}}\"}}"
}
}
Run a Saved Query (with Variables)
{
"name": "run_saved_query",
"arguments": {
"connection_name": "local",
"query_name": "user_activity",
"variables": {"userId": "12345", "startDate": "2024-01-01T00:00:00Z"},
"limit": 100
}
}
Performance
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)
MCP Client Integration
Claude Desktop
Add to your Claude Desktop config:
{
"mcpServers": {
"mongodb": {
"command": "/path/to/ro-mongodb-mcp-rs"
}
}
}
Goose CLI
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".
Generic MCP Client
The server uses JSON-RPC 2.0 over stdin/stdout:
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | ./ro-mongodb-mcp-rs
Development
Prerequisites
- Rust 1.85 or later (edition 2024)
- For K8s connections: valid kubeconfig with cluster access
- For direct connections: network access to MongoDB
Build
cargo build --release
Test
cargo test
Debug Logging
RUST_LOG=ro_mongodb_mcp_rs=debug ./target/release/ro-mongodb-mcp-rs
Lint
cargo clippy --all-targets
Version Management
Check version:
./ro-mongodb-mcp-rs --version
Release new version:
./set-version.sh 1.2.3
git push origin main --follow-tags
Troubleshooting
"No healthy pods found" (Kubernetes)
# 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>
"MongoDB credential environment variable not found" (Kubernetes)
# Check pod environment variables
kubectl exec -n <namespace> <pod-name> -- env | grep MONGO
Required variables:
MONGO_INITDB_ROOT_USERNAME_FILEMONGO_INITDB_ROOT_PASSWORD_FILE
"Failed to read data model file"
- Verify the file exists:
ls -la /path/to/schema.md - Paths support
$HOME,${VAR}, and~expansion
Connection timeout (Direct)
- Verify MongoDB is running:
mongosh mongodb://localhost:27017 - Check network connectivity
- Verify credentials in URL are correct
Query timeout
Queries timeout after 30 seconds. For large datasets:
- Add filters to reduce result size
- Use
$limitin aggregation pipelines - Use
countDocumentsfirst to check data size
Project Structure
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
Security
- 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.yaml
License
MIT License. See LICENSE for details.
Installing MongoDB Read-Only
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/chrstnwhlrt/ro-mongodb-mcp-rsFAQ
Is MongoDB Read-Only MCP free?
Yes, MongoDB Read-Only MCP is free — one-click install via Unyly at no cost.
Does MongoDB Read-Only need an API key?
No, MongoDB Read-Only runs without API keys or environment variables.
Is MongoDB Read-Only hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install MongoDB Read-Only in Claude Desktop, Claude Code or Cursor?
Open MongoDB Read-Only on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiSupabase
Database, auth and storage
by SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Sequential Thinking
Dynamic and reflective problem-solving through thought sequences.
Time
Time and timezone conversion capabilities.
Compare MongoDB Read-Only with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
