MainBook Bank Statement Converter

Converta extratos bancários em PDF para Excel, CSV ou JSON verificados, com validação de saldo.

Documentação

Conversor de Extratos Bancários MainBook

PyPI Python License: MIT

Um servidor MCP financeiro focado em uma única tarefa: transformar extratos bancários em PDF em JSON, Excel ou CSV revisados — não é um MCP de contabilidade geral. Ele roda localmente após um mainbook-mcp auth login, ou pelo endpoint hospedado da MainBook em https://mcp.mainbook.ai/mcp, onde seu cliente faz login com sua conta MainBook. Chaves de API mb_live_ existentes continuam funcionando para scripts e clientes mais antigos.

Aponte seu assistente para um extrato e peça uma planilha. O PDF vai para MainBook, que extrai cada transação, normaliza datas para YYYY-MM-DD, mantém valores como quantias exatas e re-soma o extrato para que opening balance + credits − debits tenha que bater com o saldo final. Linhas que não se encaixam são sinalizadas em vez de serem repassadas silenciosamente.

> Convert ~/Downloads/march-statement.pdf and save the Excel next to it.

  mainbook - convert_bank_statement (MCP)
  63 transactions · 4 pages · 4 credits
  Totals reconciled against the statement
  Saved to ~/Downloads/march-statement.xlsx

Done — 63 transactions. Opening 4,127.50 and closing 3,881.05 both match
the statement, and nothing was flagged.

O que não é

Ele não conecta a contas bancárias e não é uma API de Open Banking ou de dados bancários. Ele lê arquivos de extrato que você já possui. Nada é coletado e nenhuma credencial bancária está envolvida.

O que você precisa

Uma conta MainBook e as pastas que contêm seus extratos. A conversão é a única ferramenta que gasta créditos de página. Das outras quatro, get_balance e list_conversions apenas leem, get_conversion pode gravar um arquivo de resultado e output_folder altera uma preferência local; nenhuma delas altera qualquer coisa na sua conta MainBook.

Adicione ao seu cliente

Faça login uma vez pelo terminal:

uvx mainbook-mcp auth login

O comando abre a MainBook no seu navegador, mostra o mesmo código curto em ambos os lugares e aguarda sua aprovação. Ele armazena a credencial no chaveiro do sistema operacional quando o pacote opcional keyring está instalado e funcionando. Caso contrário, ele usa ~/.config/mainbook/credentials.json com permissões privadas de diretório e arquivo. Use mainbook-mcp auth status para verificar a credencial ativa no lado do servidor sem gastar créditos de página. mainbook-mcp auth logout revoga essa chave armazenada primeiro e depois remove a cópia local; se a MainBook não puder ser alcançada, ele informa claramente que a chave pode ainda estar ativa. Fazer login novamente revoga a chave armazenada anteriormente antes de salvar a substituta. A resposta do token do dispositivo não inclui e-mail ou ID de conta, então o status informa que a identidade da conta não foi fornecida, em vez de adivinhar.

Depois, adicione uma entrada à configuração MCP do seu cliente. Este é o mesmo bloco para Claude Desktop (Configurações → Desenvolvedor → Editar Config), Claude Code e Cursor; nenhuma chave é copiada nele:

{
  "mcpServers": {
    "mainbook": {
      "command": "uvx",
      "args": ["mainbook-mcp", "~/Downloads", "~/Desktop", "~/Documents"]
    }
  }
}

O Codex lê TOML, então coloque o mesmo conteúdo em ~/.codex/config.toml:

[mcp_servers.mainbook]
command = "uvx"
args = ["mainbook-mcp", "~/Downloads", "~/Desktop", "~/Documents"]

uvx vem com uv; instale uma vez com brew install uv ou curl -LsSf https://astral.sh/uv/install.sh | sh. Ele busca e executa o pacote publicado, então não há nada para baixar manualmente e nada para atualizar. Se preferir não adicionar uv, execute pip install mainbook-mcp e use "command": "mainbook-mcp" com os mesmos argumentos — você mesmo faz a atualização com pip install -U mainbook-mcp.

