mobile-mcp-ai 2.5.5__py3-none-any.whl → 2.5.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/__init__.py +1 -1
- mobile_mcp/core/basic_tools_lite.py +54 -16
- mobile_mcp/mcp_tools/mcp_server.py +8 -3
- {mobile_mcp_ai-2.5.5.dist-info → mobile_mcp_ai-2.5.7.dist-info}/METADATA +17 -30
- {mobile_mcp_ai-2.5.5.dist-info → mobile_mcp_ai-2.5.7.dist-info}/RECORD +9 -9
- {mobile_mcp_ai-2.5.5.dist-info → mobile_mcp_ai-2.5.7.dist-info}/WHEEL +1 -1
- {mobile_mcp_ai-2.5.5.dist-info/licenses → mobile_mcp_ai-2.5.7.dist-info}/LICENSE +0 -0
- {mobile_mcp_ai-2.5.5.dist-info → mobile_mcp_ai-2.5.7.dist-info}/entry_points.txt +0 -0
- {mobile_mcp_ai-2.5.5.dist-info → mobile_mcp_ai-2.5.7.dist-info}/top_level.txt +0 -0
mobile_mcp/__init__.py
CHANGED
|
@@ -1126,9 +1126,16 @@ class BasicMobileToolsLite:
|
|
|
1126
1126
|
except Exception:
|
|
1127
1127
|
return None
|
|
1128
1128
|
|
|
1129
|
-
def click_by_id(self, resource_id: str) -> Dict:
|
|
1130
|
-
"""通过 resource-id
|
|
1129
|
+
def click_by_id(self, resource_id: str, index: int = 0) -> Dict:
|
|
1130
|
+
"""通过 resource-id 点击(支持点击第 N 个元素)
|
|
1131
|
+
|
|
1132
|
+
Args:
|
|
1133
|
+
resource_id: 元素的 resource-id
|
|
1134
|
+
index: 第几个元素(从 0 开始),默认 0 表示第一个
|
|
1135
|
+
"""
|
|
1131
1136
|
try:
|
|
1137
|
+
index_desc = f"[{index}]" if index > 0 else ""
|
|
1138
|
+
|
|
1132
1139
|
if self._is_ios():
|
|
1133
1140
|
ios_client = self._get_ios_client()
|
|
1134
1141
|
if ios_client and hasattr(ios_client, 'wda'):
|
|
@@ -1136,18 +1143,28 @@ class BasicMobileToolsLite:
|
|
|
1136
1143
|
if not elem.exists:
|
|
1137
1144
|
elem = ios_client.wda(name=resource_id)
|
|
1138
1145
|
if elem.exists:
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1146
|
+
# 获取所有匹配的元素
|
|
1147
|
+
elements = elem.find_elements()
|
|
1148
|
+
if index < len(elements):
|
|
1149
|
+
elements[index].click()
|
|
1150
|
+
time.sleep(0.3)
|
|
1151
|
+
self._record_operation('click', element=f"{resource_id}{index_desc}", ref=resource_id, index=index)
|
|
1152
|
+
return {"success": True, "message": f"✅ 点击成功: {resource_id}{index_desc}"}
|
|
1153
|
+
else:
|
|
1154
|
+
return {"success": False, "message": f"❌ 索引超出范围: 找到 {len(elements)} 个元素,但请求索引 {index}"}
|
|
1143
1155
|
return {"success": False, "message": f"❌ 元素不存在: {resource_id}"}
|
|
1144
1156
|
else:
|
|
1145
1157
|
elem = self.client.u2(resourceId=resource_id)
|
|
1146
1158
|
if elem.exists(timeout=0.5):
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1159
|
+
# 获取匹配元素数量
|
|
1160
|
+
count = elem.count
|
|
1161
|
+
if index < count:
|
|
1162
|
+
elem[index].click()
|
|
1163
|
+
time.sleep(0.3)
|
|
1164
|
+
self._record_operation('click', element=f"{resource_id}{index_desc}", ref=resource_id, index=index)
|
|
1165
|
+
return {"success": True, "message": f"✅ 点击成功: {resource_id}{index_desc}" + (f" (共 {count} 个)" if count > 1 else "")}
|
|
1166
|
+
else:
|
|
1167
|
+
return {"success": False, "message": f"❌ 索引超出范围: 找到 {count} 个元素,但请求索引 {index}"}
|
|
1151
1168
|
return {"success": False, "message": f"❌ 元素不存在: {resource_id}"}
|
|
1152
1169
|
except Exception as e:
|
|
1153
1170
|
return {"success": False, "message": f"❌ 点击失败: {e}"}
|
|
@@ -2360,22 +2377,43 @@ class BasicMobileToolsLite:
|
|
|
2360
2377
|
return 0.5
|
|
2361
2378
|
|
|
2362
2379
|
def assert_text(self, text: str) -> Dict:
|
|
2363
|
-
"""
|
|
2380
|
+
"""检查页面是否包含文本(支持精确匹配和包含匹配)"""
|
|
2364
2381
|
try:
|
|
2382
|
+
exists = False
|
|
2383
|
+
match_type = ""
|
|
2384
|
+
|
|
2365
2385
|
if self._is_ios():
|
|
2366
2386
|
ios_client = self._get_ios_client()
|
|
2367
2387
|
if ios_client and hasattr(ios_client, 'wda'):
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2388
|
+
# 先尝试精确匹配
|
|
2389
|
+
if ios_client.wda(name=text).exists or ios_client.wda(label=text).exists:
|
|
2390
|
+
exists = True
|
|
2391
|
+
match_type = "精确匹配"
|
|
2392
|
+
# 再尝试包含匹配
|
|
2393
|
+
elif ios_client.wda(nameContains=text).exists or ios_client.wda(labelContains=text).exists:
|
|
2394
|
+
exists = True
|
|
2395
|
+
match_type = "包含匹配"
|
|
2396
|
+
else:
|
|
2397
|
+
# Android: 先尝试精确匹配
|
|
2398
|
+
if self.client.u2(text=text).exists():
|
|
2399
|
+
exists = True
|
|
2400
|
+
match_type = "精确匹配"
|
|
2401
|
+
# 再尝试包含匹配
|
|
2402
|
+
elif self.client.u2(textContains=text).exists():
|
|
2403
|
+
exists = True
|
|
2404
|
+
match_type = "包含匹配"
|
|
2405
|
+
|
|
2406
|
+
if exists:
|
|
2407
|
+
message = f"✅ 文本'{text}' 存在({match_type})"
|
|
2371
2408
|
else:
|
|
2372
|
-
|
|
2409
|
+
message = f"❌ 文本'{text}' 不存在"
|
|
2373
2410
|
|
|
2374
2411
|
return {
|
|
2375
2412
|
"success": True,
|
|
2376
2413
|
"found": exists,
|
|
2377
2414
|
"text": text,
|
|
2378
|
-
"
|
|
2415
|
+
"match_type": match_type if exists else None,
|
|
2416
|
+
"message": message
|
|
2379
2417
|
}
|
|
2380
2418
|
except Exception as e:
|
|
2381
2419
|
return {"success": False, "message": f"❌ 断言失败: {e}"}
|
|
@@ -331,11 +331,13 @@ class MobileMCPServer:
|
|
|
331
331
|
description="👆 通过 resource-id 点击元素(最推荐)\n\n"
|
|
332
332
|
"✅ 最稳定的定位方式\n"
|
|
333
333
|
"✅ 实时检测元素是否存在,元素不存在会报错\n"
|
|
334
|
-
"📋 使用前先调用 mobile_list_elements 获取元素 ID"
|
|
334
|
+
"📋 使用前先调用 mobile_list_elements 获取元素 ID\n"
|
|
335
|
+
"💡 当有多个相同 ID 的元素时,用 index 指定第几个(从 0 开始)",
|
|
335
336
|
inputSchema={
|
|
336
337
|
"type": "object",
|
|
337
338
|
"properties": {
|
|
338
|
-
"resource_id": {"type": "string", "description": "元素的 resource-id"}
|
|
339
|
+
"resource_id": {"type": "string", "description": "元素的 resource-id"},
|
|
340
|
+
"index": {"type": "integer", "description": "第几个元素(从 0 开始),默认 0 表示第一个", "default": 0}
|
|
339
341
|
},
|
|
340
342
|
"required": ["resource_id"]
|
|
341
343
|
}
|
|
@@ -860,7 +862,10 @@ class MobileMCPServer:
|
|
|
860
862
|
return [TextContent(type="text", text=self.format_response(result))]
|
|
861
863
|
|
|
862
864
|
elif name == "mobile_click_by_id":
|
|
863
|
-
result = self.tools.click_by_id(
|
|
865
|
+
result = self.tools.click_by_id(
|
|
866
|
+
arguments["resource_id"],
|
|
867
|
+
arguments.get("index", 0)
|
|
868
|
+
)
|
|
864
869
|
return [TextContent(type="text", text=self.format_response(result))]
|
|
865
870
|
|
|
866
871
|
elif name == "mobile_click_by_percent":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: mobile-mcp-ai
|
|
3
|
-
Version: 2.5.
|
|
3
|
+
Version: 2.5.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
|
|
@@ -31,21 +31,6 @@ Provides-Extra: ai
|
|
|
31
31
|
Requires-Dist: dashscope>=1.10.0; extra == "ai"
|
|
32
32
|
Requires-Dist: openai>=1.0.0; extra == "ai"
|
|
33
33
|
Requires-Dist: anthropic>=0.3.0; extra == "ai"
|
|
34
|
-
Provides-Extra: test
|
|
35
|
-
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
36
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
37
|
-
Requires-Dist: allure-pytest>=2.13.0; extra == "test"
|
|
38
|
-
Provides-Extra: dev
|
|
39
|
-
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
41
|
-
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
42
|
-
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
43
|
-
Provides-Extra: ios
|
|
44
|
-
Requires-Dist: tidevice>=0.11.0; extra == "ios"
|
|
45
|
-
Requires-Dist: facebook-wda>=1.4.0; extra == "ios"
|
|
46
|
-
Provides-Extra: h5
|
|
47
|
-
Requires-Dist: Appium-Python-Client>=3.0.0; extra == "h5"
|
|
48
|
-
Requires-Dist: selenium>=4.0.0; extra == "h5"
|
|
49
34
|
Provides-Extra: all
|
|
50
35
|
Requires-Dist: dashscope>=1.10.0; extra == "all"
|
|
51
36
|
Requires-Dist: openai>=1.0.0; extra == "all"
|
|
@@ -55,19 +40,21 @@ Requires-Dist: selenium>=4.0.0; extra == "all"
|
|
|
55
40
|
Requires-Dist: pytest>=8.0.0; extra == "all"
|
|
56
41
|
Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
|
|
57
42
|
Requires-Dist: allure-pytest>=2.13.0; extra == "all"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
46
|
+
Requires-Dist: twine>=4.0.0; extra == "dev"
|
|
47
|
+
Requires-Dist: build>=0.10.0; extra == "dev"
|
|
48
|
+
Provides-Extra: h5
|
|
49
|
+
Requires-Dist: Appium-Python-Client>=3.0.0; extra == "h5"
|
|
50
|
+
Requires-Dist: selenium>=4.0.0; extra == "h5"
|
|
51
|
+
Provides-Extra: ios
|
|
52
|
+
Requires-Dist: tidevice>=0.11.0; extra == "ios"
|
|
53
|
+
Requires-Dist: facebook-wda>=1.4.0; extra == "ios"
|
|
54
|
+
Provides-Extra: test
|
|
55
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
56
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
|
|
57
|
+
Requires-Dist: allure-pytest>=2.13.0; extra == "test"
|
|
71
58
|
|
|
72
59
|
# 📱 Mobile MCP AI
|
|
73
60
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
mobile_mcp/__init__.py,sha256=
|
|
1
|
+
mobile_mcp/__init__.py,sha256=sQJZTL_sxQFzmcS7jOtS2AHCfUySz40vhX96N6u1qy4,816
|
|
2
2
|
mobile_mcp/config.py,sha256=yaFLAV4bc2wX0GQPtZDo7OYF9E88tXV-av41fQsJwK4,4480
|
|
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=wPrn9y7xUspQUhXRNQXhksekz5CNVVH7CbEfiD8yUeE,153449
|
|
5
5
|
mobile_mcp/core/device_manager.py,sha256=PX3-B5bJFnKNt6C8fT7FSY8JwD-ngZ3toF88bcOV9qA,8766
|
|
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=PvKXImfN9Irru3bQJUjf4FLGn8LjY2VLzUNEl-i7xLE,8601
|
|
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=fr42BjulYQCBreWoLx5lkWEZjT60Df6RCo_kyXMOHfI,49868
|
|
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.5.
|
|
28
|
-
mobile_mcp_ai-2.5.
|
|
29
|
-
mobile_mcp_ai-2.5.
|
|
30
|
-
mobile_mcp_ai-2.5.
|
|
31
|
-
mobile_mcp_ai-2.5.
|
|
32
|
-
mobile_mcp_ai-2.5.
|
|
27
|
+
mobile_mcp_ai-2.5.7.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
28
|
+
mobile_mcp_ai-2.5.7.dist-info/METADATA,sha256=RN8xuzGt0p_qbnQkSkxcUznXmNVJgtn9KY9lotAN49Q,10213
|
|
29
|
+
mobile_mcp_ai-2.5.7.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
30
|
+
mobile_mcp_ai-2.5.7.dist-info/entry_points.txt,sha256=KB_FglozgPHBprSM1vFbIzGyheFuHFmGanscRdMJ_8A,68
|
|
31
|
+
mobile_mcp_ai-2.5.7.dist-info/top_level.txt,sha256=lLm6YpbTv855Lbh8BIA0rPxhybIrvYUzMEk9OErHT94,11
|
|
32
|
+
mobile_mcp_ai-2.5.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|