mcp-mongo
MCP Server com acesso a MongoDB — Clean Architecture, Repository Pattern, Motor (async).
Compatível com qualquer agente MCP: Claude Code, Claude Desktop, LangChain, LlamaIndex e outros via HTTP.
Índice
- Visão Geral
- Arquitetura
- Estrutura de Ficheiros
- Instalação
- Configuração
- Execução
- Capacidades MCP
- Segurança
- Testes
- Integração com Agentes
- Decisões de Arquitetura
Visão Geral
Este servidor implementa o Model Context Protocol (MCP) para expor um banco de dados MongoDB a modelos de linguagem e agentes de IA.
O agente pode:
- Executar queries
find()eaggregate()com filtros, projeções e ordenação - Inspecionar databases, collections e inferir esquemas via amostragem de documentos
- Listar índices e obter estatísticas de collections
- Executar operações de escrita (quando explicitamente habilitado)
O servidor é read-only por padrão e funciona com qualquer instância MongoDB — basta mudar o .env ou a variável MONGODB_URI.
Arquitetura
┌─────────────────────────────────────────────────────────┐
│ Agente (Claude / LangChain / …) │
└────────────────────────┬────────────────────────────────┘
│ MCP Protocol
stdio │ ou HTTP (SSE / streamable-http)
┌────────────────────────▼────────────────────────────────┐
│ MCP Server (FastMCP) │
│ │
│ ┌──────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ Tools │ │ Resources │ │ Prompts │ │
│ └────┬─────┘ └─────┬─────┘ └──────────────────┘ │
│ │ │ │
│ ┌────▼───────────────▼────────────────────────────┐ │
│ │ Repositories │ │
│ │ BaseRepository → QueryRepository │ │
│ │ → SchemaRepository │ │
│ └────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌────────────────────▼────────────────────────────┐ │
│ │ Database (Motor AsyncIOMotorClient) │ │
│ └────────────────────┬────────────────────────────┘ │
│ │ │
│ ┌────────────────────▼────────────────────────────┐ │
│ │ Config (Pydantic Settings + .env) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│ TCP
┌────────────────────────▼────────────────────────────────┐
│ MongoDB │
└─────────────────────────────────────────────────────────┘
Regra de dependência: cada camada conhece apenas a camada imediatamente abaixo. Tools não conhecem o banco diretamente; Config não conhece ninguém.
Estrutura de Ficheiros
mcp-mongo/
│
├── .env # Configuração activa (não commitado)
├── pyproject.toml # Dependências, scripts, ruff, mypy, pytest
├── .gitignore
│
├── src/
│ └── mcp_mongo/
│ ├── __init__.py
│ ├── server.py # Entry point: cria FastMCP e selecciona transporte
│ │
│ ├── config/
│ │ ├── __init__.py
│ │ └── settings.py # Pydantic Settings — MONGODB_URI ou MONGODB_*
│ │
│ ├── database/
│ │ ├── __init__.py
│ │ └── connection.py # Singleton DatabaseClient (Motor) + lifecycle
│ │
│ ├── repositories/
│ │ ├── __init__.py
│ │ ├── base.py # find_many, find_one, aggregate, writes + _serialize BSON
│ │ ├── query_repository.py # find/aggregate com guard de writes
│ │ └── schema_repository.py # Introspecção: databases, collections, schema inferido, índices, stats
│ │
│ ├── tools/
│ │ ├── __init__.py
│ │ ├── query_tools.py # find, find_one, aggregate, count, insert, update, delete
│ │ └── schema_tools.py # list_databases, list_collections, describe_collection, list_indexes, get_collection_stats
│ │
│ ├── resources/
│ │ ├── __init__.py
│ │ └── schema_resources.py # URIs: mongo://databases, mongo://db/{db}/collections, …
│ │
│ └── prompts/
│ ├── __init__.py
│ └── mongo_prompts.py # explore_database, analyse_collection, write_query, write_aggregation, optimise_query
│
└── tests/
├── __init__.py
├── conftest.py
└── tools/
├── test_query_repository.py
└── test_schema_repository.py
Instalação
Pré-requisitos: Python 3.11+, uv, MongoDB acessível.
cd mcp-mongo
# Instalar dependências
uv sync
# Com dependências de desenvolvimento
uv sync --extra dev
Configuração
Toda a configuração é feita no ficheiro .env na raiz do projeto.
cp .env .env.local
# editar com os dados do teu ambiente
Conexão com o Banco
Existem duas formas de configurar a conexão — usa a que for mais conveniente:
Opção A — MONGODB_URI (tem prioridade)
Uma única variável com a URI completa:
MONGODB_URI=mongodb://user:password@host:27017/dbname
Também suporta URIs com replica sets e opções adicionais:
MONGODB_URI=mongodb+srv://user:password@cluster.mongodb.net/dbname
Opção B — variáveis individuais
MONGODB_HOST=localhost
MONGODB_PORT=27017
MONGODB_DB=mydb
MONGODB_USER=myuser
MONGODB_PASSWORD=secret
Se
MONGODB_URIestiver definida, os valores deMONGODB_HOST,MONGODB_PORT, etc., são ignorados. Caso contrário, as vars individuais são usadas. Se nenhuma for fornecida, o servidor tenta ligar alocalhost:27017/test.
Transporte MCP
A variável MCP_TRANSPORT define como o servidor comunica com o agente:
| Valor | Protocolo | Endpoint | Indicado para |
|---|---|---|---|
stdio (padrão) | stdin/stdout | — | Claude Code, Claude Desktop, agentes locais |
sse | HTTP Server-Sent Events | http://host:port/sse | LangChain, LlamaIndex, agentes HTTP legados |
streamable-http | HTTP streaming | http://host:port/mcp | Agentes MCP modernos via HTTP |
Para HTTP, define também o host e a porta:
MCP_TRANSPORT=sse
MCP_HOST=0.0.0.0
MCP_PORT=8080
Referência completa de variáveis
| Variável | Padrão | Descrição |
|---|---|---|
MONGODB_URI | — | URI completa (prioridade sobre vars individuais) |
MONGODB_HOST | localhost | Host do MongoDB |
MONGODB_PORT | 27017 | Porta |
MONGODB_DB | test | Database padrão |
MONGODB_USER | (vazio) | Utilizador |
MONGODB_PASSWORD | (vazio) | Password |
MONGODB_AUTH_SOURCE | admin | Database de autenticação |
MONGODB_MIN_POOL_SIZE | 2 | Conexões mínimas no pool |
MONGODB_MAX_POOL_SIZE | 10 | Conexões máximas no pool |
MONGODB_SERVER_SELECTION_TIMEOUT | 5000 | Timeout de seleção de servidor (ms) |
MONGODB_ALLOWED_DATABASES | (vazio = todos) | Databases expostos (vírgula separados) |
MONGODB_ALLOW_WRITES | false | Habilita insert/update/delete |
MCP_SERVER_NAME | mongo-mcp | Nome do servidor MCP |
MCP_LOG_LEVEL | INFO | Nível de log (DEBUG, INFO, WARNING, ERROR) |
MCP_TRANSPORT | stdio | Transporte: stdio, sse, streamable-http |
MCP_HOST | 0.0.0.0 | Host do servidor HTTP (só para SSE/streamable-http) |
MCP_PORT | 8080 | Porta do servidor HTTP (só para SSE/streamable-http) |
Execução
# Modo stdio (padrão)
uv run mcp-mongo
# Modo SSE — servidor HTTP na porta 8080
MCP_TRANSPORT=sse uv run mcp-mongo
# Modo desenvolvimento com MCP Inspector
uv run mcp dev src/mcp_mongo/server.py
Capacidades MCP
Tools
Tools são funções que o agente chama activamente para executar operações.
find
Executa um find() em uma collection e retorna os documentos como JSON.
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
database | str | sim | — | Nome do database MongoDB |
collection | str | sim | — | Nome da collection |
filter | dict | não | {} | Filtro MongoDB (ex: {"status": "active"}) |
projection | dict | não | {} | Campos a incluir/excluir (ex: {"name": 1, "_id": 0}) |
sort | list | não | — | Lista de pares [campo, direção] (ex: [["age", -1]]) |
limit | int | não | 100 | Número máximo de documentos |
skip | int | não | 0 | Documentos a saltar (paginação) |
// Exemplo
{
"database": "shop",
"collection": "orders",
"filter": {"status": "pending"},
"sort": [["created_at", -1]],
"limit": 20
}
find_one
Executa um find_one() e retorna o primeiro documento encontrado.
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
database | str | sim | — | Nome do database |
collection | str | sim | — | Nome da collection |
filter | dict | não | {} | Filtro MongoDB |
projection | dict | não | {} | Campos a incluir/excluir |
aggregate
Executa um aggregation pipeline e retorna os resultados como JSON.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
collection | str | sim | Nome da collection |
pipeline | list | sim | Lista de estágios de agregação |
// Exemplo — vendas por categoria
{
"database": "shop",
"collection": "orders",
"pipeline": [
{ "$match": { "status": "completed" } },
{ "$group": { "_id": "$category", "total": { "$sum": "$amount" } } },
{ "$sort": { "total": -1 } }
]
}
count_documents
Conta documentos que correspondem ao filtro.
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
database | str | sim | — | Nome do database |
collection | str | sim | — | Nome da collection |
filter | dict | não | {} | Filtro MongoDB (vazio = conta todos) |
insert_documents
Insere um ou mais documentos. Requer MONGODB_ALLOW_WRITES=true.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
collection | str | sim | Nome da collection |
documents | list | sim | Lista de documentos a inserir |
Retorna os IDs gerados (inserted_id para um, inserted_ids para múltiplos).
update_documents
Atualiza documentos correspondentes ao filtro. Requer MONGODB_ALLOW_WRITES=true.
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
database | str | sim | — | Nome do database |
collection | str | sim | — | Nome da collection |
filter | dict | sim | — | Filtro para selecionar documentos |
update | dict | sim | — | Operação de atualização (ex: {"$set": {...}}) |
upsert | bool | não | false | Cria o documento se não existir |
Retorna matched_count, modified_count e upserted_id.
delete_documents
Remove documentos correspondentes ao filtro. Requer MONGODB_ALLOW_WRITES=true.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
collection | str | sim | Nome da collection |
filter | dict | sim | Filtro para selecionar documentos a remover |
Atenção:
filter: {}remove todos os documentos da collection.
Retorna deleted_count.
list_databases
Lista todos os databases não-sistema disponíveis no servidor MongoDB (admin, local e config são sempre excluídos).
list_collections
Lista collections de um database.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
describe_collection
Infere o esquema de uma collection via amostragem de documentos. Retorna campos, tipos dominantes e frequência de presença.
| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
database | str | sim | — | Nome do database |
collection | str | sim | — | Nome da collection |
sample_size | int | não | 100 | Número de documentos a amostrar |
Exemplo de saída:
[
{ "field": "_id", "dominant_type": "string", "presence_pct": 100.0 },
{ "field": "name", "dominant_type": "string", "presence_pct": 100.0 },
{ "field": "age", "dominant_type": "int", "presence_pct": 98.0 },
{ "field": "address.city", "dominant_type": "string", "presence_pct": 75.0 },
{ "field": "address.zip", "dominant_type": "string", "presence_pct": 60.0 },
{ "field": "tags", "dominant_type": "array", "presence_pct": 45.0 }
]
Campos de documentos embutidos (address.city) são expandidos automaticamente.
list_indexes
Lista os índices de uma collection com unicidade, esparsidade e campos cobertos.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
collection | str | sim | Nome da collection |
get_collection_stats
Retorna estatísticas de uma collection via $collStats (MongoDB 3.6+).
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
database | str | sim | Nome do database |
collection | str | sim | Nome da collection |
Inclui: document_count, size_kb, avg_document_size_bytes, storage_size_kb, index_count, total_index_size_kb.
Resources
Resources expõem dados como URIs navegáveis — o agente lê-os para obter contexto antes de agir.
| URI | Descrição |
|---|---|
mongo://databases | Lista todos os databases não-sistema |
mongo://db/{database}/collections | Lista collections de um database |
mongo://db/{database}/collection/{collection} | Schema inferido + índices + stats de uma collection |
Prompts
Prompts são templates reutilizáveis que guiam o agente numa tarefa complexa.
| Prompt | Parâmetros | Descrição |
|---|---|---|
explore_database | — | Roteiro para explorar um banco MongoDB desconhecido |
analyse_collection | database, collection | Análise detalhada de uma collection |
write_query | question | Gera um find() ou aggregate() a partir de linguagem natural |
write_aggregation | question | Gera um aggregation pipeline para análise de dados |
optimise_query | database, collection, filter_hint | Analisa e sugere optimizações para uma query |
Segurança
| Mecanismo | Detalhe |
|---|---|
| Read-only por padrão | Writes bloqueados por guard em cada método — sem acesso ao banco |
| Databases permitidos | MONGODB_ALLOWED_DATABASES limita a exposição de dados |
| Serialização BSON segura | ObjectId, Decimal128 e outros tipos BSON são convertidos para strings — sem falhas de serialização |
| Logs sanitizados | Password nunca aparece em logs (safe_uri) |
| Erros sanitizados | Exceções retornam mensagem simples ao agente, sem stack trace |
| Pool limitado | max_pool_size=10 por padrão — evita saturar o servidor |
| Ping no startup | Falha imediatamente se as credenciais ou o host estiverem incorrectos |
Para habilitar escritas:
MONGODB_ALLOW_WRITES=true
Testes
Os testes são de integração e requerem uma instância MongoDB acessível. Usam o database temporário test_mcp_tmp, que é criado e destruído automaticamente.
# Todos os testes (usa .env por padrão)
uv run pytest
# Sobrepor a URI para os testes
TEST_MONGODB_URI=mongodb://localhost:27017/test uv run pytest
# Com coverage
uv run pytest --cov=src/mcp_mongo --cov-report=html
# Verbose
uv run pytest -v
Integração com Agentes
Claude Code / Claude Desktop
Adicionar ao ~/.claude.json (user-level, disponível em todos os projetos):
{
"mcpServers": {
"mongo": {
"type": "stdio",
"command": "uv",
"args": [
"--directory", "/caminho/para/mcp-mongo",
"run", "mcp-mongo"
],
"env": {
"MONGODB_URI": "mongodb://user:pass@host:27017/mydb"
}
}
}
}
LangChain / LlamaIndex
Iniciar o servidor em modo SSE:
MCP_TRANSPORT=sse MCP_PORT=8080 uv run mcp-mongo
Conectar a partir do agente:
# LangChain + MCP
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient({
"mongo": {
"url": "http://localhost:8080/sse",
"transport": "sse",
}
})
tools = await client.get_tools()
Agentes HTTP genéricos
Iniciar em modo streamable-http:
MCP_TRANSPORT=streamable-http MCP_PORT=8080 uv run mcp-mongo
Endpoint disponível em http://localhost:8080/mcp.
Docker
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install uv && uv sync
EXPOSE 8080
CMD ["uv", "run", "mcp-mongo"]
docker run -p 8080:8080 \
-e MONGODB_URI=mongodb://user:pass@host:27017/mydb \
-e MCP_TRANSPORT=sse \
mcp-mongo
Decisões de Arquitetura
Conexão dinâmica — MONGODB_URI vs MONGODB_*
MONGODB_URI é o padrão de facto em ambientes cloud (MongoDB Atlas, Railway, Render, etc.) e suporta opções avançadas como replica sets e mongodb+srv. As vars individuais são mais legíveis para desenvolvimento local. O model_validator do Pydantic extrai os campos da URI se fornecida, garantindo que a URI interna está sempre correta independentemente de qual forma foi usada.
Motor em vez de PyMongo síncrono
Motor é o driver oficial async do MongoDB para Python. Construído sobre PyMongo mas com interface asyncio nativa — não é um wrapper de thread pool. Necessário para coexistir com FastMCP que opera em loop de eventos asyncio.
Schema por amostragem — sem $jsonSchema
MongoDB é schemaless por design. A abordagem escolhida ($sample + inferência de tipos) devolve um esquema descritivo de documentos reais sem exigir validação de schema configurada no banco. O presence_pct indica quais campos são obrigatórios na prática vs opcionais, o que é informação mais útil para o agente do que uma definição formal.
Serialização BSON centralizada em _serialize()
Tipos BSON como ObjectId, Decimal128 e datetime não são serializáveis em JSON nativo. A função _serialize() no BaseRepository converte recursivamente todos os valores antes de retornar ao agente, eliminando erros de serialização em qualquer tool ou resource.
Transporte configurável
O protocolo MCP suporta vários transportes. stdio é o padrão para agentes locais (Claude Code lança o processo e comunica por stdin/stdout). Para agentes remotos ou multi-tenant, sse e streamable-http expõem o servidor como um serviço HTTP sem qualquer alteração de código — só muda a variável de ambiente.
src/ layout
Previne que o Python encontre o módulo via path local sem instalação — o que mascararia erros de packaging e tornaria os testes menos fiáveis.
Repository Pattern
Isola as operações Motor das tools MCP. As tools expressam intenção (describe_collection), os repositórios expressam implementação ($sample + inferência). Trocar a estratégia de introspecção não exige tocar nas tools.
Lifespan para o client Motor
Garante que o client abre (e valida com ping) antes do servidor aceitar requests, e fecha sempre ao terminar — mesmo com Ctrl+C ou sinal do OS. Não há risco de conexões a vazar ou de o agente receber requests antes do banco estar pronto.