mobile-mcp-ai 2.7.5__py3-none-any.whl → 2.7.7__py3-none-any.whl
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.
- mobile_mcp/core/basic_tools_lite.py +216 -35
- mobile_mcp/mcp_tools/mcp_server.py +20 -1
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/METADATA +1 -1
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/RECORD +8 -8
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/WHEEL +0 -0
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/entry_points.txt +0 -0
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/licenses/LICENSE +0 -0
- {mobile_mcp_ai-2.7.5.dist-info → mobile_mcp_ai-2.7.7.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
3255
|
-
|
|
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(
|
|
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
|
-
|
|
3304
|
-
|
|
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
|
-
|
|
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 启动中... [
|
|
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,7 +1,7 @@
|
|
|
1
1
|
mobile_mcp/__init__.py,sha256=sQJZTL_sxQFzmcS7jOtS2AHCfUySz40vhX96N6u1qy4,816
|
|
2
2
|
mobile_mcp/config.py,sha256=-xSl9vahp3EFAA97P1ahcnQC-HHAFvccGHpnFAXeKHU,5841
|
|
3
3
|
mobile_mcp/core/__init__.py,sha256=ndMy-cLAIsQDG5op7gM_AIplycqZSZPWEkec1pEhvEY,170
|
|
4
|
-
mobile_mcp/core/basic_tools_lite.py,sha256=
|
|
4
|
+
mobile_mcp/core/basic_tools_lite.py,sha256=dflpTqtQ_3JyJ6SOAs2rJ3NZ998VDeDx4QWyfNB3NhI,232714
|
|
5
5
|
mobile_mcp/core/device_manager.py,sha256=xG5DoeNFs45pl-FTEhEWblqVwxtFK-FmVEGlNL6EqRI,8798
|
|
6
6
|
mobile_mcp/core/dynamic_config.py,sha256=Ja1n1pfb0HspGByqk2_A472mYVniKmGtNEWyjUjmgK8,9811
|
|
7
7
|
mobile_mcp/core/ios_client_wda.py,sha256=Nq9WxevhTWpVpolM-Ymp-b0nUQV3tXLFszmJHbDC4wA,18770
|
|
@@ -19,14 +19,14 @@ mobile_mcp/core/utils/logger.py,sha256=XXQAHUwT1jc70pq_tYFmL6f_nKrFlYm3hcgl-5RYR
|
|
|
19
19
|
mobile_mcp/core/utils/operation_history_manager.py,sha256=gi8S8HJAMqvkUrY7_-kVbko3Xt7c4GAUziEujRd-N-Y,4792
|
|
20
20
|
mobile_mcp/core/utils/smart_wait.py,sha256=N5wKTUYrNWPruBILqrAjpvtso8Z3GRWCfMIR_aZxPLg,8649
|
|
21
21
|
mobile_mcp/mcp_tools/__init__.py,sha256=xkro8Rwqv_55YlVyhh-3DgRFSsLE3h1r31VIb3bpM6E,143
|
|
22
|
-
mobile_mcp/mcp_tools/mcp_server.py,sha256=
|
|
22
|
+
mobile_mcp/mcp_tools/mcp_server.py,sha256=RLqe4PqwVYVemLyShY6fKYUJ44pJg52k0VBJ6PTYyyQ,54402
|
|
23
23
|
mobile_mcp/utils/__init__.py,sha256=8EH0i7UGtx1y_j_GEgdN-cZdWn2sRtZSEOLlNF9HRnY,158
|
|
24
24
|
mobile_mcp/utils/logger.py,sha256=Sqq2Nr0Y4p03erqcrbYKVPCGiFaNGHMcE_JwCkeOfU4,3626
|
|
25
25
|
mobile_mcp/utils/xml_formatter.py,sha256=uwTRb3vLbqhT8O-udzWT7s7LsV-DyDUz2DkofD3hXOE,4556
|
|
26
26
|
mobile_mcp/utils/xml_parser.py,sha256=QhL8CWbdmNDzmBLjtx6mEnjHgMFZzJeHpCL15qfXSpI,3926
|
|
27
|
-
mobile_mcp_ai-2.7.
|
|
28
|
-
mobile_mcp_ai-2.7.
|
|
29
|
-
mobile_mcp_ai-2.7.
|
|
30
|
-
mobile_mcp_ai-2.7.
|
|
31
|
-
mobile_mcp_ai-2.7.
|
|
32
|
-
mobile_mcp_ai-2.7.
|
|
27
|
+
mobile_mcp_ai-2.7.7.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
28
|
+
mobile_mcp_ai-2.7.7.dist-info/METADATA,sha256=IKnVZj4b9221G7g4Ixekb8YNVg-RfR-WPcO-hFZBuNI,11505
|
|
29
|
+
mobile_mcp_ai-2.7.7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
30
|
+
mobile_mcp_ai-2.7.7.dist-info/entry_points.txt,sha256=KB_FglozgPHBprSM1vFbIzGyheFuHFmGanscRdMJ_8A,68
|
|
31
|
+
mobile_mcp_ai-2.7.7.dist-info/top_level.txt,sha256=lLm6YpbTv855Lbh8BIA0rPxhybIrvYUzMEk9OErHT94,11
|
|
32
|
+
mobile_mcp_ai-2.7.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|