@blanketbyte/wise-mcp 1.0.6 → 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 CHANGED
@@ -272,6 +272,7 @@ 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
278
  const { code, expiresAt } = storePending(sessionKey, {
@@ -281,7 +282,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
281
282
  targetAccount: recipient.id,
282
283
  customerTransactionId: randomUUID(),
283
284
  details,
284
- expected: { amount: quote.source.amount, currency: sourceCurrency },
285
+ expected: { amount: quote.target.amount, currency: recipient.currency },
285
286
  }, summary);
286
287
  await log("transfer_prepared", { code, summary });
287
288
  return ok({
@@ -290,7 +291,7 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
290
291
  quote,
291
292
  balance_check: available >= quote.source.amount
292
293
  ? `OK: ${money(available, sourceCurrency)} available`
293
- : `Not enough ${sourceCurrency} balance (${money(available, sourceCurrency)}); the user can still pay another way in the Wise app`,
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)`,
294
295
  confirmation_code: code,
295
296
  expires_at: expiresAt.toISOString(),
296
297
  next_step: "Show the summary. Only call confirm_action if the user explicitly approves. Afterwards they pay it in the Wise app.",
@@ -327,9 +328,10 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
327
328
  try {
328
329
  if (a.kind === "transfer") {
329
330
  const t = await wise.createTransfer({ targetAccount: a.targetAccount, quoteId: a.quoteId, customerTransactionId: a.customerTransactionId, details: a.details });
330
- // Wise has been seen creating a transfer for a different amount than its own quote. Never leave the
331
- // user with a transfer they didn't approve: it's still unpaid, so cancel it and say what happened.
332
- const got = { amount: Number(t.source.amount), currency: String(t.source.currency ?? "").toUpperCase() };
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() };
333
335
  if (Math.abs(got.amount - a.expected.amount) > 0.005 || got.currency !== a.expected.currency.toUpperCase()) {
334
336
  const cancelled = await wise.cancelTransfer(t.id).then((c) => c.status, (err) => `cancel failed: ${err instanceof Error ? err.message : err}`);
335
337
  await log("transfer_amount_mismatch", {
@@ -341,12 +343,12 @@ function registerWriteTools(server, wise, { sessionKey, connectionId }, safe) {
341
343
  got,
342
344
  cancelled,
343
345
  });
344
- return fail(`Wise created transfer ${t.id} for ${money(got.amount, got.currency)} instead of the approved ` +
345
- `${money(a.expected.amount, a.expected.currency)} (quote ${a.quoteId}). ` +
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. ` +
346
348
  (cancelled === "cancelled"
347
349
  ? "It was cancelled automatically, so nothing will be paid. "
348
350
  : `Automatic cancellation didn't succeed (${cancelled}): tell the user to cancel it in the Wise app and NOT pay it. `) +
349
- "Don't retry; tell the user this is a Wise-side mismatch.");
351
+ "Don't retry; tell the user.");
350
352
  }
351
353
  await log("transfer_created", { code: confirmation_code, summary: p.summary, transfer_id: t.id, status: t.status });
352
354
  return ok({
@@ -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
- // You pay in the Wise app, usually from your balance: show that option's price.
323
- const o = options.find((x) => x.payIn === "BALANCE") ?? options[0];
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.6",
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": [