MCP Hub
Back to servers

mcp-postgres

Enables AI agents to execute SQL queries and introspect PostgreSQL schemas, tables, and indexes with read-only safety by default. Supports optional write operations and works with Claude, LangChain, and other agents via stdio or HTTP transports.

glama
Updated
Apr 3, 2026

mcp-postgres

MCP Server com acesso a PostgreSQL — Clean Architecture, Repository Pattern, asyncpg.

Compatível com qualquer agente MCP: Claude Code, Claude Desktop, LangChain, LlamaIndex e outros via HTTP.


Índice


Visão Geral

Este servidor implementa o Model Context Protocol (MCP) para expor um banco de dados PostgreSQL a modelos de linguagem e agentes de IA.

O agente pode:

  • Executar queries SQL de leitura
  • Inspecionar schemas, tabelas, índices e foreign keys
  • Obter estatísticas de tabelas
  • Executar operações de escrita (quando explicitamente habilitado)

O servidor é read-only por padrão e funciona com qualquer banco PostgreSQL — basta mudar o .env ou a variável DATABASE_URL.


Arquitetura

┌─────────────────────────────────────────────────────────┐
│              Agente (Claude / LangChain / …)            │
└────────────────────────┬────────────────────────────────┘
                         │ MCP Protocol
                    stdio │ ou HTTP (SSE / streamable-http)
┌────────────────────────▼────────────────────────────────┐
│                    MCP Server (FastMCP)                  │
│                                                         │
│   ┌──────────┐   ┌───────────┐   ┌──────────────────┐  │
│   │  Tools   │   │ Resources │   │    Prompts       │  │
│   └────┬─────┘   └─────┬─────┘   └──────────────────┘  │
│        │               │                                │
│   ┌────▼───────────────▼────────────────────────────┐   │
│   │              Repositories                       │   │
│   │   BaseRepository → QueryRepository              │   │
│   │                  → SchemaRepository             │   │
│   └────────────────────┬────────────────────────────┘   │
│                        │                                │
│   ┌────────────────────▼────────────────────────────┐   │
│   │           Database (asyncpg Pool)               │   │
│   └────────────────────┬────────────────────────────┘   │
│                        │                                │
│   ┌────────────────────▼────────────────────────────┐   │
│   │         Config (Pydantic Settings + .env)       │   │
│   └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
                         │ TCP
┌────────────────────────▼────────────────────────────────┐
│                     PostgreSQL                          │
└─────────────────────────────────────────────────────────┘

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-postgres/
│
├── .env                             # Configuração activa (não commitado)
├── .env.example                     # Template documentado de todas as variáveis
├── pyproject.toml                   # Dependências, scripts, ruff, mypy, pytest
├── .gitignore
├── claude_mcp_config.json           # Config pronta para Claude Desktop / Claude Code
│
├── src/
│   └── mcp_postgres/
│       ├── __init__.py
│       ├── server.py                # Entry point: cria FastMCP e selecciona transporte
│       │
│       ├── config/
│       │   ├── __init__.py
│       │   └── settings.py          # Pydantic Settings — DATABASE_URL ou POSTGRES_*
│       │
│       ├── database/
│       │   ├── __init__.py
│       │   └── connection.py        # Singleton pool asyncpg + context managers
│       │
│       ├── repositories/
│       │   ├── __init__.py
│       │   ├── base.py              # fetch_all, fetch_one, execute, transaction
│       │   ├── query_repository.py  # SQL arbitrário com guard de writes
│       │   └── schema_repository.py # Introspection: tabelas, colunas, índices, FK, stats
│       │
│       ├── tools/
│       │   ├── __init__.py
│       │   ├── query_tools.py       # execute_query, execute_query_one, execute_statement
│       │   └── schema_tools.py      # list_schemas/tables/indexes/fks, get_table_stats
│       │
│       ├── resources/
│       │   ├── __init__.py
│       │   └── schema_resources.py  # URIs: postgres://schema/…
│       │
│       └── prompts/
│           ├── __init__.py
│           └── sql_prompts.py       # explore_database, analyse_table, write_query, optimise_query
│
└── tests/
    ├── __init__.py
    ├── conftest.py
    └── tools/
        ├── test_query_repository.py
        └── test_schema_repository.py

