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.
- mobile_mcp/core/basic_tools_lite.py +939 -18
- mobile_mcp/core/ios_client_wda.py +4 -0
- mobile_mcp/mcp_tools/mcp_server.py +247 -53
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info}/METADATA +30 -16
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info}/RECORD +9 -9
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info}/WHEEL +1 -1
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info}/entry_points.txt +0 -0
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info/licenses}/LICENSE +0 -0
- {mobile_mcp_ai-2.3.9.dist-info → mobile_mcp_ai-2.4.2.dist-info}/top_level.txt +0 -0
|
@@ -5,7 +5,7 @@ Mobile MCP Server - 统一入口
|
|
|
5
5
|
|
|
6
6
|
纯 MCP 方案,完全依赖 Cursor 视觉能力:
|
|
7
7
|
- 不需要 AI 密钥
|
|
8
|
-
-
|
|
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="📋
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
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="📸
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"-
|
|
165
|
-
"
|
|
166
|
-
"
|
|
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="👆
|
|
195
|
-
"✅
|
|
196
|
-
"
|
|
197
|
-
"
|
|
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
|
|
210
|
-
"✅
|
|
211
|
-
"
|
|
212
|
-
"
|
|
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="👆
|
|
225
|
-
"
|
|
226
|
-
"
|
|
227
|
-
"
|
|
228
|
-
"-
|
|
229
|
-
"
|
|
230
|
-
"
|
|
231
|
-
"
|
|
232
|
-
"
|
|
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
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
561
|
+
✅ 控件树有元素时:直接点击,实时可靠
|
|
562
|
+
❌ 控件树无元素时:截图供 AI 分析
|
|
563
|
+
|
|
564
|
+
⚠️ 【时序限制】如果需要截图分析:
|
|
565
|
+
- 分析期间弹窗可能自动消失
|
|
566
|
+
- 对于定时弹窗(如广告),建议等待其自动消失
|
|
567
|
+
- 点击前可再次截图确认弹窗是否还在
|
|
424
568
|
|
|
425
|
-
|
|
426
|
-
|
|
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 启动中... [
|
|
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
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mobile-mcp-ai
|
|
3
|
-
Version: 2.
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
21
|
-
mobile_mcp_ai-2.
|
|
22
|
-
mobile_mcp_ai-2.
|
|
23
|
-
mobile_mcp_ai-2.
|
|
24
|
-
mobile_mcp_ai-2.
|
|
25
|
-
mobile_mcp_ai-2.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|