chaimi-keep-mcp 3.2.1-beta.4 → 3.2.1-beta.5

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,12 @@ AI 会自动调用 `save_income` 工具记录收入。
148
148
 
149
149
  ## 更新日志
150
150
 
151
+ ### v3.2.1-beta.5 (2026-04-26)
152
+ - **修复** 复用授权时 token 获取失败问题
153
+ - 云函数 `getDeviceToken` 支持 userCode 查询作为备选
154
+ - MCP Server 轮询时同时传入 userCode 和 deviceCode
155
+ - 彻底解决 deviceCode 不匹配导致的授权失败
156
+
151
157
  ### v3.2.1-beta.4 (2026-04-26)
152
158
  - **修复** deviceCode 保存不一致问题
153
159
  - 小程序端使用授权返回的实际 deviceCode,解决复用授权时 deviceCode 不匹配
package/oauth.js CHANGED
@@ -64,8 +64,10 @@ class OAuthManager {
64
64
  console.error('⏳ 等待用户授权,请勿关闭窗口...');
65
65
  console.error(' (请在手机微信中完成授权操作)');
66
66
  console.error('');
67
+ // 【新增】同时传入 userCode,用于复用授权场景
67
68
  const token = await this.pollForToken(
68
69
  deviceCodeRes.deviceCode,
70
+ deviceCodeRes.userCode,
69
71
  deviceCodeRes.interval * 1000 || 5000
70
72
  );
71
73
 
@@ -172,8 +174,14 @@ class OAuthManager {
172
174
  }
173
175
 
174
176
  // 单次轮询(用于后台轮询)
175
- async pollForTokenOnce(deviceCode) {
177
+ async pollForTokenOnce(deviceCode, userCode) {
176
178
  try {
179
+ const params = { deviceCode };
180
+ // 【新增】如果有 userCode,一并传入(用于复用授权场景)
181
+ if (userCode) {
182
+ params.userCode = userCode;
183
+ }
184
+
177
185
  const response = await fetch(this.mcpOAuthUrl, {
178
186
  method: 'POST',
179
187
  headers: {
@@ -181,9 +189,7 @@ class OAuthManager {
181
189
  },
182
190
  body: JSON.stringify({
183
191
  tool: 'deviceToken',
184
- params: {
185
- deviceCode
186
- }
192
+ params
187
193
  })
188
194
  });
189
195
 
@@ -217,17 +223,17 @@ class OAuthManager {
217
223
  }
218
224
  }
219
225
 
220
- async pollForToken(deviceCode, interval) {
226
+ async pollForToken(deviceCode, userCode, interval) {
221
227
  const maxAttempts = 60;
222
228
  let attempts = 0;
223
229
 
224
230
  while (attempts < maxAttempts) {
225
231
  attempts++;
226
-
227
232
  await this.delay(interval);
228
233
 
229
234
  try {
230
- const token = await this.pollForTokenOnce(deviceCode);
235
+ // 【新增】传入 userCode,用于复用授权场景
236
+ const token = await this.pollForTokenOnce(deviceCode, userCode);
231
237
  if (token) {
232
238
  return token;
233
239
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaimi-keep-mcp",
3
- "version": "3.2.1-beta.4",
3
+ "version": "3.2.1-beta.5",
4
4
  "description": "柴米记账 MCP Server - 支持 Claude、Cursor、OpenClaw、WorkBuddy 等 AI 工具直接记账",
5
5
  "main": "server.js",
6
6
  "bin": {
package/server.js CHANGED
@@ -482,7 +482,8 @@ async function getToken() {
482
482
  } else {
483
483
  // 验证码未过期,尝试直接获取token(用户可能已授权)
484
484
  try {
485
- const token = await oauthManager.pollForTokenOnce(savedAuthState.deviceCode);
485
+ // 【新增】同时传入 userCode,用于复用授权场景
486
+ const token = await oauthManager.pollForTokenOnce(savedAuthState.deviceCode, savedAuthState.userCode);
486
487
  if (token) {
487
488
  // 授权成功
488
489
  cachedToken = token.accessToken;
@@ -2110,7 +2111,8 @@ async function startAuthFlow() {
2110
2111
  authState.isWaiting = true;
2111
2112
  console.error(`🔑 使用已保存的验证码:${savedAuthState.userCode}`);
2112
2113
  // 启动后台轮询
2113
- pollForAuthInBackground(savedAuthState.deviceCode, 5000);
2114
+ // 【新增】同时传入 userCode,用于复用授权场景
2115
+ pollForAuthInBackground(savedAuthState.deviceCode, savedAuthState.userCode, 5000);
2114
2116
  return;
2115
2117
  }
2116
2118
  }
@@ -2152,7 +2154,8 @@ async function startAuthFlow() {
2152
2154
  console.error('⏳ 请在小程序中完成授权,然后再次调用');
2153
2155
 
2154
2156
  // 启动后台轮询(3分钟)
2155
- pollForAuthInBackground(deviceCodeRes.deviceCode, 5000);
2157
+ // 【新增】同时传入 userCode,用于复用授权场景
2158
+ pollForAuthInBackground(deviceCodeRes.deviceCode, deviceCodeRes.userCode, 5000);
2156
2159
 
2157
2160
  } catch (err) {
2158
2161
  authState.error = err.message;
@@ -2162,7 +2165,7 @@ async function startAuthFlow() {
2162
2165
  }
2163
2166
 
2164
2167
  // 后台轮询授权状态(3分钟)
2165
- async function pollForAuthInBackground(deviceCode, interval) {
2168
+ async function pollForAuthInBackground(deviceCode, userCode, interval) {
2166
2169
  const maxAttempts = 36; // 3分钟(36次 × 5秒)
2167
2170
  let attempts = 0;
2168
2171
 
@@ -2174,7 +2177,8 @@ async function pollForAuthInBackground(deviceCode, interval) {
2174
2177
 
2175
2178
  try {
2176
2179
  // 调用云函数检查授权状态
2177
- const token = await oauthManager.pollForTokenOnce(deviceCode);
2180
+ // 【新增】同时传入 userCode,用于复用授权场景
2181
+ const token = await oauthManager.pollForTokenOnce(deviceCode, userCode);
2178
2182
 
2179
2183
  if (token) {
2180
2184
  // 授权成功