minitap-mcp 0.1.1__py3-none-any.whl → 0.4.0__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.
@@ -0,0 +1,132 @@
1
+ """Tool for navigating to a screen and comparing it with Figma design."""
2
+
3
+ import base64
4
+ from io import BytesIO
5
+
6
+ import mcp as mcp_ref
7
+ from fastmcp import Client
8
+ from fastmcp.client.client import CallToolResult
9
+ from fastmcp.exceptions import ToolError
10
+ from fastmcp.tools.tool import ToolResult
11
+ from PIL import Image
12
+ from pydantic import Field
13
+
14
+ from minitap.mcp.core.agents.compare_screenshots import compare_screenshots
15
+ from minitap.mcp.core.config import settings
16
+ from minitap.mcp.core.decorators import handle_tool_errors
17
+ from minitap.mcp.main import mcp
18
+
19
+
20
+ @mcp.tool(
21
+ name="compare_screenshot_with_figma",
22
+ description="""
23
+ Compare a screenshot of the current state with a Figma design.
24
+
25
+ This tool:
26
+ 1. Captures a screenshot of the current state
27
+ 2. Compares the live device screenshot with the Figma design
28
+ 3. Returns a detailed comparison report with both screenshots for visual context
29
+ """,
30
+ )
31
+ @handle_tool_errors
32
+ async def compare_screenshot_with_figma(
33
+ node_id: str = Field(
34
+ description=(
35
+ "The node ID of the Figma design. Expected format is ':' separated.\n"
36
+ "Example: If given the URL https://figma.com/design/:fileKey/:fileName?node-id=1-2,\n"
37
+ "the extracted nodeId would be 1:2. Strictly respect this format."
38
+ )
39
+ ),
40
+ ) -> ToolResult:
41
+ expected_screenshot_base64 = await get_figma_screenshot(node_id)
42
+
43
+ result = await compare_screenshots(
44
+ expected_screenshot_base64=expected_screenshot_base64,
45
+ )
46
+
47
+ compressed_expected = compress_image_base64(result.expected_screenshot_base64)
48
+ compressed_current = compress_image_base64(result.current_screenshot_base64)
49
+
50
+ return ToolResult(
51
+ content=[
52
+ mcp_ref.types.TextContent(
53
+ type="text",
54
+ text="## Comparison Analysis\n\n" + str(result.comparison_text),
55
+ ),
56
+ mcp_ref.types.ImageContent(
57
+ type="image",
58
+ data=compressed_expected,
59
+ mimeType="image/jpeg",
60
+ ),
61
+ mcp_ref.types.TextContent(
62
+ type="text",
63
+ text="**Expected (Figma design)** ↑\n\n**Actual (Current device)** ↓",
64
+ ),
65
+ mcp_ref.types.ImageContent(
66
+ type="image",
67
+ data=compressed_current,
68
+ mimeType="image/jpeg",
69
+ ),
70
+ ]
71
+ )
72
+
73
+
74
+ def compress_image_base64(base64_str: str, max_width: int = 800, quality: int = 75) -> str:
75
+ """Compress and resize a base64-encoded image to reduce size.
76
+
77
+ Args:
78
+ base64_str: Base64-encoded image string
79
+ max_width: Maximum width for the resized image
80
+ quality: JPEG quality (1-95, lower = smaller file)
81
+
82
+ Returns:
83
+ Compressed base64-encoded image string
84
+ """
85
+ try:
86
+ img_data = base64.b64decode(base64_str)
87
+ img = Image.open(BytesIO(img_data))
88
+
89
+ if img.mode in ("RGBA", "P", "LA"):
90
+ background = Image.new("RGB", img.size, (255, 255, 255))
91
+ if img.mode == "P":
92
+ img = img.convert("RGBA")
93
+ if "A" in img.mode:
94
+ background.paste(img, mask=img.split()[-1])
95
+ else:
96
+ background.paste(img)
97
+ img = background
98
+ elif img.mode != "RGB":
99
+ img = img.convert("RGB")
100
+
101
+ if img.width > max_width:
102
+ ratio = max_width / img.width
103
+ new_height = int(img.height * ratio)
104
+ img = img.resize((max_width, new_height), Image.Resampling.LANCZOS)
105
+
106
+ buffer = BytesIO()
107
+ img.save(buffer, format="JPEG", quality=quality, optimize=True)
108
+ compressed_data = buffer.getvalue()
109
+
110
+ return base64.b64encode(compressed_data).decode("utf-8")
111
+ except Exception:
112
+ return base64_str
113
+
114
+
115
+ async def get_figma_screenshot(node_id: str) -> str:
116
+ try:
117
+ async with Client(settings.FIGMA_MCP_SERVER_URL) as client:
118
+ result: CallToolResult = await client.call_tool(
119
+ "get_screenshot",
120
+ {
121
+ "nodeId": node_id,
122
+ "clientLanguages": "javascript",
123
+ "clientFrameworks": "react",
124
+ },
125
+ )
126
+ if len(result.content) == 0 or not isinstance(
127
+ result.content[0], mcp_ref.types.ImageContent
128
+ ):
129
+ raise ToolError("Failed to fetch screenshot from Figma")
130
+ return result.content[0].data
131
+ except Exception as e:
132
+ raise ToolError(f"Failed to fetch screenshot from Figma: {str(e)}")
@@ -3,12 +3,13 @@
3
3
  from collections.abc import Mapping
4
4
  from typing import Any
5
5
 
6
+ from fastmcp.exceptions import ToolError
6
7
  from minitap.mobile_use.sdk.types import ManualTaskConfig
7
8
  from minitap.mobile_use.sdk.types.task import PlatformTaskRequest
8
9
  from pydantic import Field
9
10
 
10
- from minitap.mcp.core.agents import agent
11
11
  from minitap.mcp.core.decorators import handle_tool_errors
12
+ from minitap.mcp.core.sdk_agent import get_mobile_use_agent
12
13
  from minitap.mcp.main import mcp
13
14
 
14
15
 
@@ -58,7 +59,8 @@ async def execute_mobile_command(
58
59
  request = PlatformTaskRequest(
59
60
  task=ManualTaskConfig(goal=goal, output_description=output_description),
60
61
  )
62
+ agent = get_mobile_use_agent()
61
63
  result = await agent.run_task(request=request)
62
64
  return _serialize_result(result)
63
- finally:
64
- agent.clean()
65
+ except Exception as e:
66
+ raise ToolError(str(e))
@@ -0,0 +1,258 @@
1
+ """Tool for fetching and saving Figma assets locally."""
2
+
3
+ import shutil
4
+ from pathlib import Path
5
+
6
+ import mcp as mcp_ref
7
+ import requests
8
+ from fastmcp import Client
9
+ from fastmcp.client.client import CallToolResult
10
+ from fastmcp.exceptions import ToolError
11
+ from fastmcp.tools.tool import ToolResult
12
+ from pydantic import Field
13
+
14
+ from minitap.mcp.core.agents.extract_figma_assets import (
15
+ ExtractedAssets,
16
+ FigmaAsset,
17
+ extract_figma_assets,
18
+ )
19
+ from minitap.mcp.core.config import settings
20
+ from minitap.mcp.core.decorators import handle_tool_errors
21
+ from minitap.mcp.core.models import (
22
+ AssetDownloadResult,
23
+ AssetDownloadSummary,
24
+ DownloadStatus,
25
+ FigmaDesignContextOutput,
26
+ )
27
+ from minitap.mcp.main import mcp
28
+ from minitap.mcp.tools.compare_screenshot_with_figma import (
29
+ compress_image_base64,
30
+ get_figma_screenshot,
31
+ )
32
+
33
+
34
+ @mcp.tool(
35
+ name="save_figma_assets",
36
+ description="""
37
+ Fetch Figma design assets/react implementation code and save them locally in the workspace.
38
+
39
+ This tool:
40
+ 1. Calls get_design_context from Figma MCP to get the React/TypeScript code
41
+ 2. Extracts all asset URLs and code implementation from the code
42
+ 3. Downloads each asset to .mobile-use/figma_assets/<node-id>/ folder
43
+ 4. Saves the code implementation to .mobile-use/figma_assets/<node-id>/code_implementation.ts
44
+ 5. Returns a list of downloaded files
45
+ """,
46
+ )
47
+ @handle_tool_errors
48
+ async def save_figma_assets(
49
+ node_id: str = Field(
50
+ description=(
51
+ "The node ID of the Figma design. Expected format is ':' separated.\n"
52
+ "Example: If given the URL https://figma.com/design/:fileKey/:fileName?node-id=1-2,\n"
53
+ "the extracted nodeId would be 1:2. Strictly respect this format."
54
+ )
55
+ ),
56
+ file_key: str = Field(
57
+ description=(
58
+ "The file key of the Figma file.\n"
59
+ "Example: If given the URL https://figma.com/design/abc123/MyFile?node-id=1-2,\n"
60
+ "the extracted fileKey would be 'abc123'."
61
+ )
62
+ ),
63
+ workspace_path: str = Field(
64
+ default=".",
65
+ description=(
66
+ "The workspace path where assets should be saved. Defaults to current directory."
67
+ ),
68
+ ),
69
+ ) -> ToolResult:
70
+ """Fetch and save Figma assets locally."""
71
+
72
+ # Step 1: Get design context from Figma MCP
73
+ design_context = await get_design_context(node_id, file_key)
74
+
75
+ # Step 2: Extract asset URLs using LLM agent
76
+ extracted_context: ExtractedAssets = await extract_figma_assets(
77
+ design_context.code_implementation
78
+ )
79
+ if not extracted_context.assets:
80
+ raise ToolError("No assets found in the Figma design context.")
81
+
82
+ # Step 3: Create directory structure
83
+ # Convert node_id format (1:2) to folder name (1-2)
84
+ folder_name = node_id.replace(":", "-")
85
+ assets_dir = Path(workspace_path) / ".mobile-use" / "figma_assets" / folder_name
86
+
87
+ # Delete existing directory to remove stale assets
88
+ if assets_dir.exists():
89
+ shutil.rmtree(assets_dir)
90
+
91
+ # Create fresh directory
92
+ assets_dir.mkdir(parents=True, exist_ok=True)
93
+
94
+ # Step 4: Download assets with resilient error handling
95
+ download_summary = AssetDownloadSummary()
96
+
97
+ for asset in extracted_context.assets:
98
+ result = download_asset(asset, assets_dir)
99
+ if result.status == DownloadStatus.SUCCESS:
100
+ download_summary.successful.append(result)
101
+ else:
102
+ download_summary.failed.append(result)
103
+
104
+ # Step 4.5: Save code implementation
105
+ code_implementation_file = assets_dir / "code_implementation.ts"
106
+
107
+ commented_code_implementation_guidelines = ""
108
+ if design_context.code_implementation_guidelines:
109
+ commented_code_implementation_guidelines = "\n".join(
110
+ ["// " + line for line in design_context.code_implementation_guidelines.split("\n")]
111
+ )
112
+
113
+ commented_nodes_guidelines = ""
114
+ if design_context.nodes_guidelines:
115
+ commented_nodes_guidelines = "\n".join(
116
+ ["// " + line for line in design_context.nodes_guidelines.split("\n")]
117
+ )
118
+
119
+ code_implementation_file.write_text(
120
+ extracted_context.code_implementation
121
+ + "\n\n"
122
+ + commented_code_implementation_guidelines
123
+ + "\n\n"
124
+ + commented_nodes_guidelines
125
+ )
126
+
127
+ # Step 5: Generate friendly output message
128
+ result_parts = []
129
+
130
+ if download_summary.successful:
131
+ result_parts.append(
132
+ f"✅ Successfully downloaded {download_summary.success_count()} asset(s) "
133
+ f"to .mobile-use/figma_assets/{folder_name}/:\n"
134
+ )
135
+ for asset_result in download_summary.successful:
136
+ result_parts.append(f" • {asset_result.filename}")
137
+
138
+ if download_summary.failed:
139
+ result_parts.append(
140
+ f"\n\n⚠️ Failed to download {download_summary.failure_count()} asset(s):"
141
+ )
142
+ for asset_result in download_summary.failed:
143
+ error_msg = f": {asset_result.error}" if asset_result.error else ""
144
+ result_parts.append(f" • {asset_result.filename}{error_msg}")
145
+
146
+ if code_implementation_file.exists():
147
+ result_parts.append(
148
+ f"\n\n✅ Successfully saved code implementation to {code_implementation_file.name}"
149
+ )
150
+
151
+ expected_screenshot = await get_figma_screenshot(node_id)
152
+ compressed_expected = compress_image_base64(expected_screenshot)
153
+
154
+ return ToolResult(
155
+ content=[
156
+ mcp_ref.types.TextContent(
157
+ type="text",
158
+ text="\n".join(result_parts),
159
+ ),
160
+ mcp_ref.types.TextContent(
161
+ type="text",
162
+ text="**Expected (Figma design)**",
163
+ ),
164
+ mcp_ref.types.ImageContent(
165
+ type="image",
166
+ data=compressed_expected,
167
+ mimeType="image/jpeg",
168
+ ),
169
+ ]
170
+ )
171
+
172
+
173
+ async def get_design_context(node_id: str, file_key: str) -> FigmaDesignContextOutput:
174
+ """Fetch design context from Figma MCP server.
175
+
176
+ Args:
177
+ node_id: The Figma node ID in format "1:2"
178
+ file_key: The Figma file key
179
+
180
+ Returns:
181
+ The React/TypeScript code as a string
182
+
183
+ Raises:
184
+ ToolError: If fetching fails
185
+ """
186
+ try:
187
+ async with Client(settings.FIGMA_MCP_SERVER_URL) as client:
188
+ result: CallToolResult = await client.call_tool(
189
+ "get_design_context",
190
+ {
191
+ "nodeId": node_id,
192
+ "fileKey": file_key,
193
+ "clientLanguages": "typescript",
194
+ "clientFrameworks": "react",
195
+ },
196
+ )
197
+
198
+ code_implementation = ""
199
+ code_implementation_guidelines = None
200
+ nodes_guidelines = None
201
+
202
+ if len(result.content) > 0 and isinstance(result.content[0], mcp_ref.types.TextContent):
203
+ code_implementation = result.content[0].text
204
+ else:
205
+ raise ToolError("Failed to fetch design context from Figma")
206
+
207
+ if len(result.content) > 1:
208
+ if isinstance(result.content[1], mcp_ref.types.TextContent):
209
+ code_implementation_guidelines = result.content[1].text
210
+ if len(result.content) > 2 and isinstance(result.content[2], mcp_ref.types.TextContent):
211
+ nodes_guidelines = result.content[2].text
212
+
213
+ return FigmaDesignContextOutput(
214
+ code_implementation=code_implementation,
215
+ code_implementation_guidelines=code_implementation_guidelines,
216
+ nodes_guidelines=nodes_guidelines,
217
+ )
218
+ except Exception as e:
219
+ raise ToolError(
220
+ f"Failed to fetch design context from Figma: {str(e)}.\n"
221
+ "Ensure the Figma MCP server is running through the official Figma desktop app."
222
+ )
223
+
224
+
225
+ def download_asset(asset: FigmaAsset, assets_dir: Path) -> AssetDownloadResult:
226
+ """Download a single asset with error handling.
227
+
228
+ Args:
229
+ asset: FigmaAsset model with variable_name, url, and extension
230
+ assets_dir: Directory to save the asset
231
+
232
+ Returns:
233
+ AssetDownloadResult with status and optional error message
234
+ """
235
+ variable_name = asset.variable_name
236
+ url = asset.url
237
+ extension = asset.extension
238
+
239
+ # Convert camelCase variable name to filename
240
+ # e.g., imgSignal -> imgSignal.svg
241
+ filename = f"{variable_name}.{extension}"
242
+ filepath = assets_dir / filename
243
+
244
+ try:
245
+ response = requests.get(url, timeout=30)
246
+ if response.status_code == 200:
247
+ filepath.write_bytes(response.content)
248
+ return AssetDownloadResult(filename=filename, status=DownloadStatus.SUCCESS)
249
+ else:
250
+ return AssetDownloadResult(
251
+ filename=filename,
252
+ status=DownloadStatus.FAILED,
253
+ error=f"HTTP {response.status_code}",
254
+ )
255
+ except requests.exceptions.Timeout:
256
+ return AssetDownloadResult(filename=filename, status=DownloadStatus.FAILED, error="Timeout")
257
+ except Exception as e:
258
+ return AssetDownloadResult(filename=filename, status=DownloadStatus.FAILED, error=str(e))
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.3
2
+ Name: minitap-mcp
3
+ Version: 0.4.0
4
+ Summary: Model Context Protocol server for controlling Android & iOS devices with natural language
5
+ Author: Pierre-Louis Favreau, Jean-Pierre Lo, Clément Guiguet
6
+ Requires-Dist: fastmcp>=2.12.4
7
+ Requires-Dist: python-dotenv>=1.1.1
8
+ Requires-Dist: pydantic>=2.12.0
9
+ Requires-Dist: pydantic-settings>=2.10.1
10
+ Requires-Dist: minitap-mobile-use>=2.8.1
11
+ Requires-Dist: jinja2>=3.1.6
12
+ Requires-Dist: langchain-core>=0.3.75
13
+ Requires-Dist: pillow>=11.1.0
14
+ Requires-Dist: ruff==0.5.3 ; extra == 'dev'
15
+ Requires-Dist: pytest==8.4.1 ; extra == 'dev'
16
+ Requires-Dist: pytest-cov==5.0.0 ; extra == 'dev'
17
+ Requires-Python: >=3.12
18
+ Project-URL: Homepage, https://minitap.ai/
19
+ Project-URL: Source, https://github.com/minitap-ai/mobile-use
20
+ Provides-Extra: dev
21
+ Description-Content-Type: text/markdown
22
+
23
+ # Minitap MCP Server
24
+
25
+ A Model Context Protocol (MCP) server that enables AI assistants to control and interact with real mobile devices (Android & iOS) through natural language commands.
26
+
27
+ ## Quick Start
28
+
29
+ ### Installation
30
+
31
+ ```bash
32
+ pip install minitap-mcp
33
+ ```
34
+
35
+ ### Prerequisites
36
+
37
+ Before running the MCP server, ensure you have the required mobile automation tools installed:
38
+
39
+ - **For Android devices:**
40
+ - [ADB (Android Debug Bridge)](https://developer.android.com/tools/adb) - For device communication
41
+ - [Maestro](https://maestro.mobile.dev/) - For mobile automation
42
+
43
+ - **For iOS devices (macOS only):**
44
+ - Xcode Command Line Tools with `xcrun`
45
+ - [Maestro](https://maestro.mobile.dev/) - For mobile automation
46
+
47
+ For detailed setup instructions, see the [mobile-use repository](https://github.com/minitap-ai/mobile-use).
48
+
49
+ ### Running the Server
50
+
51
+ The simplest way to start:
52
+
53
+ ```bash
54
+ minitap-mcp --server --api-key your_minitap_api_key
55
+ ```
56
+
57
+ This starts the server on `localhost:8000` with your API key. Get your free API key at [platform.minitap.ai/api-keys](https://platform.minitap.ai/api-keys).
58
+
59
+ **Available CLI options:**
60
+
61
+ ```bash
62
+ minitap-mcp --server --api-key YOUR_KEY --llm-profile PROFILE_NAME
63
+ ```
64
+
65
+ - `--api-key`: Your Minitap API key (overrides `MINITAP_API_KEY` env var). Get yours at [platform.minitap.ai/api-keys](https://platform.minitap.ai/api-keys).
66
+ - `--llm-profile`: LLM profile name to use (overrides `MINITAP_LLM_PROFILE_NAME` env var). If unset, uses the default profile. Configure profiles at [platform.minitap.ai/llm-profiles](https://platform.minitap.ai/llm-profiles).
67
+
68
+ ### Configuration (Optional)
69
+
70
+ Alternatively, you can set environment variables instead of using CLI flags:
71
+
72
+ ```bash
73
+ export MINITAP_API_KEY="your_minitap_api_key"
74
+ export MINITAP_API_BASE_URL="https://platform.minitap.ai/api/v1"
75
+ export MINITAP_LLM_PROFILE_NAME="default"
76
+ ```
77
+
78
+ You can set these in your `.bashrc` or equivalent, then simply run:
79
+
80
+ ```bash
81
+ minitap-mcp --server
82
+ ```
83
+
84
+ CLI flags always override environment variables when both are present.
85
+
86
+ By default, the server will bind to `0.0.0.0:8000`. Configure via environment variables:
87
+
88
+ ```bash
89
+ export MCP_SERVER_HOST="0.0.0.0"
90
+ export MCP_SERVER_PORT="8000"
91
+ ```
92
+
93
+ ## IDE Integration
94
+
95
+ 1. Start the server: `minitap-mcp --server --api-key your_minitap_api_key`
96
+ 2. Add to your IDE MCP settings file:
97
+
98
+ ```jsonc
99
+ # For Windsurf
100
+ {
101
+ "mcpServers": {
102
+ "minitap-mcp": {
103
+ "serverUrl": "http://localhost:8000/mcp"
104
+ }
105
+ }
106
+ }
107
+ ```
108
+
109
+ ```jsonc
110
+ # For Cursor
111
+ {
112
+ "mcpServers": {
113
+ "minitap-mcp": {
114
+ "transport": "http",
115
+ "url": "http://localhost:8000/mcp"
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+
122
+ ## Available Tools
123
+
124
+ Once connected, your AI assistant can use these tools:
125
+
126
+ ### `execute_mobile_command`
127
+ Execute natural language commands on your mobile device using the Minitap SDK. This tool allows you to control your Android or iOS device using natural language.
128
+
129
+ **Parameters:**
130
+ - `goal` (required): High-level goal describing the action to perform
131
+ - `output_description` (optional): Natural language description of the desired output format. Results are returned as structured JSON (e.g., "An array with sender and subject for each email")
132
+ - `profile` (optional): Profile name to use (defaults to "default")
133
+
134
+ **Examples:**
135
+ ```
136
+ "Open the settings app and tell me the battery level"
137
+ "Find the first 3 unread emails in Gmail"
138
+ "Open Google Maps and search for the nearest coffee shop"
139
+ "Take a screenshot and save it"
140
+ ```
141
+
142
+ ### `analyze_screen`
143
+ Capture and analyze what's currently shown on the mobile device screen using a vision-capable LLM. Useful for understanding UI elements, extracting text, or identifying specific features.
144
+
145
+ **Parameters:**
146
+ - `prompt` (required): Analysis prompt describing what information to extract
147
+ - `device_id` (optional): Specific device ID to target
148
+
149
+ **Examples:**
150
+ ```js
151
+ "What app is currently open?"
152
+ "Read the text messages visible on screen"
153
+ "List all buttons and their labels on the current screen"
154
+ "Extract the phone number displayed"
155
+ ```
156
+
157
+ ## Advanced Configuration
158
+
159
+ ### Custom ADB Server
160
+
161
+ If using a remote or custom ADB server (like on WSL):
162
+
163
+ ```bash
164
+ export ADB_SERVER_SOCKET="tcp:192.168.1.100:5037"
165
+ ```
166
+
167
+ ### Vision Model
168
+
169
+ Customize the vision model used for screen analysis:
170
+
171
+ ```bash
172
+ export VISION_MODEL="qwen/qwen-2.5-vl-7b-instruct"
173
+ ```
174
+
175
+ ## Device Setup
176
+
177
+ ### Android
178
+ 1. Enable USB debugging on your device
179
+ 2. Connect via USB or network ADB
180
+ 3. Verify connection: `adb devices`
181
+
182
+ ### iOS (macOS only)
183
+ 1. Install Xcode Command Line Tools
184
+ 2. Start a simulator or connect a physical device
185
+ 3. Verify: `xcrun simctl list devices booted`
186
+
187
+ ## Troubleshooting
188
+
189
+ **No devices found:**
190
+ - Verify ADB/xcrun connection
191
+ - Check USB debugging is enabled (Android)
192
+ - Ensure device is unlocked
193
+
194
+ **Connection refused errors:**
195
+ - Check ADB/xcrun connection
196
+
197
+ **API authentication errors:**
198
+ - Verify `MINITAP_API_KEY` is set correctly
199
+
200
+ ## Links
201
+
202
+ - **Mobile-Use SDK:** [github.com/minitap-ai/mobile-use](https://github.com/minitap-ai/mobile-use)
203
+ - **Mobile-Use Documentation:** [docs.minitap.ai](https://docs.minitap.ai)
@@ -0,0 +1,25 @@
1
+ minitap/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ minitap/mcp/core/agents/compare_screenshots.md,sha256=Gt27HVzXzu71BxcanKPokz1dFPvq90vXbjE2HOn5X0I,3559
3
+ minitap/mcp/core/agents/compare_screenshots.py,sha256=Yb7kR8Cv0gWzXyNf-6IS7_9l1npfqYmL-SONJJGgzM4,2060
4
+ minitap/mcp/core/agents/extract_figma_assets.md,sha256=JrXuWF8-2PeQpVix-kf-p6zmu2gQVf9Z6ptTK1cedDk,2413
5
+ minitap/mcp/core/agents/extract_figma_assets.py,sha256=WAmn4CvN1ONJkJp2KH9l080hhZ_ge0Pdan6ejk_GWOo,2038
6
+ minitap/mcp/core/config.py,sha256=gfx-cXJsgB_W2dSNHnb5jeWEYfe3VBZUMeF1nbNAdiQ,962
7
+ minitap/mcp/core/decorators.py,sha256=iekv181o_rkv0upacFWkmPqxsZRTzuLFyOZ0sIDtQnQ,1317
8
+ minitap/mcp/core/device.py,sha256=sEO3Z-8F325hDOObdH1YBhZE60f17FmIclt5UlhY_nU,7875
9
+ minitap/mcp/core/llm.py,sha256=z_pYZkZcAchsiWPh4W79frQPANsfYyFPUe8DJo8lZO0,822
10
+ minitap/mcp/core/models.py,sha256=egLScxPAMo4u5cqY33UKba7z7DsdgqfPW409UAqW1Jg,1942
11
+ minitap/mcp/core/sdk_agent.py,sha256=-9l1YetD93dzxOeSFOT_j8dDfDFjhJLiir8bhzEjI3Y,900
12
+ minitap/mcp/core/utils.py,sha256=3uExpRoh7affIieZx3TLlZTmZCcoxWfx1YpPbwhjiJY,1791
13
+ minitap/mcp/main.py,sha256=B7KE6_5UNGKanS0WMJYBq8vp0HE_Lr0BG9KR4BwYxwU,4341
14
+ minitap/mcp/server/middleware.py,sha256=fbry_IiHmwUxVjsWgOU2goybcS1kLRXFZZ89KPH1d8E,880
15
+ minitap/mcp/server/poller.py,sha256=Qakq4yO3EJ9dXmRqtE3sJjyk0ij7VBU-NuupHhTf37g,2539
16
+ minitap/mcp/tools/analyze_screen.py,sha256=fjcjf3tTZDlxzmiQFHFNgw38bxPz4eisw57zuxshN2A,1984
17
+ minitap/mcp/tools/compare_screenshot_with_figma.py,sha256=G69F6vRFI2tE2wW-oFYPjnY8oFMD9nRZH0H-yvtD4gE,4575
18
+ minitap/mcp/tools/execute_mobile_command.py,sha256=qY3UfcDq1BtYcny1YlEF4WV9LwUJxLAmLJCm1VBzxS8,2442
19
+ minitap/mcp/tools/go_back.py,sha256=lEmADkDkXu8JGm-sY7zL7M6GlBy-lD7Iffv4yzwoQfo,1301
20
+ minitap/mcp/tools/save_figma_assets.py,sha256=EN0u0TkCUXoz8guehxm-CywKYYmZFg_d4x35eTNAovQ,9182
21
+ minitap/mcp/tools/screen_analyzer.md,sha256=TTO80JQWusbA9cKAZn-9cqhgVHm6F_qJh5w152hG3YM,734
22
+ minitap_mcp-0.4.0.dist-info/WHEEL,sha256=5w2T7AS2mz1-rW9CNagNYWRCaB0iQqBMYLwKdlgiR4Q,78
23
+ minitap_mcp-0.4.0.dist-info/entry_points.txt,sha256=rYVoXm7tSQCqQTtHx4Lovgn1YsjwtEEHfddKrfEVHuY,55
24
+ minitap_mcp-0.4.0.dist-info/METADATA,sha256=27wi_Bedtm971es6fHljAF8wE45uCkSoYYwwqqFvmY0,5885
25
+ minitap_mcp-0.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.2
2
+ Generator: uv 0.9.7
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,19 +0,0 @@
1
- import os
2
-
3
- from minitap.mobile_use.sdk import Agent
4
- from minitap.mobile_use.sdk.builders import Builders
5
-
6
-
7
- def get_mobile_use_agent():
8
- config = Builders.AgentConfig
9
- custom_adb_socket = os.getenv("ADB_SERVER_SOCKET")
10
- if custom_adb_socket:
11
- parts = custom_adb_socket.split(":")
12
- if len(parts) != 3:
13
- raise ValueError(f"Invalid ADB server socket: {custom_adb_socket}")
14
- _, host, port = parts
15
- config = config.with_adb_server(host=host, port=int(port))
16
- return Agent(config=config.build())
17
-
18
-
19
- agent = get_mobile_use_agent()