mobile-mcp-ai 2.3.9__py3-none-any.whl → 2.4.2__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.
@@ -552,5 +552,9 @@ class IOSClientWDA:
552
552
 
553
553
 
554
554
 
555
+
556
+
557
+
558
+
555
559
 
556
560
 
@@ -5,7 +5,7 @@ Mobile MCP Server - 统一入口
5
5
 
6
6
  纯 MCP 方案,完全依赖 Cursor 视觉能力:
7
7
  - 不需要 AI 密钥
8
- - 20 个核心工具
8
+ - 24 个核心工具(含 4 个长按工具)
9
9
  - 支持 Android 和 iOS
10
10
  - 保留 pytest 脚本生成
11
11
 
@@ -143,33 +143,27 @@ class MobileMCPServer:
143
143
  # ==================== 元素定位(优先使用)====================
144
144
  tools.append(Tool(
145
145
  name="mobile_list_elements",
146
- description="📋 列出页面所有可交互元素(⚠️ 录制测试脚本时必须优先调用!)\n\n"
147
- "返回 resource_id, text, bounds 等信息。\n\n"
148
- "🎯 【生成测试脚本时的定位策略】按稳定性排序:\n"
149
- "1️⃣ 【必须】先调用此工具获取元素列表\n"
150
- "2️⃣ 【推荐】有 id → 用 mobile_click_by_id(最稳定)\n"
151
- "3️⃣ 【推荐】有 text → 用 mobile_click_by_text(稳定)\n"
152
- "4️⃣ 【兜底】游戏/无法获取元素 → mobile_click_at_coords(自动转百分比)\n\n"
153
- "💡 优先使用 ID/文本定位,生成的脚本跨设备兼容性更好!",
146
+ description="📋 列出页面所有可交互元素\n\n"
147
+ "⚠️ 【重要】点击元素前必须先调用此工具!\n"
148
+ "如果元素在控件树中存在,使用 click_by_id 或 click_by_text 定位。\n"
149
+ "只有当此工具返回空或找不到目标元素时,才使用截图+坐标方式。\n\n"
150
+ "📌 控件树定位优势:\n"
151
+ "- 实时检测元素是否存在\n"
152
+ "- 元素消失时会报错,不会误点击\n"
153
+ "- 跨设备兼容性好",
154
154
  inputSchema={"type": "object", "properties": {}, "required": []}
155
155
  ))
156
156
 
157
157
  # ==================== 截图(视觉兜底)====================
