chaimi-keep-mcp 3.3.2-beta.1 → 3.3.3-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/bin/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * 柴米记账 MCP Server CLI 入口
4
+ * 柴米AI记账 MCP Server CLI 入口
5
5
  * 智能创建/更新多个 Agent 配置,保护用户已有配置
6
6
  */
7
7
 
@@ -20,7 +20,7 @@ const serverPath = path.join(__dirname, '..', 'server.js');
20
20
  // 默认的柴米记账配置
21
21
  const DEFAULT_CHAIMI_CONFIG = {
22
22
  command: 'chaimi-keep-mcp',
23
- description: '柴米记账 MCP Server - 支持 AI 工具直接记账',
23
+ description: '柴米AI记账 MCP Server - 支持 AI 工具直接记账',
24
24
  env: {
25
25
  MCP_OAUTH_URL: 'https://cloud1-2gfe5jhjef06b85d-1412172089.ap-shanghai.app.tcloudbase.com/mcpOAuth',
26
26
  MCP_HUB_URL: 'https://cloud1-2gfe5jhjef06b85d-1412172089.ap-shanghai.app.tcloudbase.com/mcpHub-mcp',
@@ -38,6 +38,18 @@ const SUPPORTED_AGENTS = [
38
38
  configPath: path.join(os.homedir(), '.mcporter', 'mcporter.json'),
39
39
  format: 'json'
40
40
  },
41
+ {
42
+ name: 'OpenClaw MCP Config',
43
+ configPath: path.join(os.homedir(), '.openclaw', 'workspace', 'config', 'mcporter.json'),
44
+ format: 'json',
45
+ platform: 'darwin'
46
+ },
47
+ {
48
+ name: 'OpenClaw MCP Config (Linux)',
49
+ configPath: path.join(os.homedir(), '.openclaw', 'workspace', 'config', 'mcporter.json'),
50
+ format: 'json',
51
+ platform: 'linux'
52
+ },
41
53
  {
42
54
  name: 'WorkBuddy (Windows)',
43
55
  configPath: path.join(os.homedir(), 'workbuddy', 'mcp.json'),
@@ -297,7 +309,7 @@ function showWelcome() {
297
309
 
298
310
  console.error('+--------------------------------------------------------+');
299
311
  console.error('| |');
300
- console.error('| 柴米记账 MCP Server v' + ver + ' |');
312
+ console.error('| 柴米AI记账 MCP Server v' + ver + ' |');
301
313
  console.error('| |');
302
314
  console.error('| 支持: OpenClaw/hermes/WorkBuddy 等国产小龙虾 |');
303
315
  console.error('| Claude/Cursor 等支持 MCP 的 Agent |');
@@ -1,4 +1,4 @@
1
- # 柴米记账 MCP Server 配置文件示例
1
+ # 柴米AI记账 MCP Server 配置文件示例
2
2
  # 复制此文件为 config.yaml 并填入您的实际配置
3
3
 
4
4
  chaihuo:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "chaimi-keep-mcp",
3
- "version": "3.3.2-beta.1",
4
- "description": "柴米记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
3
+ "version": "3.3.3-beta.1",
4
+ "description": "柴米AI记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
5
5
  "main": "server.js",
6
6
  "bin": {
7
7
  "chaimi-keep-mcp": "bin/cli.js"
@@ -44,6 +44,7 @@
44
44
  "license": "MIT",
45
45
  "dependencies": {
46
46
  "@modelcontextprotocol/sdk": "^1.0.0",
47
+ "chaimi-keep-mcp": "^3.3.2-beta.1",
47
48
  "dotenv": "^17.3.1",
48
49
  "node-fetch": "^2.7.0"
49
50
  },
package/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * 柴米记账 MCP Server (Node.js 版本)
3
+ * 柴米AI记账 MCP Server (Node.js 版本)
4
4
  * 适配微信云函数 mcpHub
5
5
  * 支持 Claude Desktop、Cursor、WorkBuddy、OpenClaw
6
6
  */
@@ -280,7 +280,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
280
280
  type: 'object',
281
281
  properties: {
282
282
  store: { type: 'string', description: '商家名称(必填)' },
283
- date: { type: 'number', description: '【必填】消费时间(毫秒级时间戳,13位数字。必须根据实际年月日时分秒计算,不允许复制示例数字)' },
283
+ date: { type: 'number', description: '消费时间(毫秒级时间戳,13位数字。如提供 date_components 可不传此字段)' },
284
+ date_components: {
285
+ type: 'object',
286
+ description: '【推荐】消费时间组件。包含:year、month、day、hour、minute、second。服务端会自动转换为时间戳'
287
+ },
284
288
  totalAmount: { type: 'number', description: '(必填)总金额(所有商品amount之和)' },
285
289
  originalAmount: { type: 'number', description: '(必填)应付金额(优惠前)' },
286
290
  discountAmount: { type: 'number', description: '(必填)优惠金额' },
@@ -1147,6 +1151,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1147
1151
  break;
1148
1152
  }
1149
1153
 
1154
+ // 【新增】转换 date_components 为 date
1155
+ if (processedArgs.date_components && !processedArgs.date) {
1156
+ const { year, month, day, hour, minute, second } = processedArgs.date_components;
1157
+
1158
+ // 校验时间组件完整性
1159
+ if (!year || !month || !day || hour === undefined || minute === undefined) {
1160
+ result = {
1161
+ success: false,
1162
+ error: 'date_components 不完整',
1163
+ code: 400,
1164
+ hint: '必须包含:year、month、day、hour、minute'
1165
+ };
1166
+ userMessage = '❌ 保存失败:时间信息不完整\n\n请确保 date_components 包含完整的年月日时分秒';
1167
+ break;
1168
+ }
1169
+
1170
+ // 转换为时间戳
1171
+ processedArgs.date = new Date(year, month - 1, day, hour, minute, second || 0).getTime();
1172
+ console.log(`[save_receipt] 时间组件转换: ${JSON.stringify(processedArgs.date_components)} → ${processedArgs.date}`);
1173
+ }
1174
+
1150
1175
  // P1: 日期合理性检查
1151
1176
  if (processedArgs.date) {
1152
1177
  const validation = validateDate(processedArgs.date, '小票日期');
@@ -44,6 +44,72 @@ function validateDate(dateInput, fieldName = '日期') {
44
44
  return { valid: true };
45
45
  }
46
46
 
47
+ /**
48
+ * 校验时间组件合理性
49
+ * @param {Object} components - 时间组件对象
50
+ * @param {string} fieldName - 字段名称(用于错误提示)
51
+ * @returns {Object} { valid: boolean, error?: string, message?: string }
52
+ */
53
+ function validateDateComponents(components, fieldName = '时间') {
54
+ if (!components || typeof components !== 'object') {
55
+ return {
56
+ valid: false,
57
+ error: '时间组件格式无效',
58
+ message: `❌ ${fieldName}组件必须是对象`
59
+ };
60
+ }
61
+
62
+ const { year, month, day, hour, minute, second } = components;
63
+
64
+ // 校验必填字段
65
+ const requiredFields = ['year', 'month', 'day', 'hour', 'minute'];
66
+ const missingFields = requiredFields.filter(f => components[f] === undefined || components[f] === null);
67
+
68
+ if (missingFields.length > 0) {
69
+ return {
70
+ valid: false,
71
+ error: '时间组件缺少必填字段',
72
+ message: `❌ ${fieldName}组件缺少: ${missingFields.join(', ')}`
73
+ };
74
+ }
75
+
76
+ // 校验数值范围
77
+ if (year < 1965 || year > 2100) {
78
+ return { valid: false, error: '年份不合法', message: `❌ ${fieldName}年份必须在 1965-2100 之间` };
79
+ }
80
+ if (month < 1 || month > 12) {
81
+ return { valid: false, error: '月份不合法', message: `❌ ${fieldName}月份必须在 1-12 之间` };
82
+ }
83
+ if (day < 1 || day > 31) {
84
+ return { valid: false, error: '日期不合法', message: `❌ ${fieldName}日期必须在 1-31 之间` };
85
+ }
86
+ if (hour < 0 || hour > 23) {
87
+ return { valid: false, error: '小时不合法', message: `❌ ${fieldName}小时必须在 0-23 之间` };
88
+ }
89
+ if (minute < 0 || minute > 59) {
90
+ return { valid: false, error: '分钟不合法', message: `❌ ${fieldName}分钟必须在 0-59 之间` };
91
+ }
92
+ if (second !== undefined && (second < 0 || second > 59)) {
93
+ return { valid: false, error: '秒数不合法', message: `❌ ${fieldName}秒数必须在 0-59 之间` };
94
+ }
95
+
96
+ // 校验日期有效性(如 2025-02-30 是无效日期)
97
+ const testDate = new Date(year, month - 1, day);
98
+ if (testDate.getMonth() !== month - 1 || testDate.getDate() !== day) {
99
+ return { valid: false, error: '日期不存在', message: `❌ ${fieldName}日期不存在(如 2月30日)` };
100
+ }
101
+
102
+ // 校验不能是未来时间
103
+ const inputDate = new Date(year, month - 1, day, hour, minute, second || 0);
104
+ const now = new Date();
105
+ if (inputDate > now) {
106
+ return { valid: false, error: '不能是未来时间', message: `❌ ${fieldName}不能是未来时间` };
107
+ }
108
+
109
+ return { valid: true };
110
+ }
111
+
47
112
  module.exports = {
48
- validateDate
113
+ validateDate,
114
+ validateDateComponents
49
115
  };