mobile-mcp-ai 2.7.5__tar.gz → 2.7.7__tar.gz

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.
Files changed (47) hide show
  1. {mobile_mcp_ai-2.7.5/mobile_mcp_ai.egg-info → mobile_mcp_ai-2.7.7}/PKG-INFO +1 -1
  2. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/basic_tools_lite.py +216 -35
  3. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mcp_tools/mcp_server.py +20 -1
  4. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7/mobile_mcp_ai.egg-info}/PKG-INFO +1 -1
  5. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/setup.py +1 -1
  6. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/LICENSE +0 -0
  7. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/MANIFEST.in +0 -0
  8. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/README.md +0 -0
  9. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/__init__.py +0 -0
  10. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/config.py +0 -0
  11. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/__init__.py +0 -0
  12. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/device_manager.py +0 -0
  13. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/dynamic_config.py +0 -0
  14. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/ios_client_wda.py +0 -0
  15. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/ios_device_manager_wda.py +0 -0
  16. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/mobile_client.py +0 -0
  17. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/template_matcher.py +0 -0
  18. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
  19. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
  20. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
  21. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
  22. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
  23. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
  24. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/utils/__init__.py +0 -0
  25. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/utils/logger.py +0 -0
  26. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/utils/operation_history_manager.py +0 -0
  27. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/core/utils/smart_wait.py +0 -0
  28. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/docs/iOS_SETUP_GUIDE.md +0 -0
  29. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mcp_tools/__init__.py +0 -0
  30. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/SOURCES.txt +0 -0
  31. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/dependency_links.txt +0 -0
  32. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/entry_points.txt +0 -0
  33. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/not-zip-safe +0 -0
  34. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/requires.txt +0 -0
  35. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/mobile_mcp_ai.egg-info/top_level.txt +0 -0
  36. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/requirements.txt +0 -0
  37. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/setup.cfg +0 -0
  38. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/auto_x_0112_151217.png +0 -0
  39. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/auto_x_0112_152037.png +0 -0
  40. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/auto_x_0112_152840.png +0 -0
  41. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/auto_x_0112_153256.png +0 -0
  42. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/auto_x_0112_154847.png +0 -0
  43. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/templates/close_buttons/gray_x_stock_ad.png +0 -0
  44. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/utils/__init__.py +0 -0
  45. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/utils/logger.py +0 -0
  46. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/utils/xml_formatter.py +0 -0
  47. {mobile_mcp_ai-2.7.5 → mobile_mcp_ai-2.7.7}/utils/xml_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.7.5
3
+ Version: 2.7.7
4
4
  Summary: 移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)
5
5
  Home-page: https://github.com/test111ddff-hash/mobile-mcp-ai
6
6
  Author: douzi
@@ -2687,6 +2687,11 @@ class BasicMobileToolsLite:
2687
2687
  # class 精简:只保留关键类型
2688
2688
  if class_name in ('EditText', 'TextInput', 'Button', 'ImageButton', 'CheckBox', 'Switch'):
2689
2689
  item['type'] = class_name
2690
+ # 重要:对于 ImageView 等图片类控件,即使没有其他属性,只要有 bounds 就应该返回
2691
+ # 因为 ImageView 可能是关闭按钮、图标等,对测试很重要
2692
+ if not item and bounds and class_name in ('ImageView', 'Image', 'ImageButton'):
2693
+ item['bounds'] = bounds
2694
+ item['type'] = class_name
2690
2695
  return item
2691
2696
 
2692
2697
  result = []
@@ -3185,6 +3190,10 @@ class BasicMobileToolsLite:
3185
3190
  center_x = (x1 + x2) // 2
3186
3191
  center_y = (y1 + y2) // 2
3187
3192
 
3193
+ # 计算相对位置(统一在循环开始计算,避免重复计算)
3194
+ rel_x = center_x / screen_width
3195
+ rel_y = center_y / screen_height
3196
+
3188
3197
  # 收集所有可点击元素(用于兜底策略:当只有一个可点击元素时点击它)
