chaimi-keep-mcp 3.1.47 → 3.1.49-beta.1

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
@@ -148,6 +148,25 @@ AI 会自动调用 `save_income` 工具记录收入。
148
148
 
149
149
  ## 更新日志
150
150
 
151
+ ### v3.1.49-beta.0 (2026-04-24)
152
+ - **修复** category 未定义错误(三个记账函数)
153
+ - save_expense: `category` → `displayCategory`
154
+ - save_receipt: `storeCategory` → `category`
155
+ - save_income: `category` → `displayCategory`
156
+ - **优化** 回复格式排版
157
+ - Agent 名称用「」包裹:`「你的小可爱」`
158
+ - 分隔符从 emoji 换成实心点 `·`
159
+ - 更简洁清晰的视觉层次
160
+
161
+ ### v3.1.48 (2026-04-24)
162
+ - **优化** 回复格式模板
163
+ - 添加缩进层级,主次信息更清晰
164
+ - 所有记账工具回复添加 4 空格缩进
165
+ - 新增 Agent 名称说明,支持自定义名称显示
166
+ - **完善** SKILL.md 文档
167
+ - 扩充友好结束语参考,按分类给出更多正能量表达
168
+ - 详细说明未授权处理流程
169
+
151
170
  ### v3.1.46-beta.0 (2026-04-22)
152
171
  - **修复** 授权流程阻塞问题:恢复到 v3.1.37 之前的非阻塞模式
153
172
  - 移除 `startAuthFlowAndWait()` 和 `waitForAuthWithPolling()` 阻塞函数
package/SKILL.md CHANGED
@@ -261,23 +261,30 @@ get_statistics period="this_week"
261
261
  记账成功后,使用以下格式回复(代码块内每行一个换行):
262
262
 
263
263
  ```
264
- 【商品名/店名】¥【金额】
265
- 已录入【柴米AI记账】
266
- 【补充信息,如购买地点日期】
264
+ 「Agent名称」已帮您录入「柴米AI记账」
265
+ · 商品/店名:【名称】 💰【金额】
266
+ · 收支类型: 【收入/支出】
267
+ · 分类:【商品类型】
268
+ · 时间:【购买日期】
267
269
  ✅ 【友好结束语】
268
270
 
269
- 消费洞察:【洞察内容】(可选)
271
+ 💡 消费洞察:【洞察内容】(可选)
270
272
  -------------
271
273
  chaimi-keep-mcp: v【版本号】
272
274
  ```
273
275
 
274
- **友好结束语参考:**
275
- - 餐饮类:用餐愉快!🍚 / 好好吃饭哦~
276
- - 食品类:吃好喝好!🍎
277
- - 交通类:出行顺利!🚗
278
- - 购物类:买得开心!🛍️
279
- - 收入类:入账顺利!💰
280
- - 通用:记账完成!继续保持~
276
+ **Agent名称说明:**
277
+ - 如果用户为当前授权设置了自定义Agent名称(如"你的小可爱"),则显示:`✅ 「你的小可爱」已帮您录入「柴米AI记账」`
278
+ - 如果未设置自定义名称(默认"柴米AI助手"),则显示:`✅ 「柴米AI助手」已帮您录入「柴米AI记账」`
279
+ - Agent名称从MCP返回的数据中获取,字段名为 `agentName`
280
+
281
+ **友好结束语参考(一定要是正能量,且给足情绪价值的词):**
282
+ - 餐饮类:用餐愉快!🍚 / 好好吃饭哦~ / 美食治愈一切!😋 / 每一餐都是生活的小确幸~ 🌟
283
+ - 食品类:吃好喝好!🍎 / 健康第一,美味加倍!💪 / 好好照顾自己哦~ 🤗
284
+ - 交通类:出行顺利!🚗 / 一路平安!🙏 / 顺利抵达,心情愉悦~ 😊
285
+ - 购物类:买得开心!🛍️ / 精明消费,品质生活!✨ / 买到心仪好物,心情美美哒~ 💕
286
+ - 收入类:入账顺利!💰 / 财富+1,好运连连!🍀 / 越努力越幸运,继续加油!🚀
287
+ - 通用:记账完成!继续保持~ ✨ / 今天的你超棒的!👍 / 记录美好生活,从每一笔开始~ 📝
281
288
 
282
289
  **消费洞察(可选):**
283
290
  - 由云函数自动生成,返回记账后的即时洞察
@@ -286,14 +293,16 @@ chaimi-keep-mcp: v【版本号】
286
293
  **真实示例:**