Instalação

Pré-requisitos: Python 3.11+, uv, PostgreSQL acessível.

cd mcp-postgres

# 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.example .env
# editar .env 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 — DATABASE_URL (tem prioridade)

Uma única variável com o DSN completo:

DATABASE_URL=postgresql://user:password@host:5432/dbname

Opção B — variáveis individuais

POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=mydb
POSTGRES_USER=postgres
POSTGRES_PASSWORD=secret

Se DATABASE_URL estiver definida, os valores de POSTGRES_HOST, POSTGRES_PORT, etc., são ignorados. Caso contrário, as vars individuais são usadas. Se nenhuma for fornecida, o servidor tenta ligar a localhost:5432/postgres.

Transporte MCP

A variável MCP_TRANSPORT define como o servidor comunica com o agente:

ValorProtocoloEndpointIndicado para
stdio (padrão)stdin/stdoutClaude Code, Claude Desktop, agentes locais
sseHTTP Server-Sent Eventshttp://host:port/sseLangChain, LlamaIndex, agentes HTTP legados
streamable-httpHTTP streaminghttp://host:port/mcpAgentes 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ávelPadrãoDescrição
DATABASE_URLDSN completo (prioridade sobre vars individuais)
POSTGRES_HOSTlocalhostHost do PostgreSQL
POSTGRES_PORT5432Porta
POSTGRES_DBpostgresNome do banco de dados
POSTGRES_USERpostgresUtilizador
POSTGRES_PASSWORD(vazio)Password
POSTGRES_MIN_POOL_SIZE2Conexões mínimas no pool
POSTGRES_MAX_POOL_SIZE10Conexões máximas no pool
POSTGRES_COMMAND_TIMEOUT60Timeout de comando em segundos
POSTGRES_ALLOWED_SCHEMASpublicSchemas expostos (vírgula; vazio = todos)
POSTGRES_ALLOW_WRITESfalseHabilita INSERT/UPDATE/DELETE/DDL
MCP_SERVER_NAMEpostgres-mcpNome do servidor MCP
MCP_LOG_LEVELINFONível de log (DEBUG, INFO, WARNING, ERROR)
MCP_TRANSPORTstdioTransporte: stdio, sse, streamable-http
MCP_HOST0.0.0.0Host do servidor HTTP (só para SSE/streamable-http)
MCP_PORT8080Porta do servidor HTTP (só para SSE/streamable-http)

Execução

# Modo stdio (padrão)
uv run mcp-postgres

# Modo SSE — servidor HTTP na porta 8080
MCP_TRANSPORT=sse uv run mcp-postgres

# Modo desenvolvimento com MCP Inspector
uv run mcp dev src/mcp_postgres/server.py

Capacidades MCP

Tools

Tools são funções que o agente chama activamente para executar operações.


execute_query

Executa uma query SELECT e retorna os resultados como JSON.

ParâmetroTipoObrigatórioDescrição
sqlstrsimQuery SQL a executar
paramslistnãoParâmetros posicionais ($1, $2, …)
-- Exemplo com parâmetro
SELECT id, name FROM users WHERE active = $1
params: [true]

execute_query_one

Executa uma query e retorna apenas o primeiro registo.

ParâmetroTipoObrigatórioDescrição
sqlstrsimQuery SQL
paramslistnãoParâmetros posicionais

execute_statement

Executa um statement de escrita. Requer POSTGRES_ALLOW_WRITES=true.

ParâmetroTipoObrigatórioDescrição
sqlstrsimINSERT / UPDATE / DELETE / DDL
paramslistnãoParâmetros posicionais

Retorna o command tag do PostgreSQL (ex: UPDATE 3).


list_schemas

Lista todos os schemas não-sistema do banco.


list_tables

Lista tabelas e views de um schema.

ParâmetroTipoPadrãoDescrição
schemastrpublicNome do schema

describe_table

Retorna as definições de colunas de uma tabela.

