Fast Mongo MCP
High-performance MongoDB + GridFS MCP server in Rust (rmcp + mongo-rust-driver)
Ask AI about Fast Mongo MCP
Powered by Claude Β· Grounded in docs
I know everything about Fast Mongo MCP. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
fast-mongo-mcp
High-performance MongoDB + GridFS MCP server, written in Rust.
A single static binary that exposes the full MongoDB driver surface (including GridFS, async job tracking, and database dump) as a Model Context Protocol server over stdio. Designed as a drop-in, performance-focused alternative to Node/Python-based MongoDB MCPs.
41 tools Β· 44 integration tests Β· ~8 MB static binary Β· zero runtime deps
Stack
- rmcp 0.3 β official Rust SDK for MCP
- mongodb 3 β official MongoDB Rust driver (async, tokio)
- tokio β async runtime with
tokio::spawnfor background jobs - schemars 1 β auto-derived JSON Schema for tool inputs
- tracing β structured logging to stderr
Quick start
git clone https://github.com/makkax/fast-mongo-mcp
cd fast-mongo-mcp
./install.sh # builds release + installs to ~/bin/
# or pass a custom destination:
./install.sh /usr/local/bin # β /usr/local/bin/fast-mongo-mcp
./install.sh ~/bin/my-name # β ~/bin/my-name (custom binary name)
install.sh builds the release binary, removes any pre-existing copy at the
destination (see Β§ macOS AMFI gotcha), copies the new
binary, runs a quick smoke test, and prints the path. If you prefer manual
control: cargo build --release and copy target/release/fast-mongo-mcp
yourself β but always rm -f the destination first on macOS.
Point it at a MongoDB and try ping:
(printf '%s\n%s\n%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ping","arguments":{}}}' ; sleep 1) \
| FAST_MONGO_URIS='main=mongodb://admin:secret@localhost:27017' \
./target/release/fast-mongo-mcp 2>/dev/null
Expected: JSON-RPC initialize response plus a tools/call response with
pong β 1 instance(s): [main], default: 'main'.
Tool inventory (38)
π©Ί Health (1)
| Tool | Description |
|---|---|
ping | Returns configured MongoDB aliases and the default instance. |
ποΈ Database & collection admin (9)
| Tool | Description |
|---|---|
list_databases | All databases on the instance. |
db_stats | dbStats command output. |
drop_database | DESTRUCTIVE β drop an entire database. |
list_collections | Collections in a database. |
create_collection | Create a new collection. |
drop_collection | DESTRUCTIVE β drop a single collection. |
rename_collection | Rename (same database), optional drop_target. |
collection_storage_size | collStats: size, count, storageSize, totalIndexSize. |
collection_schema | Infer schema via $sample aggregation. |
π Query (4)
| Tool | Description |
|---|---|
find | filter / projection / sort / limit / skip; limit clamped to [1, 1000]. |
aggregate | Pipeline as JSON array; output limit [1, 1000]. |
count | count_documents with optional filter. |
explain | explain any command with chosen verbosity. |
βοΈ Write (3)
| Tool | Description |
|---|---|
insert_many | Insert an array of documents. |
update_many | Supports both $-operator and aggregation-pipeline updates. |
delete_many | DESTRUCTIVE β bulk delete with filter. |
π Indexes (3)
| Tool | Description |
|---|---|
list_indexes | All indexes on a collection. |
create_index | Classic index (non-Atlas-Search), with options. |
drop_index | DESTRUCTIVE β drop index by name. |
πΎ Backup (1)
| Tool | Description |
|---|---|
dump_database | Dump an entire database to disk as mongodump-compatible BSON files (one .bson per collection). Skips GridFS bucket collections (.files / .chunks) by default. Output path is sandboxed under FAST_MONGO_DUMP_DIR. |
π©Ή Diagnostics (1)
| Tool | Description |
|---|---|
mongodb_logs | getLog admin command (global or startupWarnings). |
π¦ GridFS β bytes-in-response (13)
| Tool | Description |
|---|---|
gridfs_upload | Upload with base64 content + optional metadata. |
gridfs_upload_text | Convenience: UTF-8 text upload (no base64). |
gridfs_download | Download by ObjectId, returned as base64. |
gridfs_read_text | Download + UTF-8 decode. |
gridfs_find | Most recent file matching a filename. |
gridfs_list | Filter + limit on the files collection. |
gridfs_metadata | File metadata by ObjectId. |
gridfs_delete | DESTRUCTIVE β delete file + chunks. |
gridfs_update_metadata | Partial merge under metadata.<k>. |
gridfs_cleanup | TTL delete with prefix + status filter; dry_run supported. |
gridfs_watch | Poll until a file matching prefix/filter appears (or timeout). |
gridfs_buckets_list | Detect buckets via .files collection scan. |
gridfs_stats | Count + total bytes per bucket. |
π GridFS β streaming to/from disk (3)
For files larger than the ~1 MiB response cap, these tools stream directly between GridFS and a sandboxed directory on disk, returning only metadata
- the final path + SHA-256 (not the bytes).
| Tool | Description |
|---|---|
gridfs_download_to_file | Stream a GridFS file to a sandboxed path by ObjectId. Default path: {sandbox}/{filename}.{shortid}.{ext} where shortid is sha256(file_id+filename)[:8]. |
gridfs_find_to_file | Same as above but look up the most recent file by filename. |
gridfs_upload_from_file | Stream an on-disk file into GridFS. Input path must be inside the sandbox. |
All three share the sandbox root FAST_MONGO_DOWNLOAD_DIR (default
/tmp/fast-mongo-downloads) and canonicalize every path to reject
escape attempts (../, symlinks outside the sandbox, absolute paths
pointing elsewhere). Hard upper bound on download size is still
FAST_MONGO_MAX_GRIDFS_BYTES (50 MiB default), but you can raise it
freely since the bytes never enter the MCP response.
β±οΈ Async job tracking (3)
| Tool | Description |
|---|---|
start_bulk_update | Dispatch update_many to a tokio task, return job_id. |
get_job_status | Poll by job_id: running | done | failed, includes duration and result. |
list_jobs | All jobs in this MCP session, sorted by started_at desc. |
Destructive tools are still registered β they rely on the MCP host's normal user-confirmation flow to prevent accidental data loss.
Multi-instance support
Unlike MongoDB MCPs that accept only one URI per process,
fast-mongo-mcp holds a registry of named MongoDB clients so a single
binary can talk to multiple instances. Every tool accepts an optional
instance parameter to pick one.
FAST_MONGO_URIS=primary=mongodb://admin:secret@db1.example.com:27017;cache=mongodb://admin:secret@db2.example.com:27017
The first alias becomes the default when instance is omitted. Legacy
single-URI mode via FAST_MONGO_URI is also supported (alias becomes
default).
Environment variables
| Variable | Default | Purpose |
|---|---|---|
FAST_MONGO_URIS | β | Multi-URI: alias=uri;alias=uri |
FAST_MONGO_URI | β | Single URI fallback (alias becomes default) |
FAST_MONGO_POOL_SIZE | 10 | Max pool size per client |
FAST_MONGO_APP_NAME | fast-mongo-mcp | appName reported to MongoDB |
FAST_MONGO_MAX_RESPONSE_BYTES | 1048576 | Byte cap per tool response (1 MiB) |
FAST_MONGO_MAX_GRIDFS_BYTES | 52428800 | GridFS download size limit (50 MiB) |
FAST_MONGO_DUMP_DIR | /tmp/fast-mongo-dumps | Sandbox root for dump_database output paths |
FAST_MONGO_DOWNLOAD_DIR | /tmp/fast-mongo-downloads | Sandbox root for gridfs_download_to_file / gridfs_find_to_file output AND gridfs_upload_from_file input |
RUST_LOG | fast_mongo_mcp=info,mongodb=warn | Logging filter (stderr only) |
Copy .env.example to .env and adapt.
Build
Prerequisites
Install Rust (if not already):
# macOS / Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Windows β download and run: https://rustup.rs
# Requires Visual Studio C++ Build Tools (install via Visual Studio Installer)
macOS (Apple Silicon / Intel)
cargo build --release
# binary: ./target/release/fast-mongo-mcp
# Install (recommended β handles AMFI signature cache, see Β§ macOS AMFI gotcha)
./install.sh ~/bin/
# Or manually:
rm -f ~/bin/fast-mongo-mcp
cp target/release/fast-mongo-mcp ~/bin/
Expected size: ~8 MB stripped on macOS ARM64.
Windows
cargo build --release
# binary: .\target\release\fast-mongo-mcp.exe
# Install (copy to a directory on your PATH)
copy target\release\fast-mongo-mcp.exe ~\bin\
Cross-compile from macOS to Windows
rustup target add x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu
# binary: target/x86_64-pc-windows-gnu/release/fast-mongo-mcp.exe
Release profile
From Cargo.toml: lto = "fat", codegen-units = 1, strip = "symbols",
panic = "abort".
Test
Integration tests run against a real MongoDB instance. Each test uses
a unique database name (fast_mongo_mcp_test_<pid>_<n>) so parallel
execution is safe and tests clean up after themselves.
# default: mongodb://admin:secret@localhost:27017 (override via env below)
cargo test
# override target
FAST_MONGO_TEST_URI=mongodb://admin:secret@localhost:27017 cargo test
# a single test
cargo test test_ping_reports_instances
# with output visible
cargo test -- --nocapture
All 44 tests complete in ~2-4 seconds against a localhost MongoDB.
macOS AMFI gotcha
If you replace ~/bin/fast-mongo-mcp (or any other on-PATH location) by
overwriting it in place with cp / install / mv, the next launch of the
binary may exit immediately with code 137 (SIGKILL) and zero stderr
output. This is not a bug in fast-mongo-mcp β it's the macOS kernel
(AMFI, Apple Mobile File Integrity) refusing to launch a binary whose
adhoc code signature doesn't match the per-inode signature it has cached.
When cp overwrites a file in place, the destination keeps the same
inode but gets new content (and therefore a new adhoc signature). AMFI
sees the inode-cached old signature, computes the new one, finds a
mismatch, and SIGKILLs the process before main() runs.
The fix is trivial: unlink the destination first so the new binary lands on a fresh inode, the AMFI cache misses, and the kernel recomputes the signature for the new file.
# β Triggers AMFI kill on macOS Apple Silicon
cp target/release/fast-mongo-mcp ~/bin/fast-mongo-mcp
# β
Works
rm -f ~/bin/fast-mongo-mcp
cp target/release/fast-mongo-mcp ~/bin/fast-mongo-mcp
./install.sh always does the rm -f for you. Use it instead of raw cp.
Claude Desktop / Claude Code config
~/Library/Application Support/Claude/claude_desktop_config.json
(Claude Desktop) and ~/.claude.json (Claude Code) both accept the same
mcpServers block:
{
"mcpServers": {
"fast-mongo-mcp": {
"command": "/absolute/path/to/fast-mongo-mcp",
"env": {
"FAST_MONGO_URIS": "primary=mongodb://admin:secret@localhost:27017",
"RUST_LOG": "fast_mongo_mcp=info,mongodb=warn"
}
}
}
}
Restart the host (Claude Desktop / Claude Code) to pick up the change.
Architecture
src/
βββ main.rs # tokio runtime + tracing + stdio bootstrap
βββ mongo.rs # MongoRegistry: multi-URI client map
βββ server.rs # MongoMcpServer struct, JobState, ServerHandler
βββ tools.rs # #[tool_router] impl with all 38 tools + tests
βββ error.rs # ToolError enum + rmcp ErrorData conversion
βββ output.rs # BSON -> JSON + byte-cap helpers
βββ test_util.rs # TestDb RAII + test fixtures
Design choices:
- Single
#[tool_router]block intools.rsβ rmcp generates onetool_router()fn per impl, so all tools must live together. Organized by comment banners instead of file splits. - Shared state via
ArcβMongoRegistryandJobRegistryare both cheap to clone (Arc inside), soMongoMcpServerisCloneand background tokio tasks can take owned copies. - Logging to stderr only β stdout is JSON-RPC territory; one stray
println!on stdout and the protocol explodes. The tracing subscriber writes exclusively to stderr. - Byte cap on responses β prevents aggregation results from blowing
up the MCP host's context window. Override via
FAST_MONGO_MAX_RESPONSE_BYTES. - Filesystem sandbox for
dump_databaseβ the output directory must canonicalize insideFAST_MONGO_DUMP_DIRso an LLM cannot be tricked into writing BSON files to arbitrary paths.
Contributing
Pull requests welcome. Before opening one:
cargo testβ all tests must stay green.cargo fmt+cargo clippyβ no new warnings.- Conventional commit messages (
feat:,fix:,docs:,chore:). - New tools must include an integration test in
src/tools.rsunder the#[cfg(test)] mod testsmodule.
See DEVELOPMENT.md for the full runbook.
License
MIT β see LICENSE.