Os argumentos de pasta são os únicos locais onde o servidor pode ler um extrato ou gravar um resultado; qualquer coisa fora deles é recusada. MAINBOOK_ALLOWED_DIRS define a mesma lista pelo ambiente, separada pelo os.pathsep da plataforma (: no macOS/Linux, ; no Windows).

Chave de API manual para scripts e CI

MAINBOOK_API_KEY tem precedência sobre qualquer login armazenado. Mantenha o método manual para automação onde um navegador interativo não está disponível. auth login avisa quando esta variável continuará sobrescrevendo a credencial recém-armazenada:

export MAINBOOK_API_KEY="mb_live_REPLACE_ME"
mainbook-mcp

Crie e revogue chaves manuais em https://mainbook.ai/developer. Nunca as envie para repositórios.

Claude Desktop, sem tocar em arquivo de configuração

O Claude Desktop também aceita um pacote de arquivo único: Extensões → Instalar Extensão… e escolha mainbook.mcpb. Ele pede a chave de API e as pastas em uma caixa de diálogo e gerencia seu próprio runtime Python, então nada precisa ser instalado antes. O bloco de configuração acima faz o mesmo trabalho e é a melhor opção se você já mantém outros servidores lá. Crie o pacote a partir deste diretório com:

npx --yes @anthropic-ai/mcpb@2.1.2 validate manifest.json
npx --yes @anthropic-ai/mcpb@2.1.2 pack . dist/mainbook.mcpb

O que ele expõe

  • convert_bank_statement: cria um job pago de créditos de página, envia um PDF, inicia a conversão, faz polling por até 30-900 segundos e retorna o resultado revisado. JSON permanece inline. No modo stdio local, bytes XLSX/CSV são gravados em disco e apenas o caminho completo entra no contexto do modelo.
  • get_conversion: verifica um job após um timeout e retorna JSON inline ou grava XLSX/CSV em um destino local escolhido.
  • list_conversions: retorna uma página de cursor de jobs da conta mais next_cursor.
  • get_balance: retorna créditos total, reservado e disponível, todos medidos em páginas de PDF.
  • output_folder: lê ou altera a pasta de resultados local padrão.

O modo stdio local lista todas as cinco ferramentas. O modo HTTP hospedado lista exatamente as quatro primeiras; output_folder não é anunciado remotamente porque o disco do servidor não pertence ao cliente.

Não há ferramentas para comprar créditos, pagamentos, excluir jobs ou alterar dados da conta. Ferramentas que podem criar uma conversão, gravar um arquivo de resultado local ou alterar a preferência de saída são marcadas como não somente leitura. get_conversion é somente leitura em HTTP hospedado, onde não grava arquivo, e não somente leitura em stdio local, onde pode gravar XLSX ou CSV. Nenhuma é marcada como destrutiva porque arquivos de resultado existentes nunca são substituídos.

Para onde vão os arquivos de resultado

Para clientes stdio locais (Claude Desktop, Claude Code, Cursor e Codex), resultados XLSX e CSV são gravados no primeiro destino disponível nesta ordem:

  1. output_path fornecido a convert_bank_statement ou get_conversion (um nome de arquivo absoluto ou uma pasta existente);
  2. a pasta lembrada por output_folder;
  3. ao lado do PDF de origem, com o mesmo nome base e a extensão do resultado.

get_conversion não consegue inferir a pasta do PDF original. Sem output_path ou uma pasta lembrada válida, ele retorna um erro claro em vez de adivinhar um destino. Toda resposta de arquivo bem-sucedida contém o caminho absoluto e explica qual regra o selecionou. Arquivos existentes nunca são substituídos: statement.xlsx é seguido por statement (2).xlsx, depois (3), e assim por diante.

