Finanpy
MCP server for personal finance management that connects a SQLite database to any MCP client, allowing users to register, query, and analyze financial transactions through natural language.
README
💰 Finanpy — MCP Server de Finanças Pessoais
Finanpy é um servidor MCP (Model Context Protocol) para análise e gestão de finanças pessoais. Ele conecta um banco de dados SQLite a qualquer cliente MCP compatível, permitindo registrar, consultar e analisar transações financeiras através de linguagem natural.
📁 Estrutura do Projeto
.
├── finance.db # Banco de dados SQLite com as transações
├── database.py # Camada de acesso ao banco de dados
├── mcp_server.py # Servidor MCP com as ferramentas expostas
├── import_csv.py # Script para importar extratos do Nubank (CSV)
└── sample_agent.py # Agente de exemplo com LangChain + LangGraph
🗄️ Banco de Dados
O projeto utiliza SQLite com uma única tabela principal:
Tabela transactions
| Coluna | Tipo | Descrição |
|---|---|---|
id |
INTEGER | Chave primária, autoincremento |
identifier |
TEXT | Identificador único da transação (evita duplicatas) |
type |
TEXT | Tipo da transação: receita ou despesa |
amount |
REAL | Valor da transação (negativo para despesas) |
category |
TEXT | Categoria da transação (padrão: sem categoria) |
description |
TEXT | Descrição ou histórico da transação |
date |
TEXT | Data da transação em ISO 8601: YYYY-MM-DD |
Timezone: todas as datas são armazenadas em horário local (America/Sao_Paulo). Não há offset UTC explícito no banco.
Arredondamento: valores monetários são armazenados comoREALcom 2 casas decimais, usando arredondamento half-up no momento da inserção.
⚙️ Instalação
Pré-requisitos
- Python 3.10+
- uv
Dependências
uv add fastmcp
Para utilizar o agente de exemplo (sample_agent.py), instale também:
uv add langchain-openai langchain-mcp-adapters langgraph python-dotenv
Configuração
- Clone o repositório.
- Inicialize o banco de dados:
python database.py
- (Opcional) Importe um extrato do Nubank:
# Coloque o arquivo CSV exportado do Nubank na raiz do projeto:
# extrato_nubank_05_2026.csv
python import_csv.py
🚀 Executando o Servidor MCP
python mcp_server.py
Transporte STDIO
O Finanpy utiliza transporte STDIO: o cliente MCP inicia o servidor como um processo filho e se comunica com ele via stdin/stdout usando o protocolo MCP. Não há porta de rede envolvida.
Fluxo de inicialização:
- O client executa
python mcp_server.pycomo subprocesso. - O servidor anuncia suas capacidades (
tools,resources) via protocolo MCP pelostdout. - O client recebe o manifesto e passa a chamar ferramentas ou consultar recursos conforme necessário.
- O processo do servidor vive enquanto o client estiver ativo e é encerrado junto com ele.
Quando o client decide chamar cada ferramenta/recurso:
- Consulta
resumo_financeiro_atual(recurso) para orientar o raciocínio antes de responder perguntas sobre saldo ou categorias. - Chama
registrar_transacaoquando o usuário pede para registrar, lançar ou salvar uma transação. - Chama
listar_transacoesquando o usuário pede consultas, históricos ou totais por período/categoria.
🔧 Ferramentas e Recursos MCP
Ferramenta 1 — registrar_transacao
Registra uma nova transação financeira no banco de dados de forma idempotente.
Entradas:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
type |
string | ✅ | "receita" ou "despesa" |
amount |
float | ✅ | Valor absoluto da transação (sempre positivo; o sinal é inferido do type) |
category |
string | ✅ | Categoria (ex: "alimentacao", "transporte", "moradia") |
description |
string | ✅ | Texto livre descrevendo a transação |
date |
string | ❌ | Data em ISO 8601 YYYY-MM-DD (padrão: data atual) |
identifier |
string | ❌ | UUID ou chave externa para idempotência (ex: ID do extrato bancário) |
Saída (sucesso):
{
"sucesso": true,
"id": 42,
"normalizado": {
"amount": 73.90,
"date": "2026-06-23",
"type": "despesa"
},
"avisos": []
}
Saída (duplicata detectada):
{
"sucesso": false,
"code": "DUPLICATE",
"id_existente": 17,
"mensagem": "Transação com este identifier já existe."
}
Erros e limites:
| Código | Causa | O que o client deve fazer |
|---|---|---|
INVALID_DATE |
Data fora do formato ISO 8601 ou data futura | Corrigir o formato para YYYY-MM-DD antes de reenviar |
DUPLICATE |
identifier já existe no banco |
Informar o usuário; não reenviar |
BAD_TYPE |
type diferente de "receita" ou "despesa" |
Normalizar para um dos dois valores antes de reenviar |
INVALID_AMOUNT |
amount negativo, zero ou não numérico |
Solicitar o valor correto ao usuário; nunca inferir |
DB_BUSY |
SQLite travado por operação concorrente | Retry com backoff exponencial: 200ms, 400ms, 800ms (máx. 3x) |
MISSING_FIELD |
Campo obrigatório ausente | Solicitar o campo faltante ao usuário antes de reenviar |
Atenção — sinal vs. tipo: nunca envie
amountnegativo comtype="despesa". O servidor armazena despesas com sinal negativo internamente; a entrada esperada é sempre o valor absoluto. Se o client receberamountnegativo do usuário junto comtype="despesa", deve aplicarabs(amount)antes de chamar a ferramenta.
Ferramenta 2 — listar_transacoes
Lista e filtra transações financeiras armazenadas no banco.
Entradas:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
period |
string | ❌ | Período no formato YYYY-MM (ex: "2026-05") |
category |
string | ❌ | Filtra pelo nome exato da categoria |
type |
string | ❌ | "receita" ou "despesa" |
Saída (sucesso):
[
{
"id": 1,
"identifier": "69fa0c39-ca20-4683-849a-85519872249a",
"type": "receita",
"amount": 50.0,
"category": "sem categoria",
"description": "Resgate RDB",
"date": "2026-05-05"
}
]
Retorna uma lista vazia [] quando nenhum registro corresponde aos filtros (não é um erro).
Erros e limites:
| Código | Causa | O que o client deve fazer |
|---|---|---|
INVALID_PERIOD |
Formato de período inválido (ex: "05-2026") |
Corrigir para YYYY-MM antes de reenviar |
BAD_TYPE |
type diferente de "receita" ou "despesa" |
Normalizar antes de reenviar |
DB_BUSY |
SQLite travado por operação concorrente | Retry com backoff exponencial: 200ms, 400ms, 800ms (máx. 3x) |
Janela recomendada: evite consultar períodos superiores a 12 meses sem filtro de categoria, pois o retorno pode ser extenso. Prefira decompor em múltiplas chamadas mensais se necessário.
Recurso MCP — resumo_financeiro_atual
URI: finance://resumo_financeiro_atual
Recurso somente-leitura que retorna um snapshot consolidado das finanças do mês corrente. Diferente das ferramentas (que executam ações), este recurso é consultado pelo agente para orientar seu raciocínio antes de responder perguntas sobre saldo, categorias e situação financeira geral — evitando chamadas desnecessárias a listar_transacoes.
Saída:
{
"period": "2026-06",
"total_income": 9947.94,
"total_expense": 9947.94,
"balance": 0.0,
"expenses_by_category": {
"sem categoria": 9947.94
}
}
Quando o client deve consultá-lo:
- Antes de responder qualquer pergunta sobre saldo atual, total gasto ou total recebido no mês.
- Para verificar se há dados suficientes antes de sugerir categorias ao usuário.
- Como ponto de partida para decidir se é necessário chamar
listar_transacoescom filtros mais específicos.
📥 Importação de Extrato do Nubank
O script import_csv.py importa automaticamente transações a partir do CSV exportado pelo aplicativo do Nubank.
Formato esperado do CSV:
| Data | Valor | Identificador | Descrição |
|---|---|---|---|
| 05/05/2026 | -50.00 | 69fa0c7e-... | Transferência Pix |
| 06/05/2026 | 188.03 | 69fbee60-... | Resgate RDB |
O tipo da transação é derivado automaticamente pelo sinal do valor:
- Valor negativo →
despesa - Valor positivo →
receita
Transações com identifier já existente são ignoradas automaticamente (idempotência via INSERT OR IGNORE).
Categorias: todas as transações importadas via CSV chegam como
"sem categoria". Use o agente para categorizá-las após a importação.
🔄 Cenário de Uso Ponta a Ponta
Mensagem do usuário:
"Quanto gastei em alimentação em maio de 2026? E registra aí um Uber de R$ 73,90 que peguei hoje."
Raciocínio do agente:
- A pergunta envolve o mês atual — consultar o recurso
resumo_financeiro_atualpara ter contexto geral antes de filtrar. - Para o total de alimentação em maio, chamar
listar_transacoescom filtros de período e categoria. - Para registrar o Uber, chamar
registrar_transacaocom os dados fornecidos.
Passo 1 — Consulta ao recurso resumo_financeiro_atual
GET finance://resumo_financeiro_atual
Resposta do servidor:
{
"period": "2026-06",
"total_income": 1835.29,
"total_expense": 462.75,
"balance": 1372.54,
"expenses_by_category": {
"sem categoria": 462.75
}
}
O agente identifica que o mês atual é junho — a pergunta é sobre maio, então precisa de uma chamada específica.
Passo 2 — Chamada à ferramenta listar_transacoes
{
"period": "2026-05",
"category": "alimentacao",
"type": "despesa"
}
Resposta do servidor:
[
{
"id": 8,
"identifier": "nubank-2026-05-12-ifood",
"type": "despesa",
"amount": -49.90,
"category": "alimentacao",
"description": "iFood - Pizza",
"date": "2026-05-12"
},
{
"id": 15,
"identifier": "nubank-2026-05-22-mercado",
"type": "despesa",
"amount": -312.40,
"category": "alimentacao",
"description": "Mercado Extra",
"date": "2026-05-22"
}
]
Total calculado pelo agente: R$ 362,30.
Passo 3 — Chamada à ferramenta registrar_transacao
{
"type": "despesa",
"amount": 73.90,
"category": "transporte",
"description": "Uber",
"date": "2026-06-23",
"identifier": "manual-2026-06-23-uber-001"
}
Resposta do servidor:
{
"sucesso": true,
"id": 27,
"normalizado": {
"amount": 73.90,
"date": "2026-06-23",
"type": "despesa"
},
"avisos": []
}
Resposta final ao usuário:
"Em maio de 2026 você gastou R$ 362,30 em alimentação (iFood R$ 49,90 + Mercado Extra R$ 312,40). Sua despesa de Uber de R$ 73,90 foi registrada em transporte para hoje, 23/06/2026. ✅"
🤖 Agente de Exemplo
O arquivo sample_agent.py demonstra como integrar o servidor MCP com um agente LangChain + LangGraph usando GPT-4o-mini como modelo de linguagem, via transporte STDIO.
Configuração
Crie um arquivo .env na raiz do projeto:
OPENAI_API_KEY=sua_chave_aqui
Executando o agente
python sample_agent.py
Exemplo de interação real:
Finanpy - Assistente Financeiro Pessoal
Digite 'sair' para encerrar.
Você: Poderia categorizar as minhas transações realizadas? E também fazer uma somatória transacionada para cada categoria?
Finanpy: processando...
Finanpy: Aqui está a categorização das suas transações e a somatória para cada categoria:
### Receitas
1. Resgate RDB: R$ 50,00
2. Resgate RDB: R$ 188,03
...
**Total de Receitas**: R$ 9.882,74
### Despesas
1. Transferência enviada pelo Pix: R$ -50,00
...
**Total de Despesas**: R$ -10.188,84
🧩 Integração com Claude Desktop
Para usar o Finanpy diretamente no Claude Desktop, adicione ao arquivo de configuração do MCP (claude_desktop_config.json):
{
"mcpServers": {
"finanpy": {
"command": "python",
"args": ["/caminho/absoluto/para/mcp_server.py"]
}
}
}
O campo
"transport"pode ser omitido — o Claude Desktop usa STDIO por padrão. Use o caminho absoluto para omcp_server.pypara evitar erros de working directory.
Após reiniciar o Claude Desktop, as ferramentas e recursos do Finanpy estarão disponíveis automaticamente.
🔒 Segurança e Privacidade
- Dados sensíveis (PII): o banco contém informações financeiras pessoais, incluindo descrições de transações que podem conter nomes de pessoas (ex: transferências Pix). Não compartilhe o arquivo
finance.dbpublicamente. - Logs: evite ativar logging detalhado em produção, pois descrições de transações podem aparecer nos logs. Em desenvolvimento, use nível
WARNINGou superior. - Acesso ao banco: o SQLite não tem autenticação nativa. Garanta que o arquivo
finance.dbtenha permissões restritas ao usuário do sistema que executa o servidor (chmod 600 finance.db). - Variáveis de ambiente: nunca comite o arquivo
.envcom chaves de API no repositório. Adicione-o ao.gitignore.
📌 Observações Técnicas
- Datas: o campo
dateé armazenado como texto em formatoYYYY-MM-DD(ISO 8601). Entradas no formatoDD/MM/YYYY(como as do CSV do Nubank) são convertidas internamente. O client deve sempre enviar datas em ISO 8601. - Categorias: não há validação de categoria no servidor — qualquer string é aceita. Para padronizar, consulte o recurso
resumo_financeiro_atualpara ver as categorias já existentes antes de registrar uma nova transação. - Idempotência: o campo
identifiergarante que a mesma transação não seja inserida duas vezes (INSERT OR IGNORE). Ao importar extratos, use sempre o ID original do banco comoidentifier. - Concorrência: SQLite não suporta múltiplos escritores simultâneos. Se múltiplos agentes estiverem ativos, implemente retry com backoff exponencial em caso de
DB_BUSY. - Banco de dados: o arquivo
finance.dbé criado automaticamente na raiz do projeto ao executardatabase.pyoumcp_server.py.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.