287
294
 
288
295
  ```
289
- 【牛肉】¥24
290
- 已录入【柴米AI记账】
291
- 华润万家超市,2026年4月16日购买
296
+ 「你的小可爱」已帮您录入「柴米AI记账」
297
+ · 商品:猪脚 💰 ¥33
298
+ · 收支类型: 支出
299
+ · 分类: 餐饮
300
+ · 时间:2026年4月24日
292
301
  ✅ 好好吃饭哦~
293
302
 
294
- 消费洞察:这是你本周第19次餐饮消费,要不要看看本周餐饮花了多少钱?
303
+ 💡 消费洞察:这是你本周第23次餐饮消费,要不要看看本周餐饮花了多少钱?
295
304
  -------------
296
- chaimi-keep-mcp: v3.1.40
305
+ chaimi-keep-mcp: v3.1.48
297
306
  ```
298
307
 
299
308
  ---
@@ -303,10 +312,49 @@ chaimi-keep-mcp: v3.1.40
303
312
  | 错误类型 | 处理方式 |
304
313
  |----------|----------|
305
314
  | 未安装 | 引导安装:`npm install -g chaimi-keep-mcp` |
306
- | 未授权 | 引导完成 Device Flow 授权 |
307
- | Token 过期 | 引导重新授权 |
315
+ | 未授权 | MCP Server 自动返回授权错误和验证码,Agent 引导用户在小程序中完成授权 |
316
+ | Token 过期 | MCP Server 自动刷新,或返回授权错误需要重新授权 |
308
317
  | 参数错误 | 提示用户补充必要信息 |
309
318
 
319
+ ### 未授权详细处理流程
320
+
321
+ 当调用记账工具时,如果用户未授权,MCP Server 会自动返回授权错误,包含验证码。
322
+
323
+ **第 1 步:捕获授权错误**
324
+
325
+ 当 MCP Server 返回如下错误时:
326
+ ```
327
+ NEED_AUTH:GGCY-AC84
328
+ ```
329
+
330
+ 表示需要授权,验证码为 `GGCY-AC84`。
331
+
332
+ **第 2 步:引导用户完成授权**
333
+
334
+ Agent 必须向用户显示:
335
+ ```
336
+ 🔐 请先完成授权
337
+
338
+ ━━━━━━━━━━━━━━
339
+ 📱 验证码:GGCY-AC84
340
+ ━━━━━━━━━━━━━━
341
+
342
+ 请在"柴米AI记账"小程序中完成授权:
343
+
344
+ 1️⃣ 打开微信小程序"柴米AI记账"
345
+ 2️⃣ 点击"我的" → "🤖 Agent 授权"
346
+ 3️⃣ 输入验证码:GGCY-AC84
347
+ 4️⃣ 点击确认授权
348
+
349
+ 授权完成后告诉我,我将继续为您记账。
350
+ ```
351
+
352
+ **第 3 步:用户确认授权后**
353
+
354
+ 用户告知授权完成后,Agent **直接重新调用**之前的记账工具,无需其他操作。
355
+ - 如果授权成功,记账会自动完成
356
+ - 如果授权失败,会再次返回错误
357
+
310
358
  ---
311
359
 
312
360
  *最后更新:2026-04-16*
package/oauth.js CHANGED
@@ -484,6 +484,58 @@ class FileTokenStorage extends TokenStorage {
484
484
  }
485
485
  }
486
486
  }