ParâmetroTipoPadrãoDescrição
tablestrNome da tabela
schemastrpublicNome do schema

list_indexes

Lista os índices de uma tabela com unicidade e colunas cobertas.

ParâmetroTipoPadrãoDescrição
tablestrNome da tabela
schemastrpublicNome do schema

list_foreign_keys

Lista as foreign keys de uma tabela.

ParâmetroTipoPadrãoDescrição
tablestrNome da tabela
schemastrpublicNome do schema

get_table_stats

Retorna estatísticas operacionais via pg_stat_user_tables.

ParâmetroTipoPadrãoDescrição
tablestrNome da tabela
schemastrpublicNome do schema

Inclui: live_rows, dead_rows, last_vacuum, last_analyze, total_size.


Resources

Resources expõem dados como URIs navegáveis — o agente lê-os para obter contexto antes de agir.

URIDescrição
postgres://schemasLista todos os schemas do banco
postgres://schema/{schema}/tablesLista tabelas de um schema
postgres://schema/{schema}/table/{table}Colunas + índices + FK + stats de uma tabela

Prompts

Prompts são templates reutilizáveis que guiam o agente numa tarefa complexa.

PromptParâmetrosDescrição
explore_databaseRoteiro para explorar um banco desconhecido
analyse_tabletable, schemaAnálise detalhada de uma tabela
write_queryquestionGera SQL a partir de linguagem natural
optimise_querysqlAnalisa e optimiza uma query existente

Segurança

MecanismoDetalhe
Read-only por padrãoWrites bloqueados via regex antes de qualquer acesso ao banco
Schemas permitidosPOSTGRES_ALLOWED_SCHEMAS limita a exposição
Queries parametrizadasTodos os inputs são $1, $2 — sem interpolação de strings
Logs sanitizadosPassword nunca aparece em logs (safe_dsn)
Erros sanitizadosExceções retornam mensagem simples ao agente, sem stack trace
Pool limitadomax_pool_size=10 por padrão — evita saturar o banco

Para habilitar escritas:

POSTGRES_ALLOW_WRITES=true

Testes

Os testes são de integração e requerem uma instância PostgreSQL acessível. Configura o .env antes de correr.

# Todos os testes
uv run pytest

# Com coverage
uv run pytest --cov=src/mcp_postgres --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": {
    "postgres": {
      "type": "stdio",
      "command": "uv",
      "args": [
        "--directory", "/caminho/para/mcp-postgres",
        "run", "mcp-postgres"
      ],
      "env": {
        "DATABASE_URL": "postgresql://user:pass@host:5432/db"
      }
    }
  }
}

Ou usar o ficheiro claude_mcp_config.json incluído no projeto como referência.


LangChain / LlamaIndex

Iniciar o servidor em modo SSE:

MCP_TRANSPORT=sse MCP_PORT=8080 uv run mcp-postgres

Conectar a partir do agente:

# LangChain + MCP
from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient({
    "postgres": {
        "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-postgres

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-postgres"]
docker run -p 8080:8080 \
  -e DATABASE_URL=postgresql://user:pass@host:5432/db \
  -e MCP_TRANSPORT=sse \
  mcp-postgres

Decisões de Arquitetura

Conexão dinâmica — DATABASE_URL vs POSTGRES_*

DATABASE_URL é o padrão de facto em ambientes cloud (Heroku, Railway, Render, etc.). As vars individuais são mais legíveis para desenvolvimento local. O model_validator do Pydantic extrai os campos do DSN se fornecido, garantindo que o dsn interno está sempre correcto independentemente de qual forma foi usada.

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 o SQL das tools MCP. As tools expressam intenção (list_tables), os repositórios expressam implementação (query contra information_schema). Trocar o banco ou reescrever uma query não exige tocar nas tools.

asyncpg em vez de psycopg2/3

Construído especificamente para asyncio — não é um wrapper sobre uma biblioteca síncrona. Em workloads com múltiplas queries concorrentes, a diferença de performance é significativa. O pool reutiliza conexões TCP e prepara statements automaticamente.

Lifespan para o pool

Garante que o pool abre 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.

Reviews

No reviews yet

Sign in to write a review