pluggy-mcp-br
by dayvison2b
README.md
# pluggy-mcp-br
Ponte **somente leitura** entre o [Grok Bot](https://cursor.com) e os seus dados bancários brasileiros. Os dados vêm da [Pluggy](https://pluggy.ai), no plano pessoal gratuito [Meu Pluggy](https://meu.pluggy.ai), que por sua vez lê instituições do **Open Finance**.
Isto **não** é “o Open Finance brasileiro”. É um conector MCP que o seu bot consulta. Quem publica este repositório não recebe chave, senha nem extrato: cada pessoa sobe o próprio servidor e usa as próprias credenciais.
## O que dá para perguntar
| Ferramenta | O que faz |
| --- | --- |
| `list_accounts` | Contas e cartões, com número e CPF mascarados |
| `get_balances` | Saldo das contas e fatura em aberto dos cartões, sem somar os dois |
| `list_transactions` | Transações entre `from` e `to`, com `accountId` opcional |
| `list_card_bills` | Faturas de uma conta `CREDIT` |
| `spending_by_category` | Soma das saídas (`DEBIT`) por categoria |
| `connection_status` | Status do item e `consentExpiresAt` |
Não há Pix, pagamento, transferência nem qualquer escrita. A API da Pluggy, daqui, só recebe `POST /auth` e `GET`.
## Privacidade
- Credenciais da Pluggy ficam só em variáveis de ambiente do **seu** servidor.
- Transações não são gravadas em disco nem em banco. O cache é memória do processo, com TTL padrão de 60 segundos (teto de 300). Na Vercel isso dura só enquanto a instância está quente, de propósito: extrato não vai para um cache compartilhado.
- CPF válido vira `***.***.***-XX`. Número de conta e cartão ficam só com os quatro últimos dígitos.
- A descrição da transação é **dado não confiável**. Ela volta no campo `texto_nao_confiavel`, com um aviso de que não é instrução. Um texto de extrato pedindo Pix ou “ignore as instruções” não deve ser obedecido.
- O OAuth deste servidor tem um único usuário: o dono, que prova a senha `OWNER_PASSWORD`. Não há cadastro de outras pessoas.
- O resultado da ferramenta segue para o Grok Bot e, portanto, para o provedor do modelo. Este repositório não fica no meio, mas o bot que você conectar vê o que a ferramenta devolver.
## Limites que não são deste código
- O Meu Pluggy atualiza os bancos cerca de **uma vez a cada 24 horas**. Este conector não força atualização.
- A autorização do conector MeuPluggy dura **1 ano**. A data está em `consentExpiresAt`. Quando vence, as leituras voltam vazias até você autorizar de novo no dashboard. O consentimento de cada banco, dentro do Meu Pluggy, é outro prazo.
- Só entram instituições que o Open Finance e o Meu Pluggy oferecem. Uso pessoal, até 5 conexões, sem uso comercial. O guia oficial é [Personal use: Meu Pluggy](https://docs.pluggy.ai/docs/guides/meu-pluggy-personal-use).
- `GET /v2/items` não existe nesse plano. Copie cada `itemId` na tela Demo.
- A categoria da Pluggy pode vir vazia no plano gratuito (o categorizador é recurso Pro). Aí o gasto cai em `Sem categoria`.
- A chave de API da Pluggy dura 2 horas. O servidor renova com `POST /auth` e não pede para você colar essa chave.
## Limites conhecidos
- O reuso do código OAuth (cada código vale uma vez) e o limite de tentativas de senha ficam na memória da instância. Na Vercel, com várias instâncias, isso é parcial: outra instância pode não ter visto o código nem as falhas. Para cortar o acesso, troque `OAUTH_SIGNING_SECRET`.
- `npm audit` avisa do `postcss` trazido pelo Next.js. A correção exige `next@16`. Este projeto permanece no Next 15. Não use `npm audit fix --force`.
## Modo demo
O padrão é `DATA_MODE=demo`. Não chama a Pluggy e não precisa de chave. Os números são fictícios, inclusive um Nubank inventado, para você ver as seis ferramentas sem expor banco de verdade.
```bash
npm install
npm test
npm run demo:mcp
```
`demo:mcp` sobe o servidor em loopback, faz o OAuth do dono e imprime uma chamada MCP real de cada ferramenta. Se `OWNER_PASSWORD` já estiver no ambiente, o script usa essa senha. Só quando ela não existe é que o processo recebe `senha-demo-local-123`, sem gravar arquivo.
Para ler dados de verdade, ou o conector Sandbox da Pluggy, use `DATA_MODE=live` com as variáveis abaixo. A interface das ferramentas é a mesma. O Sandbox também exige Client ID, Client Secret e um `itemId`: só o modo `demo` funciona sem conta Pluggy.
## Passo a passo
### 1. Meu Pluggy e o banco
1. Crie a conta em [meu.pluggy.ai](https://meu.pluggy.ai).
2. Conecte cada banco lá. É nessa etapa que o banco pede CPF e aprovação no aplicativo. Cada banco é uma autorização separada.
3. Para o Nubank, escolha Nubank na lista do Meu Pluggy e conclua o consentimento do Open Finance no app do Nubank. O nome exato do botão muda com o app; o que importa é terminar a autorização do Open Finance, não digitar a senha do banco neste repositório.
### 2. Conector MeuPluggy no dashboard
1. Entre no [dashboard da Pluggy](https://dashboard.pluggy.ai) com a mesma conta.
2. Se a aplicação usa seleção manual de conectores, ligue **MeuPluggy** em Customization → Connectors (grupo Personal, aba Direct Connectors).
3. Abra Applications → a sua aplicação → **Demo** → **Connect Account**.
4. No widget, escolha **MeuPluggy**. Não escolha o banco de novo e não escolha Sandbox, a menos que você queira dados de teste da Pluggy.
5. Entre com a conta do Meu Pluggy.
Se o widget pedir CPF e aprovação do banco outra vez, você escolheu o conector do banco em vez de MeuPluggy. Volte e escolha MeuPluggy.
Cada banco ligado no Meu Pluggy vira um item dessa aplicação. Copie o `itemId` em Connected Items. O Client ID aparece na linha da aplicação. O Client Secret só é mostrado uma vez: se você não guardou, gere outro na página da aplicação.
### 3. Variáveis
Copie [`.env.example`](.env.example). No modo live:
| Variável | Função |
| --- | --- |
| `DATA_MODE` | `demo` (padrão) ou `live` |
| `PLUGGY_CLIENT_ID` | Client ID da aplicação |
| `PLUGGY_CLIENT_SECRET` | Client Secret da aplicação |
| `PLUGGY_ITEM_IDS` | Um ou mais `itemId`, separados por vírgula (máximo 5) |
| `PUBLIC_URL` | Origem pública exata, sem caminho. Ex.: `https://seu-app.vercel.app` |
| `OWNER_PASSWORD` | Senha do único dono, no mínimo 8 caracteres |
| `OAUTH_SIGNING_SECRET` | Segredo para assinar os tokens, no mínimo 32 caracteres |
| `OAUTH_EXTRA_REDIRECT_URIS` | Só se o cliente passar a exigir outro redirect |
| `CACHE_TTL_SECONDS` | Opcional. Padrão 60, máximo 300 |
Não commite `.env`. Trocar `OAUTH_SIGNING_SECRET` invalida as sessões. Os redirects abaixo já são aceitos e não entram na variável extra:
- `cursor://anysphere.cursor-mcp/oauth/callback`
- `https://www.cursor.com/agents/mcp/oauth/callback`
- `http://localhost:8787/callback`
`http://localhost:8787/callback` é o callback do Grok Bot / Cursor, não a porta deste servidor. Localmente o servidor usa `PORT` (padrão 3333), só em `127.0.0.1`.
### 4. Deploy na Vercel
O projeto já tem `vercel.json` e rotas Next.js. **O deploy fica com você.** Este repositório não dispara produção sozinho.
1. Importe o repositório em [vercel.com/new](https://vercel.com/new). O plano Hobby serve.
2. Framework: Next.js. Não precisa mudar o comando de build.
3. Em Settings → Environment Variables, coloque as variáveis do modo que você quer. Para um primeiro deploy sem banco, `DATA_MODE=demo` mais `OWNER_PASSWORD`, `OAUTH_SIGNING_SECRET` e `PUBLIC_URL` já bastam.
4. `PUBLIC_URL` tem de ser a origem que você vai entregar ao bot, com `https`, sem `/mcp`. Se usar domínio próprio, não deixe o valor em `*.vercel.app`.
5. Faça o deploy quando quiser. Anote a URL `https://SEU-DOMINIO/mcp`.
Confira, sem token, no navegador:
- `https://SEU-DOMINIO/.well-known/oauth-protected-resource/mcp`
- `https://SEU-DOMINIO/.well-known/oauth-authorization-server`
Os dois precisam abrir em JSON. `POST /mcp` sem token deve responder 401 com `WWW-Authenticate` apontando para o primeiro.
### 5. Grok Bot
No chat do bot, peça para adicionar o conector, por exemplo:
> Adicione este servidor MCP: https://SEU-DOMINIO/mcp
O bot só autentica conector custom por OAuth. Não há token fixo para colar. Ele registra o cliente, abre o login e você digita `OWNER_PASSWORD`. Na tela seguinte as ferramentas passam a existir.
O servidor é stateless: código, access token e refresh token são JWT assinados com `OAUTH_SIGNING_SECRET`. Não há banco de sessões. O refresh não dá para revogar um a um; para cortar o acesso, troque o segredo ou a senha e peça para conectar de novo.
### 6. Se o OAuth do bot falhar
Há relatos no fórum do Cursor ([conectores custom do Grok Bot](https://forum.cursor.com/t/grokbot-custom-connectors/169965) e [redirect_uri não permitido](https://forum.cursor.com/t/grok-bot-custom-mcp-oauth-fails-before-sign-in-redirect-uri-not-allowed/171877)). O que este servidor faz a respeito:
- Aceita, num único registro dinâmico, os três redirects que o cliente envia, inclusive `cursor://`. Provedores que recusam esse esquema quebram o registro inteiro. Aqui o esquema é permitido de propósito.
- Cliente público, PKCE `S256`, sem client secret. Se o cliente mandar `Authorization` básico ou `client_secret` no token, o valor é ignorado.
- O teste automático deste repositório registra os três URIs, erra a senha, acerta a senha e chama as ferramentas. Isso **não** é o Grok Bot de verdade: falta uma URL pública e a sua conta do bot.
Fallback, se o bot falhar:
1. `fetch failed` antes da tela de login: a URL não está pública em HTTPS. Preview com proteção, localhost e VPN não servem para o bot, que roda na nuvem. O mesmo URL pode funcionar no Cursor IDE, porque lá o OAuth sai da sua máquina.
2. Erro de `redirect_uri`: copie o URI exato da mensagem para `OAUTH_EXTRA_REDIRECT_URIS` e faça um novo deploy. Não apague os três já embutidos.
3. Não existe, no Grok Bot, um lugar seguro para token fixo ou header secreto. Não contorne com segredo no chat.
4. Enquanto o bot não conectar, dá para usar a mesma URL no `mcp.json` do Cursor IDE. Isso não liga o bot.
## Desenvolvimento
```bash
npm install
npm run dev # http://127.0.0.1:3333/mcp
npm test
npm run typecheck
npm run build # confere o bundle da Vercel, não publica
```
`npm run dev` sem `OWNER_PASSWORD` sobe o modo demo, mas o login responde que a senha não foi configurada. `npm run demo:mcp` usa a `OWNER_PASSWORD` que já estiver no ambiente; se não houver, define `senha-demo-local-123` só naquele processo e não grava arquivo.
As ferramentas no modo demo e o mascaramento estão em `test/`. `test/mcp-http.test.ts` sobe o HTTP de verdade e fala o protocolo MCP.
## Licença
[MIT](LICENSE). Pluggy, Nubank, Open Finance e Cursor são marcas de seus donos. Este projeto não é afiliado a eles.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues