@codespar/mcp-dock 0.1.0-alpha.1 → 0.2.0-alpha.2
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.
- package/README.md +24 -14
- package/dist/index.js +224 -13
- package/package.json +2 -2
- package/server.json +2 -2
- package/src/index.ts +211 -13
package/README.md
CHANGED
|
@@ -73,20 +73,30 @@ Add to `.cursor/mcp.json` or `.vscode/mcp.json`:
|
|
|
73
73
|
}
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
## Tools
|
|
77
|
-
|
|
78
|
-
| Tool |
|
|
79
|
-
|
|
80
|
-
| `create_account` |
|
|
81
|
-
| `get_account` | Retrieve account
|
|
82
|
-
| `send_pix` |
|
|
83
|
-
| `get_pix` | Retrieve Pix payment by endToEndId |
|
|
84
|
-
| `create_pix_qr_static` |
|
|
85
|
-
| `create_pix_qr_dynamic` |
|
|
86
|
-
| `refund_pix` | Refund (devolução) a Pix payment |
|
|
87
|
-
| `resolve_dict_key` |
|
|
88
|
-
| `issue_card` | Issue debit / credit / prepaid / virtual
|
|
89
|
-
| `get_card` | Retrieve card
|
|
76
|
+
## Tools (20)
|
|
77
|
+
|
|
78
|
+
| Tool | Purpose |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `create_account` | Create a digital account for an end user (CPF holder) on Dock. |
|
|
81
|
+
| `get_account` | Retrieve a Dock account by id. |
|
|
82
|
+
| `send_pix` | Initiate an outbound Pix transfer from a Dock account to any Pix key in BR. |
|
|
83
|
+
| `get_pix` | Retrieve an outbound Pix payment by endToEndId. |
|
|
84
|
+
| `create_pix_qr_static` | Create a static Pix QR (reusable, tied to a merchant Pix key). |
|
|
85
|
+
| `create_pix_qr_dynamic` | Create a dynamic Pix QR (single-use, expiring). |
|
|
86
|
+
| `refund_pix` | Refund (devolução) a Pix payment. |
|
|
87
|
+
| `resolve_dict_key` | Resolve a Pix DICT key to the account holder's identity and ISPB/branch/account. |
|
|
88
|
+
| `issue_card` | Issue a card (debit / credit / prepaid / virtual) against a Dock account. |
|
|
89
|
+
| `get_card` | Retrieve a card by id. |
|
|
90
|
+
| `list_accounts` | List Dock accounts under the merchant. |
|
|
91
|
+
| `freeze_account` | Freeze (block) a Dock account. |
|
|
92
|
+
| `unfreeze_account` | Unfreeze a previously frozen Dock account, restoring Pix and card operations. |
|
|
93
|
+
| `block_card` | Block a card temporarily (reversible). |
|
|
94
|
+
| `unblock_card` | Unblock a card that was previously blocked (reversible). |
|
|
95
|
+
| `change_card_status` | Change a card's lifecycle status: ACTIVE / BLOCKED / CANCELED. |
|
|
96
|
+
| `list_transactions` | List transactions on a Dock account (Pix in/out, card auths, fees, transfers). |
|
|
97
|
+
| `get_transaction` | Retrieve a single transaction by id. |
|
|
98
|
+
| `create_webhook` | Register a webhook endpoint to receive Dock event notifications (account.*, pix.*, card.*, transaction.*). |
|
|
99
|
+
| `list_webhooks` | List all webhook endpoints registered for the merchant. |
|
|
90
100
|
|
|
91
101
|
## Authentication
|
|
92
102
|
|
package/dist/index.js
CHANGED
|
@@ -8,17 +8,27 @@
|
|
|
8
8
|
* Card issuing is the key differentiator vs Matera — Dock is historically
|
|
9
9
|
* a card-issuing platform that expanded into full BaaS.
|
|
10
10
|
*
|
|
11
|
-
* Tools (
|
|
12
|
-
* create_account — POST
|
|
13
|
-
* get_account — GET
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
11
|
+
* Tools (20) — Banking + Pix + Card Issuing + Webhooks:
|
|
12
|
+
* create_account — POST /accounts (digital account for an end user)
|
|
13
|
+
* get_account — GET /accounts/{id}
|
|
14
|
+
* list_accounts — GET /accounts
|
|
15
|
+
* freeze_account — POST /accounts/{id}/freeze
|
|
16
|
+
* unfreeze_account — POST /accounts/{id}/unfreeze
|
|
17
|
+
* send_pix — POST /pix/payments (outbound Pix transfer)
|
|
18
|
+
* get_pix — GET /pix/payments/{endToEndId}
|
|
19
|
+
* create_pix_qr_static — POST /pix/qrcodes/static
|
|
20
|
+
* create_pix_qr_dynamic — POST /pix/qrcodes/dynamic
|
|
21
|
+
* refund_pix — POST /pix/payments/{endToEndId}/refund
|
|
22
|
+
* resolve_dict_key — GET /pix/dict/{key}
|
|
23
|
+
* issue_card — POST /cards (Dock's core differentiator)
|
|
24
|
+
* get_card — GET /cards/{id}
|
|
25
|
+
* block_card — POST /cards/{id}/block
|
|
26
|
+
* unblock_card — POST /cards/{id}/unblock
|
|
27
|
+
* change_card_status — PATCH /cards/{id}/status
|
|
28
|
+
* list_transactions — GET /accounts/{id}/transactions
|
|
29
|
+
* get_transaction — GET /transactions/{id}
|
|
30
|
+
* create_webhook — POST /webhooks
|
|
31
|
+
* list_webhooks — GET /webhooks
|
|
22
32
|
*
|
|
23
33
|
* -------------------------------------------------------------------------
|
|
24
34
|
* ALPHA STATUS — endpoint paths below are NOT verified against a live sandbox.
|
|
@@ -99,7 +109,7 @@ async function dockRequest(method, path, body) {
|
|
|
99
109
|
const text = await res.text();
|
|
100
110
|
return text ? JSON.parse(text) : {};
|
|
101
111
|
}
|
|
102
|
-
const server = new Server({ name: "mcp-dock", version: "0.
|
|
112
|
+
const server = new Server({ name: "mcp-dock", version: "0.2.0" }, { capabilities: { tools: {} } });
|
|
103
113
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
104
114
|
tools: [
|
|
105
115
|
{
|
|
@@ -278,6 +288,136 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
278
288
|
required: ["card_id"],
|
|
279
289
|
},
|
|
280
290
|
},
|
|
291
|
+
{
|
|
292
|
+
name: "list_accounts",
|
|
293
|
+
description: "List Dock accounts under the merchant. Supports pagination and filtering by holder document or status.",
|
|
294
|
+
inputSchema: {
|
|
295
|
+
type: "object",
|
|
296
|
+
properties: {
|
|
297
|
+
cpf: { type: "string", description: "Filter by holder CPF (11 digits)" },
|
|
298
|
+
status: { type: "string", enum: ["ACTIVE", "FROZEN", "CLOSED"], description: "Filter by account status" },
|
|
299
|
+
page: { type: "number", description: "Page number (1-based)" },
|
|
300
|
+
page_size: { type: "number", description: "Results per page (default 20, max 100)" },
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
name: "freeze_account",
|
|
306
|
+
description: "Freeze (block) a Dock account. Pix outflows and card spend are halted but balance is preserved. Used for fraud holds, KYC re-verification, or judicial blocks.",
|
|
307
|
+
inputSchema: {
|
|
308
|
+
type: "object",
|
|
309
|
+
properties: {
|
|
310
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
311
|
+
reason: { type: "string", description: "Reason code or free-text justification (logged for audit)" },
|
|
312
|
+
},
|
|
313
|
+
required: ["account_id"],
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
name: "unfreeze_account",
|
|
318
|
+
description: "Unfreeze a previously frozen Dock account, restoring Pix and card operations.",
|
|
319
|
+
inputSchema: {
|
|
320
|
+
type: "object",
|
|
321
|
+
properties: {
|
|
322
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
323
|
+
reason: { type: "string", description: "Reason for the unblock (optional, logged)" },
|
|
324
|
+
},
|
|
325
|
+
required: ["account_id"],
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: "block_card",
|
|
330
|
+
description: "Block a card temporarily (reversible). Use for lost-card or fraud-suspected flows. Card status goes to BLOCKED — declines all authorizations until unblocked. Different from change_card_status which permanently cancels.",
|
|
331
|
+
inputSchema: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {
|
|
334
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
335
|
+
reason: { type: "string", description: "Reason: LOST, STOLEN, SUSPECTED_FRAUD, CARDHOLDER_REQUEST" },
|
|
336
|
+
},
|
|
337
|
+
required: ["card_id"],
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: "unblock_card",
|
|
342
|
+
description: "Unblock a card that was previously blocked (reversible). Restores card to ACTIVE status. Cannot be used on permanently CANCELED cards.",
|
|
343
|
+
inputSchema: {
|
|
344
|
+
type: "object",
|
|
345
|
+
properties: {
|
|
346
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
347
|
+
},
|
|
348
|
+
required: ["card_id"],
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "change_card_status",
|
|
353
|
+
description: "Change a card's lifecycle status: ACTIVE / BLOCKED / CANCELED. Use CANCELED for permanent termination (replacement card, account closure). Status transitions are constrained — see Dock issuing docs.",
|
|
354
|
+
inputSchema: {
|
|
355
|
+
type: "object",
|
|
356
|
+
properties: {
|
|
357
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
358
|
+
status: {
|
|
359
|
+
type: "string",
|
|
360
|
+
enum: ["ACTIVE", "BLOCKED", "CANCELED"],
|
|
361
|
+
description: "Target status",
|
|
362
|
+
},
|
|
363
|
+
reason: { type: "string", description: "Reason code or free text" },
|
|
364
|
+
},
|
|
365
|
+
required: ["card_id", "status"],
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "list_transactions",
|
|
370
|
+
description: "List transactions on a Dock account (Pix in/out, card auths, fees, transfers). Supports date range and pagination. Returns ordered by timestamp desc.",
|
|
371
|
+
inputSchema: {
|
|
372
|
+
type: "object",
|
|
373
|
+
properties: {
|
|
374
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
375
|
+
start_date: { type: "string", description: "ISO-8601 date or datetime (inclusive)" },
|
|
376
|
+
end_date: { type: "string", description: "ISO-8601 date or datetime (inclusive)" },
|
|
377
|
+
type: { type: "string", description: "Filter by transaction type (PIX_IN, PIX_OUT, CARD_AUTH, FEE, etc.)" },
|
|
378
|
+
page: { type: "number", description: "Page number (1-based)" },
|
|
379
|
+
page_size: { type: "number", description: "Results per page (default 50, max 200)" },
|
|
380
|
+
},
|
|
381
|
+
required: ["account_id"],
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
name: "get_transaction",
|
|
386
|
+
description: "Retrieve a single transaction by id. Returns full detail including counterparty, fees, and originating event (Pix endToEndId, card auth code, etc.).",
|
|
387
|
+
inputSchema: {
|
|
388
|
+
type: "object",
|
|
389
|
+
properties: {
|
|
390
|
+
transaction_id: { type: "string", description: "Dock transaction id" },
|
|
391
|
+
},
|
|
392
|
+
required: ["transaction_id"],
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: "create_webhook",
|
|
397
|
+
description: "Register a webhook endpoint to receive Dock event notifications (account.*, pix.*, card.*, transaction.*). Dock signs payloads with HMAC; verify the signature on receipt.",
|
|
398
|
+
inputSchema: {
|
|
399
|
+
type: "object",
|
|
400
|
+
properties: {
|
|
401
|
+
url: { type: "string", description: "HTTPS endpoint that will receive POSTed events" },
|
|
402
|
+
events: {
|
|
403
|
+
type: "array",
|
|
404
|
+
items: { type: "string" },
|
|
405
|
+
description: "Event types to subscribe to (e.g. ['pix.received','card.authorized']). Use ['*'] for all.",
|
|
406
|
+
},
|
|
407
|
+
secret: { type: "string", description: "Optional shared secret used for HMAC signature verification" },
|
|
408
|
+
description: { type: "string", description: "Free-text label" },
|
|
409
|
+
},
|
|
410
|
+
required: ["url", "events"],
|
|
411
|
+
},
|
|
412
|
+
},
|
|
413
|
+
{
|
|
414
|
+
name: "list_webhooks",
|
|
415
|
+
description: "List all webhook endpoints registered for the merchant. Returns id, url, subscribed events, and active status.",
|
|
416
|
+
inputSchema: {
|
|
417
|
+
type: "object",
|
|
418
|
+
properties: {},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
281
421
|
],
|
|
282
422
|
}));
|
|
283
423
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -322,6 +462,77 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
322
462
|
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
323
463
|
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/cards/${id}`), null, 2) }] };
|
|
324
464
|
}
|
|
465
|
+
// TODO(verify): list_accounts wrapper path; `/accounts?cpf=&status=&page=` is the standard shape.
|
|
466
|
+
case "list_accounts": {
|
|
467
|
+
const qs = new URLSearchParams();
|
|
468
|
+
if (a.cpf)
|
|
469
|
+
qs.set("cpf", String(a.cpf));
|
|
470
|
+
if (a.status)
|
|
471
|
+
qs.set("status", String(a.status));
|
|
472
|
+
if (a.page)
|
|
473
|
+
qs.set("page", String(a.page));
|
|
474
|
+
if (a.page_size)
|
|
475
|
+
qs.set("page_size", String(a.page_size));
|
|
476
|
+
const q = qs.toString();
|
|
477
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/accounts${q ? `?${q}` : ""}`), null, 2) }] };
|
|
478
|
+
}
|
|
479
|
+
case "freeze_account": {
|
|
480
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
481
|
+
const body = {};
|
|
482
|
+
if (a.reason)
|
|
483
|
+
body.reason = a.reason;
|
|
484
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/accounts/${id}/freeze`, body), null, 2) }] };
|
|
485
|
+
}
|
|
486
|
+
case "unfreeze_account": {
|
|
487
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
488
|
+
const body = {};
|
|
489
|
+
if (a.reason)
|
|
490
|
+
body.reason = a.reason;
|
|
491
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/accounts/${id}/unfreeze`, body), null, 2) }] };
|
|
492
|
+
}
|
|
493
|
+
case "block_card": {
|
|
494
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
495
|
+
const body = {};
|
|
496
|
+
if (a.reason)
|
|
497
|
+
body.reason = a.reason;
|
|
498
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/cards/${id}/block`, body), null, 2) }] };
|
|
499
|
+
}
|
|
500
|
+
case "unblock_card": {
|
|
501
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
502
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/cards/${id}/unblock`, {}), null, 2) }] };
|
|
503
|
+
}
|
|
504
|
+
case "change_card_status": {
|
|
505
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
506
|
+
const body = { status: a.status };
|
|
507
|
+
if (a.reason)
|
|
508
|
+
body.reason = a.reason;
|
|
509
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("PATCH", `/cards/${id}/status`, body), null, 2) }] };
|
|
510
|
+
}
|
|
511
|
+
// TODO(verify): transactions list path; `/accounts/{id}/transactions` is conventional but Dock may use a top-level `/transactions?account_id=`.
|
|
512
|
+
case "list_transactions": {
|
|
513
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
514
|
+
const qs = new URLSearchParams();
|
|
515
|
+
if (a.start_date)
|
|
516
|
+
qs.set("start_date", String(a.start_date));
|
|
517
|
+
if (a.end_date)
|
|
518
|
+
qs.set("end_date", String(a.end_date));
|
|
519
|
+
if (a.type)
|
|
520
|
+
qs.set("type", String(a.type));
|
|
521
|
+
if (a.page)
|
|
522
|
+
qs.set("page", String(a.page));
|
|
523
|
+
if (a.page_size)
|
|
524
|
+
qs.set("page_size", String(a.page_size));
|
|
525
|
+
const q = qs.toString();
|
|
526
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/accounts/${id}/transactions${q ? `?${q}` : ""}`), null, 2) }] };
|
|
527
|
+
}
|
|
528
|
+
case "get_transaction": {
|
|
529
|
+
const id = encodeURIComponent(String(a.transaction_id ?? ""));
|
|
530
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/transactions/${id}`), null, 2) }] };
|
|
531
|
+
}
|
|
532
|
+
case "create_webhook":
|
|
533
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", "/webhooks", a), null, 2) }] };
|
|
534
|
+
case "list_webhooks":
|
|
535
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", "/webhooks"), null, 2) }] };
|
|
325
536
|
default:
|
|
326
537
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
327
538
|
}
|
|
@@ -348,7 +559,7 @@ async function main() {
|
|
|
348
559
|
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
|
|
349
560
|
t.onclose = () => { if (t.sessionId)
|
|
350
561
|
transports.delete(t.sessionId); };
|
|
351
|
-
const s = new Server({ name: "mcp-dock", version: "0.
|
|
562
|
+
const s = new Server({ name: "mcp-dock", version: "0.2.0" }, { capabilities: { tools: {} } });
|
|
352
563
|
server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
|
|
353
564
|
server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
|
|
354
565
|
await s.connect(t);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codespar/mcp-dock",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Dock
|
|
3
|
+
"version": "0.2.0-alpha.2",
|
|
4
|
+
"description": "MCP server for Dock \u2014 Brazilian Banking-as-a-Service (accounts, Pix, card issuing) for fintechs and embedded-finance products",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"bin": {
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github",
|
|
8
8
|
"subfolder": "packages/banking/dock"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.2.0-alpha.2",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "@codespar/mcp-dock",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.2.0-alpha.2",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
package/src/index.ts
CHANGED
|
@@ -8,17 +8,27 @@
|
|
|
8
8
|
* Card issuing is the key differentiator vs Matera — Dock is historically
|
|
9
9
|
* a card-issuing platform that expanded into full BaaS.
|
|
10
10
|
*
|
|
11
|
-
* Tools (
|
|
12
|
-
* create_account — POST
|
|
13
|
-
* get_account — GET
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
11
|
+
* Tools (20) — Banking + Pix + Card Issuing + Webhooks:
|
|
12
|
+
* create_account — POST /accounts (digital account for an end user)
|
|
13
|
+
* get_account — GET /accounts/{id}
|
|
14
|
+
* list_accounts — GET /accounts
|
|
15
|
+
* freeze_account — POST /accounts/{id}/freeze
|
|
16
|
+
* unfreeze_account — POST /accounts/{id}/unfreeze
|
|
17
|
+
* send_pix — POST /pix/payments (outbound Pix transfer)
|
|
18
|
+
* get_pix — GET /pix/payments/{endToEndId}
|
|
19
|
+
* create_pix_qr_static — POST /pix/qrcodes/static
|
|
20
|
+
* create_pix_qr_dynamic — POST /pix/qrcodes/dynamic
|
|
21
|
+
* refund_pix — POST /pix/payments/{endToEndId}/refund
|
|
22
|
+
* resolve_dict_key — GET /pix/dict/{key}
|
|
23
|
+
* issue_card — POST /cards (Dock's core differentiator)
|
|
24
|
+
* get_card — GET /cards/{id}
|
|
25
|
+
* block_card — POST /cards/{id}/block
|
|
26
|
+
* unblock_card — POST /cards/{id}/unblock
|
|
27
|
+
* change_card_status — PATCH /cards/{id}/status
|
|
28
|
+
* list_transactions — GET /accounts/{id}/transactions
|
|
29
|
+
* get_transaction — GET /transactions/{id}
|
|
30
|
+
* create_webhook — POST /webhooks
|
|
31
|
+
* list_webhooks — GET /webhooks
|
|
22
32
|
*
|
|
23
33
|
* -------------------------------------------------------------------------
|
|
24
34
|
* ALPHA STATUS — endpoint paths below are NOT verified against a live sandbox.
|
|
@@ -109,7 +119,7 @@ async function dockRequest(method: string, path: string, body?: unknown): Promis
|
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
const server = new Server(
|
|
112
|
-
{ name: "mcp-dock", version: "0.
|
|
122
|
+
{ name: "mcp-dock", version: "0.2.0" },
|
|
113
123
|
{ capabilities: { tools: {} } },
|
|
114
124
|
);
|
|
115
125
|
|
|
@@ -291,6 +301,136 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
291
301
|
required: ["card_id"],
|
|
292
302
|
},
|
|
293
303
|
},
|
|
304
|
+
{
|
|
305
|
+
name: "list_accounts",
|
|
306
|
+
description: "List Dock accounts under the merchant. Supports pagination and filtering by holder document or status.",
|
|
307
|
+
inputSchema: {
|
|
308
|
+
type: "object",
|
|
309
|
+
properties: {
|
|
310
|
+
cpf: { type: "string", description: "Filter by holder CPF (11 digits)" },
|
|
311
|
+
status: { type: "string", enum: ["ACTIVE", "FROZEN", "CLOSED"], description: "Filter by account status" },
|
|
312
|
+
page: { type: "number", description: "Page number (1-based)" },
|
|
313
|
+
page_size: { type: "number", description: "Results per page (default 20, max 100)" },
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: "freeze_account",
|
|
319
|
+
description: "Freeze (block) a Dock account. Pix outflows and card spend are halted but balance is preserved. Used for fraud holds, KYC re-verification, or judicial blocks.",
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: "object",
|
|
322
|
+
properties: {
|
|
323
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
324
|
+
reason: { type: "string", description: "Reason code or free-text justification (logged for audit)" },
|
|
325
|
+
},
|
|
326
|
+
required: ["account_id"],
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
name: "unfreeze_account",
|
|
331
|
+
description: "Unfreeze a previously frozen Dock account, restoring Pix and card operations.",
|
|
332
|
+
inputSchema: {
|
|
333
|
+
type: "object",
|
|
334
|
+
properties: {
|
|
335
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
336
|
+
reason: { type: "string", description: "Reason for the unblock (optional, logged)" },
|
|
337
|
+
},
|
|
338
|
+
required: ["account_id"],
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "block_card",
|
|
343
|
+
description: "Block a card temporarily (reversible). Use for lost-card or fraud-suspected flows. Card status goes to BLOCKED — declines all authorizations until unblocked. Different from change_card_status which permanently cancels.",
|
|
344
|
+
inputSchema: {
|
|
345
|
+
type: "object",
|
|
346
|
+
properties: {
|
|
347
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
348
|
+
reason: { type: "string", description: "Reason: LOST, STOLEN, SUSPECTED_FRAUD, CARDHOLDER_REQUEST" },
|
|
349
|
+
},
|
|
350
|
+
required: ["card_id"],
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "unblock_card",
|
|
355
|
+
description: "Unblock a card that was previously blocked (reversible). Restores card to ACTIVE status. Cannot be used on permanently CANCELED cards.",
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
360
|
+
},
|
|
361
|
+
required: ["card_id"],
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
name: "change_card_status",
|
|
366
|
+
description: "Change a card's lifecycle status: ACTIVE / BLOCKED / CANCELED. Use CANCELED for permanent termination (replacement card, account closure). Status transitions are constrained — see Dock issuing docs.",
|
|
367
|
+
inputSchema: {
|
|
368
|
+
type: "object",
|
|
369
|
+
properties: {
|
|
370
|
+
card_id: { type: "string", description: "Dock card id" },
|
|
371
|
+
status: {
|
|
372
|
+
type: "string",
|
|
373
|
+
enum: ["ACTIVE", "BLOCKED", "CANCELED"],
|
|
374
|
+
description: "Target status",
|
|
375
|
+
},
|
|
376
|
+
reason: { type: "string", description: "Reason code or free text" },
|
|
377
|
+
},
|
|
378
|
+
required: ["card_id", "status"],
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
name: "list_transactions",
|
|
383
|
+
description: "List transactions on a Dock account (Pix in/out, card auths, fees, transfers). Supports date range and pagination. Returns ordered by timestamp desc.",
|
|
384
|
+
inputSchema: {
|
|
385
|
+
type: "object",
|
|
386
|
+
properties: {
|
|
387
|
+
account_id: { type: "string", description: "Dock account id" },
|
|
388
|
+
start_date: { type: "string", description: "ISO-8601 date or datetime (inclusive)" },
|
|
389
|
+
end_date: { type: "string", description: "ISO-8601 date or datetime (inclusive)" },
|
|
390
|
+
type: { type: "string", description: "Filter by transaction type (PIX_IN, PIX_OUT, CARD_AUTH, FEE, etc.)" },
|
|
391
|
+
page: { type: "number", description: "Page number (1-based)" },
|
|
392
|
+
page_size: { type: "number", description: "Results per page (default 50, max 200)" },
|
|
393
|
+
},
|
|
394
|
+
required: ["account_id"],
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
name: "get_transaction",
|
|
399
|
+
description: "Retrieve a single transaction by id. Returns full detail including counterparty, fees, and originating event (Pix endToEndId, card auth code, etc.).",
|
|
400
|
+
inputSchema: {
|
|
401
|
+
type: "object",
|
|
402
|
+
properties: {
|
|
403
|
+
transaction_id: { type: "string", description: "Dock transaction id" },
|
|
404
|
+
},
|
|
405
|
+
required: ["transaction_id"],
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
name: "create_webhook",
|
|
410
|
+
description: "Register a webhook endpoint to receive Dock event notifications (account.*, pix.*, card.*, transaction.*). Dock signs payloads with HMAC; verify the signature on receipt.",
|
|
411
|
+
inputSchema: {
|
|
412
|
+
type: "object",
|
|
413
|
+
properties: {
|
|
414
|
+
url: { type: "string", description: "HTTPS endpoint that will receive POSTed events" },
|
|
415
|
+
events: {
|
|
416
|
+
type: "array",
|
|
417
|
+
items: { type: "string" },
|
|
418
|
+
description: "Event types to subscribe to (e.g. ['pix.received','card.authorized']). Use ['*'] for all.",
|
|
419
|
+
},
|
|
420
|
+
secret: { type: "string", description: "Optional shared secret used for HMAC signature verification" },
|
|
421
|
+
description: { type: "string", description: "Free-text label" },
|
|
422
|
+
},
|
|
423
|
+
required: ["url", "events"],
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
name: "list_webhooks",
|
|
428
|
+
description: "List all webhook endpoints registered for the merchant. Returns id, url, subscribed events, and active status.",
|
|
429
|
+
inputSchema: {
|
|
430
|
+
type: "object",
|
|
431
|
+
properties: {},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
294
434
|
],
|
|
295
435
|
}));
|
|
296
436
|
|
|
@@ -336,6 +476,64 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
336
476
|
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
337
477
|
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/cards/${id}`), null, 2) }] };
|
|
338
478
|
}
|
|
479
|
+
// TODO(verify): list_accounts wrapper path; `/accounts?cpf=&status=&page=` is the standard shape.
|
|
480
|
+
case "list_accounts": {
|
|
481
|
+
const qs = new URLSearchParams();
|
|
482
|
+
if (a.cpf) qs.set("cpf", String(a.cpf));
|
|
483
|
+
if (a.status) qs.set("status", String(a.status));
|
|
484
|
+
if (a.page) qs.set("page", String(a.page));
|
|
485
|
+
if (a.page_size) qs.set("page_size", String(a.page_size));
|
|
486
|
+
const q = qs.toString();
|
|
487
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/accounts${q ? `?${q}` : ""}`), null, 2) }] };
|
|
488
|
+
}
|
|
489
|
+
case "freeze_account": {
|
|
490
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
491
|
+
const body: Record<string, unknown> = {};
|
|
492
|
+
if (a.reason) body.reason = a.reason;
|
|
493
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/accounts/${id}/freeze`, body), null, 2) }] };
|
|
494
|
+
}
|
|
495
|
+
case "unfreeze_account": {
|
|
496
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
497
|
+
const body: Record<string, unknown> = {};
|
|
498
|
+
if (a.reason) body.reason = a.reason;
|
|
499
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/accounts/${id}/unfreeze`, body), null, 2) }] };
|
|
500
|
+
}
|
|
501
|
+
case "block_card": {
|
|
502
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
503
|
+
const body: Record<string, unknown> = {};
|
|
504
|
+
if (a.reason) body.reason = a.reason;
|
|
505
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/cards/${id}/block`, body), null, 2) }] };
|
|
506
|
+
}
|
|
507
|
+
case "unblock_card": {
|
|
508
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
509
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", `/cards/${id}/unblock`, {}), null, 2) }] };
|
|
510
|
+
}
|
|
511
|
+
case "change_card_status": {
|
|
512
|
+
const id = encodeURIComponent(String(a.card_id ?? ""));
|
|
513
|
+
const body: Record<string, unknown> = { status: a.status };
|
|
514
|
+
if (a.reason) body.reason = a.reason;
|
|
515
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("PATCH", `/cards/${id}/status`, body), null, 2) }] };
|
|
516
|
+
}
|
|
517
|
+
// TODO(verify): transactions list path; `/accounts/{id}/transactions` is conventional but Dock may use a top-level `/transactions?account_id=`.
|
|
518
|
+
case "list_transactions": {
|
|
519
|
+
const id = encodeURIComponent(String(a.account_id ?? ""));
|
|
520
|
+
const qs = new URLSearchParams();
|
|
521
|
+
if (a.start_date) qs.set("start_date", String(a.start_date));
|
|
522
|
+
if (a.end_date) qs.set("end_date", String(a.end_date));
|
|
523
|
+
if (a.type) qs.set("type", String(a.type));
|
|
524
|
+
if (a.page) qs.set("page", String(a.page));
|
|
525
|
+
if (a.page_size) qs.set("page_size", String(a.page_size));
|
|
526
|
+
const q = qs.toString();
|
|
527
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/accounts/${id}/transactions${q ? `?${q}` : ""}`), null, 2) }] };
|
|
528
|
+
}
|
|
529
|
+
case "get_transaction": {
|
|
530
|
+
const id = encodeURIComponent(String(a.transaction_id ?? ""));
|
|
531
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", `/transactions/${id}`), null, 2) }] };
|
|
532
|
+
}
|
|
533
|
+
case "create_webhook":
|
|
534
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("POST", "/webhooks", a), null, 2) }] };
|
|
535
|
+
case "list_webhooks":
|
|
536
|
+
return { content: [{ type: "text", text: JSON.stringify(await dockRequest("GET", "/webhooks"), null, 2) }] };
|
|
339
537
|
default:
|
|
340
538
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
|
341
539
|
}
|
|
@@ -361,7 +559,7 @@ async function main() {
|
|
|
361
559
|
if (!sid && isInitializeRequest(req.body)) {
|
|
362
560
|
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
|
|
363
561
|
t.onclose = () => { if (t.sessionId) transports.delete(t.sessionId); };
|
|
364
|
-
const s = new Server({ name: "mcp-dock", version: "0.
|
|
562
|
+
const s = new Server({ name: "mcp-dock", version: "0.2.0" }, { capabilities: { tools: {} } });
|
|
365
563
|
(server as any)._requestHandlers.forEach((v: any, k: any) => (s as any)._requestHandlers.set(k, v));
|
|
366
564
|
(server as any)._notificationHandlers?.forEach((v: any, k: any) => (s as any)._notificationHandlers.set(k, v));
|
|
367
565
|
await s.connect(t);
|