Exercicio Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Exercicio Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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.
.
├── 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 + LangGraphO projeto utiliza SQLite com uma única tabela principal:
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 como REAL com 2 casas decimais, usando arredondamento half-up no momento da inserção.uv add fastmcpPara utilizar o agente de exemplo (sample_agent.py), instale também:
uv add langchain-openai langchain-mcp-adapters langgraph python-dotenvpython database.py# Coloque o arquivo CSV exportado do Nubank na raiz do projeto:
# extrato_nubank_05_2026.csv
python import_csv.pypython mcp_server.pyO 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:
python mcp_server.py como subprocesso.tools, resources) via protocolo MCP pelo stdout.Quando o client decide chamar cada ferramenta/recurso:
resumo_financeiro_atual (recurso) para orientar o raciocínio antes de responder perguntas sobre saldo ou categorias.registrar_transacao quando o usuário pede para registrar, lançar ou salvar uma transação.listar_transacoes quando o usuário pede consultas, históricos ou totais por período/categoria.registrar_transacaoRegistra 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 envieamountnegativo 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.
listar_transacoesLista 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.
resumo_financeiro_atualURI: 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:
listar_transacoes com filtros mais específicos.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:
despesareceitaTransaçõ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.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:
resumo_financeiro_atual para ter contexto geral antes de filtrar.listar_transacoes com filtros de período e categoria.registrar_transacao com os dados fornecidos.Passo 1 — Consulta ao recurso `resumo_financeiro_atual`
GET finance://resumo_financeiro_atualResposta 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. ✅"
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.
Crie um arquivo .env na raiz do projeto:
OPENAI_API_KEY=sua_chave_aquipython sample_agent.pyExemplo 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,84Para 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.
finance.db publicamente.WARNING ou superior.finance.db tenha permissões restritas ao usuário do sistema que executa o servidor (chmod 600 finance.db)..env com chaves de API no repositório. Adicione-o ao .gitignore.date é armazenado como texto em formato YYYY-MM-DD (ISO 8601). Entradas no formato DD/MM/YYYY (como as do CSV do Nubank) são convertidas internamente. O client deve sempre enviar datas em ISO 8601.resumo_financeiro_atual para ver as categorias já existentes antes de registrar uma nova transação.identifier garante que a mesma transação não seja inserida duas vezes (INSERT OR IGNORE). Ao importar extratos, use sempre o ID original do banco como identifier.DB_BUSY.finance.db é criado automaticamente na raiz do projeto ao executar database.py ou mcp_server.py.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.