Peça ao cliente para chamar output_folder sem argumento para ver a configuração atual e todas as pastas permitidas. Defina com um diretório absoluto permitido, ou passe next_to_source para restaurar o padrão. A preferência é compartilhada por clientes locais na mesma máquina em ~/.mainbook/preferences.json. Uma pasta salva que está ausente ou não é mais permitida é ignorada, e essa queda é informada no resultado.

JSON permanece inline. Ele também é gravado em um arquivo .json apenas quando um output_path explícito é fornecido. No modo HTTP remoto, caminhos locais e output_folder não estão disponíveis, porque o disco do servidor não pertence ao cliente. XLSX/CSV retorna como um link de download único que expira em dez minutos quando você fez login via OAuth, e como uma instrução de download REST quando você autenticou com uma chave mb_live_ legada.

Requisitos manuais e instalação

  • Python 3.11 ou mais recente
  • Uma conta MainBook

A partir deste diretório:

python3 -m venv .venv
.venv/bin/python -m pip install .

Para preferir o chaveiro do sistema operacional em vez do fallback JSON privado, instale o extra opcional em todo ambiente que executa o comando de login ou o servidor local:

.venv/bin/python -m pip install '.[keyring]'

Use uma instalação simples, não pip install -e .. Neste checkout, a instalação editável grava um arquivo .pth que o interpretador não reconhece, então python -m mainbook_mcp falha com "No module named mainbook_mcp" enquanto o pacote parece instalado. Um arquivo idêntico com outro nome é honrado, então o conteúdo está correto e a causa ainda não foi explicada — uma instalação simples contorna isso completamente.

Se você usa o método manual para automação, mantenha valores de mb_live_... em um ambiente secreto ou configuração do cliente. Nunca os envie para repositórios.

Modo HTTP Streamable

A MainBook executa este servidor para você em https://mcp.mainbook.ai/mcp, então um cliente que fala MCP remoto não precisa instalar nada. Cole essa URL no claude.ai, Claude Desktop, ChatGPT ou Cursor e faça login com sua conta MainBook quando o cliente pedir; nenhuma chave é copiada na configuração. O Cursor usa um ID de cliente fixo em vez de se registrar, então dê a ele este bloco:

{
  "mcpServers": {
    "mainbook": {
      "url": "https://mcp.mainbook.ai/mcp",
      "auth": {
        "CLIENT_ID": "mainbook-cursor",
        "scopes": ["mainbook:read", "mainbook:convert"]
      }
    }
  }
}

Um cliente que não consegue fazer login ainda pode enviar uma chave legada de mainbook.ai/developer:

Authorization: Bearer mb_live_REPLACE_ME

Qualquer credencial é lida de cada requisição, então cada usuário de um cliente acessa sua própria conta MainBook e gasta seus próprios créditos de página. initialize e tools/list respondem sem credencial; toda chamada de ferramenta exige uma. Caminhos de arquivo locais e output_folder não existem via HTTP — passe file_url em vez de file_path, porque o disco do servidor não é seu. Resultados XLSX ou CSV retornam como um link de download único (dez minutos, uso único) para sessões OAuth, ou como uma instrução de download REST para uma chave mb_live_ legada.

Você também pode executar o mesmo modo remoto você mesmo. É HTTP Streamable sem estado com respostas JSON:

mainbook-mcp --transport http --host 127.0.0.1 --port 8000

O endpoint MCP é então http://127.0.0.1:8000/mcp. Cada cliente deve enviar seu próprio cabeçalho:

Authorization: Bearer mb_live_REPLACE_ME

O cabeçalho é lido de cada requisição de chamada de ferramenta e nunca armazenado em estado global. O modo HTTP hospedado não inspeciona MAINBOOK_API_KEY, o chaveiro do sistema operacional ou o arquivo de credencial local. Para modo remoto do Codex:

[mcp_servers.mainbook]
url = "https://mcp.mainbook.ai/mcp"
bearer_token_env_var = "MAINBOOK_API_KEY"
tool_timeout_sec = 920
default_tools_approval_mode = "writes"

Substitua a URL pelo seu próprio host se você mesmo fizer o deploy; uma implantação auto-hospedada ainda precisa de terminação HTTPS normal e controles de acesso.

OAuth no serviço hospedado

O login de conta está ativo em https://mcp.mainbook.ai/mcp (desde 2026-08-20). O verificador permanece desabilitado por padrão nesta árvore de código-fonte, então uma implantação que você mesmo executa precisa habilitá-lo deliberadamente. Onde estiver habilitado, initialize e tools/list permanecem públicos, enquanto cada chamada de ferramenta aceita uma chave mb_live_ existente ou um token de acesso RS256 da MainBook. Tokens OAuth são verificados localmente apenas contra a URL JWKS configurada da MainBook; eles nunca são encaminhados à API do Desenvolvedor. O servidor MCP envia uma credencial X-MainBook-Service nova de 60 segundos para cada requisição REST interna.

Os escopos de ferramentas hospedados são fixos em um mapa: convert_bank_statement exige mainbook:convert; get_balance, get_conversion e list_conversions exigem mainbook:read. Os metadados de recursos protegidos são publicados em /.well-known/oauth-protected-resource/mcp apenas enquanto o sinalizador estiver habilitado.

Variáveis de ambiente

  • MAINBOOK_API_KEY: opcional em stdio e tem precedência sobre um login armazenado; ignorado no modo HTTP, onde cada chamada de ferramenta deve carregar seu próprio cabeçalho Bearer.
  • MAINBOOK_API_BASE_URL: host REST, padrão https://api.mainbook.ai. O servidor anexa /api/v1/developer.
  • MAINBOOK_ALLOWED_DIRS: pastas locais permitidas para leituras de origem e gravações de resultado, separadas pelo os.pathsep da plataforma (: no macOS/Linux e ; no Windows). Argumentos posicionais de diretório têm prioridade. Se nenhum for fornecido, os padrões são ~/Downloads, ~/Desktop e ~/Documents.
  • MAINBOOK_MCP_TRANSPORT: stdio (padrão) ou http.
  • MAINBOOK_MCP_HOST: host de bind HTTP, padrão 127.0.0.1.
  • MAINBOOK_MCP_PORT: porta de bind HTTP, padrão 8000.
  • MAINBOOK_MCP_OAUTH_ENABLED: flag de recurso do verificador OAuth hospedado, padrão false. Com a flag desativada, os metadados estão ausentes e o tratamento de Bearer hospedado permanece no comportamento legado mb_live_.
  • MAINBOOK_MCP_OAUTH_ISSUER: emissor confiável exato, padrão https://api.mainbook.ai.
  • MAINBOOK_MCP_OAUTH_JWKS_URL: URL JWKS confiável, padrão https://api.mainbook.ai/.well-known/jwks.json. URLs de cabeçalho de token são ignoradas.
  • MAINBOOK_MCP_OAUTH_RESOURCE: público/recursos exatos, padrão https://mcp.mainbook.ai/mcp.
  • MAINBOOK_MCP_OAUTH_CLOCK_SKEW_SECONDS: tolerância de relógio NumericDate, padrão 5.
  • MAINBOOK_MCP_OAUTH_MAX_TOKEN_AGE_SECONDS: idade máxima aceita de iat, padrão 600.
  • MAINBOOK_MCP_OAUTH_JWKS_CACHE_TTL_SECONDS: tempo de vida do cache JWKS, padrão 300.
  • MAINBOOK_MCP_OAUTH_JWKS_REFRESH_MIN_INTERVAL_SECONDS: intervalo mínimo entre tentativas de atualização de kid desconhecido, padrão 30.
  • MCP_SERVICE_SIGNING_SECRETS: segredos de porta de serviço separados por vírgula. O MCP assina com o primeiro; o Django pode aceitar valores atuais e anteriores durante a rotação. Necessário quando o OAuth está habilitado; nunca o envie para o repositório.

Segurança de arquivos e rede

  • file_path e file_url são mutuamente exclusivos. file_path é aceito apenas via stdio local; o modo HTTP o rejeita antes que o carregador de sistema de arquivos execute e exige file_url.
  • O acesso local a file_path e as gravações de arquivos de resultado usam as mesmas pastas configuradas. Diretórios CLI posicionais têm prioridade sobre MAINBOOK_ALLOWED_DIRS; o ambiente tem prioridade sobre os padrões ~/Downloads, ~/Desktop e ~/Documents. Cada raiz é expandida e resolvida, raízes ausentes são ignoradas e as raízes ativas são impressas em stderr quando o servidor inicia. Se nenhuma raiz permanecer, o acesso local falha de forma segura enquanto o servidor continua em execução.
  • Os pais de saída são resolvidos antes da gravação e verificados por identidade de diretório, então um symlink não pode redirecionar um resultado para fora das pastas permitidas. A criação de resultados é exclusiva e segura contra colisões; arquivos existentes não são sobrescritos.
  • ~/.mainbook/preferences.json é substituído atomicamente. O diretório .mainbook tem modo 0700 e o arquivo de preferências tem modo 0600; preferências malformadas ou ilegíveis são ignoradas com segurança.
  • Credenciais de terminal usam o chaveiro do sistema operacional quando o pacote opcional é utilizável. O fallback ~/.config/mainbook/credentials.json é substituído atomicamente dentro de um diretório de modo 0700 e tem modo 0600; suas entradas de nível superior são chaveadas por URL base da API.
  • Caminhos locais são expandidos e estritamente resolvidos antes da verificação da lista de permissões, então .. e symlinks não podem fazer um alvo externo parecer estar dentro de uma pasta permitida. O caminho resolvido deve estar estritamente abaixo de uma raiz, não igual à própria raiz.
  • O arquivo local é aberto uma vez. O servidor usa fstat nesse descritor para exigir um arquivo regular e impor o limite de 50 MiB, então realiza a leitura limitada pelo mesmo descritor. Isso fecha a janela de substituição entre verificação e leitura, mas não elimina completamente a corrida entre resolver o caminho e abri-lo; o caminho ainda pode ser substituído durante esse intervalo.
  • Um arquivo local deve conter %PDF- dentro dos primeiros 1024 bytes antes que pypdf seja invocado. Extensões de nome de arquivo não são usadas para decidir se um arquivo é um PDF.
  • Arquivos remotos devem usar HTTPS. Redirecionamentos não são seguidos.
  • Respostas DNS são rejeitadas se qualquer endereço for privado, loopback, link-local, metadados, reservado ou de outra forma não público, para IPv4 e IPv6.
  • Downloads de URL conectam-se a um IP numérico já validado enquanto mantêm o hostname original para verificação de certificado TLS e o cabeçalho HTTP Host, fechando corridas de rebinding de DNS.
  • Content-Length e a contagem real de bytes transmitidos são limitados independentemente a 50 MiB.
  • PDFs são analisados localmente com pypdf e limitados a 500 páginas.
  • Cabeçalhos de upload pré-assinados do MainBook são encaminhados inalterados; a chave Bearer do MainBook nunca é enviada ao armazenamento.

Verificações de desenvolvimento

.venv/bin/python -m pip install '.[dev]'
.venv/bin/pytest
.venv/bin/pytest --cov=mainbook_mcp --cov-report=term-missing --cov-report=annotate:cov_annotate
.venv/bin/ruff check .

Todos os testes REST usam mocks ou um stub local. Nenhum teste requer ou aceita uma chave real da API MainBook.