Skip to content
Conduit

mcp server

mongodb-mcp-server

A FastMCP-powered MongoDB MCP server written in Python. This repository exposes MongoDB operations as MCP tools, allowing MCP-compatible agents and clients to connect to MongoDB, inspect databases and

VuSnow/mongodb-mcp-servercommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

This project does not publish an install method we can turn into a config. Follow the README instead.

README

synced Oct 23, 2026

MongoDB-FastMCP-Server

A Python-based MongoDB MCP server built with FastMCP.

This repository exposes MongoDB operations as MCP tools, allowing MCP-compatible clients and AI agents to connect to MongoDB, inspect databases and collections, and execute controlled database operations through a clean tool interface.

Overview

mongodb-mcp-server is designed to provide a structured bridge between MongoDB and the Model Context Protocol.

Instead of letting an agent interact with MongoDB directly, this server exposes selected database capabilities as well-defined MCP tools. This makes database access easier to control, validate, extend, and maintain.

Features

  • Connect to MongoDB from a Python MCP server
  • Expose MongoDB operations as FastMCP tools
  • List databases and collections
  • Inspect collection metadata (schema, indexes, storage size, stats, logs)
  • Run controlled queries (find, aggregate, count) against collections
  • Full CRUD support (insert, update, delete)
  • Destructive operation confirmation (2-step pattern)
  • Read-only mode support
  • Separate MongoDB client logic from MCP tool definitions
  • Designed for agentic workflows and MCP-compatible clients

Project Structure

mongodb-mcp-server/
├── pyproject.toml
├── pytest.ini
├── README.md
├── .env
├── src/
│   └── mongodb_mcp/
│       ├── __init__.py
│       ├── server.py                       # FastMCP instance, tool registration
│       ├── configs.py                      # Config via pydantic-settings (env vars)
│       │
│       ├── clients/
│       │   ├── __init__.py
│       │   └── mongodb/                    # MongoDB client (pymongo)
│       │       ├── __init__.py             # MongoDBClient (mixin composition)
│       │       ├── base.py                 # BaseMongoClient (connection, ping, close)
│       │       ├── metadata.py             # list_databases, list_collections, indexes, stats, explain, logs
│       │       ├── read.py                 # find, aggregate, aggregate_db, count_documents
│       │       ├── create.py               # insert_one, insert_many, create_collection, create_index
│       │       ├── update.py               # update_one, update_many, rename_collection
│       │       └── delete.py               # delete_one, delete_many, drop_collection, drop_database, drop_index
│       │
│       ├── services/
│       │   ├── __init__.py
│       │   ├── connection_manager.py       # Connection state machine (singleton)
│       │   └── mongodb/                    # MongoDB service layer (mixin-based)
│       │       ├── __init__.py             # MongoDBService (composed) + singleton
│       │       ├── base.py                 # BaseMongoDBService (ensure_connected, resolve_name, validation)
│       │       ├── metadata.py             # MetadataService (list, schema, indexes, stats, explain, logs)
│       │       ├── read.py                 # ReadService (find, aggregate, count_documents, distinct)
│       │       ├── create.py               # CreateService (insert, create_collection, create_index)
│       │       ├── update.py               # UpdateService (update_one, update_many, rename_collection)
│       │       └── delete.py               # DeleteService (delete_one, delete_many, drop_collection, drop_database, drop_index)
│       │
│       └── tools/                          # Tool definitions (thin layer, delegates to services)
│           ├── __init__.py                 # Logging setup
│           ├── connection.py               # connect, disconnect
│           └── mongodb/                    # MongoDB tools package
│               ├── __init__.py             # Re-exports all tools + side-effect imports
│               ├── _utils.py               # _format_not_found helper
│               ├── metadata.py             # list_databases, list_collections, collection_schema, collection_indexes, db_stats, explain_query, get_logs, collection_stats
│               ├── create.py               # insert_one, insert_many, create_collection, create_index
│               ├── read.py                 # find, aggregate, count_documents, distinct
│               ├── update.py               # update_one, update_many, rename_collection
│               └── delete.py              # delete_one, delete_many, drop_collection, drop_database, drop_index
│
└── test/
    ├── conftest.py                         # Shared fixtures, env setup
    └── units/
        ├── services/
        │   ├── test_base_service.py
        │   ├── test_connection_manager.py
        │   ├── test_metadata_service.py
        │   ├── test_create_service.py
        │   ├── test_read_service.py
        │   ├── test_update_service.py
        │   └── test_delete_service.py
        └── tools/
            ├── test_metadata_tools.py
            ├── test_create_tools.py
            ├── test_read_tools.py
            ├── test_update_tools.py
            └── test_delete_tools.py