158
158
  tools.append(Tool(
159
159
  name="mobile_take_screenshot",
160
- description="📸 截图(支持全屏和局部裁剪)\n\n"
161
- "🎯 使用场景:\n"
162
- "- 游戏(Unity/Cocos)无法获取元素时\n"
163
- "- mobile_list_elements 返回空时\n"
164
- "- 需要确认页面状态时\n\n"
165
- "🔍 【局部裁剪】精确识别小元素(如广告关闭按钮):\n"
166
- " 1. 先全屏截图,AI 返回大概坐标 (600, 200)\n"
167
- " 2. 再调用 crop_x=600, crop_y=200, crop_size=200 截取局部\n"
168
- " 3. 局部图不压缩,AI 可精确识别\n"
169
- " 4. 点击时传入 crop_offset_x/y 自动换算坐标\n\n"
170
- "⚠️ 【重要】截图会被压缩!\n"
171
- " - 全屏截图:点击时传 image_width/image_height 转换坐标\n"
172
- " - 局部截图:点击时传 crop_offset_x/crop_offset_y 转换坐标",
160
+ description="📸 截图查看屏幕内容\n\n"
161
+ "⚠️ 【推荐使用 mobile_screenshot_with_som 代替!】\n"
162
+ "SoM 截图会给元素标号,AI 可以直接说'点击几号',更精准!\n\n"
163
+ "🎯 本工具仅用于:\n"
164
+ "- 快速确认页面状态(不需要点击时)\n"
165
+ "- 操作后确认结果\n\n"
166
+ "💡 如需点击元素,请用 mobile_screenshot_with_som + mobile_click_by_som",
173
167
  inputSchema={
174
168
  "type": "object",
175
169
  "properties": {
@@ -188,13 +182,78 @@ class MobileMCPServer:
188
182
  inputSchema={"type": "object", "properties": {}, "required": []}
189
183
  ))
190
184
 
185
+ tools.append(Tool(
186
+ name="mobile_screenshot_with_som",
187
+ description="📸🏷️ Set-of-Mark 截图(⭐⭐ 强烈推荐!默认截图方式)\n\n"
188
+ "【智能标注】给每个可点击元素画框+编号,检测弹窗时额外标注可能的X按钮位置(黄色)。\n"
189
+ "AI 看图直接说'点击 3 号',调用 mobile_click_by_som(3) 即可!\n\n"
190
+ "🎯 优势:\n"
191
+ "- 元素有编号,精准点击不会误触\n"
192
+ "- 自动检测弹窗,标注可能的关闭按钮位置\n"
193
+ "- 适用于所有页面和所有操作\n\n"
194
+ "⚡ 推荐流程:\n"
195
+ "1. 任何需要操作的场景,都先调用此工具\n"
196
+ "2. 看标注图,找到目标元素编号\n"
197
+ "3. 调用 mobile_click_by_som(编号) 精准点击\n"
198
+ "4. 🔴【必须】点击后再次截图确认操作是否成功!",
199
+ inputSchema={"type": "object", "properties": {}, "required": []}
200
+ ))
201
+
202
+ tools.append(Tool(
203
+ name="mobile_click_by_som",
204
+ description="🎯 根据 SoM 编号点击元素\n\n"
205
+ "配合 mobile_screenshot_with_som 使用。\n"
206
+ "看图后直接说'点击 3 号',调用此函数即可。\n\n"
207
+ "⚠️ 【重要】点击后建议再次截图确认操作是否成功!",
208
+ inputSchema={
209
+ "type": "object",
210
+ "properties": {
211
+ "index": {
212
+ "type": "integer",
213
+ "description": "元素编号(从 1 开始,对应截图中的标注数字)"
214
+ }
215
+ },
216
+ "required": ["index"]
217
+ }
218
+ ))
219
+
220
+ tools.append(Tool(
221
+ name="mobile_screenshot_with_grid",
222
+ description="📸📏 带网格坐标的截图(精确定位神器!)\n\n"
223
+ "在截图上绘制网格线和坐标刻度,帮助快速定位元素位置。\n"
224
+ "如果检测到弹窗,会用绿色圆圈标注可能的关闭按钮位置。\n\n"
225
+ "🎯 适用场景:\n"
226
+ "- 需要精确知道某个元素的坐标\n"
227
+ "- 关闭广告弹窗时定位 X 按钮\n"
228
+ "- 元素不在控件树中时的视觉定位\n\n"
229
+ "💡 返回信息:\n"
230
+ "- 带网格标注的截图\n"
231
+ "- 弹窗边界坐标(如果检测到)\n"
232
+ "- 可能的关闭按钮位置列表(带优先级)\n\n"
233
+ "🔴 【必须】点击后必须再次截图确认操作是否成功!",
234
+ inputSchema={
235
+ "type": "object",
236
+ "properties": {
237
+ "grid_size": {
238
+ "type": "integer",
239
+ "description": "网格间距(像素),默认 100。值越小网格越密,建议 50-200"
240
+ },
241
+ "show_popup_hints": {
242
+ "type": "boolean",
243
+ "description": "是否显示弹窗关闭按钮提示位置,默认 true"
244
+ }
245
+ },
246
+ "required": []
247
+ }
248
+ ))
249
+
191
250
  # ==================== 点击操作 ====================
192
251
  tools.append(Tool(
193
252
  name="mobile_click_by_text",
194
- description="👆 通过文本点击(⭐ 录制脚本时推荐!)\n\n"
195
- "✅ 优势:跨设备兼容,不受屏幕分辨率影响\n"
196
- "📋 使用前请先调用 mobile_list_elements 确认元素有文本\n"
197
- "💡 生成的脚本使用 d(text='...') 定位,稳定可靠",
253
+ description="👆 通过文本点击元素(推荐)\n\n"
254
+ "✅ 实时检测元素是否存在,元素不存在会报错\n"
255
+ " 不会误点击到其他位置\n"
256
+ "📋 使用前先调用 mobile_list_elements 确认元素文本",
198
257
  inputSchema={
199
258
  "type": "object",
200
259
  "properties": {
@@ -206,10 +265,10 @@ class MobileMCPServer:
206
265
 
207
266
  tools.append(Tool(
208
267
  name="mobile_click_by_id",
209
- description="👆 通过 resource-id 点击(⭐⭐ 录制脚本时最推荐!)\n\n"
210
- "✅ 最稳定的定位方式,跨设备完美兼容\n"
211
- "📋 使用前请先调用 mobile_list_elements 获取元素 ID\n"
212
- "💡 生成的脚本使用 d(resourceId='...') 定位,最稳定",
268
+ description="👆 通过 resource-id 点击元素(最推荐)\n\n"
269
+ "✅ 最稳定的定位方式\n"
270
+ " 实时检测元素是否存在,元素不存在会报错\n"
271
+ "📋 使用前先调用 mobile_list_elements 获取元素 ID",
213
272
  inputSchema={
214
273
  "type": "object",
215
274
  "properties": {
@@ -221,16 +280,15 @@ class MobileMCPServer:
221
280
 
222
281
  tools.append(Tool(
223
282
  name="mobile_click_at_coords",
224
- description="👆 点击指定坐标(⚠️ 兜底方案,优先用 ID/文本定位!)\n\n"
225
- "🎯 仅在以下场景使用:\n"
226
- "- 游戏(Unity/Cocos)无法获取元素\n"
227
- "- mobile_list_elements 返回空\n"
228
- "- 元素没有 id 和 text\n\n"
229
- "⚠️ 【坐标转换】截图返回的参数直接传入:\n"
230
- " - image_width/image_height: 压缩后尺寸(AI 看到的)\n"
231
- " - original_img_width/original_img_height: 原图尺寸(用于转换)\n"
232
- " - crop_offset_x/crop_offset_y: 局部截图偏移\n\n"
233
- "✅ 自动记录百分比坐标,生成脚本时转换为跨分辨率兼容的百分比定位",
283
+ description="👆 点击指定坐标(兜底方案)\n\n"
284
+ "⚠️ 【重要】优先使用 mobile_click_by_id 或 mobile_click_by_text!\n"
285
+ "仅在 mobile_list_elements 无法获取元素时使用此工具。\n\n"
286
+ "⚠️ 【时序限制】截图分析期间页面可能变化:\n"
287
+ "- 坐标是基于截图时刻的,点击时页面可能已不同\n"
288
+ "- 如果误点击,调用 mobile_press_key(back) 返回\n"
289
+ "- 对于定时弹窗(如广告),建议等待其自动消失\n\n"
290
+ "📐 坐标转换:截图返回的 image_width/height 等参数直接传入即可\n\n"
291
+ "🔴 【必须】点击后必须再次截图确认操作是否成功!",
234
292
  inputSchema={
235
293
  "type": "object",
236
294
  "properties": {
@@ -256,7 +314,8 @@ class MobileMCPServer:
256
314
  " - (10, 5) = 左上角附近\n"
257
315
  " - (85, 90) = 右下角附近\n\n"
258
316
  "✅ 优势:同样的百分比在不同分辨率设备上都能点到相同相对位置\n"
259
- "💡 录制一次,多设备回放",
317
+ "💡 录制一次,多设备回放\n\n"
318
+ "🔴 【必须】点击后必须再次截图确认操作是否成功!",
260
319
  inputSchema={
261
320
  "type": "object",
262
321
  "properties": {
@@ -267,6 +326,89 @@ class MobileMCPServer:
267
326
  }
268
327
  ))
269
328
 
329
+ # ==================== 长按操作 ====================
330
+ tools.append(Tool(
331
+ name="mobile_long_press_by_id",
332
+ description="👆 通过 resource-id 长按(⭐⭐ 最稳定!)\n\n"
333
+ "✅ 最稳定的长按定位方式,跨设备完美兼容\n"
334
+ "📋 使用前请先调用 mobile_list_elements 获取元素 ID\n"
335
+ "💡 生成的脚本使用 d(resourceId='...').long_click() 定位,最稳定",
336
+ inputSchema={
337
+ "type": "object",
338
+ "properties": {
339
+ "resource_id": {"type": "string", "description": "元素的 resource-id"},
340
+ "duration": {"type": "number", "description": "长按持续时间(秒),默认 1.0"}
341
+ },
342
+ "required": ["resource_id"]
343
+ }
344
+ ))
345
+
346
+ tools.append(Tool(
347
+ name="mobile_long_press_by_text",
348
+ description="👆 通过文本长按(⭐ 推荐!)\n\n"
349
+ "✅ 优势:跨设备兼容,不受屏幕分辨率影响\n"
350
+ "📋 使用前请先调用 mobile_list_elements 确认元素有文本\n"
351
+ "💡 生成的脚本使用 d(text='...').long_click() 定位,稳定可靠",
352
+ inputSchema={
353
+ "type": "object",
354
+ "properties": {
355
+ "text": {"type": "string", "description": "元素的文本内容(精确匹配)"},
356
+ "duration": {"type": "number", "description": "长按持续时间(秒),默认 1.0"}
357
+ },
358
+ "required": ["text"]
359
+ }
360
+ ))
361
+
362
+ tools.append(Tool(
363
+ name="mobile_long_press_by_percent",
364
+ description="👆 通过百分比位置长按(跨设备兼容!)\n\n"
365
+ "🎯 原理:屏幕左上角是 (0%, 0%),右下角是 (100%, 100%)\n"
366
+ "📐 示例:\n"
367
+ " - (50, 50) = 屏幕正中央\n"
368
+ " - (10, 5) = 左上角附近\n"
369
+ " - (85, 90) = 右下角附近\n\n"
370
+ "✅ 优势:同样的百分比在不同分辨率设备上都能长按到相同相对位置\n"
371
+ "💡 录制一次,多设备回放",
372
+ inputSchema={
373
+ "type": "object",
374
+ "properties": {
375
+ "x_percent": {"type": "number", "description": "X 轴百分比 (0-100)"},
376
+ "y_percent": {"type": "number", "description": "Y 轴百分比 (0-100)"},
377
+ "duration": {"type": "number", "description": "长按持续时间(秒),默认 1.0"}
378
+ },
379
+ "required": ["x_percent", "y_percent"]
380
+ }
381
+ ))
382
+
383
+ tools.append(Tool(
384
+ name="mobile_long_press_at_coords",
385
+ description="👆 长按指定坐标(⚠️ 兜底方案,优先用 ID/文本定位!)\n\n"
386
+ "🎯 仅在以下场景使用:\n"
387
+ "- 游戏(Unity/Cocos)无法获取元素\n"
388
+ "- mobile_list_elements 返回空\n"
389
+ "- 元素没有 id 和 text\n\n"
390
+ "⚠️ 【坐标转换】截图返回的参数直接传入:\n"
391
+ " - image_width/image_height: 压缩后尺寸(AI 看到的)\n"
392
+ " - original_img_width/original_img_height: 原图尺寸(用于转换)\n"
393
+ " - crop_offset_x/crop_offset_y: 局部截图偏移\n\n"
394
+ "✅ 自动记录百分比坐标,生成脚本时转换为跨分辨率兼容的百分比定位",
395
+ inputSchema={
396
+ "type": "object",
397
+ "properties": {
398
+ "x": {"type": "number", "description": "X 坐标(来自 AI 分析截图)"},
399
+ "y": {"type": "number", "description": "Y 坐标(来自 AI 分析截图)"},
400
+ "duration": {"type": "number", "description": "长按持续时间(秒),默认 1.0"},
401
+ "image_width": {"type": "number", "description": "压缩后图片宽度"},
402
+ "image_height": {"type": "number", "description": "压缩后图片高度"},
403
+ "original_img_width": {"type": "number", "description": "原图宽度"},
404
+ "original_img_height": {"type": "number", "description": "原图高度"},
405
+ "crop_offset_x": {"type": "number", "description": "局部截图 X 偏移"},
406
+ "crop_offset_y": {"type": "number", "description": "局部截图 Y 偏移"}
407
+ },
408
+ "required": ["x", "y"]
409
+ }
410
+ ))
411
+
270
412
  # ==================== 输入操作 ====================
271
413
  tools.append(Tool(
272
414
  name="mobile_input_text_by_id",
@@ -412,20 +554,20 @@ class MobileMCPServer:
412
554
 
413
555
  tools.append(Tool(
414
556
  name="mobile_close_popup",
415
- description="""🚫 智能关闭弹窗(直接点击)
557
+ description="""🚫 智能关闭弹窗
416
558
 
417
- 自动识别并点击关闭按钮,一步完成。
559
+ 通过控件树识别并点击关闭按钮(×、关闭、跳过等)。
418
560
 
419
- 🎯 识别策略:
420
- 1. 文本匹配:×、X、关闭、取消、跳过
421
- 2. 描述匹配:content-desc 包含 close/关闭
422
- 3. ImageView/ImageButton 小元素
423
- 4. clickable 的小尺寸元素(角落位置优先)
561
+ 控件树有元素时:直接点击,实时可靠
562
+ 控件树无元素时:截图供 AI 分析
563
+
564
+ ⚠️ 【时序限制】如果需要截图分析:
565
+ - 分析期间弹窗可能自动消失
566
+ - 对于定时弹窗(如广告),建议等待其自动消失
567
+ - 点击前可再次截图确认弹窗是否还在
424
568
 
425
- ⚠️ 如果自动识别失败:
426
- - 会截图供 AI 分析
427
- - 用 mobile_find_close_button 先查看候选位置
428
- - 或用 mobile_click_by_percent 手动点击""",
569
+ 🔴 【必须】点击关闭后,必须再次截图确认弹窗是否真的关闭了!
570
+ 如果弹窗仍在,需要尝试其他方法或位置。""",
429
571
  inputSchema={"type": "object", "properties": {}, "required": []}
430
572
  ))
431
573
 
@@ -511,6 +653,21 @@ class MobileMCPServer:
511
653
  result = self.tools.get_screen_size()
512
654
  return [TextContent(type="text", text=self.format_response(result))]
513
655
 
656
+ elif name == "mobile_screenshot_with_grid":
657
+ result = self.tools.take_screenshot_with_grid(
658
+ grid_size=arguments.get("grid_size", 100),
659
+ show_popup_hints=arguments.get("show_popup_hints", True)
660
+ )
661
+ return [TextContent(type="text", text=self.format_response(result))]
662
+
663
+ elif name == "mobile_screenshot_with_som":
664
+ result = self.tools.take_screenshot_with_som()
665
+ return [TextContent(type="text", text=self.format_response(result))]
666
+
667
+ elif name == "mobile_click_by_som":
668
+ result = self.tools.click_by_som(arguments["index"])
669
+ return [TextContent(type="text", text=self.format_response(result))]
670
+
514
671
  # 点击
515
672
  elif name == "mobile_click_at_coords":
516
673
  result = self.tools.click_at_coords(
@@ -537,6 +694,43 @@ class MobileMCPServer:
537
694
  result = self.tools.click_by_percent(arguments["x_percent"], arguments["y_percent"])
538
695
  return [TextContent(type="text", text=self.format_response(result))]
539
696
 
697
+ # 长按
698
+ elif name == "mobile_long_press_by_id":
699
+ result = self.tools.long_press_by_id(
700
+ arguments["resource_id"],
701
+ arguments.get("duration", 1.0)
702
+ )
703
+ return [TextContent(type="text", text=self.format_response(result))]
704
+
705
+ elif name == "mobile_long_press_by_text":
706
+ result = self.tools.long_press_by_text(
707
+ arguments["text"],
708
+ arguments.get("duration", 1.0)
709
+ )
710
+ return [TextContent(type="text", text=self.format_response(result))]
711
+
712
+ elif name == "mobile_long_press_by_percent":
713
+ result = self.tools.long_press_by_percent(
714
+ arguments["x_percent"],
715
+ arguments["y_percent"],
716
+ arguments.get("duration", 1.0)
717
+ )
718
+ return [TextContent(type="text", text=self.format_response(result))]
719
+
720
+ elif name == "mobile_long_press_at_coords":
721
+ result = self.tools.long_press_at_coords(
722
+ arguments["x"],
723
+ arguments["y"],
724
+ arguments.get("duration", 1.0),
725
+ arguments.get("image_width", 0),
726
+ arguments.get("image_height", 0),
727
+ arguments.get("crop_offset_x", 0),
728
+ arguments.get("crop_offset_y", 0),
729
+ arguments.get("original_img_width", 0),
730
+ arguments.get("original_img_height", 0)
731
+ )
732
+ return [TextContent(type="text", text=self.format_response(result))]
733
+
540
734
  # 输入
541
735
  elif name == "mobile_input_text_by_id":
542
736
  result = self.tools.input_text_by_id(arguments["resource_id"], arguments["text"])
@@ -637,7 +831,7 @@ async def async_main():
637
831
  async def call_tool(name: str, arguments: dict):
638
832
  return await server.handle_tool_call(name, arguments)
639
833
 
640
- print("🚀 Mobile MCP Server 启动中... [20 个工具]", file=sys.stderr)
834
+ print("🚀 Mobile MCP Server 启动中... [24 个工具]", file=sys.stderr)
641
835
  print("📱 支持 Android / iOS", file=sys.stderr)
642
836
  print("👁️ 完全依赖 Cursor 视觉能力,无需 AI 密钥", file=sys.stderr)
643
837
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: mobile-mcp-ai
3
- Version: 2.3.9
3
+ Version: 2.4.2
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,6 +31,21 @@ 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"
34
49
  Provides-Extra: all
35
50
  Requires-Dist: dashscope>=1.10.0; extra == "all"
36
51
  Requires-Dist: openai>=1.0.0; extra == "all"
@@ -40,20 +55,19 @@ Requires-Dist: selenium>=4.0.0; extra == "all"
40
55
  Requires-Dist: pytest>=8.0.0; extra == "all"
41
56
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "all"
42
57
  Requires-Dist: allure-pytest>=2.13.0; extra == "all"
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: Appium-Python-Client>=3.0.0; extra == "ios"
53
- Provides-Extra: test
54
- Requires-Dist: pytest>=8.0.0; extra == "test"
55
- Requires-Dist: pytest-asyncio>=0.21.0; extra == "test"
56
- Requires-Dist: allure-pytest>=2.13.0; extra == "test"
58
+ Dynamic: author
59
+ Dynamic: author-email
60
+ Dynamic: classifier
61
+ Dynamic: description
62
+ Dynamic: description-content-type
63
+ Dynamic: home-page
64
+ Dynamic: keywords
65
+ Dynamic: license-file
66
+ Dynamic: project-url
67
+ Dynamic: provides-extra
68
+ Dynamic: requires-dist
69
+ Dynamic: requires-python
70
+ Dynamic: summary
57
71
 
58
72
  # 📱 Mobile MCP AI
59
73
 
@@ -1,10 +1,10 @@
1
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=ki2hTa-1Liupuvf0alQSQMRvKiZM2FJ-hdLVCAVSBOA,83010
4
+ mobile_mcp/core/basic_tools_lite.py,sha256=zFBh2GV_MNjy_kstTaudwkMmxJ7lx5Y8QTlSTcL8pAw,128383
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
- mobile_mcp/core/ios_client_wda.py,sha256=QUAoILP3P54YF1TtwgTNXxh8C_uHbuUjlMEdghA6-mk,18757
7
+ mobile_mcp/core/ios_client_wda.py,sha256=6xocIy6rgXQr-2f5oEmRlYymJhekf-KXBn_MzRALbmc,18761
8
8
  mobile_mcp/core/ios_device_manager_wda.py,sha256=A44glqI-24un7qST-E3w6BQD8mV92YVUbxy4rLlTScY,11264
9
9
  mobile_mcp/core/mobile_client.py,sha256=bno3HvU-QSAC3G4TnoFngTxqXeu-ZP5rGlEWdWh8jOo,62570
10
10
  mobile_mcp/core/utils/__init__.py,sha256=RhMMsPszmEn8Q8GoNufypVSHJxyM9lio9U6jjpnuoPI,378
@@ -12,14 +12,14 @@ mobile_mcp/core/utils/logger.py,sha256=XXQAHUwT1jc70pq_tYFmL6f_nKrFlYm3hcgl-5RYR
12
12
  mobile_mcp/core/utils/operation_history_manager.py,sha256=gi8S8HJAMqvkUrY7_-kVbko3Xt7c4GAUziEujRd-N-Y,4792
13
13
  mobile_mcp/core/utils/smart_wait.py,sha256=PvKXImfN9Irru3bQJUjf4FLGn8LjY2VLzUNEl-i7xLE,8601
14
14
  mobile_mcp/mcp_tools/__init__.py,sha256=xkro8Rwqv_55YlVyhh-3DgRFSsLE3h1r31VIb3bpM6E,143
15
- mobile_mcp/mcp_tools/mcp_server.py,sha256=Gj9rQtpcVEO1FT5Gso9WydQu_CcGjxxbh4uV6Ut5xaI,29101
15
+ mobile_mcp/mcp_tools/mcp_server.py,sha256=QEehNZCSQjyaH-ST7kmAc6lu0kbgpCpCi3MCHDmA1ZI,39504
16
16
  mobile_mcp/utils/__init__.py,sha256=8EH0i7UGtx1y_j_GEgdN-cZdWn2sRtZSEOLlNF9HRnY,158
17
17
  mobile_mcp/utils/logger.py,sha256=Sqq2Nr0Y4p03erqcrbYKVPCGiFaNGHMcE_JwCkeOfU4,3626
18
18
  mobile_mcp/utils/xml_formatter.py,sha256=uwTRb3vLbqhT8O-udzWT7s7LsV-DyDUz2DkofD3hXOE,4556
19
19
  mobile_mcp/utils/xml_parser.py,sha256=QhL8CWbdmNDzmBLjtx6mEnjHgMFZzJeHpCL15qfXSpI,3926
20
- mobile_mcp_ai-2.3.9.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
21
- mobile_mcp_ai-2.3.9.dist-info/METADATA,sha256=t_t_XDylk8sWdLkT276_v85ExSx7Ux8UX85sxtWRP28,9423
22
- mobile_mcp_ai-2.3.9.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
23
- mobile_mcp_ai-2.3.9.dist-info/entry_points.txt,sha256=KB_FglozgPHBprSM1vFbIzGyheFuHFmGanscRdMJ_8A,68
24
- mobile_mcp_ai-2.3.9.dist-info/top_level.txt,sha256=lLm6YpbTv855Lbh8BIA0rPxhybIrvYUzMEk9OErHT94,11
25
- mobile_mcp_ai-2.3.9.dist-info/RECORD,,
20
+ mobile_mcp_ai-2.4.2.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
21
+ mobile_mcp_ai-2.4.2.dist-info/METADATA,sha256=z3H9ls_6ui6xqtBzsk93FBY-E3oHlY2lSGNADimt-hU,9745
22
+ mobile_mcp_ai-2.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ mobile_mcp_ai-2.4.2.dist-info/entry_points.txt,sha256=KB_FglozgPHBprSM1vFbIzGyheFuHFmGanscRdMJ_8A,68
24
+ mobile_mcp_ai-2.4.2.dist-info/top_level.txt,sha256=lLm6YpbTv855Lbh8BIA0rPxhybIrvYUzMEk9OErHT94,11
25
+ mobile_mcp_ai-2.4.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.45.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5