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 +19 -0
- package/SKILL.md +66 -18
- package/oauth.js +52 -0
- package/package.json +1 -1
- package/server.js +78 -4
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
|
-
|
|
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
|
-
✅
|
|
290
|
-
|
|
291
|
-
|
|
296
|
+
✅ 「你的小可爱」已帮您录入「柴米AI记账」
|
|
297
|
+
· 商品:猪脚 💰 ¥33
|
|
298
|
+
· 收支类型: 支出
|
|
299
|
+
· 分类: 餐饮
|
|
300
|
+
· 时间:2026年4月24日
|
|
292
301
|
✅ 好好吃饭哦~
|
|
293
302
|
|
|
294
|
-
消费洞察:这是你本周第
|
|
303
|
+
💡 消费洞察:这是你本周第23次餐饮消费,要不要看看本周餐饮花了多少钱?
|
|
295
304
|
-------------
|
|
296
|
-
chaimi-keep-mcp: v3.1.
|
|
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
|
-
| 未授权 |
|
|
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
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
|
-
//
|
|
970
|
+
// 【新增】获取 Agent 名称
|
|
971
|
+
const agentName = await getAgentName();
|
|
972
|
+
|
|
973
|
+
// 按 SKILL 规范格式:新的回复模板
|
|
971
974
|
const displayStoreText = displayStore ? `【${displayStore}】` : '';
|
|
972
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|