paisa-mcp 0.0.7 → 0.0.11
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/index.js +226 -39
- package/dist/index.js.map +8 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38297,9 +38297,6 @@ async function encryptTransactionFields(items, key) {
|
|
|
38297
38297
|
await encryptObjectFields(item, ENCRYPTED_TXN_FIELDS, key);
|
|
38298
38298
|
}
|
|
38299
38299
|
}
|
|
38300
|
-
async function encryptMerchantFieldsOnObject(obj, key) {
|
|
38301
|
-
await encryptObjectFields(obj, ENCRYPTED_MERCHANT_FIELDS, key);
|
|
38302
|
-
}
|
|
38303
38300
|
|
|
38304
38301
|
// ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
|
|
38305
38302
|
var exports_external = {};
|
|
@@ -42360,7 +42357,39 @@ function registerAlertTools(server, client) {
|
|
|
42360
42357
|
}
|
|
42361
42358
|
|
|
42362
42359
|
// src/tools/analytics.ts
|
|
42363
|
-
function
|
|
42360
|
+
async function dec(value, key) {
|
|
42361
|
+
if (typeof value !== "string" || !value)
|
|
42362
|
+
return value;
|
|
42363
|
+
try {
|
|
42364
|
+
return await decryptField(value, key);
|
|
42365
|
+
} catch {
|
|
42366
|
+
return value;
|
|
42367
|
+
}
|
|
42368
|
+
}
|
|
42369
|
+
async function decryptAnalytics(data, key) {
|
|
42370
|
+
if (!data || typeof data !== "object")
|
|
42371
|
+
return;
|
|
42372
|
+
const d = data;
|
|
42373
|
+
const topMerchants = d.topMerchants;
|
|
42374
|
+
if (Array.isArray(topMerchants)) {
|
|
42375
|
+
for (const m of topMerchants)
|
|
42376
|
+
m.name = await dec(m.name, key);
|
|
42377
|
+
}
|
|
42378
|
+
const recent = d.recentTransactions;
|
|
42379
|
+
if (Array.isArray(recent)) {
|
|
42380
|
+
for (const t of recent) {
|
|
42381
|
+
t.description = await dec(t.description, key);
|
|
42382
|
+
if ("merchantName" in t)
|
|
42383
|
+
t.merchantName = await dec(t.merchantName, key);
|
|
42384
|
+
}
|
|
42385
|
+
}
|
|
42386
|
+
const merchant = d.merchant;
|
|
42387
|
+
if (merchant && typeof merchant === "object") {
|
|
42388
|
+
merchant.cleanName = await dec(merchant.cleanName, key);
|
|
42389
|
+
merchant.rawId = await dec(merchant.rawId, key);
|
|
42390
|
+
}
|
|
42391
|
+
}
|
|
42392
|
+
function registerAnalyticsTools(server, client, crypto3) {
|
|
42364
42393
|
server.registerTool("get_analytics", {
|
|
42365
42394
|
description: "Analytics reports. Select one via `report`:\n" + "- monthly_summary: Income, expenses, and investments for a specific month, broken down by category type. Includes budget vs actual. Requires `month` and `year`; optional `owner`.\n" + "- spending_trends: Monthly spending trends by category type over the last N months. Optional `months` (default: 6) and `owner`.\n" + "- category_analytics: Detailed spending breakdown for a specific category over time. Requires `slug`; optional `months`.\n" + "- merchant_analytics: Transaction history and spend total for a specific merchant. Requires `id`; optional `months`.",
|
|
42366
42395
|
inputSchema: {
|
|
@@ -42400,6 +42429,8 @@ function registerAnalyticsTools(server, client) {
|
|
|
42400
42429
|
data = await client.get(`/api/analytics/merchants/${params.id}`, params.months ? { months: params.months } : undefined);
|
|
42401
42430
|
break;
|
|
42402
42431
|
}
|
|
42432
|
+
if (crypto3)
|
|
42433
|
+
await decryptAnalytics(data, crypto3.key);
|
|
42403
42434
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
42404
42435
|
});
|
|
42405
42436
|
}
|
|
@@ -42607,16 +42638,57 @@ function registerGoalTools(server, client) {
|
|
|
42607
42638
|
}
|
|
42608
42639
|
};
|
|
42609
42640
|
if (type === "goal") {
|
|
42610
|
-
const {
|
|
42611
|
-
|
|
42641
|
+
const {
|
|
42642
|
+
id,
|
|
42643
|
+
goalType,
|
|
42644
|
+
name: name2,
|
|
42645
|
+
targetAmount: targetAmount2,
|
|
42646
|
+
targetDate: targetDate2,
|
|
42647
|
+
currentAmount: currentAmount2,
|
|
42648
|
+
monthlyContribution: monthlyContribution2,
|
|
42649
|
+
owner,
|
|
42650
|
+
icon,
|
|
42651
|
+
color,
|
|
42652
|
+
notes
|
|
42653
|
+
} = fields;
|
|
42654
|
+
const body2 = {
|
|
42655
|
+
type: goalType,
|
|
42656
|
+
name: name2,
|
|
42657
|
+
targetAmount: targetAmount2,
|
|
42658
|
+
targetDate: targetDate2,
|
|
42659
|
+
currentAmount: currentAmount2,
|
|
42660
|
+
monthlyContribution: monthlyContribution2,
|
|
42661
|
+
owner,
|
|
42662
|
+
icon,
|
|
42663
|
+
color,
|
|
42664
|
+
notes
|
|
42665
|
+
};
|
|
42612
42666
|
if (!id)
|
|
42613
42667
|
require2(["name", "targetAmount", "goalType"]);
|
|
42614
42668
|
const data2 = id ? await client.patch(`/api/goals/${id}`, body2) : await client.post("/api/goals", body2);
|
|
42615
42669
|
return { content: [{ type: "text", text: JSON.stringify(data2) }] };
|
|
42616
42670
|
}
|
|
42617
42671
|
if (type === "emi") {
|
|
42618
|
-
require2([
|
|
42619
|
-
|
|
42672
|
+
require2([
|
|
42673
|
+
"name",
|
|
42674
|
+
"totalAmount",
|
|
42675
|
+
"emiAmount",
|
|
42676
|
+
"startDate",
|
|
42677
|
+
"endDate",
|
|
42678
|
+
"totalMonths",
|
|
42679
|
+
"owner"
|
|
42680
|
+
]);
|
|
42681
|
+
const {
|
|
42682
|
+
name: name2,
|
|
42683
|
+
totalAmount,
|
|
42684
|
+
emiAmount,
|
|
42685
|
+
interestRate,
|
|
42686
|
+
startDate,
|
|
42687
|
+
endDate,
|
|
42688
|
+
totalMonths,
|
|
42689
|
+
paidMonths,
|
|
42690
|
+
owner
|
|
42691
|
+
} = fields;
|
|
42620
42692
|
const body2 = {
|
|
42621
42693
|
name: name2,
|
|
42622
42694
|
totalAmount,
|
|
@@ -42911,6 +42983,19 @@ function registerInvestmentTools(server, client) {
|
|
|
42911
42983
|
}
|
|
42912
42984
|
|
|
42913
42985
|
// src/tools/merchants.ts
|
|
42986
|
+
async function categorySlugToId(client) {
|
|
42987
|
+
const res = await client.get("/api/categories");
|
|
42988
|
+
const map2 = new Map;
|
|
42989
|
+
for (const root of res.data ?? []) {
|
|
42990
|
+
if (root.slug)
|
|
42991
|
+
map2.set(root.slug, root.id);
|
|
42992
|
+
for (const child of root.children ?? []) {
|
|
42993
|
+
if (child.slug)
|
|
42994
|
+
map2.set(child.slug, child.id);
|
|
42995
|
+
}
|
|
42996
|
+
}
|
|
42997
|
+
return map2;
|
|
42998
|
+
}
|
|
42914
42999
|
function registerMerchantTools(server, client, crypto3) {
|
|
42915
43000
|
server.registerTool("upsert_merchant", {
|
|
42916
43001
|
description: "Create or update a merchant in the dictionary. Omit `id` to add a new merchant (future transactions from it are auto-categorised); pass `id` to update an existing merchant's name, category, or flags.",
|
|
@@ -42918,15 +43003,21 @@ function registerMerchantTools(server, client, crypto3) {
|
|
|
42918
43003
|
id: exports_external.string().optional().describe("Merchant UUID — pass to update, omit to create"),
|
|
42919
43004
|
rawId: exports_external.string().optional().describe("Raw identifier — UPI ID or normalised name (required when creating)"),
|
|
42920
43005
|
cleanName: exports_external.string().optional().describe('Human-friendly name (e.g. "DMart")'),
|
|
42921
|
-
categorySlug: exports_external.string().optional(),
|
|
43006
|
+
categorySlug: exports_external.string().optional().describe("Category slug, e.g. 'food_delivery'"),
|
|
42922
43007
|
isPerson: exports_external.boolean().optional(),
|
|
42923
43008
|
isRecurring: exports_external.boolean().optional(),
|
|
42924
43009
|
notes: exports_external.string().optional()
|
|
42925
43010
|
}
|
|
42926
|
-
}, async ({ id, ...rest }) => {
|
|
43011
|
+
}, async ({ id, categorySlug, ...rest }) => {
|
|
42927
43012
|
const payload = { ...rest };
|
|
42928
|
-
if (
|
|
42929
|
-
await
|
|
43013
|
+
if (categorySlug) {
|
|
43014
|
+
const slugMap = await categorySlugToId(client);
|
|
43015
|
+
const categoryId = slugMap.get(categorySlug);
|
|
43016
|
+
if (!categoryId) {
|
|
43017
|
+
throw new Error(`Unknown categorySlug "${categorySlug}". Use list_categories to see valid slugs.`);
|
|
43018
|
+
}
|
|
43019
|
+
payload.categoryId = categoryId;
|
|
43020
|
+
}
|
|
42930
43021
|
const data = id ? await client.patch(`/api/merchants/${id}`, payload) : await client.post("/api/merchants", payload);
|
|
42931
43022
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
42932
43023
|
});
|
|
@@ -42938,19 +43029,32 @@ function registerMerchantTools(server, client, crypto3) {
|
|
|
42938
43029
|
}, async ({ rawId }) => {
|
|
42939
43030
|
if (crypto3 && rawId) {
|
|
42940
43031
|
const data2 = await client.get("/api/merchants");
|
|
42941
|
-
if (data2.
|
|
42942
|
-
await decryptMerchantFields(data2.
|
|
43032
|
+
if (data2.data)
|
|
43033
|
+
await decryptMerchantFields(data2.data, crypto3.key);
|
|
42943
43034
|
const needle = rawId.toLowerCase();
|
|
42944
|
-
const merchants = (data2.
|
|
43035
|
+
const merchants = (data2.data ?? []).filter((m) => String(m.rawId ?? "").toLowerCase() === needle || String(m.cleanName ?? "").toLowerCase().includes(needle));
|
|
42945
43036
|
return {
|
|
42946
|
-
content: [{ type: "text", text: JSON.stringify({ ...data2, merchants }) }]
|
|
43037
|
+
content: [{ type: "text", text: JSON.stringify({ ...data2, data: merchants }) }]
|
|
42947
43038
|
};
|
|
42948
43039
|
}
|
|
42949
43040
|
const data = rawId ? await client.get("/api/merchants", {
|
|
42950
43041
|
search: rawId
|
|
42951
43042
|
}) : await client.get("/api/merchants");
|
|
42952
|
-
if (crypto3 && data.
|
|
42953
|
-
await decryptMerchantFields(data.
|
|
43043
|
+
if (crypto3 && data.data)
|
|
43044
|
+
await decryptMerchantFields(data.data, crypto3.key);
|
|
43045
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
43046
|
+
});
|
|
43047
|
+
server.registerTool("delete_merchant", {
|
|
43048
|
+
description: "Delete merchant(s) from the dictionary. Provide `id` for a single merchant or `ids` for several. Transactions referencing a deleted merchant have their merchantId cleared. PERMANENT.",
|
|
43049
|
+
inputSchema: {
|
|
43050
|
+
id: exports_external.string().optional().describe("Single merchant UUID"),
|
|
43051
|
+
ids: exports_external.array(exports_external.string()).min(1).optional().describe("Multiple merchant UUIDs (bulk delete)")
|
|
43052
|
+
}
|
|
43053
|
+
}, async ({ id, ids }) => {
|
|
43054
|
+
if (!id && (!ids || ids.length === 0)) {
|
|
43055
|
+
throw new Error("Provide either id or ids");
|
|
43056
|
+
}
|
|
43057
|
+
const data = ids ? await client.post("/api/merchants/bulk-delete", { ids }) : await client.delete(`/api/merchants/${id}`);
|
|
42954
43058
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
42955
43059
|
});
|
|
42956
43060
|
}
|
|
@@ -43164,6 +43268,9 @@ function registerReportTools(server, client) {
|
|
|
43164
43268
|
});
|
|
43165
43269
|
}
|
|
43166
43270
|
|
|
43271
|
+
// src/tools/transactions.ts
|
|
43272
|
+
import { readFile } from "node:fs/promises";
|
|
43273
|
+
|
|
43167
43274
|
// ../reconciliation/src/aliases.ts
|
|
43168
43275
|
var MERCHANT_ALIASES = [
|
|
43169
43276
|
["Swiggy", ["swiggy", "bundl technologies", "swiggy bundl"]],
|
|
@@ -45241,7 +45348,27 @@ function settlementEnrichedData(description, type, source) {
|
|
|
45241
45348
|
return out;
|
|
45242
45349
|
}
|
|
45243
45350
|
// src/tools/transactions.ts
|
|
45244
|
-
async function
|
|
45351
|
+
async function importTransactions(client, crypto3, opts) {
|
|
45352
|
+
const rows = opts.txns.map((t2) => {
|
|
45353
|
+
const enrichedData = settlementEnrichedData(t2.description ?? "", t2.type, opts.source);
|
|
45354
|
+
return enrichedData ? { ...t2, enrichedData } : { ...t2 };
|
|
45355
|
+
});
|
|
45356
|
+
if (crypto3)
|
|
45357
|
+
await encryptTransactionFields(rows, crypto3.key);
|
|
45358
|
+
const CHUNK = 200;
|
|
45359
|
+
let imported = 0;
|
|
45360
|
+
for (let i2 = 0;i2 < rows.length; i2 += CHUNK) {
|
|
45361
|
+
const res = await client.post("/api/transactions/import-batch", {
|
|
45362
|
+
accountId: opts.accountId,
|
|
45363
|
+
source: opts.source,
|
|
45364
|
+
granularity: opts.granularity,
|
|
45365
|
+
transactions: rows.slice(i2, i2 + CHUNK)
|
|
45366
|
+
});
|
|
45367
|
+
imported += res.imported ?? 0;
|
|
45368
|
+
}
|
|
45369
|
+
return { imported };
|
|
45370
|
+
}
|
|
45371
|
+
async function runRescan(client, crypto3) {
|
|
45245
45372
|
const EMPTY_BAG2 = {
|
|
45246
45373
|
merchantAliases: [],
|
|
45247
45374
|
personAliases: [],
|
|
@@ -45255,10 +45382,23 @@ async function runRescan(client) {
|
|
|
45255
45382
|
} catch {}
|
|
45256
45383
|
const merchantsRes = await client.get("/api/merchants");
|
|
45257
45384
|
const allMerchants = merchantsRes.data ?? [];
|
|
45385
|
+
if (crypto3)
|
|
45386
|
+
await decryptMerchantFields(allMerchants, crypto3.key);
|
|
45258
45387
|
const globalMerchants = allMerchants.filter((m2) => !m2.householdId && m2.cleanName).map((m2) => ({ id: m2.id, name: m2.cleanName }));
|
|
45259
45388
|
const localMerchants = allMerchants.filter((m2) => m2.householdId && m2.cleanName).map((m2) => ({ id: m2.id, name: m2.cleanName }));
|
|
45389
|
+
const merchantCategoryById = new Map(allMerchants.filter((m2) => m2.categoryId).map((m2) => [m2.id, m2.categoryId]));
|
|
45260
45390
|
const personsRes = await client.get("/api/persons");
|
|
45261
|
-
const persons =
|
|
45391
|
+
const persons = [];
|
|
45392
|
+
for (const p2 of personsRes.data ?? []) {
|
|
45393
|
+
let name = p2.name ?? "";
|
|
45394
|
+
if (crypto3 && p2.cipher) {
|
|
45395
|
+
try {
|
|
45396
|
+
name = (await decryptPersonCipher(p2.cipher, crypto3.key)).name;
|
|
45397
|
+
} catch {}
|
|
45398
|
+
}
|
|
45399
|
+
if (name)
|
|
45400
|
+
persons.push({ id: p2.id, name });
|
|
45401
|
+
}
|
|
45262
45402
|
const allRows = [];
|
|
45263
45403
|
const limit = 200;
|
|
45264
45404
|
let cursor;
|
|
@@ -45269,24 +45409,38 @@ async function runRescan(client) {
|
|
|
45269
45409
|
params.cursor = cursor;
|
|
45270
45410
|
const res = await client.get("/api/transactions", params);
|
|
45271
45411
|
const rows = res.data ?? [];
|
|
45412
|
+
if (crypto3)
|
|
45413
|
+
await decryptTransactionFields(rows, crypto3.key);
|
|
45272
45414
|
allRows.push(...rows);
|
|
45273
45415
|
if (!res.hasMore || !res.nextCursor || rows.length === 0)
|
|
45274
45416
|
break;
|
|
45275
45417
|
cursor = res.nextCursor;
|
|
45276
45418
|
}
|
|
45277
|
-
const plan = autoCategorizeFromDescriptions({
|
|
45278
|
-
|
|
45279
|
-
|
|
45280
|
-
|
|
45281
|
-
|
|
45282
|
-
|
|
45419
|
+
const plan = autoCategorizeFromDescriptions({
|
|
45420
|
+
rows: allRows,
|
|
45421
|
+
bag,
|
|
45422
|
+
globalMerchants,
|
|
45423
|
+
localMerchants,
|
|
45424
|
+
persons
|
|
45425
|
+
});
|
|
45426
|
+
let categorized = 0;
|
|
45427
|
+
const links = plan.suggestions.flatMap((s2) => {
|
|
45428
|
+
const categoryId = s2.categoryId ?? (s2.entity.type === "merchant" ? merchantCategoryById.get(s2.entity.merchantId) ?? null : null);
|
|
45429
|
+
if (categoryId)
|
|
45430
|
+
categorized += s2.transactionIds.length;
|
|
45431
|
+
return s2.transactionIds.map((txId) => ({
|
|
45432
|
+
transactionId: txId,
|
|
45433
|
+
...s2.entity.type === "merchant" ? { merchantId: s2.entity.merchantId } : { personId: s2.entity.personId },
|
|
45434
|
+
...categoryId ? { categoryId } : {}
|
|
45435
|
+
}));
|
|
45436
|
+
});
|
|
45283
45437
|
if (links.length > 0) {
|
|
45284
45438
|
const CHUNK = 500;
|
|
45285
45439
|
for (let i2 = 0;i2 < links.length; i2 += CHUNK) {
|
|
45286
45440
|
await client.post("/api/transactions/bulk-link-entity", { links: links.slice(i2, i2 + CHUNK) });
|
|
45287
45441
|
}
|
|
45288
45442
|
}
|
|
45289
|
-
return { linked: links.length, unresolved: plan.unresolvedCount };
|
|
45443
|
+
return { linked: links.length, categorized, unresolved: plan.unresolvedCount };
|
|
45290
45444
|
}
|
|
45291
45445
|
function registerTransactionTools(server, client, crypto3) {
|
|
45292
45446
|
server.registerTool("get_transactions", {
|
|
@@ -45383,6 +45537,8 @@ function registerTransactionTools(server, client, crypto3) {
|
|
|
45383
45537
|
}
|
|
45384
45538
|
}, async ({ accountId, startDate, endDate }) => {
|
|
45385
45539
|
const data = await client.get("/api/transactions/reconciliation-context", { accountId, startDate, endDate });
|
|
45540
|
+
if (crypto3 && data.data)
|
|
45541
|
+
await decryptTransactionFields(data.data, crypto3.key);
|
|
45386
45542
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
45387
45543
|
});
|
|
45388
45544
|
server.registerTool("import_statement_batch", {
|
|
@@ -45400,19 +45556,13 @@ function registerTransactionTools(server, client, crypto3) {
|
|
|
45400
45556
|
})).describe("Transactions to insert — should not include duplicates")
|
|
45401
45557
|
}
|
|
45402
45558
|
}, async ({ accountId, source, granularity, transactions: txns }) => {
|
|
45403
|
-
const
|
|
45404
|
-
const enrichedData = settlementEnrichedData(String(t2.description ?? ""), t2.type, source);
|
|
45405
|
-
return enrichedData ? { ...t2, enrichedData } : { ...t2 };
|
|
45406
|
-
});
|
|
45407
|
-
if (crypto3)
|
|
45408
|
-
await encryptTransactionFields(rows, crypto3.key);
|
|
45409
|
-
const data = await client.post("/api/transactions/import-batch", {
|
|
45559
|
+
const data = await importTransactions(client, crypto3, {
|
|
45410
45560
|
accountId,
|
|
45411
45561
|
source,
|
|
45412
45562
|
granularity,
|
|
45413
|
-
|
|
45563
|
+
txns
|
|
45414
45564
|
});
|
|
45415
|
-
const rescan = await runRescan(client);
|
|
45565
|
+
const rescan = await runRescan(client, crypto3);
|
|
45416
45566
|
return {
|
|
45417
45567
|
content: [
|
|
45418
45568
|
{
|
|
@@ -45422,6 +45572,41 @@ function registerTransactionTools(server, client, crypto3) {
|
|
|
45422
45572
|
]
|
|
45423
45573
|
};
|
|
45424
45574
|
});
|
|
45575
|
+
server.registerTool("import_statement_file", {
|
|
45576
|
+
description: "Bulk-import a parsed statement from a local JSON file (avoids passing thousands of rows as args). " + "The file must contain a JSON array of {date (YYYY-MM-DD), amount (>0), type ('debit'|'credit'), description, referenceNumber?}. " + "Encrypts (private mode), inserts in chunks, then runs categorization ONCE at the end. Use this for large statements.",
|
|
45577
|
+
inputSchema: {
|
|
45578
|
+
accountId: exports_external.string().describe("Bank account UUID the statement belongs to"),
|
|
45579
|
+
source: exports_external.enum(["bank_statement", "cc_statement", "manual", "telegram", "wisprflow", "ai_import"]).describe("Origin of the statement"),
|
|
45580
|
+
granularity: exports_external.number().int().min(1).max(5).describe("Source trust level: 1=bank statement, 2=CC statement, 3=manual, 4=app export, 5=telegram/AI"),
|
|
45581
|
+
filePath: exports_external.string().describe("Absolute path to a JSON file containing the parsed transactions array")
|
|
45582
|
+
}
|
|
45583
|
+
}, async ({ accountId, source, granularity, filePath }) => {
|
|
45584
|
+
let txns;
|
|
45585
|
+
try {
|
|
45586
|
+
const raw = await readFile(filePath, "utf8");
|
|
45587
|
+
const parsed = JSON.parse(raw);
|
|
45588
|
+
if (!Array.isArray(parsed))
|
|
45589
|
+
throw new Error("File must contain a JSON array");
|
|
45590
|
+
txns = parsed;
|
|
45591
|
+
} catch (e2) {
|
|
45592
|
+
throw new Error(`Failed to read/parse ${filePath}: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
45593
|
+
}
|
|
45594
|
+
const data = await importTransactions(client, crypto3, {
|
|
45595
|
+
accountId,
|
|
45596
|
+
source,
|
|
45597
|
+
granularity,
|
|
45598
|
+
txns
|
|
45599
|
+
});
|
|
45600
|
+
const rescan = await runRescan(client, crypto3);
|
|
45601
|
+
return {
|
|
45602
|
+
content: [
|
|
45603
|
+
{
|
|
45604
|
+
type: "text",
|
|
45605
|
+
text: JSON.stringify({ import: data, count: txns.length, rescan })
|
|
45606
|
+
}
|
|
45607
|
+
]
|
|
45608
|
+
};
|
|
45609
|
+
});
|
|
45425
45610
|
server.registerTool("delete_transactions", {
|
|
45426
45611
|
description: "Hard-delete transactions. This is PERMANENT and cannot be undone. " + "Provide exactly one of: `id` (single transaction), `ids` (a list of transactions), " + "or `filters` (deletes all matching transactions). Returns the number of deleted transactions " + "for the bulk paths.",
|
|
45427
45612
|
inputSchema: {
|
|
@@ -45453,7 +45638,7 @@ function registerTransactionTools(server, client, crypto3) {
|
|
|
45453
45638
|
description: "Apply the household's saved learning rules (merchant aliases + category rules) to all uncategorized transactions. " + "Equivalent to the browser's auto-categorize flow. Run this after importing statements via MCP to populate merchants and categories.",
|
|
45454
45639
|
inputSchema: {}
|
|
45455
45640
|
}, async () => {
|
|
45456
|
-
const result = await runRescan(client);
|
|
45641
|
+
const result = await runRescan(client, crypto3);
|
|
45457
45642
|
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
45458
45643
|
});
|
|
45459
45644
|
server.registerTool("get_settlement_candidates", {
|
|
@@ -45463,6 +45648,8 @@ function registerTransactionTools(server, client, crypto3) {
|
|
|
45463
45648
|
}
|
|
45464
45649
|
}, async ({ ccAccountId }) => {
|
|
45465
45650
|
const data = await client.get("/api/transactions/settlement-candidates", { ccAccountId });
|
|
45651
|
+
if (crypto3 && data.data)
|
|
45652
|
+
await decryptTransactionFields(data.data, crypto3.key);
|
|
45466
45653
|
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
45467
45654
|
});
|
|
45468
45655
|
}
|
|
@@ -45529,7 +45716,7 @@ async function main() {
|
|
|
45529
45716
|
registerMerchantTools(server, client, crypto3);
|
|
45530
45717
|
registerPersonTools(server, client, crypto3);
|
|
45531
45718
|
registerCategoryTools(server, client);
|
|
45532
|
-
registerAnalyticsTools(server, client);
|
|
45719
|
+
registerAnalyticsTools(server, client, crypto3);
|
|
45533
45720
|
registerAccountTools(server, client);
|
|
45534
45721
|
registerGoalTools(server, client);
|
|
45535
45722
|
registerBudgetTools(server, client);
|
|
@@ -45559,5 +45746,5 @@ main().catch((err) => {
|
|
|
45559
45746
|
process.exit(1);
|
|
45560
45747
|
});
|
|
45561
45748
|
|
|
45562
|
-
//# debugId=
|
|
45749
|
+
//# debugId=3D60F5F759B1186A64756E2164756E21
|
|
45563
45750
|
//# sourceMappingURL=index.js.map
|