3189
3198
  if clickable:
3190
3199
  all_clickable_elements.append({
@@ -3215,6 +3224,22 @@ class BasicMobileToolsLite:
3215
3224
  in_popup = (px1 - margin_side <= center_x <= px2 + margin_side and
3216
3225
  py1 - margin_top <= center_y <= py2 + margin_bottom)
3217
3226
 
3227
+ # 【新增】兼容第三方广告页面:右上角的 ImageView 即使不在弹窗范围内,也可能是在弹窗上方的关闭按钮
3228
+ # 判断条件:ImageView 位于屏幕右上角(rel_x > 0.85, rel_y < 0.15)且尺寸合适
3229
+ is_top_right_imageview = (
3230
+ 'Image' in class_name and
3231
+ not clickable and
3232
+ rel_x > 0.85 and
3233
+ rel_y < 0.15 and
3234
+ 15 <= width <= 120 and
3235
+ 15 <= height <= 120
3236
+ )
3237
+
3238
+ # 如果是右上角 ImageView,即使不在弹窗范围内,也认为是关闭按钮候选
3239
+ if is_top_right_imageview:
3240
+ in_popup = True
3241
+ is_floating_close = True # 标记为浮动关闭按钮
3242
+
3218
3243
  # 检查是否是浮动关闭按钮(在弹窗外侧:上方或下方)
3219
3244
  # 上方浮动关闭按钮(常见:右上角外侧)
3220
3245
  if center_y < py1 and center_y > py1 - margin_top:
@@ -3241,8 +3266,14 @@ class BasicMobileToolsLite:
3241
3266
  # 浮动关闭按钮(在弹窗上方外侧)给予高额加分
3242
3267
  if is_floating_close:
3243
3268
  popup_edge_bonus += 5.0 # 大幅加分
3269
+ # 右上角 ImageView 额外加分(第三方广告页面常见)
3270
+ if is_top_right_imageview:
3271
+ popup_edge_bonus += 2.0 # 额外加分
3244
3272
  elif not popup_detected:
3245
- # 没有检测到弹窗时,只处理有明确关闭特征的元素
3273
+ # 没有检测到弹窗时,处理有明确关闭特征的元素
3274
+ # 同时,也考虑底部中央的 clickable 小元素(可能是关闭按钮)
3275
+ # 注意:右上角的 ImageView 只在有弹窗的情况下才识别,避免误识别正常页面的右上角图标
3276
+
3246
3277
  # 检查是否有明确的关闭特征(文本、resource-id、content-desc)
3247
3278
  has_explicit_close_feature = (
3248
3279
  text in close_texts or
@@ -3251,18 +3282,24 @@ class BasicMobileToolsLite:
3251
3282
  'dismiss' in resource_id.lower() or
3252
3283
  'cancel' in resource_id.lower()
3253
3284
  )
3254
- if not has_explicit_close_feature:
3255
- continue # 没有明确关闭特征,跳过
3256
- # 有明确关闭特征时,允许处理
3285
+
3286
+ # 【新增】底部中央的 clickable 小元素也可能是关闭按钮(常见于全屏广告、激励视频等)
3287
+ is_bottom_center_clickable = (
3288
+ clickable and
3289
+ rel_y > 0.75 and # 底部区域(屏幕下方 25%)
3290
+ 0.35 < rel_x < 0.65 and # 中央区域(屏幕中间 30%)
3291
+ width >= 20 and width <= 150 and # 合理尺寸
3292
+ height >= 20 and height <= 150
3293
+ )
3294
+
3295
+ if not has_explicit_close_feature and not is_bottom_center_clickable:
3296
+ continue # 没有明确关闭特征,且不是底部中央的 clickable 小元素,跳过
3297
+ # 有明确关闭特征或底部中央 clickable 小元素时,允许处理
3257
3298
  in_popup = True
3258
3299
 
3259
3300
  if not in_popup:
3260
3301
  continue
3261
3302
 
3262
- # 相对位置(0-1)
3263
- rel_x = center_x / screen_width
3264
- rel_y = center_y / screen_height
3265
-
3266
3303
  score = 0
3267
3304
  match_type = ""
3268
3305
  position = self._get_position_name(rel_x, rel_y)
@@ -3280,7 +3317,7 @@ class BasicMobileToolsLite:
3280
3317
  # ===== 策略3:clickable 的小尺寸元素(优先于非 clickable)=====
3281
3318
  elif clickable:
3282
3319
  min_size = max(20, int(screen_width * 0.03))
3283
- max_size = max(120, int(screen_width * 0.15))
3320
+ max_size = max(150, int(screen_width * 0.15)) # 扩大最大尺寸,兼容更大的关闭按钮
3284
3321
  if min_size <= width <= max_size and min_size <= height <= max_size:
3285
3322
  # clickable 元素基础分更高
3286
3323
  base_score = 8.0
@@ -3288,6 +3325,10 @@ class BasicMobileToolsLite:
3288
3325
  if is_floating_close:
3289
3326
  base_score = 12.0
3290
3327
  match_type = "floating_close"
3328
+ # 【新增】底部中央的 clickable 小元素(可能是关闭按钮,常见于全屏广告)
3329
+ elif rel_y > 0.75 and 0.35 < rel_x < 0.65:
3330
+ base_score = 10.0 # 给予较高分数
3331
+ match_type = "bottom_center_close"
3291
3332
  elif 'Image' in class_name:
3292
3333
  score = base_score + 2.0
3293
3334
  match_type = "clickable_image"
@@ -3296,12 +3337,19 @@ class BasicMobileToolsLite:
3296
3337
  score = base_score + self._get_position_score(rel_x, rel_y) + popup_edge_bonus
3297
3338
 
3298
3339
  # ===== 策略4:ImageView/ImageButton 类型的小元素(非 clickable)=====
3340
+ # 【增强】兼容第三方广告页面:右上角的 ImageView 即使 clickable="false" 也识别为关闭按钮
3299
3341
  elif 'Image' in class_name:
3300
3342
  min_size = max(15, int(screen_width * 0.02))
3301
3343
  max_size = max(120, int(screen_width * 0.12))
3302
3344
  if min_size <= width <= max_size and min_size <= height <= max_size:
3303
- score = 5.0 + self._get_position_score(rel_x, rel_y) + popup_edge_bonus
3304
- match_type = "ImageView"
3345
+ base_score = 5.0
3346
+ # 右上角的 ImageView 给予更高分数(第三方广告页面常见)
3347
+ if rel_x > 0.85 and rel_y < 0.15:
3348
+ base_score = 8.0 # 提高分数,优先识别
3349
+ match_type = "ImageView_top_right"
3350
+ else:
3351
+ match_type = "ImageView"
3352
+ score = base_score + self._get_position_score(rel_x, rel_y) + popup_edge_bonus
3305
3353
 
3306
3354
  # XML 顺序加分(后出现的元素在上层,更可能是弹窗内的元素)
3307
3355
  if score > 0:
@@ -3553,8 +3601,69 @@ class BasicMobileToolsLite:
3553
3601
  has_mask_layer = True
3554
3602
  mask_idx = elem['idx']
3555
3603
 
3556
- # 跳过全屏元素
3557
- if area_ratio > 0.9:
3604
+ # 先检查是否有强弹窗特征(用于后续判断)
3605
+ has_strong_popup_feature = (
3606
+ any(kw in class_name for kw in dialog_class_keywords) or
3607
+ any(kw in resource_id.lower() for kw in dialog_id_keywords) or
3608
+ any(kw in resource_id.lower() for kw in ad_popup_keywords) # 广告弹窗关键词
3609
+ )
3610
+
3611
+ # 检查是否有子元素是关闭按钮(作为弹窗特征)
3612
+ has_close_button_child = False
3613
+ elem_bounds = elem['bounds']
3614
+ for other_elem in all_elements:
3615
+ if other_elem['idx'] == elem['idx']:
3616
+ continue
3617
+ if other_elem['is_close_button']:
3618
+ # 检查关闭按钮是否在这个元素范围内
3619
+ ox1, oy1, ox2, oy2 = other_elem['bounds']
3620
+ ex1, ey1, ex2, ey2 = elem_bounds
3621
+ if ex1 <= ox1 and ey1 <= oy1 and ex2 >= ox2 and ey2 >= oy2:
3622
+ has_close_button_child = True
3623
+ break
3624
+
3625
+ # 检查是否有右上角的 ImageView 关闭按钮(全屏广告页常见)
3626
+ has_top_right_close = False
3627
+ if area_ratio > 0.9: # 全屏元素才检查
3628
+ for other_elem in all_elements:
3629
+ if other_elem['idx'] == elem['idx']:
3630
+ continue
3631
+ # 检查是否是右上角的 ImageView
3632
+ ox1, oy1, ox2, oy2 = other_elem['bounds']
3633
+ o_center_x = other_elem['center_x']
3634
+ o_center_y = other_elem['center_y']
3635
+ o_width = other_elem['width']
3636
+ o_height = other_elem['height']
3637
+ o_class = other_elem['class']
3638
+
3639
+ rel_x = o_center_x / screen_width
3640
+ rel_y = o_center_y / screen_height
3641
+
3642
+ # 右上角的 ImageView(即使 clickable="false")
3643
+ if ('Image' in o_class and
3644
+ rel_x > 0.85 and rel_y < 0.15 and
3645
+ 15 <= o_width <= 120 and 15 <= o_height <= 120):
3646
+ # 检查是否在当前元素范围内或附近
3647
+ if (ex1 <= ox1 and ey1 <= oy1 and ex2 >= ox2 and ey2 >= oy2) or \
3648
+ (abs(ex2 - ox1) < 50 and abs(ey1 - oy2) < 50): # 在元素右上角附近
3649
+ has_top_right_close = True
3650
+ break
3651
+
3652
+ # 【特殊处理】全屏广告页:如果面积 > 90% 但有关闭按钮或广告特征,也识别为弹窗
3653
+ is_fullscreen_ad = (
3654
+ area_ratio > 0.9 and
3655
+ (
3656
+ # 有关闭按钮作为子元素
3657
+ has_close_button_child or
3658
+ # 有右上角的 ImageView 关闭按钮
3659
+ has_top_right_close or
3660
+ # 有广告相关的强特征
3661
+ any(kw in resource_id.lower() for kw in ad_popup_keywords)
3662
+ )
3663
+ )
3664
+
3665
+ # 如果不是全屏广告页,跳过全屏元素
3666
+ if area_ratio > 0.9 and not is_fullscreen_ad:
3558
3667
  continue
3559
3668
 
3560
3669
  # 跳过太小的元素
@@ -3577,27 +3686,6 @@ class BasicMobileToolsLite:
3577
3686
  if 'search' in resource_id.lower() or 'Search' in class_name:
3578
3687
  continue # 跳过顶部搜索栏
3579
3688
 
3580
- # 先检查是否有强弹窗特征(用于后续判断)
3581
- has_strong_popup_feature = (
3582
- any(kw in class_name for kw in dialog_class_keywords) or
3583
- any(kw in resource_id.lower() for kw in dialog_id_keywords) or
3584
- any(kw in resource_id.lower() for kw in ad_popup_keywords) # 广告弹窗关键词
3585
- )
3586
-
3587
- # 检查是否有子元素是关闭按钮(作为弹窗特征)
3588
- has_close_button_child = False
3589
- elem_bounds = elem['bounds']
3590
- for other_elem in all_elements:
3591
- if other_elem['idx'] == elem['idx']:
3592
- continue
3593
- if other_elem['is_close_button']:
3594
- # 检查关闭按钮是否在这个元素范围内
3595
- ox1, oy1, ox2, oy2 = other_elem['bounds']
3596
- ex1, ey1, ex2, ey2 = elem_bounds
3597
- if ex1 <= ox1 and ey1 <= oy1 and ex2 >= ox2 and ey2 >= oy2:
3598
- has_close_button_child = True
3599
- break
3600
-
3601
3689
  # 【非弹窗特征】如果元素包含明显的页面内容特征,则不是弹窗
3602
3690
  # 检查是否包含视频播放器、内容列表等页面元素
3603
3691
  page_content_keywords = ['video', 'player', 'recycler', 'list', 'scroll', 'viewpager', 'fragment']
@@ -3636,6 +3724,10 @@ class BasicMobileToolsLite:
3636
3724
  if has_close_button_child:
3637
3725
  confidence += 0.3
3638
3726
 
3727
+ # 【强特征】全屏广告页且有右上角关闭按钮 (+0.4)
3728
+ if is_fullscreen_ad and has_top_right_close:
3729
+ confidence += 0.4
3730
+
3639
3731
  # 【中等特征】居中显示 (+0.2)
3640
3732
  # 但如果没有强特征,降低权重
3641
3733
  center_x = elem['center_x']
@@ -3647,7 +3739,8 @@ class BasicMobileToolsLite:
3647
3739
  any(kw in class_name for kw in dialog_class_keywords) or
3648
3740
  any(kw in resource_id.lower() for kw in dialog_id_keywords) or
3649
3741
  any(kw in resource_id.lower() for kw in ad_popup_keywords) or
3650
- has_close_button_child
3742
+ has_close_button_child or
3743
+ (is_fullscreen_ad and has_top_right_close) # 全屏广告页且有右上角关闭按钮
3651
3744
  )
3652
3745
 
3653
3746
  if is_centered_x and is_centered_y:
@@ -4843,4 +4936,92 @@ class BasicMobileToolsLite:
4843
4936
  return {"success": False, "error": f"需要安装依赖: {e}"}
4844
4937
  except Exception as e:
4845
4938
  return {"success": False, "error": f"添加模板失败: {e}"}
4939
+
4940
+ def open_new_chat(self, message: str = "继续执行飞书用例") -> Dict:
4941
+ """打开 Cursor 新会话并发送消息
4942
+
4943
+ 用于飞书用例批量执行时,自动分批继续。
4944
+
4945
+ Args:
4946
+ message: 发送到新会话的消息,默认"继续执行飞书用例"
4947
+
4948
+ Returns:
4949
+ 执行结果
4950
+
4951
+ 依赖:
4952
+ pip install pyautogui pyperclip pygetwindow (macOS/Windows)
4953
+ """
4954
+ import sys
4955
+ import platform
4956
+
4957
+ try:
4958
+ import pyautogui
4959
+ import pyperclip
4960
+ except ImportError:
4961
+ return {
4962
+ "success": False,
4963
+ "error": "缺少依赖,请执行: pip install pyautogui pyperclip pygetwindow"
4964
+ }
4965
+
4966
+ try:
4967
+ system = platform.system()
4968
+
4969
+ # 1. 激活 Cursor 窗口
4970
+ if system == "Darwin": # macOS
4971
+ import subprocess
4972
+ # 使用 osascript 激活 Cursor
4973
+ script = '''
4974
+ tell application "Cursor"
4975
+ activate
4976
+ end tell
4977
+ '''
4978
+ subprocess.run(["osascript", "-e", script], check=True)
4979
+ time.sleep(0.3)
4980
+
4981
+ # 2. 快捷键打开新会话 (Cmd+T)
4982
+ pyautogui.hotkey('command', 't')
4983
+
4984
+ elif system == "Windows":
4985
+ try:
4986
+ import pygetwindow as gw
4987
+ cursor_windows = gw.getWindowsWithTitle('Cursor')
4988
+ if cursor_windows:
4989
+ cursor_windows[0].activate()
4990
+ time.sleep(0.3)
4991
+ except:
4992
+ pass # 如果激活失败,继续尝试发送快捷键
4993
+
4994
+ # 2. 快捷键打开新会话 (Ctrl+T)
4995
+ pyautogui.hotkey('ctrl', 't')
4996
+
4997
+ else: # Linux
4998
+ # 2. 快捷键打开新会话 (Ctrl+T)
4999
+ pyautogui.hotkey('ctrl', 't')
5000
+
5001
+ time.sleep(0.5) # 等待新会话打开
5002
+
5003
+ # 3. 复制消息到剪贴板并粘贴
5004
+ pyperclip.copy(message)
5005
+ time.sleep(0.1)
5006
+
5007
+ if system == "Darwin":
5008
+ pyautogui.hotkey('command', 'v')
5009
+ else:
5010
+ pyautogui.hotkey('ctrl', 'v')
5011
+
5012
+ time.sleep(0.2)
5013
+
5014
+ # 4. 按 Enter 发送
5015
+ pyautogui.press('enter')
5016
+
5017
+ return {
5018
+ "success": True,
5019
+ "message": f"✅ 已打开新会话并发送: {message}"
5020
+ }
5021
+
5022
+ except Exception as e:
5023
+ return {
5024
+ "success": False,
5025
+ "error": f"打开新会话失败: {e}"
5026
+ }
4846
5027
 
@@ -867,6 +867,19 @@ class MobileMCPServer:
867
867
  }
