chaimi-bookkeeping-mcp 2.2.5 → 2.2.6
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/package.json +1 -1
- package/server.js +101 -4
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -84,9 +84,24 @@ const server = new Server(
|
|
|
84
84
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
85
85
|
return {
|
|
86
86
|
tools: [
|
|
87
|
+
{
|
|
88
|
+
name: 'quick_book',
|
|
89
|
+
description: '极简快捷记账 - 自动识别支出/收入,智能匹配分类。输入如:"午餐 30 元"、"工资 8000 元"、"木屋烧烤 35 元"',
|
|
90
|
+
inputSchema: {
|
|
91
|
+
type: 'object',
|
|
92
|
+
properties: {
|
|
93
|
+
name: { type: 'string', description: '商品/服务名称或自然语言描述(必填)' },
|
|
94
|
+
amount: { type: 'number', description: '金额(必填)' },
|
|
95
|
+
category: { type: 'string', description: '分类(可选,系统自动推荐)' },
|
|
96
|
+
store: { type: 'string', description: '商家名称(可选)' },
|
|
97
|
+
note: { type: 'string', description: '备注(可选)' },
|
|
98
|
+
},
|
|
99
|
+
required: ['name', 'amount'],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
87
102
|
{
|
|
88
103
|
name: 'save_expense',
|
|
89
|
-
description: '保存单商品消费记录(AI文字记账)',
|
|
104
|
+
description: '保存单商品消费记录(AI 文字记账)',
|
|
90
105
|
inputSchema: {
|
|
91
106
|
type: 'object',
|
|
92
107
|
properties: {
|
|
@@ -97,8 +112,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
97
112
|
unit: { type: 'string', description: '单位(如:斤、个、瓶)' },
|
|
98
113
|
category: { type: 'string', description: '分类(如:餐饮、食品、交通)' },
|
|
99
114
|
store: { type: 'string', description: '商家名称' },
|
|
100
|
-
agentType: { type: 'string', description: 'Agent类型(如:workbuddy、claude、cursor)' },
|
|
101
|
-
apiProvider: { type: 'string', description: 'AI提供商' },
|
|
115
|
+
agentType: { type: 'string', description: 'Agent 类型(如:workbuddy、claude、cursor)' },
|
|
116
|
+
apiProvider: { type: 'string', description: 'AI 提供商' },
|
|
102
117
|
rawInput: { type: 'string', description: '用户原始输入' },
|
|
103
118
|
},
|
|
104
119
|
required: ['name', 'amount', 'price', 'quantity'],
|
|
@@ -351,8 +366,56 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
351
366
|
|
|
352
367
|
// 根据工具类型选择处理流程
|
|
353
368
|
switch (name) {
|
|
369
|
+
case 'quick_book': {
|
|
370
|
+
// 极简快捷记账:自动识别支出/收入,智能匹配分类
|
|
371
|
+
console.log('处理极简快捷记账...');
|
|
372
|
+
|
|
373
|
+
// 1. 判断是支出还是收入
|
|
374
|
+
const isIncome = isIncomeName(args.name);
|
|
375
|
+
|
|
376
|
+
// 2. 智能匹配分类
|
|
377
|
+
const category = args.category || getCategory(args.name);
|
|
378
|
+
|
|
379
|
+
// 3. 自动补全参数
|
|
380
|
+
const completedArgs = {
|
|
381
|
+
name: sanitizeString(args.name, 100),
|
|
382
|
+
amount: validateAmount(args.amount),
|
|
383
|
+
price: args.price || validateAmount(args.amount),
|
|
384
|
+
quantity: args.quantity || 1,
|
|
385
|
+
unit: args.unit || '个',
|
|
386
|
+
category: category,
|
|
387
|
+
store: sanitizeString(args.store, 100) || '未知商家',
|
|
388
|
+
note: sanitizeString(args.note, 500),
|
|
389
|
+
agentType: args.agentType || '',
|
|
390
|
+
apiProvider: args.apiProvider || '',
|
|
391
|
+
rawInput: args.rawInput || args.name,
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// 4. 根据类型选择接口
|
|
395
|
+
if (isIncome) {
|
|
396
|
+
// 收入记账
|
|
397
|
+
console.log('识别为收入,调用 save_income...');
|
|
398
|
+
const mcpParams = convertParams('save_income', completedArgs);
|
|
399
|
+
result = await callMcpHub('addIncome', mcpParams, token);
|
|
400
|
+
|
|
401
|
+
if (result.success) {
|
|
402
|
+
userMessage = `✅ 记账成功\n\n| 收入来源 | 金额 | 分类 |\n|------|------|------|\n| ${completedArgs.name} | ${completedArgs.amount}元 | ${completedArgs.category || '其他收入'} |\n\n已保存到你的柴米记账小程序数据库。`;
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
// 支出记账
|
|
406
|
+
console.log('识别为支出,调用 save_expense...');
|
|
407
|
+
const mcpParams = convertParams('save_expense', completedArgs);
|
|
408
|
+
result = await callMcpHub('addExpense', mcpParams, token);
|
|
409
|
+
|
|
410
|
+
if (result.success) {
|
|
411
|
+
userMessage = `✅ 记账成功\n\n| 商品 | 金额 | 分类 | 商家 |\n|------|------|------|------|\n| ${completedArgs.name} | ${completedArgs.amount}元 | ${completedArgs.category || '其他'} | ${completedArgs.store} |\n\n已保存到你的柴米记账小程序数据库。`;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
|
|
354
417
|
case 'save_expense': {
|
|
355
|
-
// 步骤1:校验数据完整性
|
|
418
|
+
// 步骤 1:校验数据完整性
|
|
356
419
|
console.log('校验消费数据完整性...');
|
|
357
420
|
const validationResult = await callMcpPrompt(
|
|
358
421
|
'validateResult',
|
|
@@ -663,6 +726,40 @@ function convertParams(toolName, args) {
|
|
|
663
726
|
}
|
|
664
727
|
}
|
|
665
728
|
|
|
729
|
+
// 智能分类:根据商品名称匹配分类
|
|
730
|
+
function getCategory(name) {
|
|
731
|
+
if (!name) return '其他';
|
|
732
|
+
|
|
733
|
+
const categoryMap = {
|
|
734
|
+
'餐饮': ['饭', '菜', '餐', '酒', '饮料', '咖啡', '茶', '早餐', '午餐', '晚餐', '夜宵', '烧烤', '火锅', '快餐', '外卖', '小吃', '奶茶', '面包', '蛋糕'],
|
|
735
|
+
'交通': ['车', '油', '票', '打车', '公交', '地铁', '加油', '停车', '租车', '火车', '飞机', '轮船', '客运'],
|
|
736
|
+
'购物': ['买', '购', '商场', '超市', '衣服', '鞋', '包', '化妆品', '护肤品', '数码', '电器', '家具', '日用品'],
|
|
737
|
+
'娱乐': ['玩', '游戏', '电影', '歌', 'KTV', '酒吧', '旅游', '景点', '门票', '健身', '运动', '书', '音乐'],
|
|
738
|
+
'医疗': ['药', '医', '病', '医院', '诊所', '体检', '疫苗', '牙科', '眼科', '门诊'],
|
|
739
|
+
'教育': ['学', '课', '培训', '考试', '学校', '学费', '教材', '文具', '培训费'],
|
|
740
|
+
'居住': ['房', '租', '物业', '水电', '燃气', '网络', '宽带', '话费', '维修', '装修'],
|
|
741
|
+
'工资': ['工资', '薪水', '奖金', '提成', '分红', '补贴', '津贴', '绩效'],
|
|
742
|
+
'其他收入': ['红包', '转账', '借款', '还款', '退款', '理赔', '中奖', '利息'],
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
for (const [category, keywords] of Object.entries(categoryMap)) {
|
|
746
|
+
if (keywords.some(keyword => name.includes(keyword))) {
|
|
747
|
+
return category;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
return '其他';
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// 判断是否为收入
|
|
755
|
+
function isIncomeName(name) {
|
|
756
|
+
if (!name) return false;
|
|
757
|
+
|
|
758
|
+
const incomeKeywords = ['工资', '薪水', '奖金', '提成', '分红', '补贴', '津贴', '绩效', '红包', '转账', '借款', '还款', '退款', '理赔', '中奖', '利息', '收入', '入账', '到账'];
|
|
759
|
+
|
|
760
|
+
return incomeKeywords.some(keyword => name.includes(keyword));
|
|
761
|
+
}
|
|
762
|
+
|
|
666
763
|
// 获取月份最后一天
|
|
667
764
|
function getMonthEndDate(yearMonth) {
|
|
668
765
|
const [year, month] = yearMonth.split('-').map(Number);
|