chaimi-keep-mcp 3.3.3-beta.12 → 3.3.3-beta.14

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/README.md CHANGED
@@ -89,6 +89,12 @@ export MCP_PROMPT_URL="你的Prompt服务地址"
89
89
 
90
90
  ## Changelog
91
91
 
92
+ ### v3.3.3-beta.13 (2026-04-30)
93
+ - **变更** 多端记账分类统一 - 支持商品分类和记账分类分离
94
+ - 保持 `category`(记账分类,43个标准分类)
95
+ - 新增 `productCategory`(商品一级分类,展示用)
96
+ - 新增 `productSubCategory`(商品子分类,展示用)
97
+
92
98
  ### v3.3.3-beta.8 (2026-04-30)
93
99
  - **变更** 配置存储路径迁移 - 从 `~/.mcporter/` 迁移到 `~/.chaimi-keep/`,避免与其他 MCP 工具冲突
94
100
  - **优化** 安全权限 - 新增目录权限控制(0700),敏感文件权限控制(0600)
package/SKILL.md CHANGED
@@ -128,15 +128,19 @@ chaimi-keep-mcp ⭐ 本Skill
128
128
  └─ get_skill() 获取 SKILL.md 规范
129
129
  └─ references/response-templates.md 了解回复模板
130
130
 
131
- 第2步:拿Token
132
- └─ 文字记账:get_text_parse_prompt() 获取 Token 和解析模板
133
- └─ 小票记账:get_parse_prompt() 获取 Token 和解析模板
131
+ 第2步:拿凭证
132
+ └─ 文字记账:get_text_parse_prompt() 获取凭证和解析模板
133
+ └─ 小票记账:get_parse_prompt() 获取凭证和解析模板
134
+
135
+ 【强制流程】必须先调用此工具,让 AI 解析用户输入
136
+ 此工具会返回解析结果,你只需将结果原样传给 save_expense/save_income
137
+ ⚠️ 禁止自行解析或提取任何字段,必须让 AI 处理
134
138
 
135
139
  第3步:AI解析
136
- └─ 按模板解析用户输入,生成结构化数据 + _requestToken
140
+ └─ 按模板解析用户输入,生成结构化数据 + _flowmate
137
141
 
138
142
  第4步:执行记账
