@blanketbyte/wise-mcp 1.1.0 → 1.1.1
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/dist/schemas.js +146 -0
- package/dist/tools.js +39 -17
- package/dist/wise/service.js +5 -0
- package/package.json +1 -1
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Output schemas: the shape of each tool's structuredContent. They're loose on purpose (extra keys allowed, values
|
|
4
|
+
* that come from Wise may be missing), so a new field in Wise's API can never make a tool call fail validation.
|
|
5
|
+
*/
|
|
6
|
+
const id = z.union([z.number(), z.string()]);
|
|
7
|
+
const num = z.number().nullish();
|
|
8
|
+
const str = z.string().nullish();
|
|
9
|
+
const money = z.looseObject({ amount: num, currency: str });
|
|
10
|
+
const profileRef = z.looseObject({ id, type: z.string() });
|
|
11
|
+
const profile = z.looseObject({ id, type: z.string(), name: str });
|
|
12
|
+
const recipient = z.looseObject({
|
|
13
|
+
id,
|
|
14
|
+
name: str,
|
|
15
|
+
currency: str,
|
|
16
|
+
type: str,
|
|
17
|
+
account: str.describe("Account number or IBAN, as Wise shows it"),
|
|
18
|
+
details: str,
|
|
19
|
+
owned_by_me: z.boolean().nullish(),
|
|
20
|
+
profile_id: id.nullish(),
|
|
21
|
+
active: z.boolean().nullish(),
|
|
22
|
+
profile: profileRef.optional(),
|
|
23
|
+
});
|
|
24
|
+
const transferShape = {
|
|
25
|
+
id,
|
|
26
|
+
created: str,
|
|
27
|
+
status: str.describe("Wise transfer status, e.g. incoming_payment_waiting, outgoing_payment_sent, cancelled"),
|
|
28
|
+
reference: str,
|
|
29
|
+
source: money.describe("Amount converted, in the source currency (excludes the fee)"),
|
|
30
|
+
target: money.describe("Amount the recipient gets"),
|
|
31
|
+
recipient_id: id.nullish(),
|
|
32
|
+
};
|
|
33
|
+
const quote = z.looseObject({
|
|
34
|
+
id: z.string(),
|
|
35
|
+
source: money.describe("What you pay"),
|
|
36
|
+
target: money.describe("What the recipient gets, when paid from the Wise balance"),
|
|
37
|
+
rate: num,
|
|
38
|
+
rate_type: str,
|
|
39
|
+
rate_expires: str,
|
|
40
|
+
fee: money.optional(),
|
|
41
|
+
pay_in: str,
|
|
42
|
+
pay_out: str,
|
|
43
|
+
estimated_delivery: str,
|
|
44
|
+
delivery: str,
|
|
45
|
+
notices: z.array(z.string()).optional(),
|
|
46
|
+
pay_in_options: z
|
|
47
|
+
.array(z.looseObject({ pay_in: z.string(), fee: num, target_amount: num }))
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Price per payment method, cheapest first (methods with the same price merged)"),
|
|
50
|
+
});
|
|
51
|
+
const pending = {
|
|
52
|
+
status: z.string().describe("awaiting_user_confirmation"),
|
|
53
|
+
summary: z.string().describe("Show this to the user before confirming"),
|
|
54
|
+
confirmation_code: z.string(),
|
|
55
|
+
expires_at: z.string(),
|
|
56
|
+
};
|
|
57
|
+
export const outputs = {
|
|
58
|
+
list_profiles: { profiles: z.array(profile) },
|
|
59
|
+
list_balances: {
|
|
60
|
+
balances: z.array(z.looseObject({
|
|
61
|
+
id,
|
|
62
|
+
profile: profileRef,
|
|
63
|
+
kind: z.string().describe("balance or jar"),
|
|
64
|
+
name: str,
|
|
65
|
+
currency: str,
|
|
66
|
+
amount: num.describe("Available to spend or send now; reserved money is already taken out of it"),
|
|
67
|
+
reserved: num.describe("Held for pending transactions (mostly card payments not settled yet). Already deducted from amount: not extra money"),
|
|
68
|
+
total_worth: num.describe("Only when it differs from amount, e.g. invested balances"),
|
|
69
|
+
note: str,
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
get_transactions: {
|
|
73
|
+
profile,
|
|
74
|
+
count: z.number(),
|
|
75
|
+
transactions: z.array(z.looseObject({
|
|
76
|
+
id,
|
|
77
|
+
date: str,
|
|
78
|
+
type: str,
|
|
79
|
+
status: str,
|
|
80
|
+
title: str.describe("Merchant or counterparty"),
|
|
81
|
+
description: str,
|
|
82
|
+
direction: str.describe("in, out or neutral (between your own balances)"),
|
|
83
|
+
amount: num,
|
|
84
|
+
currency: str,
|
|
85
|
+
amount_text: str,
|
|
86
|
+
secondary_amount: money.optional(),
|
|
87
|
+
secondary_text: str,
|
|
88
|
+
resource: z.looseObject({ type: str, id: id.nullish() }).optional(),
|
|
89
|
+
})),
|
|
90
|
+
next_cursor: str,
|
|
91
|
+
},
|
|
92
|
+
list_transfers: {
|
|
93
|
+
profile,
|
|
94
|
+
total: z.number(),
|
|
95
|
+
transfers: z.array(z.looseObject({ ...transferShape, recipient_name: str })),
|
|
96
|
+
truncated: z.boolean().optional(),
|
|
97
|
+
},
|
|
98
|
+
get_transfer: {
|
|
99
|
+
...transferShape,
|
|
100
|
+
recipient: recipient.optional(),
|
|
101
|
+
rate: num,
|
|
102
|
+
quote_id: str,
|
|
103
|
+
has_active_issues: z.boolean().nullish(),
|
|
104
|
+
raw_status: str,
|
|
105
|
+
note: str,
|
|
106
|
+
},
|
|
107
|
+
list_recipients: { count: z.number(), recipients: z.array(recipient) },
|
|
108
|
+
get_exchange_rate: { source: str, target: str, rate: num, time: str },
|
|
109
|
+
get_quote: quote.shape,
|
|
110
|
+
get_recipient_requirements: {
|
|
111
|
+
options: z.array(z.looseObject({
|
|
112
|
+
type: z.string().describe("Pass as `type` to prepare_recipient"),
|
|
113
|
+
title: str,
|
|
114
|
+
usage: str,
|
|
115
|
+
fields: z.array(z.looseObject({
|
|
116
|
+
key: z.string(),
|
|
117
|
+
name: str,
|
|
118
|
+
required: z.boolean(),
|
|
119
|
+
type: str,
|
|
120
|
+
example: str,
|
|
121
|
+
pattern: str,
|
|
122
|
+
allowed: z.array(z.looseObject({ key: id, name: str })).optional(),
|
|
123
|
+
refresh_on_change: z.boolean().optional(),
|
|
124
|
+
})),
|
|
125
|
+
})),
|
|
126
|
+
},
|
|
127
|
+
prepare_recipient: pending,
|
|
128
|
+
prepare_transfer: {
|
|
129
|
+
...pending,
|
|
130
|
+
quote,
|
|
131
|
+
balance_check: z.string(),
|
|
132
|
+
next_step: z.string(),
|
|
133
|
+
},
|
|
134
|
+
prepare_cancel_transfer: pending,
|
|
135
|
+
confirm_action: {
|
|
136
|
+
status: z.string().describe("created_awaiting_payment, recipient_created or cancelled"),
|
|
137
|
+
summary: z.string(),
|
|
138
|
+
transfer_id: id.optional(),
|
|
139
|
+
wise_status: str,
|
|
140
|
+
recipient: recipient.optional(),
|
|
141
|
+
wise_shows_until_paid: z.string().optional(),
|
|
142
|
+
note: z.string().optional(),
|
|
143
|
+
next_step: z.string().optional(),
|
|
144
|
+
},
|
|
145
|
+
discard_action: { status: z.string().describe("discarded or not_found"), message: z.string() },
|
|
146
|
+
};
|
package/dist/tools.js
CHANGED
|
@@ -6,8 +6,11 @@ import { config } from "./config.js";
|
|
|
6
6
|
import { ACTIVITY_TYPES, UNPAID_PRICE_NOTE } from "./wise/service.js";
|
|
7
7
|
import { WiseAccessRevokedError } from "./wise/client.js";
|
|
8
8
|
import { storePending, takePending, discardPending } from "./pending.js";
|
|
9
|
+
import { outputs } from "./schemas.js";
|
|
10
|
+
/** Every tool returns an object: as text (for older clients) and as structuredContent matching its output schema. */
|
|
9
11
|
const ok = (data) => ({
|
|
10
|
-
content: [{ type: "text", text:
|
|
12
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
|
13
|
+
structuredContent: data,
|
|
11
14
|
});
|
|
12
15
|
const fail = (message) => ({ content: [{ type: "text", text: message }], isError: true });
|
|
13
16
|
const date = z
|
|
@@ -43,18 +46,20 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
43
46
|
title: "List Wise profiles",
|
|
44
47
|
description: "List the Wise profiles (personal and business) this token can access, with id, type and name.",
|
|
45
48
|
inputSchema: {},
|
|
49
|
+
outputSchema: outputs.list_profiles,
|
|
46
50
|
annotations: READ,
|
|
47
|
-
}, async () => safe(async () => ok(await wise.listProfiles())));
|
|
51
|
+
}, async () => safe(async () => ok({ profiles: await wise.listProfiles() })));
|
|
48
52
|
server.registerTool("list_balances", {
|
|
49
53
|
title: "List Wise balances",
|
|
50
|
-
description: "Current balances in every currency plus Jars (savings),
|
|
54
|
+
description: "Current balances in every currency plus Jars (savings). `amount` is what's available now; `reserved` (pending card payments) is already deducted from it, not extra money. Default: all profiles. " +
|
|
51
55
|
"Empty balances are hidden unless include_empty is true.",
|
|
52
56
|
inputSchema: {
|
|
53
57
|
profile: profileArg.describe('Profile id, "personal", "business", part of the name, or "all" (default)'),
|
|
54
58
|
include_empty: z.boolean().optional().describe("Also list balances with 0"),
|
|
55
59
|
},
|
|
60
|
+
outputSchema: outputs.list_balances,
|
|
56
61
|
annotations: READ,
|
|
57
|
-
}, async ({ profile, include_empty }) => safe(async () => ok(await wise.listBalances(await wise.resolveProfiles(profile), include_empty ?? false))));
|
|
62
|
+
}, async ({ profile, include_empty }) => safe(async () => ok({ balances: await wise.listBalances(await wise.resolveProfiles(profile), include_empty ?? false) })));
|
|
58
63
|
server.registerTool("get_transactions", {
|
|
59
64
|
title: "Get Wise transactions",
|
|
60
65
|
description: "List activity on a Wise profile, newest first: card payments, transfers, conversions, cashback, direct debits. " +
|
|
@@ -68,7 +73,10 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
68
73
|
.string()
|
|
69
74
|
.optional()
|
|
70
75
|
.describe(`One of ${Object.keys(ACTIVITY_TYPES).join(", ")}, or a raw Wise monetaryResourceType (e.g. CARD_TRANSACTION)`),
|
|
71
|
-
status: z
|
|
76
|
+
status: z
|
|
77
|
+
.enum(["COMPLETED", "IN_PROGRESS", "UPCOMING", "REQUIRES_ATTENTION", "CANCELLED"])
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Only activity in this state, e.g. UPCOMING for pending card payments"),
|
|
72
80
|
since: date.optional().describe("Only on/after this date (YYYY-MM-DD or ISO timestamp)"),
|
|
73
81
|
until: date.optional().describe("Only on/before this date (YYYY-MM-DD or ISO timestamp)"),
|
|
74
82
|
search: z
|
|
@@ -78,6 +86,7 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
78
86
|
limit: z.number().int().min(1).max(500).optional().describe("Max items (default 50)"),
|
|
79
87
|
cursor: z.string().optional().describe("next_cursor from a previous call"),
|
|
80
88
|
},
|
|
89
|
+
outputSchema: outputs.get_transactions,
|
|
81
90
|
annotations: READ,
|
|
82
91
|
}, async (args) => safe(async () => {
|
|
83
92
|
const profile = await wise.resolveProfile(args.profile);
|
|
@@ -100,12 +109,13 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
100
109
|
"Filter by date (YYYY-MM-DD), status (e.g. outgoing_payment_sent, processing, cancelled) or search (reference/recipient). Default profile: personal.",
|
|
101
110
|
inputSchema: {
|
|
102
111
|
profile: profileArg,
|
|
103
|
-
since: date.optional(),
|
|
104
|
-
until: date.optional(),
|
|
112
|
+
since: date.optional().describe("Only transfers created on/after this date (YYYY-MM-DD or ISO timestamp)"),
|
|
113
|
+
until: date.optional().describe("Only transfers created on/before this date (YYYY-MM-DD or ISO timestamp)"),
|
|
105
114
|
status: z.string().optional().describe("Wise transfer status, e.g. outgoing_payment_sent"),
|
|
106
115
|
search: z.string().optional().describe("Case-insensitive match on reference or recipient name"),
|
|
107
116
|
limit: z.number().int().min(1).max(200).optional().describe("Max transfers (default 25)"),
|
|
108
117
|
},
|
|
118
|
+
outputSchema: outputs.list_transfers,
|
|
109
119
|
annotations: READ,
|
|
110
120
|
}, async (args) => safe(async () => {
|
|
111
121
|
const profile = await wise.resolveProfile(args.profile);
|
|
@@ -116,6 +126,7 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
116
126
|
title: "Get a Wise transfer",
|
|
117
127
|
description: "Details of one transfer: amounts in both currencies, rate, reference, status, created date and recipient.",
|
|
118
128
|
inputSchema: { id: z.coerce.number().int().describe("Transfer id (from list_transfers or a TRANSFER activity's resource.id)") },
|
|
129
|
+
outputSchema: outputs.get_transfer,
|
|
119
130
|
annotations: READ,
|
|
120
131
|
}, async ({ id }) => safe(async () => ok(await wise.getTransfer(id))));
|
|
121
132
|
server.registerTool("list_recipients", {
|
|
@@ -126,6 +137,7 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
126
137
|
currency: currency.optional().describe("Only recipients in this currency, e.g. EUR"),
|
|
127
138
|
search: z.string().optional().describe("Case-insensitive match on name or account"),
|
|
128
139
|
},
|
|
140
|
+
outputSchema: outputs.list_recipients,
|
|
129
141
|
annotations: READ,
|
|
130
142
|
}, async ({ profile, currency, search }) => safe(async () => {
|
|
131
143
|
const s = search?.trim().toLowerCase();
|
|
@@ -141,6 +153,7 @@ export function registerTools(server, wise, { sessionKey, connectionId, onRevoke
|
|
|
141
153
|
target: currency.describe("Target currency, e.g. RON"),
|
|
142
154
|
at: date.optional().describe("Historic rate at this date/time (default: now)"),
|
|
143
155
|
},
|
|
156
|
+
outputSchema: outputs.get_exchange_rate,
|
|
144
157
|
annotations: READ,
|
|
145
158
|
}, async ({ source, target, at }) => safe(async () => ok(await wise.getRate(source, target, at))));
|
|
146
159
|
if (config.WRITES_ENABLED)
|
|
@@ -159,13 +172,14 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
159
172
|
description: "Price a transfer or conversion: rate, fee, amount received and estimated delivery. Creates nothing the user sees and moves no money. " +
|
|
160
173
|
"Give either send_amount (in source_currency) or receive_amount (in target_currency).",
|
|
161
174
|
inputSchema: {
|
|
162
|
-
source_currency: currency,
|
|
163
|
-
target_currency: currency,
|
|
164
|
-
send_amount: z.number().positive().optional(),
|
|
165
|
-
receive_amount: z.number().positive().optional(),
|
|
175
|
+
source_currency: currency.describe("Currency you send, e.g. EUR"),
|
|
176
|
+
target_currency: currency.describe("Currency the recipient gets, e.g. RON (same as source_currency for a same-currency transfer)"),
|
|
177
|
+
send_amount: z.number().positive().optional().describe("Amount to send, in source_currency (give this or receive_amount)"),
|
|
178
|
+
receive_amount: z.number().positive().optional().describe("Amount the recipient should get, in target_currency (give this or send_amount)"),
|
|
166
179
|
recipient_id: z.number().int().optional().describe("Saved recipient, for an exact price and delivery time"),
|
|
167
180
|
profile: profileArg,
|
|
168
181
|
},
|
|
182
|
+
outputSchema: outputs.get_quote,
|
|
169
183
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
170
184
|
}, async (a) => safe(async () => {
|
|
171
185
|
if (!!a.send_amount === !!a.receive_amount)
|
|
@@ -189,16 +203,17 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
189
203
|
amount: z.number().positive().optional().describe("Typical amount (default 100); some routes depend on it"),
|
|
190
204
|
profile: profileArg,
|
|
191
205
|
},
|
|
206
|
+
outputSchema: outputs.get_recipient_requirements,
|
|
192
207
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
193
208
|
}, async (a) => safe(async () => {
|
|
194
209
|
const profile = await wise.resolveProfile(a.profile);
|
|
195
|
-
return ok(await wise.recipientRequirements(profile, a.source_currency ?? a.currency, a.currency, a.amount ?? 100));
|
|
210
|
+
return ok({ options: await wise.recipientRequirements(profile, a.source_currency ?? a.currency, a.currency, a.amount ?? 100) });
|
|
196
211
|
}));
|
|
197
212
|
server.registerTool("prepare_recipient", {
|
|
198
213
|
title: "Prepare a new Wise recipient",
|
|
199
214
|
description: `Step 1 of 2 to save a new recipient. Use get_recipient_requirements first for the right \`type\` and \`details\` keys. ${TWO_STEP}`,
|
|
200
215
|
inputSchema: {
|
|
201
|
-
currency,
|
|
216
|
+
currency: currency.describe("Currency of the recipient's account, e.g. EUR"),
|
|
202
217
|
type: z.string().min(1).describe("Requirement type, e.g. iban, sort_code, aba"),
|
|
203
218
|
account_holder_name: z.string().min(2).describe("Recipient's full name or business name"),
|
|
204
219
|
details: z
|
|
@@ -207,6 +222,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
207
222
|
owned_by_me: z.boolean().optional().describe("True if this is the user's own account elsewhere"),
|
|
208
223
|
profile: profileArg,
|
|
209
224
|
},
|
|
225
|
+
outputSchema: outputs.prepare_recipient,
|
|
210
226
|
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
211
227
|
}, async (a) => safe(async () => {
|
|
212
228
|
const profile = await wise.resolveProfile(a.profile);
|
|
@@ -235,6 +251,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
235
251
|
.describe("Extra fields Wise requires on some routes, e.g. transferPurpose, sourceOfFunds (a previous attempt lists them)"),
|
|
236
252
|
profile: profileArg.describe("Default: the profile the recipient belongs to"),
|
|
237
253
|
},
|
|
254
|
+
outputSchema: outputs.prepare_transfer,
|
|
238
255
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
239
256
|
}, async (a) => safe(async () => {
|
|
240
257
|
if (!!a.send_amount === !!a.receive_amount)
|
|
@@ -301,7 +318,8 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
301
318
|
server.registerTool("prepare_cancel_transfer", {
|
|
302
319
|
title: "Prepare cancelling a Wise transfer",
|
|
303
320
|
description: `Step 1 of 2 to cancel a transfer that hasn't been paid yet (status incoming_payment_waiting). ${TWO_STEP}`,
|
|
304
|
-
inputSchema: { transfer_id: z.coerce.number().int() },
|
|
321
|
+
inputSchema: { transfer_id: z.coerce.number().int().describe("Id of the unpaid transfer (from list_transfers or prepare_transfer's confirmation)") },
|
|
322
|
+
outputSchema: outputs.prepare_cancel_transfer,
|
|
305
323
|
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
306
324
|
}, async ({ transfer_id }) => safe(async () => {
|
|
307
325
|
const t = await wise.getTransfer(transfer_id);
|
|
@@ -309,7 +327,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
309
327
|
return fail(`Transfer ${transfer_id} is "${t.status}"; Wise only allows cancelling unpaid transfers (incoming_payment_waiting) via API.`);
|
|
310
328
|
}
|
|
311
329
|
const summary = `Cancel transfer ${t.id}: ${money(t.source.amount, t.source.currency)} → ${t.recipient?.name ?? `recipient ${t.recipient_id}`} ` +
|
|
312
|
-
`(${money(t.target.amount, t.target.currency)})${t.reference ? `, reference "${t.reference}"` : ""}, created ${t.created}`;
|
|
330
|
+
`(${money(t.target.amount, t.target.currency)}, Wise's price until paid)${t.reference ? `, reference "${t.reference}"` : ""}, created ${t.created}`;
|
|
313
331
|
const { code, expiresAt } = storePending(sessionKey, { kind: "cancel_transfer", transferId: t.id }, summary);
|
|
314
332
|
await log("cancel_prepared", { code, summary });
|
|
315
333
|
return ok({ status: "awaiting_user_confirmation", summary, confirmation_code: code, expires_at: expiresAt.toISOString() });
|
|
@@ -320,6 +338,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
320
338
|
"explicitly approved that exact summary in their latest message. Codes are single-use and expire after 10 minutes. " +
|
|
321
339
|
"Transfers are created unpaid: the user pays them in the Wise app.",
|
|
322
340
|
inputSchema: { confirmation_code: z.string().describe("Code from a prepare_* tool, e.g. TX-1A2B3C4D") },
|
|
341
|
+
outputSchema: outputs.confirm_action,
|
|
323
342
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
324
343
|
}, async ({ confirmation_code }) => safe(async () => {
|
|
325
344
|
const p = takePending(sessionKey, confirmation_code);
|
|
@@ -385,13 +404,16 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
385
404
|
server.registerTool("discard_action", {
|
|
386
405
|
title: "Discard a prepared Wise action",
|
|
387
406
|
description: "Throw away an action prepared with a prepare_* tool, before it's confirmed.",
|
|
388
|
-
inputSchema: { confirmation_code: z.string() },
|
|
407
|
+
inputSchema: { confirmation_code: z.string().describe("Code from a prepare_* tool to throw away, e.g. TX-1A2B3C4D") },
|
|
408
|
+
outputSchema: outputs.discard_action,
|
|
389
409
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false },
|
|
390
410
|
}, async ({ confirmation_code }) => {
|
|
391
411
|
const removed = discardPending(sessionKey, confirmation_code);
|
|
392
412
|
if (removed)
|
|
393
413
|
await log("action_discarded", { code: confirmation_code });
|
|
394
|
-
return ok(removed
|
|
414
|
+
return ok(removed
|
|
415
|
+
? { status: "discarded", message: "Discarded. Nothing was sent to Wise." }
|
|
416
|
+
: { status: "not_found", message: "No pending action with that code." });
|
|
395
417
|
});
|
|
396
418
|
}
|
|
397
419
|
const stripHtml = (s) => s.replace(/<[^>]*>/g, "").trim();
|
package/dist/wise/service.js
CHANGED
|
@@ -122,6 +122,11 @@ export class WiseService {
|
|
|
122
122
|
amount: b.amount?.value,
|
|
123
123
|
reserved: b.reservedAmount?.value || undefined,
|
|
124
124
|
total_worth: b.totalWorth?.value !== b.amount?.value ? b.totalWorth?.value : undefined,
|
|
125
|
+
// Stated in the data itself: assistants read values more reliably than schema descriptions.
|
|
126
|
+
note: b.reservedAmount?.value
|
|
127
|
+
? `${b.reservedAmount.value} ${b.currency} is held for pending payments and already deducted from amount: ` +
|
|
128
|
+
`${b.amount?.value} ${b.currency} is available now. Don't add the reserved amount to the total.`
|
|
129
|
+
: undefined,
|
|
125
130
|
}));
|
|
126
131
|
}));
|
|
127
132
|
return perProfile.flat().filter((b) => includeEmpty || Number(b.amount) !== 0 || Number(b.reserved ?? 0) !== 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blanketbyte/wise-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "MCP server for Wise: read balances, card payments, transfers and recipients, and prepare transfers you approve twice. Runs locally (npx, for Claude, Codex, Cursor…) or as a remote connector for Claude and ChatGPT.",
|
|
5
5
|
"mcpName": "io.github.BlanketByte/wise-mcp",
|
|
6
6
|
"keywords": [
|