487
+
488
+ // 【新增】保存 Agent 名称(不修改授权流程,仅用于记账回复)
489
+ async saveAgentName(agentName) {
490
+ try {
491
+ const agentNamePath = this.path.join(this.path.dirname(this.filePath), 'agent-name.json');
492
+ const data = {
493
+ agentName: agentName || '柴米AI助手',
494
+ updatedAt: new Date().toISOString()
495
+ };
496
+ await this.fs.writeFile(agentNamePath, JSON.stringify(data, null, 2), { mode: 0o600 });
497
+ } catch (err) {
498
+ // 忽略错误,不影响主流程
499
+ }
500
+ }
501
+
502
+ // 【新增】读取 Agent 名称
503
+ async loadAgentName() {
504
+ try {
505
+ const agentNamePath = this.path.join(this.path.dirname(this.filePath), 'agent-name.json');
506
+ const data = await this.fs.readFile(agentNamePath, 'utf8');
507
+ const parsed = JSON.parse(data);
508
+ return parsed.agentName || '柴米AI助手';
509
+ } catch (err) {
510
+ return '柴米AI助手';
511
+ }
512
+ }
513
+
514
+ // 【新增】保存 deviceCode
515
+ async saveDeviceCode(deviceCode) {
516
+ try {
517
+ const deviceCodePath = this.path.join(this.path.dirname(this.filePath), 'device-code.json');
518
+ const data = {
519
+ deviceCode,
520
+ updatedAt: new Date().toISOString()
521
+ };
522
+ await this.fs.writeFile(deviceCodePath, JSON.stringify(data, null, 2), { mode: 0o600 });
523
+ } catch (err) {
524
+ // 忽略错误
525
+ }
526
+ }
527
+
528
+ // 【新增】读取 deviceCode
529
+ async loadDeviceCode() {
530
+ try {
531
+ const deviceCodePath = this.path.join(this.path.dirname(this.filePath), 'device-code.json');
532
+ const data = await this.fs.readFile(deviceCodePath, 'utf8');
533
+ const parsed = JSON.parse(data);
534
+ return parsed.deviceCode;
535
+ } catch (err) {
536
+ return null;
537
+ }
538
+ }
487
539
  }
488
540
 
489
541
  module.exports = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaimi-keep-mcp",
3
- "version": "3.1.47",
3
+ "version": "3.1.49-beta.1",
4
4
  "description": "柴米记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -967,9 +967,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
967
967
  achievementsText = '\n\n🎉 成就解锁:' + result.newlyUnlocked.map(a => `${a.icon} ${a.title}(+${a.points}分)`).join(';');
968
968
  }
969
969
 
970
- // SKILL 规范格式:记账成功 + 友好结束语 + 消费洞察 + 成就 + 版本号
970
+ // 【新增】获取 Agent 名称
971
+ const agentName = await getAgentName();
972
+
973
+ // 按 SKILL 规范格式:新的回复模板
971
974
  const displayStoreText = displayStore ? `【${displayStore}】` : '';
972
- userMessage = `✅ ${displayName}${displayStoreText} ¥${displayAmount} 已录入柴米AI记账。\n\n${friendlyEnding}${insightsText}${achievementsText}\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
975
+ const dateStr = result.data?.date ? new Date(result.data.date).toLocaleDateString('zh-CN') : new Date().toLocaleDateString('zh-CN');
976
+ userMessage = `✅ 「${agentName}」已帮您录入「柴米AI记账」\n · 商品/店名:${displayName}${displayStoreText} 💰¥${displayAmount}\n · 收支类型: 支出\n · 分类:${result.data?.categoryName || displayCategory}\n · 时间:${dateStr}\n✅ ${friendlyEnding}${insightsText}${achievementsText}\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
973
977
 
974
978
  if (!processedArgs.agentType || !processedArgs.apiProvider) {
975
979
  userMessage += '\n\n💡 提示:传递agentType和apiProvider参数可解锁小程序记录来源统计功能,示例:agentType="openclaw", apiProvider="doubao"';
@@ -1208,7 +1212,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1208
1212
  achievementsText = '\n\n🎉 成就解锁:' + result.newlyUnlocked.map(a => `${a.icon} ${a.title}(+${a.points}分)`).join(';');
1209
1213
  }
1210
1214
 
1211
- userMessage = `✅ ${storeName} ¥${totalAmount} 已录入柴米AI记账(${itemCount}件商品)。\n\n${friendlyEnding}${insightsText}${achievementsText}\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
1215
+ // 【新增】获取 Agent 名称
1216
+ const agentName = await getAgentName();
1217
+
1218
+ // 按 SKILL 规范格式:新的回复模板
1219
+ const dateStr = result.data?.date ? new Date(result.data.date).toLocaleDateString('zh-CN') : new Date().toLocaleDateString('zh-CN');
1220
+ userMessage = `✅ 「${agentName}」已帮您录入「柴米AI记账」\n · 商品/店名:${storeName} 💰¥${totalAmount}\n · 收支类型: 支出\n · 分类:${result.data?.storeCategory || category}\n · 商品数量:${itemCount}件\n · 时间:${dateStr}\n✅ ${friendlyEnding}${insightsText}${achievementsText}\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
1212
1221
 
