Skip to content

Commit 8718908

Browse files
committed
feat: ✨ remove description field to improve bank compatibility
- Remove description field from all PIX interfaces and schemas - Eliminate field 62 (Additional Data) from EMV payload generation - Update all tests to reflect simplified PIX structure - Update README examples to remove description usage - Reduces PIX code size from 155+ to 129 characters - Improves bank acceptance by removing potential rejection source BREAKING CHANGE: description parameter no longer supported in generateStaticPix
1 parent 85b435d commit 8718908

File tree

6 files changed

+92
-158
lines changed

6 files changed

+92
-158
lines changed

README.md

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ curl -X POST http://localhost:3000/tools/call \
5555
"pixKey": "10891990909",
5656
"amount": 100.50,
5757
"recipientName": "Franco Camelo Aguzzi",
58-
"recipientCity": "Florianopolis",
59-
"description": "Payment for services"
58+
"recipientCity": "Florianopolis"
6059
}
6160
}'
6261
```
@@ -69,7 +68,6 @@ const result = await mcpClient.callTool('generateStaticPix', {
6968
amount: 100.5,
7069
recipientName: 'Franco Camelo Aguzzi',
7170
recipientCity: 'Florianopolis',
72-
description: 'Payment for services',
7371
});
7472
```
7573

@@ -150,11 +148,10 @@ Creates a static Pix payment QR code following BACEN EMV 4.0 standards.
150148
- `amount` (number): Payment amount in BRL (0.01 to 999,999.99)
151149
- `recipientName` (string): Name of the payment recipient (max 25 chars)
152150
- `recipientCity` (string): City of the payment recipient (max 15 chars)
153-
- `description` (string, optional): Payment description (max 25 chars)
154151

155152
**Returns:**
156153

157-
- Payment details (amount, recipient, city, description)
154+
- Payment details (amount, recipient, city)
158155
- Pix copy-paste code (EMV format)
159156
- QR code image (base64 data URL)
160157
- Success status and message
@@ -197,17 +194,11 @@ npm run format
197194
- [x] EMV 4.0 compliance
198195
- [x] CRC16-CCITT validation
199196
- [x] All Pix key types support
197+
- [x] Public deployment
200198

201199
### Phase 2: MCP Discovery
202200

203201
- [ ] Register with MCP registry
204-
- [ ] Public deployment
205-
206-
### Phase 3: Tool Expansion
207-
208-
- [ ] Dynamic Pix codes (with expiration)
209-
- [ ] Payment status checking
210-
- [ ] Webhook support for payment notifications
211202

212203
## 🔒 Security & Validation
213204

src/index.ts

Lines changed: 51 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
55
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
66
import http from 'http';
77
import { URL } from 'url';
8-
import {
9-
CallToolRequestSchema,
10-
ListToolsRequestSchema,
11-
} from '@modelcontextprotocol/sdk/types.js';
8+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
129
import { z } from 'zod';
1310
import { StaticPixService } from './services/StaticPixService.js';
1411

@@ -18,7 +15,6 @@ const GenerateStaticPixSchema = z.object({
1815
amount: z.number().positive().max(999999.99),
1916
recipientName: z.string().min(1).max(25),
2017
recipientCity: z.string().min(1).max(15),
21-
description: z.string().optional().default(''),
2218
});
2319