Architecture

┌─────────────────────────────────────────────────────────┐
│  Tools Layer (tools/)                                   │
│  - Defines MCP tool name, description, schema           │
│  - Formats output for LLM consumption                  │
│  - Try/except top-level, returns user-friendly messages │
├─────────────────────────────────────────────────────────┤
│  Services Layer (services/mongodb/)                     │
│  - Auto-connect (ensure_connected)                      │
│  - Input validation (_validate_name)                    │
│  - Lazy name resolution with fuzzy suggestions          │
│  - Read-only mode enforcement                           │
│  - Error classification and logging                     │
├─────────────────────────────────────────────────────────┤
│  Clients Layer (clients/mongodb/)                       │
│  - Pure pymongo async calls                             │
│  - No business logic, no error handling                 │
│  - Translates Python params → pymongo operations        │
└─────────────────────────────────────────────────────────┘
            │
            ▼
       MongoDB (via AsyncMongoClient)

Key Design Decisions

  • Lazy Name Resolution: Tools call MongoDB directly first. Only when results are empty/error does the service layer resolve names and suggest alternatives. Zero overhead on happy path.
  • Mixin Composition: Both client and service layers use the same pattern — base class + mixins → composed class. Easy to extend with new operation types.
  • Singleton Services: connection_manager and mongodb_service are module-level singletons shared across all tools.
  • Structured Logging: Every layer uses Python logging with prefix tags ([connection], [resolve], [tool:name]) for easy grep-based debugging.

Implementation Plan

PhaseStatusDescription
1✅ DoneProject setup: pyproject.toml, FastMCP server skeleton, config
2✅ DoneClient layer: MongoDBClient (mixin-based) + ConnectionManager
3✅ DoneService layer + Metadata tools: list-databases, list-collections, collection-schema, db-stats, collection-indexes, collection-stats, explain, logs
4✅ DoneCRUD tools: ✅ create (insert, create_collection, create_index) · ✅ read (find, aggregate, count_documents, distinct) · ✅ update (update_one, update_many, rename_collection) · ✅ delete (delete_one, delete_many, drop_collection, drop_database, drop_index)

Quick Start

# Install in editable mode
pip install -e ".[dev]"

# Set connection string
export MONGODB_CONNECTION_STRING="mongodb://localhost:27017"

# Run server (stdio transport)
fastmcp run src/mongodb_mcp/server.py:mcp

# Or use FastMCP dev UI
fastmcp dev src/mongodb_mcp/server.py:mcp

MCP Inspector

MCP Inspector is a browser-based tool for interactively testing MCP servers and their tools.

# Run MCP Inspector against this server (npx, no install required)
npx @modelcontextprotocol/inspector fastmcp run src/mongodb_mcp/server.py:mcp

Then open http://localhost:6274 in your browser. From there you can:

  • Browse all registered tools and their input schemas
  • Call tools manually and inspect structured responses
  • Debug tool outputs without needing a full MCP client

Note: Set MONGODB_CONNECTION_STRING in your environment or .env file before running.

Install Node.js (required for npx)

macOS

brew install node

Ubuntu / Debian

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

Windows

Download and run the installer from nodejs.org.

Verify installation:

node --version   # should be ≥ 18
npx --version

Testing

# Install test dependencies
pip install -e ".[dev]"

# Run all unit tests
python -m pytest test/units/ -v

# Run specific test file
python -m pytest test/units/services/test_base_service.py -v

# Run with short traceback
python -m pytest test/units/ --tb=short

# Run with coverage (if pytest-cov installed)
python -m pytest test/units/ --cov=mongodb_mcp --cov-report=term-missing

Note: Tests mock all MongoDB interactions — no running MongoDB instance required for unit tests.

Configuration

Environment variables (or .env file):

VariableDefaultDescription
MONGODB_CONNECTION_STRING(required)MongoDB connection URI
READ_ONLYtrueOnly allow read/metadata operations
ALLOW_DESTRUCTIVEfalseAllow destructive operations (delete, drop). Requires READ_ONLY=false
DEFAULT_TIMEOUT_MS30000Default timeout for MongoDB operations
WRITE_ALLOWLIST(unset)Comma-separated db.collection patterns allowed for writes (see below)

Write Allowlist

When READ_ONLY=false, you can further restrict which databases/collections accept writes:

# Allow specific targets
WRITE_ALLOWLIST=mydb.users,mydb.orders,testdb.*

# Allow all collections in a database
WRITE_ALLOWLIST=prod.*

# Explicit allow-all
WRITE_ALLOWLIST=*

# Not set or empty → allow all (backward compatible)
PatternMeaning
db.colExact match only
db.*All collections in that database
*Allow all writes
(empty/unset)Allow all writes (backward compatible)

Security Model

Write operations go through 3 policy checks:

_check_write_allowed()         → READ_ONLY=false?
_check_destructive_allowed()   → ALLOW_DESTRUCTIVE=true? (delete/drop only)
_check_write_target()          → WRITE_ALLOWLIST match?
READ_ONLYALLOW_DESTRUCTIVEAllowed operations
true (default)(ignored)Read + metadata only
falsefalse (default)insert, update, create_index, create_collection, rename_collection
falsetrueAll of above + delete_one, delete_many, drop_collection, drop_database, drop_index

rename_collection with drop_target=true also requires ALLOW_DESTRUCTIVE=true since it destroys the target collection.

Tech Stack

Available Tools

ToolDescriptionParamsResolves names?
connectConnect to a MongoDB instanceconnection_string — MongoDB URI. Default: from env—
disconnectDisconnect from MongoDB(none)—
list_databasesList all databases with size(none)No
list_collectionsList collections in a databasedatabase — Database nameNo
collection_schemaSample documents to infer schemadatabase — Database namecollection — Collection namesample_size — Number of docs to sample. Default: 20Yes (lazy)
collection_indexesList indexes for a collectiondatabase — Database namecollection — Collection nameYes (lazy)
db_statsGet database statisticsdatabase — Database nameYes (lazy)
explain_queryExplain a query plan (find/aggregate/count)database — Database namecollection — Collection namemethod — One of: find, aggregate, countargs — JSON string of method argumentsverbosity — Detail level. Default: "queryPlanner"Yes (lazy)
get_logsGet MongoDB server log entrieslog_type — Log category. Default: "global"limit — Max lines to return. Default: 50No
insert_oneInsert a single documentdatabase — Database namecollection — Collection namedocument — JSON string of documentNo
insert_manyInsert multiple documentsdatabase — Database namecollection — Collection namedocuments — JSON array of documentsordered — Ordered insert. Default: falseNo
create_collectionCreate a new collectiondatabase — Database namecollection — Collection nameNo
create_indexCreate an index on a collectiondatabase — Database namecollection — Collection namekeys — JSON array of [field, direction] pairsunique — Unique index. Default: falsename — Custom index name (optional)Yes (lazy)
findQuery documents from a collectiondatabase — Database namecollection — Collection namefilter — JSON filter. Default: "{}"projection — JSON projection (optional)sort — JSON array of [field, direction] pairs (optional)skip — Documents to skip. Default: 0limit — Max documents. Default: 10Yes (lazy)
aggregateRun an aggregation pipelinedatabase — Database namecollection — Collection namepipeline — JSON array of stage objectslimit — Max results. Default: 1000Yes (lazy)
count_documentsCount documents matching a filterdatabase — Database namecollection — Collection namefilter — JSON filter. Default: "{}"Yes (lazy)
distinctGet distinct values of a fielddatabase — Database namecollection — Collection namefield — Field namefilter — JSON filter. Default: "{}"Yes (lazy)
collection_statsGet storage statistics for a collectiondatabase — Database namecollection — Collection nameYes (lazy)
update_oneUpdate a single document matching a filterdatabase — Database namecollection — Collection namefilter — JSON filter stringupdate — JSON update with operators ($set, $inc, etc.)upsert — Insert if no match. Default: falseYes (lazy)
update_manyUpdate all documents matching a filterdatabase — Database namecollection — Collection namefilter — JSON filter stringupdate — JSON update with operators ($set, $inc, etc.)upsert — Insert if no match. Default: falseYes (lazy)
rename_collectionRename a collectiondatabase — Database namecollection — Current collection namenew_name — New collection namedrop_target — Overwrite if target exists. Default: falseYes (lazy)
delete_oneDelete a single document matching a filterdatabase — Database namecollection — Collection namefilter — JSON filter stringYes (lazy)
delete_manyDelete all documents matching a filterdatabase — Database namecollection — Collection namefilter — JSON filter string. Use '{}' to delete allYes (lazy)
drop_collectionDrop a collection and all its data (irreversible)database — Database namecollection — Collection nameYes (lazy)
drop_databaseDrop an entire database (irreversible)database — Database nameYes (lazy)
drop_indexDrop an index by namedatabase — Database namecollection — Collection nameindex_name — Index name (use collection_indexes to find names)Yes (lazy)

Lazy resolve: On happy path (correct name, data exists), no extra queries. Only when results are empty/error does the service resolve names and suggest fuzzy alternatives for user confirmation.

Write tools require READ_ONLY=false in configuration.

License

Apache-2.0

↑↓ navigate openesc close