868
868
  ))
869
869
 
870
+ # ==================== Cursor 会话管理 ====================
871
+ tools.append(Tool(
872
+ name="mobile_open_new_chat",
873
+ description="🆕 打开Cursor新会话。用于飞书用例批量执行时自动分批继续。",
874
+ inputSchema={
875
+ "type": "object",
876
+ "properties": {
877
+ "message": {"type": "string", "description": "发送到新会话的消息", "default": "继续执行飞书用例"}
878
+ },
879
+ "required": []
880
+ }
881
+ ))
882
+
870
883
  return tools
871
884
 
872
885
  async def handle_tool_call(self, name: str, arguments: dict):
@@ -1152,6 +1165,12 @@ class MobileMCPServer:
1152
1165
  result = {"success": False, "error": "请提供 x_percent/y_percent 或 screenshot_path/x/y/width/height"}
1153
1166
  return [TextContent(type="text", text=self.format_response(result))]
1154
1167
 
1168
+ # Cursor 会话管理
1169
+ elif name == "mobile_open_new_chat":
1170
+ message = arguments.get("message", "继续执行飞书用例")
1171
+ result = self.tools.open_new_chat(message)
1172
+ return [TextContent(type="text", text=self.format_response(result))]
1173
+
1155
1174
  else:
1156
1175
  return [TextContent(type="text", text=f"❌ 未知工具: {name}")]
