mobile-mcp-ai 2.6.6__tar.gz → 2.6.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.6.6/mobile_mcp_ai.egg-info → mobile_mcp_ai-2.6.7}/PKG-INFO +1 -1
  2. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/basic_tools_lite.py +130 -6
  3. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mcp_tools/mcp_server.py +12 -3
  4. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7/mobile_mcp_ai.egg-info}/PKG-INFO +1 -1
  5. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/SOURCES.txt +21 -1
  6. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/setup.py +1 -1
  7. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/LICENSE +0 -0
  8. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/MANIFEST.in +0 -0
  9. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/README.md +0 -0
  10. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/__init__.py +0 -0
  11. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/config.py +0 -0
  12. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/__init__.py +0 -0
  13. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/device_manager.py +0 -0
  14. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/dynamic_config.py +0 -0
  15. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/ios_client_wda.py +0 -0
  16. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/ios_device_manager_wda.py +0 -0
  17. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/mobile_client.py +0 -0
  18. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/template_matcher.py +0 -0
  19. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
  20. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
  21. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
  22. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
  23. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
  24. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
  25. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/utils/__init__.py +0 -0
  26. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/utils/logger.py +0 -0
  27. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/utils/operation_history_manager.py +0 -0
  28. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/core/utils/smart_wait.py +0 -0
  29. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/docs/iOS_SETUP_GUIDE.md +0 -0
  30. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mcp_tools/__init__.py +0 -0
  31. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/dependency_links.txt +0 -0
  32. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/entry_points.txt +0 -0
  33. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/not-zip-safe +0 -0
  34. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/requires.txt +0 -0
  35. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/mobile_mcp_ai.egg-info/top_level.txt +0 -0
  36. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/requirements.txt +0 -0
  37. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/setup.cfg +0 -0
  38. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/auto_x_0112_151217.png +0 -0
  39. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/auto_x_0112_152037.png +0 -0
  40. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/auto_x_0112_152840.png +0 -0
  41. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/auto_x_0112_153256.png +0 -0
  42. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/auto_x_0112_154847.png +0 -0
  43. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/templates/close_buttons/gray_x_stock_ad.png +0 -0
  44. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/utils/__init__.py +0 -0
  45. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/utils/logger.py +0 -0
  46. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.7}/utils/xml_formatter.py +0 -0
  47. {mobile_mcp_ai-2.6.6 → mobile_mcp_ai-2.6.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.6.6
3
+ Version: 2.6.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
@@ -2731,6 +2731,9 @@ class BasicMobileToolsLite:
2731
2731
  # 如果置信度不够高,记录但继续尝试查找关闭按钮
2732
2732
  popup_detected = popup_bounds is not None and popup_confidence >= 0.6
2733
2733
 
2734
+ # 【重要修复】如果没有检测到弹窗区域,只搜索有明确关闭特征的元素(文本、resource-id等)
2735
+ # 避免误点击普通页面的右上角图标
2736
+
2734
2737
  # ===== 第二步:在弹窗范围内查找关闭按钮 =====
2735
2738
  for idx, elem in enumerate(all_elements):
2736
2739
  text = elem.attrib.get('text', '')
@@ -2738,6 +2741,7 @@ class BasicMobileToolsLite:
2738
2741
  bounds_str = elem.attrib.get('bounds', '')
2739
2742
  class_name = elem.attrib.get('class', '')
2740
2743
  clickable = elem.attrib.get('clickable', 'false') == 'true'
2744
+ resource_id = elem.attrib.get('resource-id', '')
2741
2745
 
2742
2746
  if not bounds_str:
2743
2747
  continue
@@ -2754,7 +2758,7 @@ class BasicMobileToolsLite:
2754
2758
  center_y = (y1 + y2) // 2
2755
2759
 
2756
2760
  # 如果检测到弹窗区域,检查元素是否在弹窗范围内或附近
2757
- in_popup = True
2761
+ in_popup = False
2758
2762
  popup_edge_bonus = 0
2759
2763
  is_floating_close = False # 是否是浮动关闭按钮(在弹窗外部上方)
2760
2764
  if popup_bounds:
@@ -2795,6 +2799,20 @@ class BasicMobileToolsLite:
2795
2799
  # 浮动关闭按钮(在弹窗上方外侧)给予高额加分
2796
2800
  if is_floating_close:
2797
2801
  popup_edge_bonus += 5.0 # 大幅加分
2802
+ elif not popup_detected:
2803
+ # 没有检测到弹窗时,只处理有明确关闭特征的元素
2804
+ # 检查是否有明确的关闭特征(文本、resource-id、content-desc)
2805
+ has_explicit_close_feature = (
2806
+ text in close_texts or
2807
+ any(kw in content_desc.lower() for kw in close_desc_keywords) or
2808
+ 'close' in resource_id.lower() or
2809
+ 'dismiss' in resource_id.lower() or
2810
+ 'cancel' in resource_id.lower()
2811
+ )
2812
+ if not has_explicit_close_feature:
2813
+ continue # 没有明确关闭特征,跳过
2814
+ # 有明确关闭特征时,允许处理
2815
+ in_popup = True
2798
2816
 
2799
2817
  if not in_popup:
2800
2818
  continue
@@ -3102,6 +3120,15 @@ class BasicMobileToolsLite:
3102
3120
  resource_id = elem.attrib.get('resource-id', '')
3103
3121
  clickable = elem.attrib.get('clickable', 'false') == 'true'
3104
3122
 
3123
+ # 检查是否是关闭按钮
3124
+ is_close_button = (
3125
+ 'close' in resource_id.lower() or
3126
+ 'dismiss' in resource_id.lower() or
3127
+ 'cancel' in resource_id.lower() or
3128
+ '×' in elem.attrib.get('text', '') or
3129
+ 'X' in elem.attrib.get('text', '')
3130
+ )
3131
+
3105
3132
  all_elements.append({
3106
3133
  'idx': idx,
3107
3134
  'bounds': (x1, y1, x2, y2),
@@ -3114,6 +3141,7 @@ class BasicMobileToolsLite:
3114
3141
  'clickable': clickable,
3115
3142
  'center_x': (x1 + x2) // 2,
3116
3143
  'center_y': (y1 + y2) // 2,
3144
+ 'is_close_button': is_close_button,
3117
3145
  })
3118
3146
 
3119
3147
  if not all_elements:
@@ -3122,6 +3150,8 @@ class BasicMobileToolsLite:
3122
3150
  # 弹窗检测关键词
3123
3151
  dialog_class_keywords = ['Dialog', 'Popup', 'Alert', 'Modal', 'BottomSheet', 'PopupWindow']
3124
3152
  dialog_id_keywords = ['dialog', 'popup', 'alert', 'modal', 'bottom_sheet', 'overlay', 'mask']
3153
+ # 广告弹窗关键词(全屏广告、激励视频等)
3154
+ ad_popup_keywords = ['ad_close', 'ad_button', 'full_screen', 'interstitial', 'reward', 'close_icon', 'close_btn']
3125
3155
 
3126
3156
  popup_candidates = []
3127
3157
  has_mask_layer = False
@@ -3152,6 +3182,59 @@ class BasicMobileToolsLite:
3152
3182
  if y1 < 50:
3153
3183
  continue
3154
3184
 
3185
+ # 【非弹窗特征】如果元素包含底部导航栏(底部tab),则不是弹窗
3186
+ # 底部导航栏通常在屏幕底部,高度约100-200像素
3187
+ if y2 > screen_height * 0.85:
3188
+ # 检查是否包含tab相关的resource-id或class
3189
+ if 'tab' in resource_id.lower() or 'Tab' in class_name or 'navigation' in resource_id.lower():
3190
+ continue # 跳过底部导航栏
3191
+
3192
+ # 【非弹窗特征】如果元素包含顶部搜索栏,则不是弹窗
3193
+ if y1 < screen_height * 0.15:
3194
+ if 'search' in resource_id.lower() or 'Search' in class_name:
3195
+ continue # 跳过顶部搜索栏
3196
+
3197
+ # 先检查是否有强弹窗特征(用于后续判断)
3198
+ has_strong_popup_feature = (
3199
+ any(kw in class_name for kw in dialog_class_keywords) or
3200
+ any(kw in resource_id.lower() for kw in dialog_id_keywords) or
3201
+ any(kw in resource_id.lower() for kw in ad_popup_keywords) # 广告弹窗关键词
3202
+ )
3203
+
3204
+ # 检查是否有子元素是关闭按钮(作为弹窗特征)
3205
+ has_close_button_child = False
3206
+ elem_bounds = elem['bounds']
3207
+ for other_elem in all_elements:
3208
+ if other_elem['idx'] == elem['idx']:
3209
+ continue
3210
+ if other_elem['is_close_button']:
3211
+ # 检查关闭按钮是否在这个元素范围内
3212
+ ox1, oy1, ox2, oy2 = other_elem['bounds']
3213
+ ex1, ey1, ex2, ey2 = elem_bounds
3214
+ if ex1 <= ox1 and ey1 <= oy1 and ex2 >= ox2 and ey2 >= oy2:
3215
+ has_close_button_child = True
3216
+ break
3217
+
3218
+ # 【非弹窗特征】如果元素包含明显的页面内容特征,则不是弹窗
3219
+ # 检查是否包含视频播放器、内容列表等页面元素
3220
+ page_content_keywords = ['video', 'player', 'recycler', 'list', 'scroll', 'viewpager', 'fragment']
3221
+ if any(kw in resource_id.lower() or kw in class_name.lower() for kw in page_content_keywords):
3222
+ # 如果面积很大且没有强弹窗特征,则不是弹窗
3223
+ if area_ratio > 0.6 and not has_strong_popup_feature:
3224
+ continue
3225
+
3226
+ # 【非弹窗特征】如果元素面积过大(接近全屏),即使居中也不应该是弹窗
3227
+ # 真正的弹窗通常不会超过屏幕的60%
3228
+ # 对于面积 > 0.6 的元素,如果没有强特征,直接跳过(避免误判首页内容区域)
3229
+ if area_ratio > 0.6 and not has_strong_popup_feature:
3230
+ continue # 跳过大面积非弹窗元素(接近全屏的内容区域,如首页视频播放区域)
3231
+
3232
+ # 对于面积 > 0.7 的元素,即使有强特征也要更严格
3233
+ if area_ratio > 0.7:
3234
+ # 需要非常强的特征才认为是弹窗
3235
+ if not has_strong_popup_feature:
3236
+ continue
3237
+
3155
3238
  confidence = 0.0
3156
3239
 
3157
3240
  # 【强特征】class 名称包含弹窗关键词 (+0.5)
@@ -3162,19 +3245,46 @@ class BasicMobileToolsLite:
3162
3245
  if any(kw in resource_id.lower() for kw in dialog_id_keywords):
3163
3246
  confidence += 0.4
3164
3247
 
3248
+ # 【强特征】resource-id 包含广告弹窗关键词 (+0.4)
3249
+ if any(kw in resource_id.lower() for kw in ad_popup_keywords):
3250
+ confidence += 0.4
3251
+
3252
+ # 【强特征】包含关闭按钮作为子元素 (+0.3)
3253
+ if has_close_button_child:
3254
+ confidence += 0.3
3255
+
3165
3256
  # 【中等特征】居中显示 (+0.2)
3257
+ # 但如果没有强特征,降低权重
3166
3258
  center_x = elem['center_x']
3167
3259
  center_y = elem['center_y']
3168
3260
  is_centered_x = abs(center_x - screen_width / 2) < screen_width * 0.15
3169
3261
  is_centered_y = abs(center_y - screen_height / 2) < screen_height * 0.25
3262
+
3263
+ has_strong_feature = (
3264
+ any(kw in class_name for kw in dialog_class_keywords) or
3265
+ any(kw in resource_id.lower() for kw in dialog_id_keywords) or
3266
+ any(kw in resource_id.lower() for kw in ad_popup_keywords) or
3267
+ has_close_button_child
3268
+ )
3269
+
3170
3270
  if is_centered_x and is_centered_y:
3171
- confidence += 0.2
3271
+ if has_strong_feature:
3272
+ confidence += 0.2
3273
+ else:
3274
+ confidence += 0.1 # 没有强特征时降低权重
3172
3275
  elif is_centered_x:
3173
- confidence += 0.1
3276
+ if has_strong_feature:
3277
+ confidence += 0.1
3278
+ else:
3279
+ confidence += 0.05 # 没有强特征时降低权重
3174
3280
 
3175
3281
  # 【中等特征】非全屏但有一定大小 (+0.15)
3282
+ # 但如果没有强特征,降低权重
3176
3283
  if 0.15 < area_ratio < 0.75:
3177
- confidence += 0.15
3284
+ if has_strong_feature:
3285
+ confidence += 0.15
3286
+ else:
3287
+ confidence += 0.08 # 没有强特征时降低权重
3178
3288
 
3179
3289
  # 【弱特征】XML 顺序靠后(在视图层级上层)(+0.1)
3180
3290
  if elem['idx'] > len(all_elements) * 0.5:
@@ -3201,8 +3311,22 @@ class BasicMobileToolsLite:
3201
3311
  popup_candidates.sort(key=lambda x: (x['confidence'], x['idx']), reverse=True)
3202
3312
  best = popup_candidates[0]
3203
3313
 
3204
- # 只有置信度 >= 0.6 才返回弹窗
3205
- if best['confidence'] >= 0.6:
3314
+ # 更严格的阈值:只有置信度 >= 0.7 才返回弹窗
3315
+ # 如果没有强特征(class或resource-id包含弹窗关键词),需要更高的置信度
3316
+ has_strong_feature = (
3317
+ any(kw in best['class'] for kw in dialog_class_keywords) or
3318
+ any(kw in best['resource_id'].lower() for kw in dialog_id_keywords) or
3319
+ any(kw in best['resource_id'].lower() for kw in ad_popup_keywords)
3320
+ )
3321
+
3322
+ if has_strong_feature:
3323
+ # 有强特征时,阈值0.7
3324
+ threshold = 0.7
3325
+ else:
3326
+ # 没有强特征时,阈值0.85(更严格)
3327
+ threshold = 0.85
3328
+
3329
+ if best['confidence'] >= threshold:
3206
3330
  return best['bounds'], best['confidence']
3207
3331
 
3208
3332
  return None, best['confidence']
@@ -255,7 +255,7 @@ class MobileMCPServer:
255
255
  "- 自动检测弹窗,标注可能的关闭按钮位置\n"
256
256
  "- 适用于所有页面和所有操作\n\n"
257
257
  "⚡ 推荐流程:\n"
258
- "1. 任何需要操作的场景,都先调用此工具\n"
258
+ "1. 找不到目标元素时,优先调用此工具\n"
259
259
  "2. 看标注图,找到目标元素编号\n"
260
260
  "3. 调用 mobile_click_by_som(编号) 精准点击\n"
261
261
  "4. 🔴【必须】点击后再次截图确认操作是否成功!",
@@ -514,14 +514,23 @@ class MobileMCPServer:
514
514
  tools.append(Tool(
515
515
  name="mobile_swipe",
516
516
  description="👆 滑动屏幕。方向:up/down/left/right\n\n"
517
+ "🎯 适用场景:\n"
518
+ "- 滑动页面(列表、页面切换)\n"
519
+ "- 拖动进度条/滑块(SeekBar、ProgressBar)\n"
520
+ "- 滑动选择器(Picker、Slider)\n\n"
517
521
  "💡 左右滑动时,可指定高度坐标或百分比:\n"
518
522
  "- y: 指定高度坐标(像素)\n"
519
523
  "- y_percent: 指定高度百分比 (0-100)\n"
520
- "- 两者都未指定时,使用屏幕中心高度\n\n"
524
+ "- 两者都未指定时,使用屏幕中心高度\n"
525
+ "- 📌 拖动进度条时,使用进度条的 Y 位置(百分比或像素)\n\n"
521
526
  "💡 横向滑动(left/right)时,可指定滑动距离:\n"
522
527
  "- distance: 滑动距离(像素)\n"
523
528
  "- distance_percent: 滑动距离百分比 (0-100)\n"
524
- "- 两者都未指定时,使用默认距离(屏幕宽度的 60%)",
529
+ "- 两者都未指定时,使用默认距离(屏幕宽度的 60%)\n"
530
+ "- 📌 拖动进度条时,distance_percent 控制拖动幅度\n\n"
531
+ "💡 拖动进度条示例:\n"
532
+ "- 倒退:direction='left', y_percent=91(进度条位置), distance_percent=30\n"
533
+ "- 前进:direction='right', y_percent=91, distance_percent=30",
525
534
  inputSchema={
526
535
  "type": "object",
527
536
  "properties": {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.6.6
3
+ Version: 2.6.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
@@ -1,6 +1,8 @@
1
1
  LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
+ __init__.py
5
+ config.py
4
6
  requirements.txt
5
7
  setup.py
6
8
  ./__init__.py
@@ -29,13 +31,27 @@ setup.py
29
31
  ./utils/logger.py
30
32
  ./utils/xml_formatter.py
31
33
  ./utils/xml_parser.py
34
+ core/__init__.py
35
+ core/basic_tools_lite.py
36
+ core/device_manager.py
37
+ core/dynamic_config.py
38
+ core/ios_client_wda.py
39
+ core/ios_device_manager_wda.py
40
+ core/mobile_client.py
41
+ core/template_matcher.py
32
42
  core/templates/close_buttons/auto_x_0112_151217.png
33
43
  core/templates/close_buttons/auto_x_0112_152037.png
34
44
  core/templates/close_buttons/auto_x_0112_152840.png
35
45
  core/templates/close_buttons/auto_x_0112_153256.png
36
46
  core/templates/close_buttons/auto_x_0112_154847.png
37
47
  core/templates/close_buttons/gray_x_stock_ad.png
48
+ core/utils/__init__.py
49
+ core/utils/logger.py
50
+ core/utils/operation_history_manager.py
51
+ core/utils/smart_wait.py
38
52
  docs/iOS_SETUP_GUIDE.md
53
+ mcp_tools/__init__.py
54
+ mcp_tools/mcp_server.py
39
55
  mobile_mcp_ai.egg-info/PKG-INFO
40
56
  mobile_mcp_ai.egg-info/SOURCES.txt
41
57
  mobile_mcp_ai.egg-info/dependency_links.txt
@@ -48,4 +64,8 @@ templates/close_buttons/auto_x_0112_152037.png
48
64
  templates/close_buttons/auto_x_0112_152840.png
49
65
  templates/close_buttons/auto_x_0112_153256.png
50
66
  templates/close_buttons/auto_x_0112_154847.png
51
- templates/close_buttons/gray_x_stock_ad.png
67
+ templates/close_buttons/gray_x_stock_ad.png
68
+ utils/__init__.py
69
+ utils/logger.py
70
+ utils/xml_formatter.py
71
+ utils/xml_parser.py
@@ -25,7 +25,7 @@ if requirements_file.exists():
25
25
 
26
26
  setup(
27
27
  name="mobile-mcp-ai",
28
- version="2.6.6", # 增强 swipe 方法 - 支持自定义横向滑动距离
28
+ version="2.6.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