1213
1222
  if (!processedArgs.agentType || !processedArgs.apiProvider) {
1214
1223
  userMessage += '\n\n💡 提示:传递agentType和apiProvider参数可解锁小程序记录来源统计功能,示例:agentType="openclaw", apiProvider="doubao"';
@@ -1433,7 +1442,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1433
1442
  const displayStore = processedArgs.store || '';
1434
1443
  const displayStoreText = displayStore ? `【${displayStore}】` : '';
1435
1444
 
1436
- userMessage = `✅ ${displayName}${displayStoreText} ¥${displayAmount} 已录入柴米AI记账。\n\n入账顺利!💰\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
1445
+ // 【新增】获取 Agent 名称
1446
+ const agentName = await getAgentName();
1447
+
1448
+ // 按 SKILL 规范格式:新的回复模板
1449
+ const dateStr = result.data?.date ? new Date(result.data.date).toLocaleDateString('zh-CN') : new Date().toLocaleDateString('zh-CN');
1450
+ userMessage = `✅ 「${agentName}」已帮您录入「柴米AI记账」\n · 商品/店名:${displayName}${displayStoreText} 💰¥${displayAmount}\n · 收支类型: 收入\n · 分类:${result.data?.categoryName || displayCategory}\n · 时间:${dateStr}\n✅ 入账顺利!💰\n-------------\nchaimi-keep-mcp: v${MCP_VERSION}`;
1437
1451
  }
1438
1452
  break;
1439
1453
  }
@@ -1521,6 +1535,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1521
1535
  userMessage = `❌ 操作失败:${result.error || '未知错误'}`;
1522
1536
  }
1523
1537
 
1538
+ // 【新增】在结果中添加 agentName,让 Agent 可以使用
1539
+ const agentName = await getAgentName();
1540
+ if (result && typeof result === 'object') {
1541
+ result.agentName = agentName;
1542
+ }
1543
+
1524
1544
  return {
1525
1545
  content: [
1526
1546
  {
@@ -1938,6 +1958,55 @@ let authState = {
1938
1958
  error: null
1939
1959
  };
1940
1960
 
1961
+ // 【新增】获取 Agent 名称(仅用于记账回复,不修改授权流程)
1962
+ async function getAgentName() {
1963
+ try {
1964
+ if (oauthManager && oauthManager.tokenStorage) {
1965
+ const localName = await oauthManager.tokenStorage.loadAgentName();
1966
+
1967
+ // 如果是默认名称,尝试从云端获取
1968
+ if (localName === '柴米AI助手') {
1969
+ // 获取保存的 deviceCode
1970
+ const deviceCode = await oauthManager.tokenStorage.loadDeviceCode();
1971
+ if (deviceCode) {
1972
+ // 从云端获取
1973
+ const cloudName = await fetchAgentNameFromCloud(deviceCode);
1974
+ if (cloudName && cloudName !== '柴米AI助手') {
1975
+ await oauthManager.tokenStorage.saveAgentName(cloudName);
1976
+ return cloudName;
1977
+ }
1978
+ }
1979
+ }
1980
+
1981
+ return localName;
1982
+ }
1983
+ } catch (err) {
1984
+ // 忽略错误
1985
+ }
1986
+ return '柴米AI助手';
1987
+ }
1988
+
1989
+ // 【新增】从云端获取 Agent 名称
1990
+ async function fetchAgentNameFromCloud(deviceCode) {
1991
+ try {
1992
+ const response = await fetch(MCP_OAUTH_URL, {
1993
+ method: 'POST',
1994
+ headers: { 'Content-Type': 'application/json' },
1995
+ body: JSON.stringify({
1996
+ tool: 'getDeviceInfo',
1997
+ params: { deviceCode }
1998
+ })
1999
+ });
2000
+ const result = await response.json();
2001
+ if (result.success && result.data.agentName) {
2002
+ return result.data.agentName;
2003
+ }
2004
+ } catch (err) {
2005
+ // 忽略错误
2006
+ }
2007
+ return null;
2008
+ }
2009
+
1941
2010
  async function main() {
1942
2011
  await initOAuthManager();
1943
2012
 
@@ -2017,6 +2086,11 @@ async function pollForAuthInBackground(deviceCode, interval) {
2017
2086
 
2018
2087
  // 保存token到文件
2019
2088
  await oauthManager.tokenStorage.save(token);
2089
+
2090
+ // 【新增】保存默认 Agent 名称和 deviceCode(首次记账时会获取真实名称)
2091
+ await oauthManager.tokenStorage.saveAgentName('柴米AI助手');
2092
+ await oauthManager.tokenStorage.saveDeviceCode(authState.deviceCode);
2093
+
2020
2094
  // 清除授权状态
2021
2095
  await oauthManager.clearAuthState();
2022
2096