@blanketbyte/wise-mcp 1.0.5 → 1.0.7
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/tools.js +33 -2
- package/dist/wise/service.js +6 -2
- package/package.json +1 -1
package/dist/tools.js
CHANGED
|
@@ -272,9 +272,18 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
272
272
|
`${recipient.name} (${recipient.account ?? recipient.type}) receives ${money(quote.target.amount, recipient.currency)}` +
|
|
273
273
|
(quote.fee ? `, fee ${money(quote.fee.amount, sourceCurrency)}` : "") +
|
|
274
274
|
(sourceCurrency !== recipient.currency ? `, rate ${quote.rate}` : "") +
|
|
275
|
+
(quote.pay_in && quote.pay_in !== "BALANCE" ? `, priced for paying by ${quote.pay_in}` : "") +
|
|
275
276
|
(details.reference ? `, reference "${details.reference}"` : "") +
|
|
276
277
|
(quote.delivery ? `, ${stripHtml(quote.delivery)}` : "");
|
|
277
|
-
const { code, expiresAt } = storePending(sessionKey, {
|
|
278
|
+
const { code, expiresAt } = storePending(sessionKey, {
|
|
279
|
+
kind: "transfer",
|
|
280
|
+
profileId: profile.id,
|
|
281
|
+
quoteId: quote.id,
|
|
282
|
+
targetAccount: recipient.id,
|
|
283
|
+
customerTransactionId: randomUUID(),
|
|
284
|
+
details,
|
|
285
|
+
expected: { amount: quote.target.amount, currency: recipient.currency },
|
|
286
|
+
}, summary);
|
|
278
287
|
await log("transfer_prepared", { code, summary });
|
|
279
288
|
return ok({
|
|
280
289
|
status: "awaiting_user_confirmation",
|
|
@@ -282,7 +291,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
282
291
|
quote,
|
|
283
292
|
balance_check: available >= quote.source.amount
|
|
284
293
|
? `OK: ${money(available, sourceCurrency)} available`
|
|
285
|
-
: `Not enough ${sourceCurrency} balance (${money(available, sourceCurrency)})
|
|
294
|
+
: `Not enough ${sourceCurrency} balance (${money(available, sourceCurrency)}): the price assumes paying from the Wise balance, so tell the user to top it up first (paying another way in the app can cost more)`,
|
|
286
295
|
confirmation_code: code,
|
|
287
296
|
expires_at: expiresAt.toISOString(),
|
|
288
297
|
next_step: "Show the summary. Only call confirm_action if the user explicitly approves. Afterwards they pay it in the Wise app.",
|
|
@@ -319,6 +328,28 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
|
|
|
319
328
|
try {
|
|
320
329
|
if (a.kind === "transfer") {
|
|
321
330
|
const t = await wise.createTransfer({ targetAccount: a.targetAccount, quoteId: a.quoteId, customerTransactionId: a.customerTransactionId, details: a.details });
|
|
331
|
+
// Never leave the user with a transfer they didn't approve (e.g. priced with another pay-in and a different
|
|
332
|
+
// fee): it's still unpaid, so cancel it and say what happened. Wise's transfer source amount excludes the
|
|
333
|
+
// fee, so compare what the recipient gets.
|
|
334
|
+
const got = { amount: Number(t.target.amount), currency: String(t.target.currency ?? "").toUpperCase() };
|
|
335
|
+
if (Math.abs(got.amount - a.expected.amount) > 0.005 || got.currency !== a.expected.currency.toUpperCase()) {
|
|
336
|
+
const cancelled = await wise.cancelTransfer(t.id).then((c) => c.status, (err) => `cancel failed: ${err instanceof Error ? err.message : err}`);
|
|
337
|
+
await log("transfer_amount_mismatch", {
|
|
338
|
+
code: confirmation_code,
|
|
339
|
+
summary: p.summary,
|
|
340
|
+
transfer_id: t.id,
|
|
341
|
+
quote_id: a.quoteId,
|
|
342
|
+
expected: a.expected,
|
|
343
|
+
got,
|
|
344
|
+
cancelled,
|
|
345
|
+
});
|
|
346
|
+
return fail(`Wise created transfer ${t.id} where the recipient gets ${money(got.amount, got.currency)} instead of the approved ` +
|
|
347
|
+
`${money(a.expected.amount, a.expected.currency)} (quote ${a.quoteId}), so the price differs from the summary. ` +
|
|
348
|
+
(cancelled === "cancelled"
|
|
349
|
+
? "It was cancelled automatically, so nothing will be paid. "
|
|
350
|
+
: `Automatic cancellation didn't succeed (${cancelled}): tell the user to cancel it in the Wise app and NOT pay it. `) +
|
|
351
|
+
"Don't retry; tell the user.");
|
|
352
|
+
}
|
|
322
353
|
await log("transfer_created", { code: confirmation_code, summary: p.summary, transfer_id: t.id, status: t.status });
|
|
323
354
|
return ok({
|
|
324
355
|
status: "created_awaiting_payment",
|
package/dist/wise/service.js
CHANGED
|
@@ -220,6 +220,9 @@ export class WiseService {
|
|
|
220
220
|
sourceAmount: q.sourceAmount ?? null,
|
|
221
221
|
targetAmount: q.targetAmount ?? null,
|
|
222
222
|
targetAccount: q.targetAccount,
|
|
223
|
+
// Without this Wise prices the transfer with its default pay-in (often a bank transfer, with a fee), even
|
|
224
|
+
// though the user pays from their Wise balance in the app. BALANCE goes first and the transfer uses it.
|
|
225
|
+
preferredPayIn: "BALANCE",
|
|
223
226
|
});
|
|
224
227
|
return mapQuote(raw);
|
|
225
228
|
}
|
|
@@ -319,8 +322,9 @@ function mapRecipient(r) {
|
|
|
319
322
|
}
|
|
320
323
|
function mapQuote(q) {
|
|
321
324
|
const options = (q.paymentOptions ?? []).filter((o) => !o.disabled && (!q.payOut || o.payOut === q.payOut));
|
|
322
|
-
//
|
|
323
|
-
|
|
325
|
+
// Show the price of the pay-in Wise will use for the transfer: the quote's own payIn, otherwise the first option
|
|
326
|
+
// (createQuote asks for BALANCE first). Showing another option's price once hid a 0.95 EUR fee.
|
|
327
|
+
const o = options.find((x) => q.payIn && x.payIn === q.payIn) ?? options[0];
|
|
324
328
|
return {
|
|
325
329
|
id: String(q.id),
|
|
326
330
|
source: { amount: o?.sourceAmount ?? q.sourceAmount, currency: q.sourceCurrency },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blanketbyte/wise-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
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": [
|