@marcelocorrea/mcp-safrapay 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +335 -0
  2. package/dist/index.js +564 -0
  3. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,335 @@
1
+ # SafraPay MCP Server
2
+
3
+ Servidor MCP (Model Context Protocol) para integração com a API SafraPay, permitindo que agentes de IA realizem operações completas de pagamento, gestão de clientes, recorrência e muito mais.
4
+
5
+ ## 🚀 Versão 0.2.0 - Arquitetura Agrupada com Autenticação Automática
6
+
7
+ Esta versão implementa uma arquitetura agrupada onde **12 ferramentas** cobrem **110+ endpoints** da API SafraPay, ao invés de criar uma ferramenta por endpoint.
8
+
9
+ ### ⚡ Autenticação Automática
10
+
11
+ O servidor gerencia a autenticação **completamente de forma automática**:
12
+ - ✅ Gera token automaticamente na primeira requisição
13
+ - ✅ Reautentica automaticamente quando o token expira (erro 401)
14
+ - ✅ Usa as credenciais configuradas via variáveis de ambiente
15
+ - ✅ **Você NUNCA precisa se preocupar com autenticação!**
16
+
17
+ ### Benefícios da Arquitetura Agrupada
18
+
19
+ - ✅ **Escalável**: Não há limite de ferramentas para gerenciar
20
+ - ✅ **Organizada**: Ferramentas agrupadas por contexto funcional
21
+ - ✅ **Flexível**: Agente IA monta as requisições baseado na documentação
22
+ - ✅ **Completa**: Acesso a toda a API SafraPay com documentação embarcada
23
+ - ✅ **Automática**: Autenticação e renovação de token transparentes
24
+
25
+ ## 📦 Instalação
26
+
27
+ ```bash
28
+ npm install
29
+ npm run build
30
+ ```
31
+
32
+ ## ⚙️ Configuração
33
+
34
+ Crie um arquivo `.env` na raiz do projeto:
35
+
36
+ ```env
37
+ # Ambiente: HML ou PROD
38
+ SAFRA_ENV=HML
39
+
40
+ # Credenciais (obtenha no portal SafraPay)
41
+ SAFRA_CLIENT_ID=seu-client-id
42
+ SAFRA_CLIENT_SECRET=seu-merchant-token
43
+
44
+ # Token (opcional - será gerado automaticamente)
45
+ SAFRA_ACCESS_TOKEN=
46
+ ```
47
+
48
+ ## 🔧 Configuração no Claude Code
49
+
50
+ Adicione ao arquivo de configuração do MCP:
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "safrapay": {
56
+ "command": "node",
57
+ "args": ["/caminho/para/banco-safra-mcp/dist/index.js"],
58
+ "env": {
59
+ "SAFRA_ENV": "HML",
60
+ "SAFRA_CLIENT_SECRET": "seu-merchant-token"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ ## 🛠️ Ferramentas Disponíveis
68
+
69
+ O servidor expõe **12 ferramentas agrupadas** que cobrem toda a API SafraPay:
70
+
71
+ ### 1. `safrapay_authentication`
72
+ Gestão de usuários SafraPay
73
+ - CRUD de usuários
74
+ - Listar merchants do usuário
75
+
76
+ **IMPORTANTE**: A autenticação de token é **AUTOMÁTICA**. Não é necessário chamar endpoints de autenticação manualmente.
77
+
78
+ ### 2. `safrapay_payments`
79
+ Processamento de pagamentos completo
80
+ - Clientes (customers)
81
+ - Cartão de crédito/débito
82
+ - 3D Secure (3DS)
83
+ - PIX
84
+ - Boleto
85
+ - Consulta de BIN
86
+ - Produtos
87
+ - Planos de taxas
88
+
89
+ ### 3. `safrapay_charges`
90
+ Gestão de cobranças
91
+ - Buscar cobrança
92
+ - Capturar pré-autorização
93
+ - Cancelar/estornar
94
+
95
+ ### 4. `safrapay_vault`
96
+ Tokenização de cartões (Cartão Protegido)
97
+ - Salvar cartão
98
+ - Atualizar cartão
99
+ - Buscar cartões
100
+ - Cartão temporário
101
+ - Validação zero dollar
102
+
103
+ ### 5. `safrapay_recurrence`
104
+ Planos e assinaturas recorrentes
105
+ - CRUD de planos
106
+ - CRUD de assinaturas
107
+ - Assinaturas em lote
108
+ - Relatórios
109
+
110
+ ### 6. `safrapay_payment_link`
111
+ Links de pagamento (SmartCheckout)
112
+ - Criar link
113
+ - Listar links
114
+ - Detalhes e exclusão
115
+
116
+ ### 7. `safrapay_checkout`
117
+ Sessões de checkout
118
+ - Checkout Redirect
119
+ - Checkout Lightbox
120
+ - Checkout Transparente
121
+
122
+ ### 8. `safrapay_split`
123
+ Split de pagamentos
124
+ - Gestão de recebedores
125
+ - Configuração de split
126
+ - Extrato digital
127
+ - Saldo disponível
128
+
129
+ ### 9. `safrapay_accreditation`
130
+ Credenciamento
131
+ - Gestão de merchants
132
+ - Sub-merchants
133
+ - Taxas e produtos
134
+ - Upload de documentos
135
+ - Reconciliação
136
+ - Adquirentes virtuais
137
+
138
+ ### 10. `safrapay_webhook`
139
+ Webhooks para eventos
140
+ - Criar webhooks
141
+ - Listar webhooks
142
+ - Cancelar webhook
143
+
144
+ ### 11. `safrapay_chargeback`
145
+ Gestão de disputas
146
+ - Resumo de disputas
147
+ - Detalhes de disputa
148
+ - Aceitar débito
149
+ - Representação secundária
150
+
151
+ ### 12. `safrapay_tef`
152
+ Integração com PinPads
153
+ - Fluxo transacional completo
154
+ - Funções auxiliares
155
+
156
+ ## 💡 Exemplos de Uso
157
+
158
+ ### Exemplo 1: Criar uma transação de crédito
159
+
160
+ ```
161
+ Usuário: "Crie uma transação de crédito de R$ 100,00"
162
+
163
+ Agente IA usa: safrapay_payments
164
+ {
165
+ "api": "GATEWAY",
166
+ "method": "POST",
167
+ "path": "/v2/charge/authorization",
168
+ "body": {
169
+ "charge": {
170
+ "merchantChargeId": "ORDER-123",
171
+ "transactions": [{
172
+ "card": {
173
+ "cardholderName": "JOAO SILVA",
174
+ "cardNumber": "4111111111111111",
175
+ "expirationMonth": 12,
176
+ "expirationYear": 2025,
177
+ "securityCode": "123"
178
+ },
179
+ "paymentType": 2,
180
+ "amount": 10000,
181
+ "installmentNumber": 1,
182
+ "installmentType": 0,
183
+ "autoCapture": true
184
+ }],
185
+ "source": 1
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ ### Exemplo 2: Criar cobrança PIX
192
+
193
+ ```
194
+ Usuário: "Crie uma cobrança PIX de R$ 50,00"
195
+
196
+ Agente IA usa: safrapay_payments
197
+ {
198
+ "api": "GATEWAY",
199
+ "method": "POST",
200
+ "path": "/v2/charge/pix",
201
+ "body": {
202
+ "charge": {
203
+ "merchantChargeId": "PIX-456",
204
+ "transactions": [{
205
+ "amount": 5000,
206
+ "paymentType": "Pix"
207
+ }],
208
+ "source": 1
209
+ }
210
+ }
211
+ }
212
+ ```
213
+
214
+ ### Exemplo 3: Criar assinatura recorrente
215
+
216
+ ```
217
+ Usuário: "Crie uma assinatura mensal de R$ 99,90"
218
+
219
+ Passo 1 - Criar plano (safrapay_recurrence):
220
+ {
221
+ "api": "PORTAL",
222
+ "method": "POST",
223
+ "path": "/plan",
224
+ "body": {
225
+ "name": "Plano Premium",
226
+ "amount": 9990,
227
+ "interval": 3,
228
+ "intervalCount": 1
229
+ }
230
+ }
231
+
232
+ Passo 2 - Criar assinatura (safrapay_recurrence):
233
+ {
234
+ "api": "GATEWAY",
235
+ "method": "POST",
236
+ "path": "/subscription",
237
+ "body": {
238
+ "planId": "plan-123",
239
+ "customerId": "customer-456",
240
+ "cardToken": "token-abc"
241
+ }
242
+ }
243
+ ```
244
+
245
+ ## 📚 Documentação Completa
246
+
247
+ Consulte os arquivos na raiz do projeto:
248
+
249
+ - **`SAFRAPAY_API_MAPPING.md`**: Mapeamento completo de todas as rotas organizadas por grupo
250
+ - **`API_DOCUMENTATION.md`**: Documentação técnica detalhada com exemplos de request/response
251
+
252
+ ## 🔑 Enumeradores Importantes
253
+
254
+ ### Status de Transação
255
+ - `1` - Pendente
256
+ - `2` - Autorizada
257
+ - `3` - Capturada
258
+ - `4` - Cancelada
259
+ - `5` - Negada
260
+ - `6` - Estornada
261
+
262
+ ### Tipos de Pagamento
263
+ - `2` - Crédito
264
+ - `3` - Débito
265
+ - `4` - Boleto
266
+ - `5` - PIX
267
+ - `"Pix"` - PIX (string)
268
+ - `"Boleto"` - Boleto (string)
269
+
270
+ ### Tipos de Parcelamento
271
+ - `0` - À vista
272
+ - `2` - Emissor (com juros)
273
+ - `3` - Lojista (sem juros)
274
+
275
+ ### Intervalos de Recorrência
276
+ - `1` - Diário
277
+ - `2` - Semanal
278
+ - `3` - Mensal
279
+ - `4` - Anual
280
+
281
+ ### Source (Origem)
282
+ - `1` - E-commerce/API
283
+ - `2` - Mobile
284
+ - `3` - Recorrência
285
+ - `4` - Telefone
286
+
287
+ ## 🌐 Ambientes
288
+
289
+ ### Homologação (HML)
290
+ - Portal API: `https://portal-api-hml.safrapay.com.br`
291
+ - Gateway API: `https://payment-hml.safrapay.com.br`
292
+ - Reconciliation API: `https://reconciliation-api-hml.safrapay.com.br`
293
+
294
+ ### Produção (PROD)
295
+ - Portal API: `https://portal-api.safrapay.com.br`
296
+ - Gateway API: `https://payment.safrapay.com.br`
297
+ - Reconciliation API: `https://reconciliation-api.safrapay.com.br`
298
+
299
+ ## ⚡ Desenvolvimento
300
+
301
+ ```bash
302
+ # Compilar
303
+ npm run build
304
+
305
+ # Modo watch (desenvolvimento)
306
+ npm run dev
307
+
308
+ # Executar
309
+ npm start
310
+ ```
311
+
312
+ ## 🔒 Segurança
313
+
314
+ - NUNCA armazene dados de cartão completos
315
+ - Use tokenização sempre que possível
316
+ - Implemente validação zero dollar antes de cobranças recorrentes
317
+ - Utilize HTTPS em todos os endpoints
318
+ - Monitore transações suspeitas
319
+
320
+ ## 🤝 Contribuindo
321
+
322
+ Este é um projeto em desenvolvimento ativo. Sugestões e melhorias são bem-vindas!
323
+
324
+ ## 📄 Licença
325
+
326
+ ISC
327
+
328
+ ## 👤 Autor
329
+
330
+ Marcelo Correa
331
+
332
+ ---
333
+
334
+ **Versão**: 0.2.0
335
+ **Última atualização**: Janeiro 2026
package/dist/index.js ADDED
@@ -0,0 +1,564 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
8
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
9
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
10
+ const axios_1 = __importDefault(require("axios"));
11
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
12
+ const dotenv_1 = __importDefault(require("dotenv"));
13
+ const zod_1 = require("zod");
14
+ dotenv_1.default.config();
15
+ // --- Configuração de Constantes e Tipos ---
16
+ const API_ENVS = {
17
+ HML: {
18
+ PORTAL: "https://portal-api-hml.safrapay.com.br",
19
+ GATEWAY: "https://payment-hml.safrapay.com.br",
20
+ RECONCILIATION: "https://reconciliation-api-hml.safrapay.com.br"
21
+ },
22
+ PROD: {
23
+ PORTAL: "https://portal-api.safrapay.com.br",
24
+ GATEWAY: "https://payment.safrapay.com.br",
25
+ RECONCILIATION: "https://reconciliation-api.safrapay.com.br"
26
+ }
27
+ };
28
+ class SafraPayServer {
29
+ server;
30
+ env;
31
+ axiosInstances;
32
+ token = null;
33
+ merchantToken;
34
+ isAuthenticating = false;
35
+ constructor() {
36
+ this.server = new index_js_1.Server({
37
+ name: "@marcelocorrea/mcp-safrapay",
38
+ version: "0.2.0",
39
+ }, {
40
+ capabilities: {
41
+ tools: {},
42
+ },
43
+ });
44
+ // Determina ambiente (Default: HML para segurança)
45
+ this.env = (process.env.SAFRA_ENV === "PROD") ? "PROD" : "HML";
46
+ this.token = process.env.SAFRA_ACCESS_TOKEN || null;
47
+ // Valida se o MerchantToken está configurado
48
+ const merchantToken = process.env.SAFRA_CLIENT_SECRET;
49
+ if (!merchantToken) {
50
+ throw new Error("SAFRA_CLIENT_SECRET (MerchantToken) não configurado. " +
51
+ "Por favor, configure a variável de ambiente antes de iniciar o servidor.");
52
+ }
53
+ this.merchantToken = merchantToken;
54
+ console.error(`[SafraPay MCP] Ambiente: ${this.env}`);
55
+ console.error(`[SafraPay MCP] Token configurado: ${this.token ? "Sim" : "Não (será gerado automaticamente)"}`);
56
+ console.error(`[SafraPay MCP] MerchantToken presente: Sim`);
57
+ // Inicializa instâncias Axios para cada serviço base
58
+ this.axiosInstances = {
59
+ PORTAL: this.createAxiosInstance(API_ENVS[this.env].PORTAL),
60
+ GATEWAY: this.createAxiosInstance(API_ENVS[this.env].GATEWAY),
61
+ RECONCILIATION: this.createAxiosInstance(API_ENVS[this.env].RECONCILIATION),
62
+ };
63
+ this.setupToolHandlers();
64
+ // Error handling
65
+ this.server.onerror = (error) => console.error("[MCP Error]", error);
66
+ process.on("SIGINT", async () => {
67
+ await this.server.close();
68
+ process.exit(0);
69
+ });
70
+ }
71
+ createAxiosInstance(baseURL) {
72
+ const instance = axios_1.default.create({
73
+ baseURL,
74
+ headers: {
75
+ "Content-Type": "application/json",
76
+ },
77
+ });
78
+ // Interceptor de requisição: adiciona token
79
+ instance.interceptors.request.use((config) => {
80
+ if (this.token) {
81
+ config.headers.Authorization = `Bearer ${this.token}`;
82
+ }
83
+ return config;
84
+ });
85
+ // Interceptor de resposta: reautentica automaticamente em caso de 401
86
+ instance.interceptors.response.use((response) => response, async (error) => {
87
+ const originalRequest = error.config;
88
+ // Se recebeu 401 e ainda não tentou reautenticar
89
+ if (error.response?.status === 401 && !originalRequest._retry) {
90
+ originalRequest._retry = true;
91
+ try {
92
+ // Reautentica automaticamente
93
+ await this.autoAuthenticate();
94
+ // Atualiza o header com o novo token
95
+ originalRequest.headers.Authorization = `Bearer ${this.token}`;
96
+ // Retenta a requisição original
97
+ return instance(originalRequest);
98
+ }
99
+ catch (authError) {
100
+ console.error("[SafraPay MCP] Falha na reautenticação automática:", authError);
101
+ return Promise.reject(error);
102
+ }
103
+ }
104
+ return Promise.reject(error);
105
+ });
106
+ return instance;
107
+ }
108
+ /**
109
+ * Autentica automaticamente usando as credenciais configuradas
110
+ */
111
+ async autoAuthenticate() {
112
+ // Evita múltiplas chamadas simultâneas de autenticação
113
+ if (this.isAuthenticating) {
114
+ await new Promise(resolve => setTimeout(resolve, 1000));
115
+ return;
116
+ }
117
+ this.isAuthenticating = true;
118
+ try {
119
+ console.error("[SafraPay MCP] Gerando novo token automaticamente...");
120
+ const response = await axios_1.default.post(`${API_ENVS[this.env].PORTAL}/v1/Login/GenerateToken`, {}, {
121
+ headers: {
122
+ "MerchantToken": this.merchantToken,
123
+ "Content-Type": "application/json"
124
+ }
125
+ });
126
+ if (response.data && response.data.generatedToken) {
127
+ this.token = response.data.generatedToken;
128
+ console.error("[SafraPay MCP] Token gerado com sucesso!");
129
+ }
130
+ else {
131
+ throw new Error("Token não retornado pela API");
132
+ }
133
+ }
134
+ finally {
135
+ this.isAuthenticating = false;
136
+ }
137
+ }
138
+ setupToolHandlers() {
139
+ this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
140
+ tools: [
141
+ {
142
+ name: "safrapay_authentication",
143
+ description: `Gestão de usuários SafraPay.
144
+
145
+ NOTA: A autenticação de token é AUTOMÁTICA. O servidor reautentica automaticamente quando necessário usando as credenciais configuradas via variáveis de ambiente. Você NÃO precisa chamar os endpoints de autenticação manualmente.
146
+
147
+ GESTÃO DE USUÁRIOS:
148
+ - POST /v1/User - Criar: { name, email, password, phone?, role? }
149
+ - GET /v1/User - Buscar: query { userId? }
150
+ - PUT /v1/User - Atualizar: { userId, name?, email?, phone? }
151
+ - GET /v1/User/Merchants - Listar merchants: query { currentPage?, pageSize?, sortDirection? }
152
+ - DELETE /v1/User/{userId} - Deletar
153
+
154
+ Use 'api' para especificar PORTAL ou GATEWAY, 'method' para o verbo HTTP, 'path' para o endpoint e 'body' para dados.`,
155
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
156
+ api: zod_1.z.enum(["PORTAL", "GATEWAY"]).describe("API base (PORTAL ou GATEWAY)"),
157
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE"]).describe("Método HTTP"),
158
+ path: zod_1.z.string().describe("Caminho do endpoint"),
159
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo da requisição JSON"),
160
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
161
+ })),
162
+ },
163
+ {
164
+ name: "safrapay_payments",
165
+ description: `Processamento de pagamentos: cartão, PIX, boleto, produtos e taxas.
166
+
167
+ CLIENTES (Customers):
168
+ - POST /customer - Criar: { merchantCustomerId, name, email?, birthDate?, phone?, document?, address? }
169
+ - PUT /customer - Atualizar: mesma estrutura
170
+ - GET /customer - Buscar: query { customerId?, merchantCustomerId? }
171
+
172
+ CARTÃO DE CRÉDITO:
173
+ - POST /v2/charge/authorization - Transação: { charge: { merchantChargeId, customer?, transactions: [{ card: { cardholderName, cardNumber, expirationMonth, expirationYear, securityCode }, paymentType: 2, amount, installmentNumber, installmentType, autoCapture?, softDescriptor? }], source: 1 } }
174
+ - POST /v2/charge/preauthorization - Pré-autorização
175
+ - POST /v2/charge/preauthorization/incremental - Incremental: { chargeId, transactionId, incrementalAmount }
176
+ - POST /v2/charge/capture - Captura: { chargeId, transactionId?, amount? }
177
+
178
+ 3DS (3D Secure):
179
+ - POST /v2/charge/ecommerce/3ds/setup - Setup
180
+ - PUT /v2/charge/ecommerce/3ds/enrollment - Enrollment
181
+ - PUT /v2/charge/ecommerce - Transação 3DS
182
+
183
+ PIX:
184
+ - POST /v2/charge/pix - Criar: { charge: { merchantChargeId, transactions: [{ amount, paymentType: "Pix", expirationDate? }], source: 1 } }
185
+ Response: { chargeId, transactions: [{ qrCode, qrCodeText }] }
186
+
187
+ BOLETO:
188
+ - POST /v2/charge/boleto - Criar: { charge: { merchantChargeId, customer, transactions: [{ amount, paymentType: "Boleto", dueDate, instructions?, fine?, interest?, discount? }] } }
189
+ - GET /v2/charge/{chargeId}/boleto/{transactionId} - Consultar
190
+
191
+ BIN:
192
+ - GET /Card/Bin/Brand/{bin} - Consultar bandeira
193
+
194
+ PRODUTOS:
195
+ - POST /v1/product - Criar: { name, description?, price, sku?, active? }
196
+ - GET /v1/product - Listar: query { currentPage?, pageSize?, active? }
197
+ - PUT /v1/product/{productId} - Atualizar
198
+ - GET /v1/product/{productId} - Buscar
199
+
200
+ TAXAS:
201
+ - POST /tax - Criar: { name, description?, fees: [{ paymentType, installmentNumber, fee, fixedFee? }] }
202
+ - GET /tax - Listar
203
+ - PUT /tax - Atualizar
204
+ - DELETE /tax/{taxPlanId} - Deletar
205
+ - PUT /tax/Activate/{taxPlanId} - Ativar
206
+
207
+ VALORES: em centavos (1000 = R$ 10,00)
208
+ paymentType: 2=Crédito, 3=Débito
209
+ installmentType: 0=À vista, 2=Com juros, 3=Sem juros`,
210
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
211
+ api: zod_1.z.enum(["PORTAL", "GATEWAY"]).describe("API base"),
212
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE"]).describe("Método HTTP"),
213
+ path: zod_1.z.string().describe("Caminho do endpoint"),
214
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
215
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
216
+ })),
217
+ },
218
+ {
219
+ name: "safrapay_charges",
220
+ description: `Gestão de cobranças: buscar, capturar e cancelar.
221
+
222
+ ENDPOINTS:
223
+ - GET /v2/charge/{chargeId} - Buscar cobrança
224
+ Response: { chargeId, merchantChargeId, status, amount, transactions: [...] }
225
+
226
+ - POST /v2/charge/capture - Capturar cobrança pré-autorizada
227
+ Body: { chargeId, transactionId?, amount? }
228
+
229
+ - POST /v2/charge/cancelation - Cancelar/Estornar cobrança
230
+ Body: { chargeId, transactionId?, amount? }
231
+
232
+ STATUS: 1=Pendente, 2=Autorizada, 3=Capturada, 4=Cancelada, 5=Negada, 6=Estornada`,
233
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
234
+ method: zod_1.z.enum(["GET", "POST"]).describe("Método HTTP"),
235
+ path: zod_1.z.string().describe("Caminho do endpoint (ex: /v2/charge/{chargeId})"),
236
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
237
+ })),
238
+ },
239
+ {
240
+ name: "safrapay_vault",
241
+ description: `Tokenização e armazenamento seguro de cartões (Cartão Protegido).
242
+
243
+ CARTÃO:
244
+ - POST /card - Salvar: { customerId, card: { cardholderName, cardNumber, expirationMonth, expirationYear, securityCode }, alias? }
245
+ Response: { cardToken, maskedCardNumber, cardBrand }
246
+
247
+ - PUT /card - Atualizar: { cardToken, expirationMonth?, expirationYear?, alias? }
248
+
249
+ - GET /card - Buscar: query { cardToken }
250
+
251
+ - GET /card/byCustomer - Por cliente: query { customerId }
252
+
253
+ - DELETE /card/{cardId} - Deletar
254
+
255
+ CARTÃO TEMPORÁRIO:
256
+ - POST /temporary/card - Criar: { card: {...} }
257
+ Response: { temporaryToken, expiresIn }
258
+
259
+ VALIDAÇÃO ZERO DOLLAR:
260
+ - POST /card/validation/zerodollar - Validar: { customerId, card: {...} }
261
+ Response: { cardToken, validationResult, transactionId }
262
+
263
+ Use cardToken nas transações ao invés dos dados completos do cartão.`,
264
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
265
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE"]).describe("Método HTTP"),
266
+ path: zod_1.z.string().describe("Caminho do endpoint"),
267
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
268
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
269
+ })),
270
+ },
271
+ {
272
+ name: "safrapay_recurrence",
273
+ description: `Gestão de planos e assinaturas recorrentes.
274
+
275
+ PLANOS:
276
+ - POST /plan - Criar: { name, description?, amount, interval: 1-4 (1=Diário, 2=Semanal, 3=Mensal, 4=Anual), intervalCount, trialDays?, cycles?, active? }
277
+ - PUT /plan - Atualizar: { planId, ... }
278
+ - GET /plan/all - Listar: query { currentPage?, pageSize?, active? }
279
+ - DELETE /plan - Deletar: query { planId }
280
+
281
+ ASSINATURAS:
282
+ - POST /subscription - Criar: { planId, customerId, cardToken?, startDate?, description?, metadata? }
283
+ - POST /subscription/bulk - Em lote: { subscriptions: [{...}] }
284
+ - PUT /subscription/cancelation/{subscriptionId} - Cancelar: { cancelReason? }
285
+ - GET /subscription/{subscriptionId} - Buscar
286
+ - GET /subscription - Listar: query { currentPage?, pageSize?, status?, customerId? }
287
+ - GET /subscription/report - Relatório: query { startDate, endDate, format? }
288
+ - PATCH /subscription/{subscriptionId} - Atualizar: { cardToken?, metadata? }
289
+
290
+ VALORES: amount em centavos
291
+ cycles: null = infinito`,
292
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
293
+ api: zod_1.z.enum(["PORTAL", "GATEWAY"]).describe("API base"),
294
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).describe("Método HTTP"),
295
+ path: zod_1.z.string().describe("Caminho do endpoint"),
296
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
297
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
298
+ })),
299
+ },
300
+ {
301
+ name: "safrapay_payment_link",
302
+ description: `Links de pagamento (SmartCheckout).
303
+
304
+ ENDPOINTS:
305
+ - POST /paymentlink - Criar: { name, description?, amount, maxInstallments?, expirationDate?, paymentTypes?, metadata? }
306
+ Response: { smartcheckoutId, url }
307
+
308
+ - GET /smartcheckout/{smartcheckoutId}/detail - Detalhes
309
+
310
+ - DELETE /smartcheckout/{smartcheckoutId} - Deletar
311
+
312
+ - GET /smartcheckout - Listar: query { currentPage?, pageSize?, status? }
313
+
314
+ paymentTypes: 2=Crédito, 3=Débito, 4=Boleto, 5=Pix`,
315
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
316
+ method: zod_1.z.enum(["GET", "POST", "DELETE"]).describe("Método HTTP"),
317
+ path: zod_1.z.string().describe("Caminho do endpoint"),
318
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
319
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
320
+ })),
321
+ },
322
+ {
323
+ name: "safrapay_checkout",
324
+ description: `Criação de sessões de checkout com SDK.
325
+
326
+ ENDPOINTS:
327
+ - POST /smartcheckout - Criar: { charge: { merchantChargeId, amount, customer?, source: 1 }, settings: { type: 1-3 (1=Redirect, 2=Lightbox, 3=Transparente), paymentTypes?, maxInstallments?, returnUrl?, callbackUrl? } }
328
+ Response: { smartcheckoutId, url?, token? }
329
+
330
+ - GET /smartcheckout/{smartcheckoutId}/detail - Detalhes
331
+
332
+ SDKs disponíveis para integração frontend.`,
333
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
334
+ method: zod_1.z.enum(["GET", "POST"]).describe("Método HTTP"),
335
+ path: zod_1.z.string().describe("Caminho do endpoint"),
336
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
337
+ })),
338
+ },
339
+ {
340
+ name: "safrapay_split",
341
+ description: `Split de pagamentos entre múltiplos recebedores.
342
+
343
+ RECEBEDORES:
344
+ - POST /receiver - Criar: { name, document: { type: 1-2 (1=CPF, 2=CNPJ), number }, bankAccount: { bank, agency, agencyDigit?, account, accountDigit, accountType: 1-2 (1=Corrente, 2=Poupança) }, email?, phone? }
345
+ Response: { receiverId }
346
+ - PUT /receiver - Atualizar: { receiverId, ... }
347
+ - GET /receiver/{receiverId} - Buscar
348
+
349
+ SPLIT:
350
+ - PUT /charge/split/ - Configurar: { chargeId, splits: [{ receiverId, type: 1-2 (1=Percentual, 2=Fixo), value, feeResponsible }] }
351
+
352
+ EXTRATO (Reconciliation API):
353
+ - GET /Account/Movement/Extract - query { startDate, endDate, receiverId?, currentPage?, pageSize? }
354
+ - GET /Future/Movement/Resume - query { receiverId? }
355
+ - GET /Account/Movement/Amount/Available - query { receiverId? }`,
356
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
357
+ api: zod_1.z.enum(["PORTAL", "GATEWAY", "RECONCILIATION"]).describe("API base"),
358
+ method: zod_1.z.enum(["GET", "POST", "PUT"]).describe("Método HTTP"),
359
+ path: zod_1.z.string().describe("Caminho do endpoint"),
360
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
361
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
362
+ })),
363
+ },
364
+ {
365
+ name: "safrapay_accreditation",
366
+ description: `Credenciamento: gestão de estabelecimentos (merchants) e adquirentes virtuais.
367
+
368
+ ESTABELECIMENTO:
369
+ - POST /v1/Merchant - Criar: { name, tradeName, document: { type, number }, email, phone, address, businessCategory, mcc, parentMerchantId? }
370
+ - PUT /v1/Merchant - Atualizar: { merchantId, ... }
371
+ - DELETE /v1/Merchant - Deletar: query { merchantId }
372
+ - GET /v1/Merchant - Listar: query { currentPage?, pageSize? }
373
+ - GET /v1/Merchant/{merchantId} - Buscar
374
+ - GET /v1/Merchant/GetChildMerchantsByParentId - Sub-merchants: query { parentMerchantId }
375
+ - GET /v1/Merchant/GetByUserId - Por usuário: query { userId }
376
+ - GET /v1/Merchant/{merchantId}/Taxes - Taxas
377
+ - GET /v1/Merchant/Mcc - Listar MCCs
378
+ - GET /v1/Merchant/Terminal - Terminais: query { merchantId? }
379
+ - GET /v1/Merchant/{merchantId}/BankSlipTaxesPlan - Taxas boleto
380
+ - GET /v1/Merchant/Taxes/Products - Produtos de taxas
381
+ - PUT /v1/Merchant/{merchantId}/Taxes/Products - Atualizar produtos: { products: [{ productId, active }] }
382
+ - PUT /v1/Merchant/UploadDocuments - Upload docs (multipart/form-data)
383
+ - POST /v1/Merchant/{merchantId}/Reconciliation - Criar reconciliação: { acquirerId, clientId, clientSecret }
384
+ - DELETE /v1/Merchant/{merchantId}/Reconciliation/{acquirerId}/{clientId} - Deletar
385
+ - PATCH /v1/Merchant/{merchantId}/Reconciliation/{acquirerId}/{clientId} - Atualizar: { clientSecret?, active? }
386
+
387
+ ADQUIRENTE VIRTUAL:
388
+ - POST /VirtualAcquirer - Criar: { name, cnpj, active? }
389
+ - GET /VirtualAcquirer - Listar
390
+ - PUT /VirtualAcquirer/{virtualAcquirerId} - Atualizar
391
+ - DELETE /VirtualAcquirer/{virtualAcquirerId} - Deletar`,
392
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
393
+ method: zod_1.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]).describe("Método HTTP"),
394
+ path: zod_1.z.string().describe("Caminho do endpoint"),
395
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
396
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
397
+ isMultipart: zod_1.z.boolean().optional().describe("true para upload de arquivos"),
398
+ })),
399
+ },
400
+ {
401
+ name: "safrapay_webhook",
402
+ description: `Configuração de webhooks para notificações de eventos.
403
+
404
+ ENDPOINTS:
405
+ - POST /webhook/bulk - Criar: { url, events: ["CHARGE_PAID", "CHARGE_REFUNDED", "CHARGE_CANCELED", "CHARGE_CHARGEBACK", "SUBSCRIPTION_CREATED", "SUBSCRIPTION_CANCELED", "SUBSCRIPTION_PAYMENT_SUCCESS", "SUBSCRIPTION_PAYMENT_FAILED"], active?, headers? }
406
+
407
+ - GET /webhook - Listar: query { currentPage?, pageSize? }
408
+
409
+ - PUT /Webhook/Cancel/{webhookId} - Cancelar
410
+
411
+ EVENTOS:
412
+ - CHARGE_PAID: Cobrança paga
413
+ - CHARGE_REFUNDED: Estornada
414
+ - CHARGE_CANCELED: Cancelada
415
+ - CHARGE_CHARGEBACK: Chargeback
416
+ - SUBSCRIPTION_*: Eventos de assinatura`,
417
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
418
+ method: zod_1.z.enum(["GET", "POST", "PUT"]).describe("Método HTTP"),
419
+ path: zod_1.z.string().describe("Caminho do endpoint"),
420
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
421
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
422
+ })),
423
+ },
424
+ {
425
+ name: "safrapay_chargeback",
426
+ description: `Gestão de disputas e chargebacks.
427
+
428
+ ENDPOINTS:
429
+ - GET /v1/disputes/summary - Resumo: query { startDate?, endDate? }
430
+
431
+ - GET /v1/disputes/total - Total: query { status? }
432
+
433
+ - GET /v1/disputes/{disputeId} - Detalhes
434
+
435
+ - POST /v1/disputes/{disputeId}/debts/accept - Aceitar débito: { acceptReason? }
436
+
437
+ - POST /v1/disputes/second-presentment - Representação (multipart): { disputeId, documents: File[], description }`,
438
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
439
+ method: zod_1.z.enum(["GET", "POST"]).describe("Método HTTP"),
440
+ path: zod_1.z.string().describe("Caminho do endpoint"),
441
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
442
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
443
+ isMultipart: zod_1.z.boolean().optional().describe("true para upload de documentos"),
444
+ })),
445
+ },
446
+ {
447
+ name: "safrapay_tef",
448
+ description: `Integração com PinPads via protocolo TEF.
449
+
450
+ FLUXO TRANSACIONAL:
451
+ - POST /Init - Inicializar: { terminalId, softwareVersion }
452
+ - POST /Payment - Pagamento: { amount, installments, transactionType }
453
+ - GET /Abort - Abortar
454
+ - GET /Cancelation - Cancelar: query { transactionId, amount? }
455
+ - GET /Reversal - Estornar: query { transactionId }
456
+ - GET /GetPending - Buscar pendências
457
+ - GET /Confirm - Confirmar: query { transactionId }
458
+
459
+ FUNÇÕES AUXILIARES:
460
+ - GET /Display - Display
461
+ - POST /DataPicker - Seletor: { options: string[], message }
462
+ - GET /WaitEvent - Aguardar evento
463
+ - GET /Status - Status
464
+ - GET /RemoveCard - Remover cartão`,
465
+ inputSchema: (0, zod_to_json_schema_1.zodToJsonSchema)(zod_1.z.object({
466
+ method: zod_1.z.enum(["GET", "POST"]).describe("Método HTTP"),
467
+ path: zod_1.z.string().describe("Caminho do endpoint"),
468
+ body: zod_1.z.record(zod_1.z.any()).optional().describe("Corpo JSON"),
469
+ params: zod_1.z.record(zod_1.z.any()).optional().describe("Query parameters"),
470
+ })),
471
+ },
472
+ ],
473
+ }));
474
+ this.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
475
+ try {
476
+ const toolName = request.params.name;
477
+ const args = request.params.arguments;
478
+ // Todas as ferramentas agrupadas usam o mesmo handler genérico
479
+ if (toolName.startsWith("safrapay_")) {
480
+ return await this.handleGroupedTool(toolName, args);
481
+ }
482
+ throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}`);
483
+ }
484
+ catch (error) {
485
+ const errorMessage = error.response?.data
486
+ ? JSON.stringify(error.response.data)
487
+ : error.message;
488
+ return {
489
+ content: [
490
+ {
491
+ type: "text",
492
+ text: `Erro na execução: ${errorMessage}`,
493
+ },
494
+ ],
495
+ isError: true,
496
+ };
497
+ }
498
+ });
499
+ }
500
+ async handleGroupedTool(toolName, args) {
501
+ const { api, method, path, body, params, headers, isMultipart } = args;
502
+ // Determina qual API usar baseado no contexto
503
+ let apiType;
504
+ if (toolName === "safrapay_authentication") {
505
+ apiType = api || "PORTAL";
506
+ }
507
+ else if (toolName === "safrapay_payments") {
508
+ apiType = api || "GATEWAY";
509
+ }
510
+ else if (toolName === "safrapay_charges" || toolName === "safrapay_vault" || toolName === "safrapay_checkout" || toolName === "safrapay_tef") {
511
+ apiType = "GATEWAY";
512
+ }
513
+ else if (toolName === "safrapay_recurrence") {
514
+ apiType = api || (path.includes("/plan") ? "PORTAL" : "GATEWAY");
515
+ }
516
+ else if (toolName === "safrapay_payment_link") {
517
+ apiType = "PORTAL";
518
+ }
519
+ else if (toolName === "safrapay_split") {
520
+ apiType = api || (path.includes("/Account") || path.includes("/Future") ? "RECONCILIATION" : "PORTAL");
521
+ }
522
+ else if (toolName === "safrapay_accreditation" || toolName === "safrapay_webhook" || toolName === "safrapay_chargeback") {
523
+ apiType = "PORTAL";
524
+ }
525
+ else {
526
+ apiType = api || "GATEWAY";
527
+ }
528
+ const instance = this.axiosInstances[apiType];
529
+ const config = {
530
+ method,
531
+ url: path,
532
+ data: body,
533
+ params,
534
+ headers: headers || {},
535
+ };
536
+ if (isMultipart) {
537
+ config.headers = {
538
+ ...config.headers,
539
+ "Content-Type": "multipart/form-data",
540
+ };
541
+ }
542
+ // Se não há token, autentica antes da primeira requisição
543
+ if (!this.token) {
544
+ await this.autoAuthenticate();
545
+ }
546
+ // Executa a requisição (o interceptor cuida da reautenticação automática se necessário)
547
+ const response = await instance.request(config);
548
+ return {
549
+ content: [
550
+ {
551
+ type: "text",
552
+ text: JSON.stringify(response.data, null, 2),
553
+ },
554
+ ],
555
+ };
556
+ }
557
+ async run() {
558
+ const transport = new stdio_js_1.StdioServerTransport();
559
+ await this.server.connect(transport);
560
+ console.error(`SafraPay MCP Server v0.2.0 running on stdio [Env: ${this.env}]`);
561
+ }
562
+ }
563
+ const server = new SafraPayServer();
564
+ server.run().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@marcelocorrea/mcp-safrapay",
3
+ "version": "0.2.0",
4
+ "description": "MCP Server for SafraPay Integration",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "mcp-safrapay": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "start": "node dist/index.js",
16
+ "dev": "tsc --watch",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "mcp-server",
22
+ "safrapay",
23
+ "safra",
24
+ "model-context-protocol",
25
+ "payment",
26
+ "payment-gateway",
27
+ "pix",
28
+ "boleto",
29
+ "credit-card",
30
+ "brasil",
31
+ "brazil"
32
+ ],
33
+ "author": "Marcelo Correa",
34
+ "license": "ISC",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/marcelocorrea/mcp-safrapay.git"
38
+ },
39
+ "homepage": "https://github.com/marcelocorrea/mcp-safrapay#readme",
40
+ "bugs": {
41
+ "url": "https://github.com/marcelocorrea/mcp-safrapay/issues"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ },
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "^1.0.1",
48
+ "axios": "^1.6.0",
49
+ "dotenv": "^16.0.0",
50
+ "zod": "^3.22.0",
51
+ "zod-to-json-schema": "^3.25.1"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.0.0",
55
+ "typescript": "^5.0.0"
56
+ }
57
+ }