1157
1176
 
@@ -1174,7 +1193,7 @@ async def async_main():
1174
1193
  async def call_tool(name: str, arguments: dict):
1175
1194
  return await server.handle_tool_call(name, arguments)
1176
1195
 
1177
- print("🚀 Mobile MCP Server 启动中... [26 个工具]", file=sys.stderr)
1196
+ print("🚀 Mobile MCP Server 启动中... [27 个工具]", file=sys.stderr)
1178
1197
  print("📱 支持 Android / iOS", file=sys.stderr)
1179
1198
  print("👁️ 完全依赖 Cursor 视觉能力,无需 AI 密钥", file=sys.stderr)
1180
1199
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.7.5
3
+ Version: 2.7.7
4
4
  Summary: 移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)
5
5
  Home-page: https://github.com/test111ddff-hash/mobile-mcp-ai
6
6
  Author: douzi
@@ -25,7 +25,7 @@ if requirements_file.exists():
25
25
 
26
26
  setup(
27
27
  name="mobile-mcp-ai",
28
- version="2.7.5", # 优化弹窗关闭逻辑:添加特殊弹窗兜底策略
28
+ version="2.7.7", # 更新飞书用例执行规则:支持边执行边验证,步骤与预期结果一一对应
29
29
  author="douzi",
30
30
  author_email="1492994674@qq.com",
31
31
  description="移动端自动化 MCP Server - 支持 Android/iOS,AI 功能可选(基础工具不需要 AI)",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes