mobile-mcp-ai 2.1.2__py3-none-any.whl → 2.5.8__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 +34 -0
- mobile_mcp/config.py +142 -0
- mobile_mcp/core/basic_tools_lite.py +3266 -0
- {core → mobile_mcp/core}/device_manager.py +2 -2
- mobile_mcp/core/dynamic_config.py +272 -0
- mobile_mcp/core/ios_client_wda.py +569 -0
- mobile_mcp/core/ios_device_manager_wda.py +306 -0
- {core → mobile_mcp/core}/mobile_client.py +279 -39
- mobile_mcp/core/template_matcher.py +429 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_151217.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_152037.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_152840.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_153256.png +0 -0
- mobile_mcp/core/templates/close_buttons/auto_x_0112_154847.png +0 -0
- mobile_mcp/core/templates/close_buttons/gray_x_stock_ad.png +0 -0
- {core → mobile_mcp/core}/utils/smart_wait.py +3 -3
- mobile_mcp/mcp_tools/__init__.py +10 -0
- mobile_mcp/mcp_tools/mcp_server.py +1071 -0
- mobile_mcp_ai-2.5.8.dist-info/METADATA +469 -0
- mobile_mcp_ai-2.5.8.dist-info/RECORD +32 -0
- mobile_mcp_ai-2.5.8.dist-info/entry_points.txt +2 -0
- mobile_mcp_ai-2.5.8.dist-info/licenses/LICENSE +201 -0
- mobile_mcp_ai-2.5.8.dist-info/top_level.txt +1 -0
- core/ai/__init__.py +0 -11
- core/ai/ai_analyzer.py +0 -197
- core/ai/ai_config.py +0 -116
- core/ai/ai_platform_adapter.py +0 -399
- core/ai/smart_test_executor.py +0 -520
- core/ai/test_generator.py +0 -365
- core/ai/test_generator_from_history.py +0 -391
- core/ai/test_generator_standalone.py +0 -293
- core/assertion/__init__.py +0 -9
- core/assertion/smart_assertion.py +0 -341
- core/basic_tools.py +0 -377
- core/h5/__init__.py +0 -10
- core/h5/h5_handler.py +0 -548
- core/ios_client.py +0 -219
- core/ios_device_manager.py +0 -252
- core/locator/__init__.py +0 -10
- core/locator/cursor_ai_auto_analyzer.py +0 -119
- core/locator/cursor_vision_helper.py +0 -414
- core/locator/mobile_smart_locator.py +0 -1640
- core/locator/position_analyzer.py +0 -813
- core/locator/script_updater.py +0 -157
- core/nl_test_runner.py +0 -585
- core/smart_app_launcher.py +0 -334
- core/smart_tools.py +0 -311
- mcp/__init__.py +0 -8
- mcp/mcp_server.py +0 -1919
- mcp/mcp_server_simple.py +0 -476
- mobile_mcp_ai-2.1.2.dist-info/METADATA +0 -567
- mobile_mcp_ai-2.1.2.dist-info/RECORD +0 -45
- mobile_mcp_ai-2.1.2.dist-info/entry_points.txt +0 -2
- mobile_mcp_ai-2.1.2.dist-info/top_level.txt +0 -4
- vision/__init__.py +0 -10
- vision/vision_locator.py +0 -404
- {core → mobile_mcp/core}/__init__.py +0 -0
- {core → mobile_mcp/core}/utils/__init__.py +0 -0
- {core → mobile_mcp/core}/utils/logger.py +0 -0
- {core → mobile_mcp/core}/utils/operation_history_manager.py +0 -0
- {utils → mobile_mcp/utils}/__init__.py +0 -0
- {utils → mobile_mcp/utils}/logger.py +0 -0
- {utils → mobile_mcp/utils}/xml_formatter.py +0 -0
- {utils → mobile_mcp/utils}/xml_parser.py +0 -0
- {mobile_mcp_ai-2.1.2.dist-info → mobile_mcp_ai-2.5.8.dist-info}/WHEEL +0 -0
mcp/mcp_server_simple.py
DELETED
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Mobile MCP Server(重构版)- AI 可选
|
|
5
|
-
|
|
6
|
-
架构说明:
|
|
7
|
-
- 基础工具:不需要 AI 密钥,提供精确的元素操作
|
|
8
|
-
- 智能工具:需要 AI 密钥(可选),提供自然语言定位
|
|
9
|
-
|
|
10
|
-
用户可以选择:
|
|
11
|
-
1. 只用基础工具 → 不需要配置 AI
|
|
12
|
-
2. 启用智能功能 → 需要配置 AI(创建 .env 文件)
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
import asyncio
|
|
16
|
-
import sys
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
from typing import Optional
|
|
19
|
-
|
|
20
|
-
# 添加项目路径
|
|
21
|
-
mobile_mcp_dir = Path(__file__).parent.parent
|
|
22
|
-
project_root = mobile_mcp_dir.parent.parent
|
|
23
|
-
backend_dir = project_root / "backend"
|
|
24
|
-
|
|
25
|
-
sys.path.insert(0, str(project_root))
|
|
26
|
-
sys.path.insert(0, str(backend_dir))
|
|
27
|
-
|
|
28
|
-
from mcp.types import Tool, TextContent
|
|
29
|
-
from mcp.server import Server
|
|
30
|
-
from mcp.server.stdio import stdio_server
|
|
31
|
-
|
|
32
|
-
from mobile_mcp.core.mobile_client import MobileClient
|
|
33
|
-
from mobile_mcp.core.basic_tools import BasicMobileTools
|
|
34
|
-
from mobile_mcp.core.smart_tools import SmartMobileTools
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class SimpleMobileMCPServer:
|
|
38
|
-
"""简化的 Mobile MCP Server"""
|
|
39
|
-
|
|
40
|
-
def __init__(self):
|
|
41
|
-
"""初始化 MCP Server"""
|
|
42
|
-
self.client: Optional[MobileClient] = None
|
|
43
|
-
self.basic_tools: Optional[BasicMobileTools] = None
|
|
44
|
-
self.smart_tools: Optional[SmartMobileTools] = None
|
|
45
|
-
self._initialized = False
|
|
46
|
-
|
|
47
|
-
async def initialize(self):
|
|
48
|
-
"""延迟初始化设备连接"""
|
|
49
|
-
if not self._initialized:
|
|
50
|
-
# 初始化移动客户端
|
|
51
|
-
self.client = MobileClient()
|
|
52
|
-
|
|
53
|
-
# 初始化基础工具(总是可用)
|
|
54
|
-
self.basic_tools = BasicMobileTools(self.client)
|
|
55
|
-
|
|
56
|
-
# 初始化智能工具(检查 AI 可用性)
|
|
57
|
-
self.smart_tools = SmartMobileTools(self.client)
|
|
58
|
-
|
|
59
|
-
ai_status = self.smart_tools.get_ai_status()
|
|
60
|
-
print(f"\n{ai_status['message']}\n", file=sys.stderr)
|
|
61
|
-
|
|
62
|
-
self._initialized = True
|
|
63
|
-
|
|
64
|
-
def get_tools(self):
|
|
65
|
-
"""注册 MCP 工具"""
|
|
66
|
-
tools = []
|
|
67
|
-
|
|
68
|
-
# ==================== 基础工具(不需要 AI)====================
|
|
69
|
-
|
|
70
|
-
tools.extend([
|
|
71
|
-
Tool(
|
|
72
|
-
name="mobile_list_elements",
|
|
73
|
-
description="📋 列出页面所有可交互元素(不需要 AI)。返回 resource_id, text, bounds 等信息,供后续精确操作使用。",
|
|
74
|
-
inputSchema={
|
|
75
|
-
"type": "object",
|
|
76
|
-
"properties": {},
|
|
77
|
-
"required": []
|
|
78
|
-
}
|
|
79
|
-
),
|
|
80
|
-
Tool(
|
|
81
|
-
name="mobile_click_by_id",
|
|
82
|
-
description="👆 通过 resource-id 点击元素(不需要 AI)。精确可靠的点击方式。先用 mobile_list_elements 查找元素 ID。",
|
|
83
|
-
inputSchema={
|
|
84
|
-
"type": "object",
|
|
85
|
-
"properties": {
|
|
86
|
-
"resource_id": {
|
|
87
|
-
"type": "string",
|
|
88
|
-
"description": "元素的 resource-id,如 'com.app:id/search_btn'"
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
"required": ["resource_id"]
|
|
92
|
-
}
|
|
93
|
-
),
|
|
94
|
-
Tool(
|
|
95
|
-
name="mobile_click_by_text",
|
|
96
|
-
description="👆 通过文本内容点击元素(不需要 AI)。适合文本完全匹配的场景。",
|
|
97
|
-
inputSchema={
|
|
98
|
-
"type": "object",
|
|
99
|
-
"properties": {
|
|
100
|
-
"text": {
|
|
101
|
-
"type": "string",
|
|
102
|
-
"description": "元素的文本内容(精确匹配),如 '登录'"
|
|
103
|
-
}
|
|
104
|
-
},
|
|
105
|
-
"required": ["text"]
|
|
106
|
-
}
|
|
107
|
-
),
|
|
108
|
-
Tool(
|
|
109
|
-
name="mobile_click_at_coords",
|
|
110
|
-
description="👆 点击指定坐标(不需要 AI)。可以从 mobile_list_elements 获取的 bounds 计算坐标。",
|
|
111
|
-
inputSchema={
|
|
112
|
-
"type": "object",
|
|
113
|
-
"properties": {
|
|
114
|
-
"x": {
|
|
115
|
-
"type": "number",
|
|
116
|
-
"description": "X 坐标(像素)"
|
|
117
|
-
},
|
|
118
|
-
"y": {
|
|
119
|
-
"type": "number",
|
|
120
|
-
"description": "Y 坐标(像素)"
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
"required": ["x", "y"]
|
|
124
|
-
}
|
|
125
|
-
),
|
|
126
|
-
Tool(
|
|
127
|
-
name="mobile_input_text_by_id",
|
|
128
|
-
description="⌨️ 通过 resource-id 在输入框输入文本(不需要 AI)。",
|
|
129
|
-
inputSchema={
|
|
130
|
-
"type": "object",
|
|
131
|
-
"properties": {
|
|
132
|
-
"resource_id": {
|
|
133
|
-
"type": "string",
|
|
134
|
-
"description": "输入框的 resource-id"
|
|
135
|
-
},
|
|
136
|
-
"text": {
|
|
137
|
-
"type": "string",
|
|
138
|
-
"description": "要输入的文本"
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
"required": ["resource_id", "text"]
|
|
142
|
-
}
|
|
143
|
-
),
|
|
144
|
-
Tool(
|
|
145
|
-
name="mobile_find_elements_by_class",
|
|
146
|
-
description="🔍 按类名查找元素(不需要 AI)。如查找所有输入框: 'android.widget.EditText'",
|
|
147
|
-
inputSchema={
|
|
148
|
-
"type": "object",
|
|
149
|
-
"properties": {
|
|
150
|
-
"class_name": {
|
|
151
|
-
"type": "string",
|
|
152
|
-
"description": "类名,如 'android.widget.EditText'"
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
"required": ["class_name"]
|
|
156
|
-
}
|
|
157
|
-
),
|
|
158
|
-
Tool(
|
|
159
|
-
name="mobile_wait_for_element",
|
|
160
|
-
description="⏳ 等待元素出现(不需要 AI)。用于等待页面加载完成。",
|
|
161
|
-
inputSchema={
|
|
162
|
-
"type": "object",
|
|
163
|
-
"properties": {
|
|
164
|
-
"resource_id": {
|
|
165
|
-
"type": "string",
|
|
166
|
-
"description": "元素的 resource-id"
|
|
167
|
-
},
|
|
168
|
-
"timeout": {
|
|
169
|
-
"type": "number",
|
|
170
|
-
"description": "超时时间(秒),默认 10秒",
|
|
171
|
-
"default": 10
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
"required": ["resource_id"]
|
|
175
|
-
}
|
|
176
|
-
),
|
|
177
|
-
Tool(
|
|
178
|
-
name="mobile_take_screenshot",
|
|
179
|
-
description="📸 截取屏幕截图(不需要 AI)。用于 Cursor AI 视觉识别、调试或记录测试过程。",
|
|
180
|
-
inputSchema={
|
|
181
|
-
"type": "object",
|
|
182
|
-
"properties": {
|
|
183
|
-
"description": {
|
|
184
|
-
"type": "string",
|
|
185
|
-
"description": "截图描述(可选),用于生成文件名"
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
"required": []
|
|
189
|
-
}
|
|
190
|
-
),
|
|
191
|
-
Tool(
|
|
192
|
-
name="mobile_take_screenshot_region",
|
|
193
|
-
description="📸 截取屏幕指定区域(不需要 AI)。用于局部截图和分析。",
|
|
194
|
-
inputSchema={
|
|
195
|
-
"type": "object",
|
|
196
|
-
"properties": {
|
|
197
|
-
"x1": {
|
|
198
|
-
"type": "number",
|
|
199
|
-
"description": "左上角X坐标"
|
|
200
|
-
},
|
|
201
|
-
"y1": {
|
|
202
|
-
"type": "number",
|
|
203
|
-
"description": "左上角Y坐标"
|
|
204
|
-
},
|
|
205
|
-
"x2": {
|
|
206
|
-
"type": "number",
|
|
207
|
-
"description": "右下角X坐标"
|
|
208
|
-
},
|
|
209
|
-
"y2": {
|
|
210
|
-
"type": "number",
|
|
211
|
-
"description": "右下角Y坐标"
|
|
212
|
-
},
|
|
213
|
-
"description": {
|
|
214
|
-
"type": "string",
|
|
215
|
-
"description": "截图描述(可选)"
|
|
216
|
-
}
|
|
217
|
-
},
|
|
218
|
-
"required": ["x1", "y1", "x2", "y2"]
|
|
219
|
-
}
|
|
220
|
-
),
|
|
221
|
-
])
|
|
222
|
-
|
|
223
|
-
# ==================== 智能工具(需要 AI,可选)====================
|
|
224
|
-
|
|
225
|
-
tools.extend([
|
|
226
|
-
Tool(
|
|
227
|
-
name="mobile_smart_click",
|
|
228
|
-
description="🤖 智能定位并点击(需要 AI 密钥,可选功能)。使用自然语言描述元素,如'右上角的设置按钮'。\n\n"
|
|
229
|
-
"⚠️ 如未配置 AI,请使用基础工具:mobile_list_elements + mobile_click_by_id",
|
|
230
|
-
inputSchema={
|
|
231
|
-
"type": "object",
|
|
232
|
-
"properties": {
|
|
233
|
-
"description": {
|
|
234
|
-
"type": "string",
|
|
235
|
-
"description": "元素的自然语言描述,如 '顶部搜索框'、'登录按钮'"
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
"required": ["description"]
|
|
239
|
-
}
|
|
240
|
-
),
|
|
241
|
-
Tool(
|
|
242
|
-
name="mobile_smart_input",
|
|
243
|
-
description="🤖 智能定位输入框并输入(需要 AI 密钥,可选功能)。使用自然语言描述输入框。\n\n"
|
|
244
|
-
"⚠️ 如未配置 AI,请使用:mobile_input_text_by_id",
|
|
245
|
-
inputSchema={
|
|
246
|
-
"type": "object",
|
|
247
|
-
"properties": {
|
|
248
|
-
"description": {
|
|
249
|
-
"type": "string",
|
|
250
|
-
"description": "输入框的自然语言描述,如 '用户名输入框'"
|
|
251
|
-
},
|
|
252
|
-
"text": {
|
|
253
|
-
"type": "string",
|
|
254
|
-
"description": "要输入的文本"
|
|
255
|
-
}
|
|
256
|
-
},
|
|
257
|
-
"required": ["description", "text"]
|
|
258
|
-
}
|
|
259
|
-
),
|
|
260
|
-
Tool(
|
|
261
|
-
name="mobile_analyze_screenshot",
|
|
262
|
-
description="🤖 使用 AI 分析截图并返回坐标(需要 AI 密钥,可选功能)。用于 Cursor AI 无法直接识别的复杂场景。\n\n"
|
|
263
|
-
"使用流程:\n"
|
|
264
|
-
"1. 先用 mobile_take_screenshot 截图\n"
|
|
265
|
-
"2. 调用此工具分析截图\n"
|
|
266
|
-
"3. 根据返回的坐标使用 mobile_click_at_coords 点击\n\n"
|
|
267
|
-
"⚠️ 需要配置支持视觉识别的 AI(GPT-4V、Claude 3、Qwen-VL)",
|
|
268
|
-
inputSchema={
|
|
269
|
-
"type": "object",
|
|
270
|
-
"properties": {
|
|
271
|
-
"screenshot_path": {
|
|
272
|
-
"type": "string",
|
|
273
|
-
"description": "截图文件路径"
|
|
274
|
-
},
|
|
275
|
-
"description": {
|
|
276
|
-
"type": "string",
|
|
277
|
-
"description": "要查找的元素描述"
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
"required": ["screenshot_path", "description"]
|
|
281
|
-
}
|
|
282
|
-
),
|
|
283
|
-
Tool(
|
|
284
|
-
name="mobile_get_ai_status",
|
|
285
|
-
description="ℹ️ 获取 AI 功能状态。检查是否已配置 AI 密钥,智能工具是否可用。",
|
|
286
|
-
inputSchema={
|
|
287
|
-
"type": "object",
|
|
288
|
-
"properties": {},
|
|
289
|
-
"required": []
|
|
290
|
-
}
|
|
291
|
-
),
|
|
292
|
-
])
|
|
293
|
-
|
|
294
|
-
# ==================== 通用工具 ====================
|
|
295
|
-
|
|
296
|
-
tools.extend([
|
|
297
|
-
Tool(
|
|
298
|
-
name="mobile_snapshot",
|
|
299
|
-
description="📸 获取页面快照。查看当前页面结构和元素信息。",
|
|
300
|
-
inputSchema={
|
|
301
|
-
"type": "object",
|
|
302
|
-
"properties": {},
|
|
303
|
-
"required": []
|
|
304
|
-
}
|
|
305
|
-
),
|
|
306
|
-
Tool(
|
|
307
|
-
name="mobile_launch_app",
|
|
308
|
-
description="🚀 启动应用",
|
|
309
|
-
inputSchema={
|
|
310
|
-
"type": "object",
|
|
311
|
-
"properties": {
|
|
312
|
-
"package_name": {
|
|
313
|
-
"type": "string",
|
|
314
|
-
"description": "应用包名"
|
|
315
|
-
}
|
|
316
|
-
},
|
|
317
|
-
"required": ["package_name"]
|
|
318
|
-
}
|
|
319
|
-
),
|
|
320
|
-
Tool(
|
|
321
|
-
name="mobile_press_key",
|
|
322
|
-
description="⌨️ 按键操作(home, back, enter 等)",
|
|
323
|
-
inputSchema={
|
|
324
|
-
"type": "object",
|
|
325
|
-
"properties": {
|
|
326
|
-
"key": {
|
|
327
|
-
"type": "string",
|
|
328
|
-
"description": "按键名称:home, back, enter, search"
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
"required": ["key"]
|
|
332
|
-
}
|
|
333
|
-
),
|
|
334
|
-
Tool(
|
|
335
|
-
name="mobile_swipe",
|
|
336
|
-
description="👆 滑动屏幕",
|
|
337
|
-
inputSchema={
|
|
338
|
-
"type": "object",
|
|
339
|
-
"properties": {
|
|
340
|
-
"direction": {
|
|
341
|
-
"type": "string",
|
|
342
|
-
"enum": ["up", "down", "left", "right"],
|
|
343
|
-
"description": "滑动方向"
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
"required": ["direction"]
|
|
347
|
-
}
|
|
348
|
-
),
|
|
349
|
-
])
|
|
350
|
-
|
|
351
|
-
return tools
|
|
352
|
-
|
|
353
|
-
async def handle_tool_call(self, name: str, arguments: dict):
|
|
354
|
-
"""处理工具调用"""
|
|
355
|
-
await self.initialize()
|
|
356
|
-
|
|
357
|
-
try:
|
|
358
|
-
# ==================== 基础工具 ====================
|
|
359
|
-
if name == "mobile_list_elements":
|
|
360
|
-
result = self.basic_tools.list_elements()
|
|
361
|
-
return [TextContent(type="text", text=str(result))]
|
|
362
|
-
|
|
363
|
-
elif name == "mobile_click_by_id":
|
|
364
|
-
result = self.basic_tools.click_by_id(arguments["resource_id"])
|
|
365
|
-
return [TextContent(type="text", text=str(result))]
|
|
366
|
-
|
|
367
|
-
elif name == "mobile_click_by_text":
|
|
368
|
-
result = self.basic_tools.click_by_text(arguments["text"])
|
|
369
|
-
return [TextContent(type="text", text=str(result))]
|
|
370
|
-
|
|
371
|
-
elif name == "mobile_click_at_coords":
|
|
372
|
-
result = self.basic_tools.click_at_coords(arguments["x"], arguments["y"])
|
|
373
|
-
return [TextContent(type="text", text=str(result))]
|
|
374
|
-
|
|
375
|
-
elif name == "mobile_input_text_by_id":
|
|
376
|
-
result = self.basic_tools.input_text_by_id(
|
|
377
|
-
arguments["resource_id"],
|
|
378
|
-
arguments["text"]
|
|
379
|
-
)
|
|
380
|
-
return [TextContent(type="text", text=str(result))]
|
|
381
|
-
|
|
382
|
-
elif name == "mobile_find_elements_by_class":
|
|
383
|
-
result = self.basic_tools.find_elements_by_class(arguments["class_name"])
|
|
384
|
-
return [TextContent(type="text", text=str(result))]
|
|
385
|
-
|
|
386
|
-
elif name == "mobile_wait_for_element":
|
|
387
|
-
timeout = arguments.get("timeout", 10)
|
|
388
|
-
result = self.basic_tools.wait_for_element(arguments["resource_id"], timeout)
|
|
389
|
-
return [TextContent(type="text", text=str(result))]
|
|
390
|
-
|
|
391
|
-
elif name == "mobile_take_screenshot":
|
|
392
|
-
description = arguments.get("description", "")
|
|
393
|
-
result = self.basic_tools.take_screenshot(description)
|
|
394
|
-
return [TextContent(type="text", text=str(result))]
|
|
395
|
-
|
|
396
|
-
elif name == "mobile_take_screenshot_region":
|
|
397
|
-
description = arguments.get("description", "")
|
|
398
|
-
result = self.basic_tools.take_screenshot_region(
|
|
399
|
-
arguments["x1"], arguments["y1"],
|
|
400
|
-
arguments["x2"], arguments["y2"],
|
|
401
|
-
description
|
|
402
|
-
)
|
|
403
|
-
return [TextContent(type="text", text=str(result))]
|
|
404
|
-
|
|
405
|
-
# ==================== 智能工具 ====================
|
|
406
|
-
elif name == "mobile_smart_click":
|
|
407
|
-
result = await self.smart_tools.smart_click(arguments["description"])
|
|
408
|
-
return [TextContent(type="text", text=str(result))]
|
|
409
|
-
|
|
410
|
-
elif name == "mobile_smart_input":
|
|
411
|
-
result = await self.smart_tools.smart_input(
|
|
412
|
-
arguments["description"],
|
|
413
|
-
arguments["text"]
|
|
414
|
-
)
|
|
415
|
-
return [TextContent(type="text", text=str(result))]
|
|
416
|
-
|
|
417
|
-
elif name == "mobile_analyze_screenshot":
|
|
418
|
-
result = await self.smart_tools.analyze_screenshot_with_ai(
|
|
419
|
-
arguments["screenshot_path"],
|
|
420
|
-
arguments["description"]
|
|
421
|
-
)
|
|
422
|
-
return [TextContent(type="text", text=str(result))]
|
|
423
|
-
|
|
424
|
-
elif name == "mobile_get_ai_status":
|
|
425
|
-
result = self.smart_tools.get_ai_status()
|
|
426
|
-
return [TextContent(type="text", text=str(result))]
|
|
427
|
-
|
|
428
|
-
# ==================== 通用工具 ====================
|
|
429
|
-
elif name == "mobile_snapshot":
|
|
430
|
-
snapshot = await self.client.snapshot()
|
|
431
|
-
return [TextContent(type="text", text=snapshot)]
|
|
432
|
-
|
|
433
|
-
elif name == "mobile_launch_app":
|
|
434
|
-
await self.client.launch_app(arguments["package_name"])
|
|
435
|
-
return [TextContent(type="text", text=f"✅ 已启动: {arguments['package_name']}")]
|
|
436
|
-
|
|
437
|
-
elif name == "mobile_press_key":
|
|
438
|
-
await self.client.press_key(arguments["key"])
|
|
439
|
-
return [TextContent(type="text", text=f"✅ 已按键: {arguments['key']}")]
|
|
440
|
-
|
|
441
|
-
elif name == "mobile_swipe":
|
|
442
|
-
await self.client.swipe(arguments["direction"])
|
|
443
|
-
return [TextContent(type="text", text=f"✅ 已滑动: {arguments['direction']}")]
|
|
444
|
-
|
|
445
|
-
else:
|
|
446
|
-
return [TextContent(type="text", text=f"❌ 未知工具: {name}")]
|
|
447
|
-
|
|
448
|
-
except Exception as e:
|
|
449
|
-
error_msg = str(e)
|
|
450
|
-
return [TextContent(type="text", text=f"❌ 执行失败: {error_msg}")]
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
async def main():
|
|
454
|
-
"""启动 MCP Server"""
|
|
455
|
-
server = SimpleMobileMCPServer()
|
|
456
|
-
mcp_server = Server("mobile-mcp-simplified")
|
|
457
|
-
|
|
458
|
-
@mcp_server.list_tools()
|
|
459
|
-
async def list_tools():
|
|
460
|
-
return server.get_tools()
|
|
461
|
-
|
|
462
|
-
@mcp_server.call_tool()
|
|
463
|
-
async def call_tool(name: str, arguments: dict):
|
|
464
|
-
return await server.handle_tool_call(name, arguments)
|
|
465
|
-
|
|
466
|
-
print("🚀 Mobile MCP Server (简化版) 启动中...", file=sys.stderr)
|
|
467
|
-
print("📋 基础工具:总是可用(不需要 AI)", file=sys.stderr)
|
|
468
|
-
print("🤖 智能工具:需要配置 AI 密钥(可选)", file=sys.stderr)
|
|
469
|
-
|
|
470
|
-
async with stdio_server() as (read_stream, write_stream):
|
|
471
|
-
await mcp_server.run(read_stream, write_stream, mcp_server.create_initialization_options())
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
if __name__ == "__main__":
|
|
475
|
-
asyncio.run(main())
|
|
476
|
-
|