139
- └─ 调用工具(save_expense/income/receipt,带上 _requestToken
143
+ └─ 调用工具(save_expense/income/receipt,带上 _flowmate
140
144
  └─ 根据 _templateLocation 使用模板渲染美学回复
141
145
  ```
142
146
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaimi-keep-mcp",
3
- "version": "3.3.3-beta.12",
3
+ "version": "3.3.3-beta.14",
4
4
  "description": "柴米AI记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -265,8 +265,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
265
265
  properties: {
266
266
  name: { type: 'string', description: '商品名称(必填)' },
267
267
  amount: { type: 'number', description: '金额(必填)' },
268
- category: { type: 'string', description: '【必填】分类,如:餐饮、食品、交通' },
269
- subCategory: { type: 'string', description: '子分类(可选)' },
268
+ category: { type: 'string', description: '【必填】支出分类(43个标准分类之一,如:餐饮、食品、交通、蔬菜)' },
270
269
  unit: { type: 'string', description: '单位(可选)' },
271
270
  marketPrice: { type: 'string', description: '市场单价(可选)' },
272
271
  store: { type: 'string', description: '商家名称(可选)' },
@@ -314,10 +313,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
314
313
  amount: { type: 'number', description: '【必填】金额,必须等于 price × quantity' },
315
314
  weight: { type: 'string', description: '重量' },
316
315
  marketPrice: { type: 'string', description: '【必填】单价数值,根据unit计算,如unit=元/500g,则marketPrice=金额÷重量(g)×500' },
317
- category: { type: 'string', description: '【必填】主分类(如:蔬菜、肉类、水果、水产,常见超市购物分类)' },
318
- subCategory: { type: 'string', description: '子分类(如:叶菜类、根茎类、猪肉类,超市细分类目),推荐填写' },
316
+ // 【改造】商品分类字段
317
+ productCategory: { type: 'string', description: '【必填】商品一级分类(如:蔬菜、肉类、水果、日化用品)' },
318
+ productSubCategory: { type: 'string', description: '商品二级分类(如:叶菜类、根茎类、家居清洁)' },
319
+ // 【改造】记账分类字段
320
+ category: { type: 'string', description: '【必填】记账分类(43个标准分类之一,如:蔬菜、购物、餐饮)' },
319
321
  },
320
- required: ['name', 'amount', 'price', 'quantity', 'unit', 'marketPrice', 'category'],
322
+ required: ['name', 'amount', 'price', 'quantity', 'unit', 'marketPrice', 'productCategory', 'category'],
321
323
  },
322
324
  },
323
325
  agentType: { type: 'string', description: '【必填】Agent类型:claude-desktop、cursor、openclaw、workbuddy、trae' },
@@ -340,7 +342,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
340
342
  startDate: { type: 'string', description: '开始日期(ISO格式,如:2026-04-01)' },
341
343
  endDate: { type: 'string', description: '结束日期(ISO格式,如:2026-04-30)' },
342
344
  category: { type: 'string', description: '按分类筛选(如:餐饮、食品、交通)' },
343
- subCategory: { type: 'string', description: '按子分类筛选(如:叶菜类、猪肉类)' },
344
345
  store: { type: 'string', description: '按商家名称筛选' },
345
346
  source: { type: 'string', description: '按来源筛选(如:mcp_txt_expense、mcp_receipt)' },
346
347
  keyword: { type: 'string', description: '按商品名称关键词搜索' },
@@ -411,13 +412,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
411
412
  },
412
413
  {
413
414
  name: 'save_income',
414
- description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_income _flowmate="SOLINWANG..." name="红包" amount=100 category="礼金" rawInput="收红包100元"',
415
+ description: '【文本记账-收入】用户提及收入关键词(工资、红包、转账、退款等)时用此工具。前置:必须先调用get_skill获取规范,再调用get_text_parse_prompt获取凭证和解析模板。用法:mcporter call 柴米AI记账.save_income _flowmate="SOLINWANG..." name="红包" amount=100 category="红包" rawInput="收红包100元"',
415
416
  inputSchema: {
416
417
  type: 'object',
417
418
  properties: {
418
419
  name: { type: 'string', description: '收入来源(如:工资、奖金、红包)(必填)' },
419
420
  amount: { type: 'number', description: '收入金额(必填)' },
420
- category: { type: 'string', description: '(必填)收入分类(如:工资、奖金、投资)' },
421
+ category: { type: 'string', description: '【必填】收入分类(8个标准分类之一:工资、兼职、奖金、红包、退款、理财、转账、其他)' },
421
422
  store: { type: 'string', description: '付款方(如:公司名称)(可选)' },
422
423
  date: { type: 'number', description: '【必填】收入时间(毫秒级时间戳,13位数字。必须根据实际年月日时分秒计算,不允许复制示例数字)' },
423
424
  note: { type: 'string', description: '备注(可选)' },
@@ -1169,7 +1170,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1169
1170
  break;
1170
1171
  }
1171
1172
 
1172
- // 检查 items 中每个商品的必填字段(包括 category)
1173
+ // 检查 items 中每个商品的必填字段(包括分类字段)
1173
1174
  const invalidItems = [];
1174
1175
  processedArgs.items.forEach((item, index) => {
1175
1176
  const itemMissingFields = [];
@@ -1177,7 +1178,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1177
1178
  if (!item.hasOwnProperty('amount') || item.amount === undefined) itemMissingFields.push('amount');
1178
1179
  if (!item.hasOwnProperty('price') || item.price === undefined) itemMissingFields.push('price');
1179
1180
  if (!item.hasOwnProperty('quantity') || item.quantity === undefined) itemMissingFields.push('quantity');
1180
- if (!item.hasOwnProperty('category') || item.category === '') itemMissingFields.push('category');
1181
+ // 【改造】检查新字段 productCategory category
1182
+ if (!item.hasOwnProperty('productCategory') || item.productCategory === '') {
1183
+ itemMissingFields.push('productCategory');
1184
+ }
1185
+ if (!item.hasOwnProperty('category') || item.category === '') {
1186
+ itemMissingFields.push('category');
1187
+ }
1181
1188
 
1182
1189
  if (itemMissingFields.length > 0) {
1183
1190
  invalidItems.push(`商品${index + 1}(${item.name || '未命名'})缺少字段: ${itemMissingFields.join(', ')}`);
@@ -2111,7 +2118,6 @@ function convertParams(toolName, args) {
2111
2118
  price: amount,
2112
2119
  quantity: 1,
2113
2120
  category: sanitizeString(args.category, 50) || '其他',
2114
- subCategory: sanitizeString(args.subCategory, 50) || '',
2115
2121
  unit: sanitizeString(args.unit, 20) || '',
2116
2122
  weight: '',
2117
2123
  marketPrice: sanitizeString(args.marketPrice, 50) || '',
@@ -2152,8 +2158,10 @@ function convertParams(toolName, args) {
2152
2158
  name: sanitizeString(item.name, 100),
2153
2159
  originalName: sanitizeString(item.originalName, 200) || sanitizeString(item.name, 100),
2154
2160
  amount: amount,
2161
+ // 【改造】新字段
2162
+ productCategory: sanitizeString(item.productCategory, 50) || '其他',
2163
+ productSubCategory: sanitizeString(item.productSubCategory, 50) || '',
2155
2164
  category: sanitizeString(item.category, 50) || '其他',
2156
- subCategory: sanitizeString(item.subCategory, 50) || '',
2157
2165
  transactionType: sanitizeString(item.transactionType, 50) || 'expense',
2158
2166
  price: validateAmount(item.price),
2159
2167
  quantity: item.quantity ? String(item.quantity).substring(0, 20) : '1',