2420
class PixMCPServer {
@@ -53,7 +49,8 @@ class PixMCPServer {
5349
tools: [
5450
{
5551
name: 'generateStaticPix',
56-
description: 'Generate a static Pix QR code for any Pix key (works without API credentials)',
52+
description:
53+
'Generate a static Pix QR code for any Pix key (works without API credentials)',
5754
inputSchema: {
5855
type: 'object',
5956
properties: {
@@ -81,11 +78,6 @@ class PixMCPServer {
8178
minLength: 1,
8279
maxLength: 15,
8380
},
84-
description: {
85-
type: 'string',
86-
description: 'Optional payment description',
87-
maxLength: 25,
88-
},
8981
},
9082
required: ['pixKey', 'amount', 'recipientName', 'recipientCity'],
9183
},
@@ -112,7 +104,7 @@ class PixMCPServer {
112104
case 'generateStaticPix': {
113105
const validatedArgs = GenerateStaticPixSchema.parse(args);
114106
const result = await this.staticPixService.createStaticPix(validatedArgs);
115-
107+
116108
return {
117109
content: [
118110
{
@@ -122,7 +114,6 @@ class PixMCPServer {
122114
**Payment Details:**
123115
- Amount: R$ ${result.paymentDetails.amountFormatted}
124116
- Recipient: ${result.paymentDetails.recipient}
125-
- Description: ${result.paymentDetails.description || 'N/A'}
126117
- PIX Key: ${result.paymentDetails.pixKey}
127118
- City: ${result.paymentDetails.city}
128119
@@ -132,9 +123,9 @@ class PixMCPServer {
132123
**QR Code:**
133124
${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code generation failed'}
134125
135-
⚠️ **Note**: This is a static Pix code. Payment confirmation must be checked manually by the recipient.`
136-
}
137-
]
126+
⚠️ **Note**: This is a static Pix code. Payment confirmation must be checked manually by the recipient.`,
127+
},
128+
],
138129
};
139130
}
140131

@@ -144,17 +135,17 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
144135
timestamp: new Date().toISOString(),
145136
version: '2.0.0',
146137
mode: 'static-pix',
147-
status: 'operational'
138+
status: 'operational',
148139
};
149-
140+
150141
return {
151142
content: [
152143
{
153144
type: 'text',
154-
text: `✅ Server is healthy\nVersion: ${status.version}\nMode: ${status.mode}\nStatus: ${status.status}`
155-
}
145+
text: `✅ Server is healthy\nVersion: ${status.version}\nMode: ${status.mode}\nStatus: ${status.status}`,
146+
},
156147
],
157-
status
148+
status,
158149
};
159150
}
160151

@@ -182,23 +173,25 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
182173
res.setHeader('Access-Control-Allow-Origin', '*');
183174
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
184175
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
185-
176+
186177
if (req.method === 'OPTIONS') {
187178
res.writeHead(200);
188179
res.end();
189180
return;
190181
}
191182

192183
const url = new URL(req.url!, `http://${req.headers.host}`);
193-
184+
194185
if (url.pathname === '/health') {
195186
res.writeHead(200, { 'Content-Type': 'application/json' });
196-
res.end(JSON.stringify({
197-
status: 'healthy',
198-
service: 'pix-mcp-server',
199-
version: '1.0.0',
200-
timestamp: new Date().toISOString()
201-
}));
187+
res.end(
188+
JSON.stringify({
189+
status: 'healthy',
190+
service: 'pix-mcp-server',
191+
version: '1.0.0',
192+
timestamp: new Date().toISOString(),
193+
})
194+
);
202195
return;
203196
}
204197

@@ -223,18 +216,14 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
223216
minLength: 1,
224217
maxLength: 100,
225218
},
226-
description: {
227-
type: 'string',
228-
description: 'Optional payment description',
229-
maxLength: 200,
230-
},
231219
},
232220
required: ['amount', 'recipientName'],
233221
},
234222
},
235223
{
236224
name: 'generateStaticPix',
237-
description: 'Generate a static Pix QR code for any Pix key (works without API credentials)',
225+
description:
226+
'Generate a static Pix QR code for any Pix key (works without API credentials)',
238227
inputSchema: {
239228
type: 'object',
240229
properties: {
@@ -262,11 +251,6 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
262251
minLength: 1,
263252
maxLength: 15,
264253
},
265-
description: {
266-
type: 'string',
267-
description: 'Optional payment description',
268-
maxLength: 25,
269-
},
270254
},
271255
required: ['pixKey', 'amount', 'recipientName', 'recipientCity'],
272256
},
@@ -289,37 +273,38 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
289273

290274
if (url.pathname === '/tools/call' && req.method === 'POST') {
291275
let body = '';
292-
req.on('data', chunk => body += chunk);
276+
req.on('data', (chunk) => (body += chunk));
293277
req.on('end', async () => {
294278
try {
295279
const { name, arguments: args } = JSON.parse(body);
296-
280+
297281
// Handle tool calls directly
298282
if (name === 'generateStaticPix') {
299283
const validatedArgs = GenerateStaticPixSchema.parse(args);
300284
const result = await this.staticPixService.createStaticPix(validatedArgs);
301-
285+
302286
const response = {
303-
content: [{
304-
type: 'text',
305-
text: `✅ Static Pix QR code generated successfully!
287+
content: [
288+
{
289+
type: 'text',
290+
text: `✅ Static Pix QR code generated successfully!
306291
307292
**Payment Details:**
308293
- Amount: ${result.paymentDetails.amountFormatted}
309294
- Recipient: ${result.paymentDetails.recipient}
310295
- City: ${result.paymentDetails.city}
311-
- Description: ${result.paymentDetails.description || 'N/A'}
312296
313297
**Pix Code (copy and paste):**
314298
\`${result.pixCode}\`
315299
316300
**QR Code:**
317301
${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code generation failed'}
318302
319-
⚠️ **Note**: This is a static Pix code. Payment confirmation must be checked manually by the recipient.`
320-
}]
303+
⚠️ **Note**: This is a static Pix code. Payment confirmation must be checked manually by the recipient.`,
304+
},
305+
],
321306
};
322-
307+
323308
res.writeHead(200, { 'Content-Type': 'application/json' });
324309
res.end(JSON.stringify(response));
325310
} else if (name === 'healthCheck') {
@@ -328,23 +313,25 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
328313
timestamp: new Date().toISOString(),
329314
version: '2.0.0',
330315
mode: 'static-pix',
331-
status: 'operational'
316+
status: 'operational',
332317
};
333-
318+
334319
const response = {
335-
content: [{
336-
type: 'text',
337-
text: `🟢 **Pix MCP Server Health Check**
320+
content: [
321+
{
322+
type: 'text',
323+
text: `🟢 **Pix MCP Server Health Check**
338324
339325
**Status:** ${status.server}
340326
**Version:** ${status.version}
341327
**Mode:** ${status.mode}
342328
**Timestamp:** ${status.timestamp}
343329
344-
✅ All systems operational`
345-
}]
330+
✅ All systems operational`,
331+
},
332+
],
346333
};
347-
334+
348335
res.writeHead(200, { 'Content-Type': 'application/json' });
349336
res.end(JSON.stringify(response));
350337
} else {
@@ -353,10 +340,12 @@ ${result.qrCodeDataUrl ? `![QR Code](${result.qrCodeDataUrl})` : 'QR Code genera
353340
} catch (error) {
354341
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
355342
const response = {
356-
content: [{
357-
type: 'text',
358-
text: `❌ Error: ${errorMessage}`,
359-
}],
343+
content: [
344+
{
345+
type: 'text',
346+
text: `❌ Error: ${errorMessage}`,
347+
},
348+
],
360349
isError: true,
361350
};
362351
res.writeHead(400, { 'Content-Type': 'application/json' });

src/services/PixService.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
import { PixChargeRequest, PixChargeResponse, StaticPixRequest, StaticPixResponse } from '../types/PixTypes.js';
1+
import {
2+
PixChargeRequest,
3+
PixChargeResponse,
4+
StaticPixRequest,
5+
StaticPixResponse,
6+
} from '../types/PixTypes.js';
27
import { StaticPixService } from './StaticPixService.js';
38

49
export class PixService {
@@ -27,21 +32,21 @@ export class PixService {
2732
amount: request.amount,
2833
recipientName: request.recipientName,
2934
recipientCity: request.recipientCity,
30-
description: request.description || ''
3135
});
3236

3337
return {
3438
txid: `static-${Date.now()}`,
3539
amount: result.paymentDetails.amount,
3640
recipientName: result.paymentDetails.recipient,
37-
description: result.paymentDetails.description,
3841
pixCode: result.pixCode,
3942
qrCodeDataUrl: result.qrCodeDataUrl,
4043
expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days from now
41-
provider: 'static-pix'
44+
provider: 'static-pix',
4245
};
4346
} catch (error) {
44-
throw new Error(`Failed to create static Pix: ${error instanceof Error ? error.message : 'Unknown error'}`);
47+
throw new Error(
48+
`Failed to create static Pix: ${error instanceof Error ? error.message : 'Unknown error'}`
49+
);
4550
}
4651
}
4752

0 commit comments

Comments
 (0)