Actual Budget MCP
Servidor MCP Docker que conecta Claude Desktop/LibreChat/LobeChat ao Actual Budget para orçamento em linguagem natural, gerenciamento de transações e insights financeiros.
Documentação
Servidor Actual MCP
Converse com seu orçamento. Execute em qualquer lugar. Confie em produção.
O Actual MCP Server é um servidor Model Context Protocol que conecta qualquer assistente de IA compatível com MCP (como LibreChat, LobeChat, Claude Desktop e outros) diretamente à sua instância auto-hospedada do Actual Budget. Faça perguntas em linguagem natural, crie transações, analise gastos e gerencie todo o seu orçamento sem nunca abrir a interface do Actual Budget.
┌─────────────┐ MCP/HTTP ┌──────────────────┐ Actual API ┌──────────────┐
│ LibreChat │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │
│ LobeChat │ │ Server │ │ Budget │
│ (remote) │ │ (84 tools) │ │ Server │
└─────────────┘ └──────────────────┘ └──────────────┘
┌─────────────┐ MCP/stdio ┌──────────────────┐ Actual API ┌──────────────┐
│ Claude │ ◄───────────► │ Actual MCP │ ◄───────────► │ Actual │
│ Desktop │ │ Server │ │ Budget │
│ (local) │ │ (84 tools) │ │ Server │
└─────────────┘ └──────────────────┘ └──────────────┘
Por que este projeto?
A maioria das implementações de MCP para Actual Budget são pontes stdio simples, projetadas para uso local de usuário único com Claude Desktop. Este projeto vai além:
- 84 ferramentas, a cobertura mais abrangente disponível. Contas, transações, categorias, beneficiários, tags, notas, regras, orçamentos, operações em lote, sincronização bancária e muito mais. Cobre a API acessível do Actual Budget sem lacunas reais.
- Transporte HTTP e stdio. Funciona como um servidor remoto real para LibreChat/LobeChat (
--http), ou como um processo local direto para Claude Desktop (--stdio). Nenhum Docker ou servidor HTTP é necessário para uso local. - 6 ferramentas exclusivas com tecnologia ActualQL. Pesquise e resuma transações por mês, valor, categoria ou beneficiário usando o mecanismo de consulta nativo do Actual Budget. Resultados agregados, sem dados brutos despejados na janela de contexto da IA.
- Alternância de múltiplos orçamentos em tempo de execução. Configure vários arquivos de orçamento e deixe a IA alternar entre eles no meio da conversa com
actual_budgets_switch. Funciona em ambos os transportes: HTTP vincula o orçamento ativo à sessão MCP, e stdio (Claude Desktop, Claude Code, Cursor) obtém uma sessão sintética por processo, de modo que uma alternância é limitada àquele processo em vez de compartilhada globalmente (#348). - Pronto para múltiplos usuários com OIDC. Proteja cada sessão com JWTs validados por JWKS e ACLs de orçamento por usuário. Nenhum token compartilhado é necessário.
- Confiabilidade de nível de produção em ambos os transportes. Pooling de conexões HTTP (até 15 sessões simultâneas) e um processo stdio de longa duração que faz login UMA VEZ e reutiliza essa conexão para cada chamada de ferramenta, em vez de reautenticar a cada chamada, para que Claude Desktop e Claude Code permaneçam rápidos e uma rajada de chamadas não arrisque uma tempestade de logins por chamada contra o limitador upstream. Repetição automática com backoff exponencial e uma suíte de testes completa (unitários + E2E + integração).
Verificado em funcionamento com LibreChat, LobeChat e Claude Desktop. Todas as 84 ferramentas testadas de ponta a ponta. Qualquer cliente compatível com MCP deve funcionar.
Sumário
- Início Rápido
- Atualização
- Ferramentas Disponíveis
- Configuração
- Alternância de Múltiplos Orçamentos
- Transporte e Autenticação
- Testes
- Documentação
- Contribuição
- Arquitetura
- Licença
- Agradecimentos
- Aviso Legal
- Suporte
- Patrocínio
Início Rápido
Pré-requisitos
- Servidor Actual Budget em execução (local ou remoto)
- Seu ID de Sincronização do Orçamento: Actual → Configurações → Mostrar Configurações Avançadas → ID de Sincronização
- Node.js 22+ (método npm) ou Docker
Opção A: Docker (recomendado)
docker run -d \
--name actual-mcp-server-backend \
-p 3600:3600 \
# Use the same URL you type in your browser to open Actual Budget:
# http://localhost:5006 (if Actual Budget runs on the same machine)
# http://192.168.1.50:5006 (if it runs on another machine on your network)
# https://actual.yourdomain.com (if you use a domain name)
# http://actual:5006 (if both containers share a Docker network; use container name)
-e ACTUAL_SERVER_URL=http://localhost:5006 \
-e ACTUAL_PASSWORD=your_password \
-e ACTUAL_BUDGET_SYNC_ID=your_sync_id \
-e MCP_SSE_AUTHORIZATION=your_secret_token \
-v actual-mcp-data:/app/data \ # required, see note below
-v actual-mcp-logs:/app/logs \
ghcr.io/agigante80/actual-mcp-server:latest
Por que o volume
/app/dataé necessário: O Actual Budget não expõe uma API REST. A biblioteca oficial@actual-app/api(usada internamente por este servidor) funciona baixando uma cópia local dos dados do seu orçamento, executando todas as consultas nessa cópia local e, em seguida, sincronizando as alterações de volta. O volume/app/datadá ao contêiner um local persistente e gravável para armazenar essa cópia local (é o diretório que a imagem cria e possui como usuário de execução). Sem ele, o contêiner não tem onde gravar e falhará na inicialização. Consulte a documentação da API do Actual para detalhes.O actual-mcp não precisa ser executado na mesma máquina que o Actual Budget. Você pode ter o Actual Budget em um servidor e o actual-mcp em outro — desde que
ACTUAL_SERVER_URLaponte para sua instância do Actual Budget, tudo funciona.
Verifique se está em execução:
# Quick health check
curl http://localhost:3600/health
# Expected: {"status":"ok","transport":"http","version":"..."}
# Full MCP handshake (also verifies your token)
curl -s -X POST http://localhost:3600/http \
-H "Authorization: Bearer your_secret_token" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli-test","version":"1.0"}}}' \
| python3 -m json.tool
# Success: JSON response with "protocolVersion" and "serverInfo"
# Wrong token: {"error": "Unauthorized"}
# Server not running: curl: (7) Failed to connect
Também disponível no Docker Hub: agigante80/actual-mcp-server:latest
Opção B: Docker Compose
git clone https://github.com/agigante80/actual-mcp-server.git
cd actual-mcp-server
cp .env.example .env # fill in ACTUAL_SERVER_URL, ACTUAL_PASSWORD, ACTUAL_BUDGET_SYNC_ID
docker compose --profile production up -d # production: MCP server listens on :3600
# or
docker compose --profile dev up -d # dev mode with hot-reload
O arquivo compose define apenas os perfis
deveproduction. O servidor MCP escuta em:3600diretamente: não há proxy reverso integrado nem servidor Actual Budget integrado, então aponteACTUAL_SERVER_URLpara sua própria instância do Actual. Para TLS, habilite HTTPS nativo comMCP_ENABLE_HTTPS=true(maisMCP_HTTPS_CERTeMCP_HTTPS_KEY), ou coloque o servidor atrás do seu próprio proxy reverso.
Opção C: npm (servidor HTTP)
Requer Node.js 22+. npm e npx não impõem isso, então verifique com
node --versionprimeiro. Em um Node mais antigo, o servidor se recusa a iniciar e informa isso. Observe quenpxexecuta qualquernodeque estiver primeiro no seuPATH, que nem sempre é o que você instalou mais recentemente.
# Quick start via npx (no clone needed):
ACTUAL_SERVER_URL=http://localhost:5006 \
ACTUAL_PASSWORD=your_password \
ACTUAL_BUDGET_SYNC_ID=your-sync-id \
MCP_SSE_AUTHORIZATION=your_token \
npx actual-mcp-server --http
# Or clone for development / custom config:
git clone https://github.com/agigante80/actual-mcp-server.git
cd actual-mcp-server
npm install
cp .env.example .env # fill in required values
npm run build
npm run dev -- --http
O servidor inicia em http://localhost:3600/http por padrão (a porta de escuta é MCP_BRIDGE_PORT, padrão 3600).
Opção D: stdio (Claude Desktop nativo, sem Docker ou servidor HTTP necessário)
O transporte stdio executa o servidor MCP como um processo filho. O Claude Desktop o inicia diretamente e se comunica via stdin/stdout. Nenhuma porta de rede, token de autenticação ou Docker é necessário. Nenhum clone é necessário: npx baixa e armazena em cache o pacote automaticamente.
Adicione a claude_desktop_config.json (consulte docs/guides/MCP_CLIENTS_SETUP.md para a localização do arquivo de configuração e todas as opções de cliente):
{
"mcpServers": {
"actual-budget": {
"command": "npx",
"args": ["-y", "actual-mcp-server", "--stdio"],
"env": {
"ACTUAL_SERVER_URL": "http://localhost:5006",
"ACTUAL_PASSWORD": "your_actual_password",
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here",
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/data-dir"
}
}
}
}
Nenhum token necessário. O stdio é executado como um processo local de propriedade do seu usuário. O próprio transporte é o limite de segurança. Todas as 84 ferramentas estão disponíveis.
MCP_BRIDGE_DATA_DIRdeve ser um caminho absoluto. Sem um, o diretório de dados é resolvido em relação a onde o cliente inicia o processo, o que pode ser imprevisível. O diretório é criado automaticamente na primeira execução.
Opção E: Unraid (Aplicativos da Comunidade)
O Actual MCP Server está publicado na loja Community Applications do Unraid: ca.unraid.net/apps/actual-mcp-server. Isso executa o transporte HTTP, a escolha certa para LibreChat, LobeChat e outros clientes MCP remotos.
Instale-o na aba Apps (Community Applications):
- Abra a aba Apps e pesquise por
actual-mcp-server, depois clique em Instalar. - Preencha URL do servidor Actual, senha do servidor Actual e ID de Sincronização do servidor Actual (o ID de Sincronização está no Actual Budget: abra o orçamento, Configurações, Mostrar configurações avançadas, ID de Sincronização).
- Defina um token de autenticação MCP forte. Gere um com
openssl rand -hex 32. Um token em branco desativa toda a autenticação HTTP e expõe seus dados financeiros sem autenticação na LAN, então isso é obrigatório (consulte Transporte e Autenticação). - Deixe PUID=99 e PGID=100 (
nobody:users) para que o contêiner possa gravar nos diretórios de Dados e Logs do appdata, depois inicie-o. - Alcance o endpoint de saúde pelo link WebUI do contêiner (porta
3600); aponte seu cliente MCP parahttp://[server-ip]:3600/httpcom o token Bearer.
O modelo do Unraid está em unraid/actual-mcp-server.xml. Para o fluxo de publicação, consulte docs/UNRAID_CA_PUBLISHING.md.
Conecte um cliente de IA
LibreChat / LobeChat: adicione a librechat.yaml (ou configurações do plugin MCP do LobeChat):
mcpServers:
actual-mcp:
type: "streamable-http"
url: "http://actual-mcp-server-backend:3600/http"
headers:
Authorization: "Bearer YOUR_TOKEN_HERE"
serverInstructions: true
timeout: 600000
Consulte docs/guides/AI_CLIENT_SETUP.md para configuração completa de LibreChat, LobeChat, rede e proxy HTTPS/TLS.
Claude Desktop via HTTP (quando o servidor já está em execução como contêiner Docker):
{
"mcpServers": {
"actual-budget": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:3600/http",
"--header",
"Authorization: Bearer YOUR_TOKEN_HERE"
]
}
}
}
Claude Desktop via stdio (nativo, sem servidor HTTP necessário; consulte a Opção D acima):
{
"mcpServers": {
"actual-budget": {
"command": "node",
"args": ["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"],
"env": {
"ACTUAL_SERVER_URL": "http://localhost:5006",
"ACTUAL_PASSWORD": "your_password",
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id",
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data"
}
}
}
}
Consulte docs/guides/MCP_CLIENTS_SETUP.md para todas as opções (incluindo Cursor, VS Code, Gemini CLI), correções de caminho Linux/NVM e solução de problemas.
Atualização
Docker (Opção A)
docker pull ghcr.io/agigante80/actual-mcp-server:latest
docker stop actual-mcp-server-backend
docker rm actual-mcp-server-backend
# Re-run the original docker run command with the same flags and volumes
Também disponível no Docker Hub: docker pull agigante80/actual-mcp-server:latest
Docker Compose (Opção B)
docker compose pull
docker compose --profile production up -d
npm / repositório clonado (Opção C)
git pull
npm install
npm run build
# Then restart the server
npx / stdio (Opções C e D)
Se você executar npx actual-mcp-server sem uma versão instalada globalmente, o npx buscará a versão mais recente do registro automaticamente. Mas se você instalou globalmente anteriormente (npm install -g actual-mcp-server), a instalação global tem precedência, então você deve atualizá-la explicitamente:
# Upgrade the global install
npm install -g actual-mcp-server
# Or force the registry version without touching your global install
npx actual-mcp-server@latest --http
Para Claude Desktop (stdio), reinicie o Claude após a atualização.
Ferramentas Disponíveis
84 ferramentas em todas as categorias. Todas as ferramentas usam a convenção de nomenclatura actual_<category>_<action>.
Contas (12)
| Ferramenta | Descrição |
|---|---|
actual_accounts_list | Listar todas as contas |
actual_accounts_create | Criar nova conta |
actual_accounts_update | Atualizar detalhes da conta. Um id que não existe é recusado em vez de criar um registro parcial |
actual_accounts_delete | Excluir conta permanentemente |
actual_accounts_close | Fechar conta. Uma conta SEM transações é REMOVIDA pelo Actual, não fechada |
actual_accounts_reopen | Reabrir conta fechada. Um id que não é uma conta é recusado em vez de criar uma |
actual_accounts_get_balance | Obter saldo da conta em uma data |
actual_account_flow_summary | Explicar a mudança exata de saldo em um conjunto de contas em um intervalo de datas: renda externa, saída de despesas, créditos, entradas não categorizadas e transferências para dentro, para fora ou dentro da seleção, com uma reconciliação exata |
actual_account_groups_list | Listar os grupos de contas personalizados usados para organizar contas na barra lateral (Actual 26.9.0+) |
actual_account_groups_create | Criar um grupo de contas. Atribuir contas a ele é uma chamada separada de actual_accounts_update |
actual_account_groups_update | Renomear um grupo de contas ou alterar sua posição na barra lateral. Um grupo que não existe é recusado, sem gravar nada |
actual_account_groups_delete | Excluir um grupo de contas. Suas contas NÃO são excluídas, elas ficam sem grupo |
Transações (17)
Padrão (7)
| Ferramenta | Descrição |
|---|---|
actual_transactions_get | Obter transações de uma conta |
actual_transactions_filter | Filtrar com critérios avançados |
actual_transactions_create | Criar nova(s) transação(ões), incluindo divisões (passe um array subtransactions) |
actual_transactions_import | Importar e reconciliar transações |
actual_transactions_update | Atualizar uma transação, dividir uma simples no lugar ou editar os filhos de uma divisão existente via subtransactions |
actual_transactions_delete | Excluir uma transação |
actual_transactions_merge | Mesclar duas transações da mesma conta e mesmo valor (por exemplo, um duplicado importado do banco e um lançamento manual). O upstream mantém uma (a importada primeiro) e EXCLUI a outra, preenchendo apenas os campos vazios de beneficiário, categoria, notas e agendamento da linha mantida e seus flags falsos de compensado e reconciliado; irreversível |
Transações divididas: passe um array
subtransactions(cada filho precisa de umamountem centavos inteiros;categoryenotessão opcionais). Os valores dos filhos devem somar oamountdo pai (o servidor não aplica isso, então a ferramenta o faz). Um pai dividido não carrega categoria própria: coloque as categorias nos filhos.actual_transactions_updatecomsubtransactionsedita os filhos de uma transação que já é dividida, ou divide uma transação simples NO MESMO LUGAR: mantém seu id,imported_ide estado de compensação, para que uma transação sincronizada com o banco possa ser dividida sem quebrar a correspondência de importação. Sua própria categoria é limpa, e um filho que não nomeia categoria a herda. Um filho dividido não pode ser dividido novamente. Nota:actual_transactions_importencaminha um arraysubtransactionspara a API, mas NÃO aplica a verificação de soma, então useactual_transactions_createpara divisões com saldo garantido.
Utilitário (2)
| Ferramenta | Descrição |
|---|---|
actual_transactions_uncategorized | Resumo de transações não categorizadas (totalCount, totalAmount, detalhamento por conta); passe includeTransactions:true para linhas paginadas |
actual_transactions_update_batch | Aplica muitas atualizações de transações em UMA chamada (updates: [{ id, fields }]); retorna contagens de sucesso e falha por item |
Exclusivo com ActualQL (8), único deste servidor MCP
| Ferramenta | Descrição |
|---|---|
actual_transactions_aggregate | Totais determinísticos em centavos inteiros agrupados por mês, categoria, grupo de categorias, beneficiário ou conta; transferências excluídas via transfer_id e filhos divididos contados uma vez |
actual_transactions_search_by_month | Busca por mês usando a transformação $month |
actual_transactions_search_by_amount | Encontra por faixa de valor |
actual_transactions_search_by_category | Busca por nome de categoria |
actual_transactions_search_by_payee | Encontra por beneficiário/fornecedor |
actual_transactions_summary_by_category | Resumo de gastos agrupado por categoria |
actual_transactions_summary_by_payee | Principais fornecedores com totais e contagens |
actual_recurring_expenses_summary | Detecta cobranças recorrentes (assinaturas, contas) a partir do histórico lançado: cadência (com tolerância a variação de data e fim do mês), valor mais recente, mudanças de preço, ocorrências, custo anualizado e estado ativo ou inativo |
Transferências (1)
| Ferramenta | Descrição |
|---|---|
actual_transfers_create | Cria uma transferência pareada entre duas contas (débito + crédito vinculados por transfer_id, idêntico ao "Fazer Transferência" da interface) |
Nota: Use
actual_transfers_createpara qualquer movimentação entre contas, nãoactual_transactions_create. A ferramenta dedicada cria ambos os lados (débito e crédito) atomicamente para que os livros permaneçam equilibrados. Limitações: ambas as contas devem existir e estar abertas, efrom_accountdeve ser diferente deto_account.
Categorias (4)
actual_categories_get · actual_categories_create · actual_categories_update · actual_categories_delete
Grupos de Categorias (4)
actual_category_groups_get · actual_category_groups_create · actual_category_groups_update · actual_category_groups_delete
Beneficiários (7)
actual_payees_get · actual_payees_common_list · actual_payees_create · actual_payees_update · actual_payees_delete · actual_payees_merge · actual_payee_rules_get
Etiquetas (4)
actual_tags_list · actual_tags_create · actual_tags_update · actual_tags_delete
| Ferramenta | Descrição |
|---|---|
actual_tags_list | Lista todas as etiquetas (id, palavra da etiqueta, cor e descrição opcionais) |
actual_tags_create | Cria ou faz upsert de uma etiqueta por nome; retorna o UUID da etiqueta |
actual_tags_update | Atualiza nome, cor ou descrição da etiqueta por UUID |
actual_tags_delete | Exclusão suave de uma etiqueta por UUID |
Notas (2)
actual_notes_get · actual_notes_update
| Ferramenta | Descrição |
|---|---|
actual_notes_get | Obtém a nota de qualquer entidade (UUID de conta/categoria/grupo de categorias/beneficiário, ou orçamento-AAAA-MM) |
actual_notes_update | Define ou limpa a nota de qualquer entidade; valida se a entidade existe ou corresponde ao padrão orçamento-AAAA-MM |
Preferências (1)
| Ferramenta | Descrição |
|---|---|
actual_preferences_get | Lê as preferências de exibição sincronizadas do orçamento (formato de número, formato de data, moeda, primeiro dia da semana). Somente exibição: todos os valores permanecem em centavos inteiros |
Orçamentos (12)
| Ferramenta | Descrição |
|---|---|
actual_budgets_list_available | Lista todos os arquivos de orçamento configurados |
actual_budgets_switch | Alterna o orçamento ativo (multi-orçamento) |
actual_budgets_get_all | Lista os arquivos de orçamento disponíveis |
actual_budgets_getMonths | Lista os meses do orçamento |
actual_budgets_getMonth | Obtém o orçamento de um mês específico |
actual_budgets_setAmount | Define o valor do orçamento da categoria. O mês deve ser um que o orçamento possua (veja actual_budgets_getMonths) |
actual_budgets_transfer | Transfere valor entre categorias |
actual_budgets_setCarryover | Ativa/desativa o repasse (carryover) |
actual_budgets_holdForNextMonth | Reserva fundos para o próximo mês. O Actual limita a reserva ao que resta para orçar, então a resposta informa o valor realmente reservado |
actual_budgets_resetHold | Redefine o estado da reserva |
actual_budgets_export | Exporta o orçamento ativo como um .zip para ACTUAL_EXPORT_DIR; retorna caminho, tamanho em bytes e sha256, nunca o conteúdo do arquivo |
actual_budgets_import | Restaura um orçamento a partir de um .zip do Actual ou de uma exportação YNAB4/YNAB5. Destrutivo: o id do orçamento vem do arquivo, então reimportar uma exportação substitui os dados desse orçamento em vez de fazer uma cópia. Também carrega o orçamento importado, alterando o orçamento ativo da sessão |
Regras (6)
actual_rules_get · actual_rules_create · actual_rules_update · actual_rules_delete
| Ferramenta | Descrição |
|---|---|
actual_rules_create_or_update | Upsert idempotente: cria uma regra, ou atualiza a existente que corresponde às mesmas condições, em uma única chamada. Use isto em vez de obter-depois-criar ao reexecutar uma configuração de categorização, para que execuções repetidas não acumulem regras duplicadas |
actual_rules_create_batch | Cria de 1 a 50 regras em uma chamada, cada uma exatamente como a entrada de actual_rules_create. Melhor esforço, não atômico (veja Operações em Lote): uma regra que falha em suas próprias verificações, nomeia uma categoria, beneficiário ou conta que não existe, ou é rejeitada pelo Actual é reportada com seu índice enquanto o restante continua |
Agendamentos (4)
| Ferramenta | Descrição |
|---|---|
actual_schedules_get | Lista transações agendadas, com sua próxima data de ocorrência |
actual_schedules_create | Cria um agendamento (único ou recorrente); a recorrência é uma configuração tipada, veja src/lib/schemas/recur.ts |
actual_schedules_update | Atualiza valor, beneficiário, conta ou recorrência de um agendamento existente |
actual_schedules_delete | Exclui um agendamento |
Consulta Avançada e Sincronização (2)
| Ferramenta | Descrição |
|---|---|
actual_query_run | Executa consulta ActualQL personalizada |
actual_bank_sync | Dispara sincronização bancária (GoCardless/SimpleFIN) |
Operações em Lote (1)
Quatro ferramentas aceitam muitos itens em uma chamada, para clientes que permitem apenas algumas chamadas de ferramenta por turno. Elas compartilham UM contrato: cada item é aplicado de forma independente e não atômica. Não há rollback, então itens aplicados antes de uma falha permanecem aplicados; um item ruim é reportado pelo seu índice e o restante continua; uma falha de infraestrutura (conexão perdida, timeout) falha a chamada inteira, e então você deve reler os dados antes de tentar novamente qualquer coisa. Um caminho em lote nunca tenta uma criação por conta própria.
actual_transactions_update_batch(contado em Transações): atualiza até 50 transações,{id, fields}cada. Resultado:{ succeeded: [{id}], failed: [{id, error}], total, successCount, failureCount }. Itens marcados como "não tentados" nunca foram enviados. Releia comactual_transactions_getantes de tentar novamente qualquer item.actual_transactions_import(contado em Transações): criação em lote com semântica de importação (deduplicação e reconciliação com transações existentes, regras opcionalmente aplicadas). Use para adicionar muitas transações de uma vez.actual_budget_updates_batch: define valores de orçamento e/ou flags de repasse para 1 a 100 pares mês/categoria, e a forma de reequilibrar categorias: leia o mês comactual_budgets_getMonth, depois envie um lote de valores absolutos. Cada operação precisa de pelo menos um deamount(centavos inteiros) oucarryover. Resultado:{ succeeded: [{index, month, categoryId}], failed: [{index, month, categoryId, error}], total, successCount, failureCount }. Uma categoria desconhecida, um mês fora do intervalo ou um repasse em uma categoria de renda falha apenas naquele item. Após um timeout, leia os meses de volta comactual_budgets_getMonthantes de tentar novamente.actual_rules_create_batch(contado em Regras): cria de 1 a 50 regras, cada uma exatamente como a entrada deactual_rules_create. Resultado:{ succeeded: [{index, id}], failed: [{index, error}], total, successCount, failureCount }. Itens marcados como "não tentados" nunca foram enviados. Releia comactual_rules_getantes de tentar novamente qualquer item.
Informações do Servidor e Consulta (5)
| Ferramenta | Descrição |
|---|---|
actual_server_info | Status do servidor, versão, informações de build |
actual_server_get_version | Versão do servidor Actual Budget |
actual_get_context | Recupera contas abertas, grupos de categorias com categorias aninhadas e beneficiários (ordenados por nome, limitados por payeeLimit) em uma única chamada |
actual_get_id_by_name | Resolve um nome exato → UUID para contas, categorias, beneficiários |
actual_entities_search | Encontra contas/categorias/beneficiários por um padrão de nome (contém/começaCom/terminaCom/exato/aproximado). Corrige "beneficiário não encontrado" a partir de um nome parcial ou digitado incorretamente |
Gerenciamento de Sessão (2)
actual_session_list · actual_session_close
Configuração
Toda a configuração é feita por variáveis de ambiente. Copie .env.example para .env para começar.
Referência Completa de Variáveis de Ambiente
| Variável | Padrão | Obrigatório | Descrição |
|---|---|---|---|
| Conexão com o Actual Budget | |||
ACTUAL_SERVER_URL | (nenhum) | Sim | URL do seu servidor Actual Budget. Use a mesma URL que você digita no navegador: http://localhost:5006 (local), http://192.168.1.x:5006 (rede), https://actual.yourdomain.com (domínio) ou http://actual:5006 (nome do contêiner se estiver na mesma rede Docker) |
ACTUAL_PASSWORD | (nenhum) | Sim | Senha de login do seu servidor Actual Budget, aquela que você digita na própria tela de login. Não é a mesma que ACTUAL_BUDGET_PASSWORD (que descriptografa um orçamento criptografado E2E) e não tem relação com AUTH_PROVIDER=oidc (que controla como os clientes MCP autenticam neste servidor, não como este servidor autentica no Actual). Este servidor sempre faz login no Actual com uma senha, portanto o login por senha upstream deve permanecer habilitado |
ACTUAL_BUDGET_SYNC_ID | (nenhum) | Sim | ID de sincronização do orçamento do Actual (Configurações e depois ID de sincronização) |
ACTUAL_BUDGET_PASSWORD | (nenhum) | Não | Senha de criptografia opcional para orçamentos criptografados |
ALLOW_INSECURE_UPSTREAM | false | Não | Permitir um upstream http:// mesmo quando ACTUAL_BUDGET_PASSWORD está definido (#161). Desativado por padrão para que um upstream em texto simples com senha de criptografia seja recusado |
ACTUAL_OP_TIMEOUT_MS | 30000 | Não | Tempo limite por operação (ms) para cada chamada de API upstream do Actual (inicialização, download do orçamento, sincronização e cada operação de ferramenta). Uma chamada travada é rejeitada após esse limite para não segurar o mutex global da API para sempre e travar chamadas subsequentes de ferramentas (#270). Defina como 0 para desativar |
ACTUAL_IMPORT_TIMEOUT_MS | 600000 | Não | Tempo limite separado e maior (ms) para importação de orçamento, que é legitimamente longa em vez de travada. Uma importação é uma carga rastreada, então todas as outras sessões esperam por ela; limitá-la ao tempo limite geral de operação transformou a importação grande de um locatário em uma paralisação em todo o processo (#407). Defina como 0 para desativar |
| Configurações do Servidor MCP | |||
MCP_BRIDGE_PORT | 3600 | Não | Porta para o servidor MCP escutar |
MCP_BRIDGE_BIND_HOST | 0.0.0.0 | Não | Endereço do host para vincular o servidor (0.0.0.0 = todas as interfaces) |
MCP_BRIDGE_DATA_DIR | ./actual-data | Não | Diretório para armazenar dados locais do Actual Budget (SQLite). Obrigatório ser um caminho persistente. A biblioteca @actual-app/api baixa uma cópia local do seu orçamento aqui para executar consultas; use um volume montado no Docker para persistir entre reinicializações |
ACTUAL_EXPORT_DIR | (não definido) | Não | Diretório onde actual_budgets_export grava arquivos de .zip do orçamento. Não definido significa <MCP_BRIDGE_DATA_DIR>/exports, que é gravável e persistido na imagem Docker. Deve ser gravável pelo usuário em tempo de execução |
MCP_BRIDGE_PUBLIC_HOST | detectado automaticamente | Não | Hostname/IP público para o servidor (mostrado nos logs) |
MCP_BRIDGE_PUBLIC_SCHEME | detectado automaticamente | Não | Esquema público (http ou https) |
MCP_BRIDGE_USE_TLS | false | Não | Defina como true para anunciar https:// na URL do servidor (para configurações de proxy reverso onde o TLS é encerrado upstream) |
| Configuração de Transporte | |||
MCP_TRANSPORT_MODE | --http | Não | Modo de transporte. Apenas --http é um valor válido; stdio é selecionado via a flag CLI --stdio, não esta variável |
MCP_HTTP_PATH | /http | Não | Caminho de roteamento do endpoint HTTP |
MCP_BRIDGE_HTTP_PATH | igual a MCP_HTTP_PATH | Não | Caminho HTTP anunciado mostrado aos clientes (definido quando um proxy reverso reescreve o caminho) |
MCP_HTTP_BODY_LIMIT | 512kb | Não | Tamanho máximo aceito do corpo da solicitação JSON-RPC (ex.: 512kb, 1mb, 1048576). Validado na inicialização: um tamanho inválido, zero ou estourado recusa iniciar nomeando a variável (#466) |
| Superfície de Ferramentas | |||
MCP_TOOLSETS | all | Não | Grupos de conjuntos de ferramentas separados por vírgula (context, transactions, analysis, budget, rules, schedules, structure, query, admin) e predefinições (chat) para publicar; all publica todas as ferramentas. Nomes desconhecidos recusam iniciar. Veja Reduzindo a superfície de ferramentas |
MCP_TOOLS | (vazio) | Não | Ferramentas extras para adicionar além de MCP_TOOLSETS, pelo nome registrado completo (ex.: actual_accounts_list). Nomes desconhecidos recusam iniciar |
MCP_READ_ONLY | false | Não | true oculta e recusa as 47 ferramentas com capacidade de escrita. Apenas true ou false (sem diferenciar maiúsculas/minúsculas) são aceitos; qualquer outro valor recusa iniciar |
| Gerenciamento de Sessões | |||
USE_CONNECTION_POOL | true | Não | Habilitar pool de conexões baseado em sessão |
MAX_CONCURRENT_SESSIONS | 15 | Não | Máximo de sessões MCP simultâneas permitidas |
SESSION_IDLE_TIMEOUT_MINUTES | 5 | Não | Minutos antes da limpeza de sessões ociosas |
| Segurança e Autenticação | |||
AUTH_PROVIDER | none | Não | Modo de autenticação: none (Bearer estático) ou oidc (JWT validado por JWKS) |
MCP_SSE_AUTHORIZATION | (nenhum) | Não | Token Bearer estático (AUTH_PROVIDER=none; altamente recomendado em produção) |
MCP_ALLOW_UNAUTHENTICATED | false | Não | Opt-out para autenticação HTTP obrigatória por padrão (#242). Em um bind não-loopback sem token e sem OIDC, o servidor recusa iniciar; defina como true para executar aberto deliberadamente (ex.: atrás do seu próprio proxy) |
OIDC_ISSUER | (nenhum) | Se OIDC | URL do emissor OIDC (ex.: https://sso.example.com) |
OIDC_ALLOW_INSECURE_ISSUER | false | Não | Permitir um emissor OIDC em texto simples (http) em uma rede confiável (#244). Desativado por padrão (emissor http recusado na inicialização); defina true apenas para testes locais/LAN |
OIDC_RESOURCE | (nenhum) | Se OIDC | URL canônica deste servidor, o identificador de recurso RFC 9728 e o aud esperado (#461). Use a URL completa do endpoint público MCP, ex.: https://actual-mcp.example.com/http, sem barra final. Deve ser uma URL http(s) absoluta (um client id simples recusa iniciar); coloque um aud de client-id em OIDC_ACCEPTED_AUDIENCES em vez disso |
OIDC_ACCEPTED_AUDIENCES | (nenhum) | Não | Valores extras aceitos de aud além de OIDC_RESOURCE, separados por vírgula (#245). Para IdPs que colocam o client-id em aud (ex.: Authentik) ou a URI de redirecionamento do cliente OAuth (Cloudflare Access for SaaS). Lista de permissões estrita, nunca um curinga |
OIDC_JWKS_TRUSTED_HOSTS | (nenhum) | Não | Hosts JWKS entre origens opt-in, separados por vírgula host ou host:port (#254). Para IdPs cujo jwks_uri vive em outro host, ex.: Google precisa de www.googleapis.com. Correspondência exata, sem curingas; padrão vazio mantém apenas mesma origem |
OIDC_JWKS_URI | (nenhum) | Não | URL JWKS direta que ignora a descoberta OpenID (#462), para emissores sem documento de descoberta (Cloudflare Access: https://<team>.cloudflareaccess.com/cdn-cgi/access/certs). Mesmas regras de https, credenciais e origem ou host confiável que um jwks_uri descoberto, além de sem query ou fragmento. Quando definido, /.well-known/oauth-authorization-server não é servido e AUTH_BUDGET_ACL_IDENTITY_SOURCE=userinfo é recusado |
OIDC_TOKEN_SOURCE | authorization | Não | Onde o JWT Bearer é lido (#462): authorization (padrão) ou cf-access-jwt-assertion para um servidor MCP atrás do Cloudflare Access com Managed OAuth (o edge encaminha o Access JWT assinado nesse cabeçalho; Authorization nunca é consultado, OIDC_SCOPES deve estar vazio, OIDC_SCOPES_SUPPORTED é permitido e a origem deve ser alcançável apenas via Cloudflare). Veja a receita do Cloudflare em docs/guides/AI_CLIENT_SETUP.md |
OIDC_SCOPES | (nenhum) | Não | Escopos obrigatórios (aplicados) separados por vírgula, também anunciados. Deixe vazio quando os JWTs do IdP não carregam claim scope (Cloudflare Access for SaaS, ou Casdoor quando o cliente não solicita escopo) |
OIDC_SCOPES_SUPPORTED | (nenhum) | Não | Escopos separados por vírgula anunciados em scopes_supported mas não aplicados. Use quando os JWTs do IdP não carregam claim scope mas o cliente precisa de um escopo como offline_access anunciado (ex.: Gemini com Cloudflare Access for SaaS). Escopos obrigatórios de OIDC_SCOPES também são sempre anunciados. Anunciar offline_access desbloqueia um refresh token que este servidor não pode revogar: veja Limitando um refresh token vazado |
AUTH_BUDGET_ACL | (nenhum) | Não | ACL de orçamento por usuário; veja Configuração de Clientes de IA. Validado na inicialização: um valor que não seja um objeto JSON de arrays de strings recusa iniciar (#551). Não definido ou {} significa sem restrições |
AUTH_BUDGET_ACL_SOURCE | static | Não | static usa o mapa AUTH_BUDGET_ACL acima. actual deriva a ACL da própria lista de acesso por arquivo do servidor Actual, então revogar alguém no Actual tem efeito aqui sem edição de configuração. Requer um servidor Actual multiusuário (OpenID) que foi inicializado com senha primeiro |
AUTH_BUDGET_ACL_CLAIM | auto | Não | Qual claim do token identifica o principal quando a fonte é actual. auto espelha a própria precedência do Actual (preferred_username, login, email, id, sub) e corresponde o resultado ao userName do Actual. Defina um único nome de claim para fixar um em vez disso |
AUTH_BUDGET_ACL_IDENTITY_MAP | (vazio) | Não | Ligações explícitas de <sub>=<Actual userName>, separadas por vírgula, usadas quando a fonte é actual. Consultadas antes da precedência de claims e autoritativas: um sub vinculado cujo alvo não corresponde a nenhum arquivo de orçamento é negado em vez de cair para um claim. Use quando seu token de acesso não carrega o claim que o Actual armazenou, ou após uma renomeação no lado do IdP |
AUTH_BUDGET_ACL_IDENTITY_SOURCE | token | Não | Onde a ACL lê claims de identidade quando a fonte é actual. token usa o token de acesso verificado (sem chamada de rede). userinfo chama o endpoint UserInfo do IdP, que é o mesmo documento do qual o Actual deriva userName, e corrige implantações onde o token de acesso não tem o claim que o Actual armazenou. Opt-in porque torna o IdP uma dependência rígida da autorização |
AUTH_BUDGET_ACL_USERINFO_TIMEOUT_MS | 5000 | Não | Tempo limite para a solicitação UserInfo, limitado entre 250ms e 60s. Sem valor de desativação: uma chamada sem limite no caminho de autenticação transforma um IdP lento em uma interrupção |
MCP_ENABLE_HTTPS | false | Não | Habilitar TLS nativo. Requer MCP_HTTPS_CERT e MCP_HTTPS_KEY |
MCP_HTTPS_CERT | (nenhum) | Não | Caminho para o arquivo de certificado PEM (obrigatório quando MCP_ENABLE_HTTPS=true) |
MCP_HTTPS_KEY | (nenhum) | Não | Caminho para o arquivo de chave privada PEM (obrigatório quando MCP_ENABLE_HTTPS=true) |
| Configuração de Logging | |||
MCP_BRIDGE_STORE_LOGS | false | Não | Habilitar logging em arquivo (vs apenas console) |
MCP_BRIDGE_LOG_DIR | app/logs (ao lado da instalação) | Não | Diretório para arquivos de log (se STORE_LOGS=true). .env.example e Docker definem explicitamente (ex.: ./logs, /app/logs) |
MCP_BRIDGE_LOG_LEVEL | debug (dev) / info (prod) | Não | Nível de log: error, warn, info, debug |
LOG_FORMAT | automático | Não | Formato de saída de log: json ou pretty. Precedência: LOG_FORMAT explícito vence, senão NODE_ENV=production seleciona json, senão pretty |
MCP_SERVICE_NAME | actual-mcp-server | Não | Nome do serviço carimbado em cada registro de log estruturado (json) |
Rotação de Logs (quando MCP_BRIDGE_STORE_LOGS=true) | |||
MCP_BRIDGE_MAX_FILES | 14d | Não | Manter logs rotacionados por N dias (ex.: 14d, 30d) |
MCP_BRIDGE_MAX_LOG_SIZE | 20m | Não | Rotacionar quando o arquivo atingir o tamanho (ex.: 20m, 100m) |
MCP_BRIDGE_ROTATE_DATEPATTERN | YYYY-MM-DD | Não | Padrão de data para nomes de arquivos de log rotacionados |
| Desenvolvimento e Depuração | |||
DEBUG | (nenhum) | Não | Habilitar modo de depuração (logging verboso) quando definido para qualquer valor verdadeiro |
LOG_LEVEL | (nenhum) | Não | Alternância de detecção de depuração: defina como debug para habilitar saída extra de depuração de transporte. Distinto de MCP_BRIDGE_LOG_LEVEL (o nível do winston); não tem padrão e não é em si um nível de log |
MCP_BRIDGE_DEBUG_TRANSPORT | false | Não | Habilitar registro de depuração em nível de transporte |
| Avançado/Interno | |||
ACTUAL_API_CONCURRENCY | 5 | Não | Máximo de operações simultâneas da API do Actual |
NODE_ENV | (nenhum) / production | Não | Ambiente do Node. Sem padrão do aplicativo; a imagem Docker define production, que seleciona logs JSON e oculta rastreamentos de pilha em respostas de erro |
VERSION | detectado automaticamente | Não | Versão do servidor (definida automaticamente pelo build/Docker) |
TZ | UTC | Não | Fuso horário para carimbos de data/hora (ex.: America/New_York) |
Reduzindo a superfície de ferramentas
Todas as 84 ferramentas são publicadas por padrão. Clientes de chat com um orçamento de ferramentas pequeno (Gemini, LibreChat) se saem melhor com menos, então a superfície pode ser reduzida na inicialização. Uma ferramenta que não é publicada também é recusada se um cliente a chamar pelo nome, e a recusa nomeia a configuração responsável.
| Conjunto de ferramentas | Ferramentas | Conteúdo |
|---|---|---|
context | 14 | Orientação, consultas e informações do servidor |
transactions | 13 | Leitura de transações, criação, atualização, exclusão, importação e transferências |
analysis | 7 | Resumos, agregações e saldos |
budget | 10 | Meses de orçamento, valores, saldo remanescente, retenções, transferências, atualizações em lote e notas |
rules | 7 | Regras e regras de beneficiário, incluindo actual_rules_create_batch |
schedules | 4 | Transações agendadas |
structure | 21 | Contas, grupos de contas, categorias, grupos de categorias, beneficiários e tags |
query | 1 | actual_query_run (somente SELECT) |
admin | 6 | Alternância de orçamento, importação, exportação, sincronização bancária e gerenciamento de sessão |
Cada ferramenta está em exatamente um grupo. O preset chat corta entre eles e publica 12 ferramentas: actual_get_context, actual_query_run, actual_transactions_create, actual_transactions_update, actual_transactions_delete, actual_transactions_update_batch, actual_rules_create, actual_rules_create_batch, actual_budget_updates_batch, actual_budgets_transfer, actual_budgets_setAmount e actual_budgets_getMonth. Medido no payload tools/list, todas as 84 ferramentas têm 108.164 bytes e o preset chat tem 25.949 bytes (cerca de 6,5 mil tokens economizados, uma redução de 76%).
MCP_READ_ONLY=true adicionalmente oculta e recusa toda ferramenta com capacidade de escrita (47 das 83, incluindo actual_bank_sync, actual_budgets_export, actual_budgets_switch e actual_session_close), deixando 36. actual_session_list permanece disponível em somente leitura. Consulte Segurança e Privacidade.
Exemplo: um assistente de chat.
MCP_TOOLSETS=chat
MCP_TOOLS=actual_accounts_list,actual_payees_get
Exemplo: um assistente doméstico somente leitura.
MCP_TOOLSETS=context,analysis,query
MCP_READ_ONLY=true
Uma configuração que resulta em zero ferramentas se recusa a iniciar.
Alternância de Múltiplos Orçamentos
Configure vários arquivos do Actual Budget para que a IA possa alternar entre eles em tempo de execução usando actual_budgets_list_available e actual_budgets_switch.
BUDGET_N_SERVER_URL e BUDGET_N_PASSWORD recorrem a ACTUAL_SERVER_URL / ACTUAL_PASSWORD quando omitidos.
| Variável | Obrigatória | Padrão |
|---|---|---|
BUDGET_DEFAULT_NAME | Não | "Default" |
BUDGET_N_NAME | Sim (habilita grupo) | (nenhum) |
BUDGET_N_SYNC_ID | Sim | (nenhum) |
BUDGET_N_SERVER_URL | Não | ACTUAL_SERVER_URL |
BUDGET_N_PASSWORD | Não | ACTUAL_PASSWORD |
BUDGET_N_ENCRYPTION_PASSWORD | Não | (nenhum) |
# Default budget
ACTUAL_SERVER_URL=http://actual:5006
ACTUAL_PASSWORD=my-password
ACTUAL_BUDGET_SYNC_ID=aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa
BUDGET_DEFAULT_NAME=Personal
# Budget 1 (same server, same password)
BUDGET_1_NAME=Family
BUDGET_1_SYNC_ID=bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb
# Budget 2 (different server)
BUDGET_2_NAME=Business
BUDGET_2_SERVER_URL=https://actual-office.example.com
BUDGET_2_PASSWORD=office-password
BUDGET_2_SYNC_ID=cccccccc-cccc-cccc-cccc-cccccccccccc
Transporte e Autenticação
O servidor suporta dois modos de transporte:
| Modo | Flag | Caso de uso | Autenticação |
|---|---|---|---|
| HTTP | --http | LibreChat, LobeChat, Docker, implantações multiusuário | Token Bearer ou OIDC |
| stdio | --stdio | Claude Desktop, Cursor, uso local de usuário único | Nenhuma (isolamento de processo do SO) |
Os dois modos são mutuamente exclusivos. Passe exatamente uma flag ao iniciar o servidor.
Transporte stdio
stdio é a maneira mais simples de conectar o Claude Desktop diretamente ao Actual Budget. O servidor MCP roda como um processo filho; o Claude Desktop o inicia, comunica-se via stdin/stdout usando NDJSON (o formato de transmissão MCP), e o processo encerra limpo quando o Claude Desktop fecha.
Propriedades principais do modo stdio:
- Sem porta de rede. O transporte é um pipe, não um socket.
- Sem token de autenticação. A propriedade do processo é o limite de segurança.
- Todos os logs vão para stderr para nunca corromper o enquadramento JSON-RPC no stdout
- O processo encerra quando o stdin fecha (Claude Desktop desligando)
- Todas as 84 ferramentas estão disponíveis, idênticas ao modo HTTP
Inicie manualmente para verificar:
cd /path/to/actual-mcp-server
ACTUAL_SERVER_URL=http://localhost:5006 \
ACTUAL_PASSWORD=your_password \
ACTUAL_BUDGET_SYNC_ID=your-sync-id \
node dist/src/index.js --stdio
Envie uma solicitação de teste (mantenha o stdin aberto com sleep):
{ echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'; sleep 5; } \
| ACTUAL_SERVER_URL=http://localhost:5006 ACTUAL_PASSWORD=your_password ACTUAL_BUDGET_SYNC_ID=your-sync-id \
node dist/src/index.js --stdio 2>/dev/null
Configuração do Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"actual-budget": {
"command": "node",
"args": ["/absolute/path/to/actual-mcp-server/dist/src/index.js", "--stdio"],
"env": {
"ACTUAL_SERVER_URL": "http://localhost:5006",
"ACTUAL_PASSWORD": "your_actual_password",
"ACTUAL_BUDGET_SYNC_ID": "your-sync-id-here",
"MCP_BRIDGE_DATA_DIR": "/absolute/path/to/actual-mcp-server/actual-data"
}
}
}
}
O caminho deve ser absoluto. O Claude Desktop não herda
PATHdo shell, entãonodetambém deve ser absoluto se você usar NVM ou uma instalação não padrão:/home/youruser/.nvm/versions/node/v22.x.x/bin/node.
Consulte docs/guides/MCP_CLIENTS_SETUP.md para todas as opções de conexão (stdio nativo, mcp-remote via HTTP/HTTPS), outros clientes (Cursor, VS Code, Gemini CLI, Claude Code), correções de caminho no Linux e solução de problemas.
Transporte HTTP
Transporte HTTP usa o endpoint /http (StreamableHTTP) com token Bearer opcional ou autenticação OIDC.
Token Bearer estático (usuário único)
# Generate a token
openssl rand -hex 32
# Add to .env
MCP_SSE_AUTHORIZATION=your_token_here
Os clientes enviam: Authorization: Bearer your_token_here
OIDC (multiusuário)
AUTH_PROVIDER=oidc
OIDC_ISSUER=https://sso.yourdomain.com
OIDC_RESOURCE=https://actual-mcp.yourdomain.com/http # this server's public MCP URL (the expected 'aud')
OIDC_ACCEPTED_AUDIENCES=your-client-id # only if your IdP puts the client id in 'aud' (#245)
OIDC_SCOPES= # leave empty when the tokens carry no scope claim
# OIDC_SCOPES_SUPPORTED=openid,offline_access # extra scopes advertised in discovery without enforcement (#472)
OIDC_RESOURCE é a URL canônica deste servidor MCP (a "URI canônica do servidor" da especificação de autorização MCP e o identificador de recurso RFC 9728), não um ID de cliente IdP: a rota de metadados de recurso protegido e o público de token esperado são ambos derivados dela, e um valor que não é uma URL http(s) absoluta se recusa a iniciar com uma mensagem nomeando a variável (#461). Use a URL completa do endpoint público (https://host/http, ou o que MCP_BRIDGE_HTTP_PATH / MCP_HTTP_PATH anunciar) em vez da origem nua: com a forma de endpoint, o servidor publica tanto o documento específico do caminho (canônico) quanto uma cópia raiz para clientes que olham apenas a raiz (#473), e ele avisa na inicialização quando o caminho do recurso e o caminho anunciado discordam.
Endpoints de descoberta OAuth (automáticos no modo OIDC). Quando AUTH_PROVIDER=oidc, o servidor publica os dois documentos de metadados que um cliente OAuth precisa para inicializar um login, então mcp-remote e o conector nativo do Claude.ai podem descobrir o fluxo sem configuração manual de endpoint:
GET /.well-known/oauth-protected-resource[<path>](RFC 9728): identifica este servidor como um recurso protegido e aponta para seuOIDC_ISSUERcomo o servidor de autorização. A rota segueOIDC_RESOURCE: comhttps://host/http, o documento canônico é servido em/.well-known/oauth-protected-resource/http(RFC 9728 seção 3.1) e uma cópia raiz também é servida em/.well-known/oauth-protected-resourcepara clientes que pulam a URL específica do caminho (ex.: Google Gemini, #473); a origem nua serve apenas o caminho raiz. O SDK MCP oficial tenta a URL específica do caminho primeiro e recorre à raiz.GET /.well-known/oauth-authorization-server(RFC 8414, #285): os metadados do servidor de autorização (seusauthorization_endpoint/token_endpoint/registration_endpoint), re-servidos do próprio documento de descoberta OpenID do seu IdP. Isso está aqui porque vários clientes o procuram na origem do servidor de recursos, e alguns IdPs (ex.: Authentik) não o expõem onde esses clientes procuram. É buscado uma vez na inicialização e servido literalmente, expõe apenas endpoints que seu IdP já publica publicamente e não requer autenticação (um cliente o lê antes de ter um token). Nenhuma configuração extra é necessária; está ausente quandoAUTH_PROVIDERnão éoidc.
De onde vem a ACL de orçamento por usuário. Por padrão, a ACL é o mapa AUTH_BUDGET_ACL que você mantém manualmente. Desde v0.10.x, ela pode ser derivada da própria lista de acesso por arquivo do servidor Actual, então conceder ou revogar alguém no Actual tem efeito aqui sem edição de configuração e reinicialização:
AUTH_BUDGET_ACL_SOURCE=actual # default: static (the AUTH_BUDGET_ACL map)
AUTH_BUDGET_ACL_CLAIM=auto # default: mirrors Actual's own claim precedence
Como funciona a correspondência. O Actual não armazena o sub do seu IdP. Quando um usuário faz login, o Actual resolve sua identidade como o primeiro não vazio de preferred_username, login, email, id, sub, salva essa string como o userName do usuário e gera seu próprio UUID não relacionado como userId. A ACL, portanto, corresponde seu token contra userName, usando essa mesma precedência. AUTH_BUDGET_ACL_CLAIM=auto (o padrão) faz exatamente isso; defina-o para um único nome de claim para fixar um em vez disso.
Três coisas para saber antes de habilitar:
- Requer um servidor Actual multiusuário, ou seja, um configurado com
ACTUAL_OPENID_*. Em um servidor somente com senha, não existem usuários nomeados e todo principal resolve para nada. - Seu servidor Actual deve ter sido inicializado com uma SENHA antes de o OpenID ser adicionado. Este é um pré-requisito rígido deste servidor MCP em geral, não apenas deste recurso:
@actual-app/apiautentica com uma senha, e um servidor Actual configurado com OpenID do zero recusa login por senha, então este servidor não pode se conectar a ele de forma alguma. Uma senha não pode ser adicionada depois. - A identidade é tão confiável quanto o claim por trás dela. OIDC garante que
subé único e nunca reatribuído;preferred_usernameeemailnão carregam tal garantia e são frequentemente editáveis pelo usuário. Essa exposição é herdada do Actual, que chaveia suas próprias contas da mesma forma, não introduzida aqui: qualquer um que possa definir seupreferred_usernamepara o seu pode se passar por você no login do Actual também. Se isso importa para você, fixeAUTH_BUDGET_ACL_CLAIMa um claim que seu IdP não permite que usuários editem e certifique-se de que esse é o claim que seu IdP usa para preencher ouser_namedo Actual.
É opt-in e falha fechada: se a lista de orçamentos não puder ser lida, ou o principal não corresponder a nenhum arquivo, o acesso é negado em vez de concedido.
Consulte Configuração de Cliente de IA, OIDC para o formato AUTH_BUDGET_ACL, notas sobre Casdoor e a receita Cloudflare Access for SaaS + Gemini.
Testes
| Comando | O Que Testa | Requer Servidor Ativo |
|---|---|---|
npm run build | Compilação TypeScript | Não |
npm run test:unit-js | Teste de fumaça de 84 ferramentas, validação de esquema, ACL de autenticação | Não |
npm run test:adapter | Adaptador, lógica de repetição, concorrência | Não |
npm run test:e2e | Conformidade com o protocolo MCP (Playwright) | Não |
npm run test:e2e:docker:full | Integração de pilha completa | Sim (Docker) |
npm run test:integration | Verificações de sanidade do servidor ativo | Sim |
npm run test:integration:full | Suíte completa de integração ativa | Sim |
Níveis de teste de integração (tests/manual/): sanity → smoke → normal → extended → full → cleanup
Consulte tests/manual/README.md e tests/e2e/README.md para detalhes.
Documentação
| Documento | Conteúdo |
|---|---|
| docs/guides/MCP_CLIENTS_SETUP.md | Comece aqui para conectar Claude Desktop, Cursor, VS Code (Copilot), Gemini CLI ou Claude Code |
| docs/guides/AI_CLIENT_SETUP.md | Configuração do LibreChat e LobeChat, rede Docker, proxy HTTPS/TLS, OIDC |
| docs/guides/DEPLOYMENT.md | Docker, perfis Docker Compose, configuração de produção, Kubernetes |
| docs/ARCHITECTURE.md | Camadas de componentes, fluxo de dados, protocolos de transporte |
| docs/SECURITY_AND_PRIVACY.md | Modelos de autenticação, modelo de ameaça, endurecimento |
| docs/TESTING_AND_RELIABILITY.md | Estratégia de teste, cobertura, padrões de confiabilidade |
| docs/NEW_TOOL_CHECKLIST.md | Guia passo a passo para adicionar uma nova ferramenta MCP |
| CONTRIBUTING.md | Configuração de desenvolvimento, padrões de código, processo de PR |
| .env.example | Referência de variáveis de ambiente totalmente anotada |
Contribuindo
Contribuições são bem-vindas! Consulte CONTRIBUTING.md para configuração de desenvolvimento, padrões de código e o processo de PR.
Fluxo rápido:
- Fork →
git checkout -b feature/my-feature - Faça alterações + adicione testes
npm run build && npm run test:unit-jsdeve passar- Abra um Pull Request
Arquitetura
- Runtime: Node.js 22 (Alpine Linux no Docker)
- Linguagem: TypeScript (ESM, resolução de módulo NodeNext)
- SDK MCP:
@modelcontextprotocol/sdk - API Actual:
@actual-app/api - Validação: Zod (tipos em runtime + JSON Schema para entradas de ferramentas)
- Transportes: Express + StreamableHTTP (
--http) ·StdioServerTransport(--stdio) - Registro: Winston com rotação diária (toda saída roteada para stderr no modo stdio)
Toda chamada à API do Actual passa pelo wrapper
withActualApi()emsrc/lib/actual-adapter.ts, que gerencia o ciclo de vida de init/shutdown, tentativas (3 tentativas, backoff exponencial) e limitação de concorrência. Consulte docs/ARCHITECTURE.md para a documentação completa do design.
Licença
MIT. Consulte LICENSE para detalhes.
Agradecimentos
- Actual Budget: software de orçamento de código aberto
- Model Context Protocol: integração padronizada de aplicativos de IA
- LibreChat: alternativa de código aberto ao ChatGPT
- s-stefanov/actual-mcp: padrão de adaptador original
Aviso Legal
Este projeto começou como um exercício pessoal de aprendizado para explorar a tecnologia Model Context Protocol. É um projeto independente de código aberto, não afiliado, endossado ou apoiado pelo Actual Budget ou qualquer outra organização.
O software é fornecido como está, sem garantia de qualquer tipo. O autor não aceita responsabilidade por como ele é usado, por qualquer perda de dados, erros financeiros ou outras consequências decorrentes do seu uso. Se você conectá-lo a dados financeiros reais, faz isso inteiramente por sua conta e risco.
Suporte
- GitHub Issues: relatórios de bugs, solicitações de recursos, perguntas e ideias
Versão: 0.22.46 | Número de Ferramentas: 84 (compatibilidade LibreChat verificada)
Patrocínio
Eu construo e mantenho isso no meu próprio tempo. É gratuito, permanece gratuito e é mantido de qualquer forma.
Se isso economizou seu tempo e você quiser agradecer, pode fazê-lo em github.com/sponsors/agigante80. Totalmente opcional, e nada sobre o projeto muda de qualquer forma.