minitap-mcp 0.4.3__tar.gz → 0.5.0__tar.gz
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.
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/PKG-INFO +1 -1
- minitap_mcp-0.5.0/minitap/mcp/core/agents/extract_figma_assets.py +69 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/tools/save_figma_assets.py +4 -6
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/pyproject.toml +1 -1
- minitap_mcp-0.4.3/minitap/mcp/core/agents/extract_figma_assets.md +0 -64
- minitap_mcp-0.4.3/minitap/mcp/core/agents/extract_figma_assets.py +0 -96
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/PYPI_README.md +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/__init__.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/agents/compare_screenshots.md +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/agents/compare_screenshots.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/config.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/decorators.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/device.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/llm.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/logging_config.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/models.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/sdk_agent.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/core/utils.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/main.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/server/middleware.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/server/poller.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/tools/analyze_screen.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/tools/compare_screenshot_with_figma.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/tools/execute_mobile_command.py +0 -0
- {minitap_mcp-0.4.3 → minitap_mcp-0.5.0}/minitap/mcp/tools/screen_analyzer.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: minitap-mcp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Model Context Protocol server for controlling Android & iOS devices with natural language
|
|
5
5
|
Author: Pierre-Louis Favreau, Jean-Pierre Lo, Clément Guiguet
|
|
6
6
|
Requires-Dist: fastmcp>=2.12.4
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Agent to extract Figma asset URLs from design context code using regex."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FigmaAsset(BaseModel):
|
|
9
|
+
"""Represents a single Figma asset."""
|
|
10
|
+
|
|
11
|
+
variable_name: str = Field(description="The variable name from the code (e.g., imgSignal)")
|
|
12
|
+
url: str = Field(description="The full URL to the asset")
|
|
13
|
+
extension: str = Field(description="The file extension (e.g., svg, png, jpg)")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ExtractedAssets(BaseModel):
|
|
17
|
+
"""Container for all extracted Figma assets."""
|
|
18
|
+
|
|
19
|
+
assets: list[FigmaAsset] = Field(
|
|
20
|
+
default_factory=list,
|
|
21
|
+
description="List of all extracted assets from the Figma design context",
|
|
22
|
+
)
|
|
23
|
+
code_implementation: str = Field(
|
|
24
|
+
description="The React/TypeScript code with imports instead of const declarations"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def extract_figma_assets(design_context_code: str) -> ExtractedAssets:
|
|
29
|
+
"""Extract asset URLs from Figma design context code using regex.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
design_context_code: The React/TypeScript code from get_design_context
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
ExtractedAssets with list of assets and transformed code
|
|
36
|
+
"""
|
|
37
|
+
# Regex captures: (1) variable name, (2) full URL, (4) extension
|
|
38
|
+
# Supports http/https, any domain, query strings, optional semicolon
|
|
39
|
+
pattern = r'const\s+(\w+)\s*=\s*["\']((https?://[^"\']+?)\.(\w+)(?:\?[^"\']*)?)["\'];?'
|
|
40
|
+
matches = re.finditer(pattern, design_context_code)
|
|
41
|
+
|
|
42
|
+
assets = []
|
|
43
|
+
asset_lines = []
|
|
44
|
+
|
|
45
|
+
for match in matches:
|
|
46
|
+
var_name = match.group(1)
|
|
47
|
+
url = match.group(2)
|
|
48
|
+
extension = match.group(4)
|
|
49
|
+
|
|
50
|
+
assets.append(FigmaAsset(variable_name=var_name, url=url, extension=extension))
|
|
51
|
+
asset_lines.append(match.group(0))
|
|
52
|
+
|
|
53
|
+
import_statements = []
|
|
54
|
+
for asset in assets:
|
|
55
|
+
import_statements.append(
|
|
56
|
+
f"import {asset.variable_name} from './{asset.variable_name}.{asset.extension}';"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
transformed_code = design_context_code
|
|
60
|
+
for line in asset_lines:
|
|
61
|
+
transformed_code = transformed_code.replace(line, "")
|
|
62
|
+
|
|
63
|
+
lines = transformed_code.split("\n")
|
|
64
|
+
while lines and not lines[0].strip():
|
|
65
|
+
lines.pop(0)
|
|
66
|
+
|
|
67
|
+
final_code = "\n".join(import_statements) + "\n\n" + "\n".join(lines)
|
|
68
|
+
|
|
69
|
+
return ExtractedAssets(assets=assets, code_implementation=final_code)
|
|
@@ -41,9 +41,9 @@ logger = get_logger(__name__)
|
|
|
41
41
|
|
|
42
42
|
This tool:
|
|
43
43
|
1. Calls get_design_context from Figma MCP to get the React/TypeScript code
|
|
44
|
-
2. Extracts
|
|
44
|
+
2. Extracts asset URLs and transforms const declarations to import statements
|
|
45
45
|
3. Downloads each asset to .mobile-use/figma_assets/<node-id>/ folder
|
|
46
|
-
4. Saves the code
|
|
46
|
+
4. Saves the transformed code to .mobile-use/figma_assets/<node-id>/code_implementation.ts
|
|
47
47
|
5. Returns a list of downloaded files
|
|
48
48
|
""",
|
|
49
49
|
)
|
|
@@ -75,10 +75,8 @@ async def save_figma_assets(
|
|
|
75
75
|
# Step 1: Get design context from Figma MCP
|
|
76
76
|
design_context = await get_design_context(node_id, file_key)
|
|
77
77
|
|
|
78
|
-
# Step 2: Extract asset URLs
|
|
79
|
-
extracted_context: ExtractedAssets =
|
|
80
|
-
design_context.code_implementation
|
|
81
|
-
)
|
|
78
|
+
# Step 2: Extract asset URLs and transform code
|
|
79
|
+
extracted_context: ExtractedAssets = extract_figma_assets(design_context.code_implementation)
|
|
82
80
|
if not extracted_context.assets:
|
|
83
81
|
raise ToolError("No assets found in the Figma design context.")
|
|
84
82
|
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
You are an expert at parsing React/TypeScript code to extract asset URLs and generate clean, documented code implementations.
|
|
2
|
-
|
|
3
|
-
Your task is to:
|
|
4
|
-
|
|
5
|
-
1. Extract all asset URLs from the provided code snippet
|
|
6
|
-
2. Generate a clean `code_implementation` output that includes the React code with embedded comments referencing implementation and node guidelines
|
|
7
|
-
|
|
8
|
-
**Instructions:**
|
|
9
|
-
|
|
10
|
-
## Part 1: Extract Asset URLs
|
|
11
|
-
|
|
12
|
-
1. Look for all constant declarations that contain URLs pointing to assets (images, SVGs, etc.)
|
|
13
|
-
2. These constants typically follow patterns like:
|
|
14
|
-
|
|
15
|
-
- `const imgVariableName = "http://localhost:3845/assets/[hash].[extension]";`
|
|
16
|
-
- The variable names usually start with `img` followed by a descriptive name in camelCase
|
|
17
|
-
|
|
18
|
-
3. For each asset URL found, extract:
|
|
19
|
-
- The **variable name** (e.g., `imgSignal`, `imgBatteryThreeQuarters`)
|
|
20
|
-
- The **full URL** (e.g., `http://localhost:3845/assets/685c5ac58caa29556e29737cf8f8c9605d9c8571.svg`)
|
|
21
|
-
- The **file extension** from the URL (e.g., `svg`, `png`, `jpg`)
|
|
22
|
-
|
|
23
|
-
## Part 2: Generate Code Implementation
|
|
24
|
-
|
|
25
|
-
The `code_implementation` field should contain:
|
|
26
|
-
|
|
27
|
-
1. The React/TypeScript code with **LOCAL asset imports** instead of HTTP URLs:
|
|
28
|
-
|
|
29
|
-
- Convert `const imgSignal = "http://localhost:3845/assets/[hash].svg";`
|
|
30
|
-
- To `import imgSignal from './assets/imgSignal.svg';` (or appropriate relative path)
|
|
31
|
-
- Use the **exact same variable names** as in the original const declarations
|
|
32
|
-
- **CRITICAL**: Preserve the variable naming convention
|
|
33
|
-
|
|
34
|
-
2. Preserve all `data-node-id` attributes and other metadata in the code
|
|
35
|
-
|
|
36
|
-
## Part 3: Return Format
|
|
37
|
-
|
|
38
|
-
Return a JSON object with two fields:
|
|
39
|
-
|
|
40
|
-
- `assets`: Array of extracted asset objects
|
|
41
|
-
- `code_implementation`: String containing the React code with embedded guideline comments
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"assets": [
|
|
46
|
-
{
|
|
47
|
-
"variable_name": "imgSignal",
|
|
48
|
-
"url": "http://localhost:3845/assets/685c5ac58caa29556e29737cf8f8c9605d9c8571.svg",
|
|
49
|
-
"extension": "svg"
|
|
50
|
-
},
|
|
51
|
-
...
|
|
52
|
-
],
|
|
53
|
-
"code_implementation": "import ... function ..."
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
**Important:**
|
|
58
|
-
|
|
59
|
-
- Only extract asset URLs
|
|
60
|
-
- Preserve the exact variable names as they appear in the code
|
|
61
|
-
- DO NOT MISS any assets
|
|
62
|
-
- If no assets are found, return an empty array for `assets`
|
|
63
|
-
- Return ONLY the JSON object with both `assets` and `code_implementation` fields
|
|
64
|
-
- Do NOT include the const declarations of the assets in the code_implementation output - convert them to imports.
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"""Agent to extract Figma asset URLs from design context code."""
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import uuid
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
from jinja2 import Template
|
|
8
|
-
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
|
|
9
|
-
from pydantic import BaseModel, Field
|
|
10
|
-
|
|
11
|
-
from minitap.mcp.core.llm import get_minitap_llm
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class FigmaAsset(BaseModel):
|
|
15
|
-
"""Represents a single Figma asset."""
|
|
16
|
-
|
|
17
|
-
variable_name: str = Field(description="The variable name from the code (e.g., imgSignal)")
|
|
18
|
-
url: str = Field(description="The full URL to the asset")
|
|
19
|
-
extension: str = Field(description="The file extension (e.g., svg, png, jpg)")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class ExtractedAssets(BaseModel):
|
|
23
|
-
"""Container for all extracted Figma assets."""
|
|
24
|
-
|
|
25
|
-
assets: list[FigmaAsset] = Field(
|
|
26
|
-
default_factory=list,
|
|
27
|
-
description="List of all extracted assets from the Figma design context",
|
|
28
|
-
)
|
|
29
|
-
code_implementation: str = Field(
|
|
30
|
-
description=(
|
|
31
|
-
"The React/TypeScript code\n"
|
|
32
|
-
"with the local url declarations turned into const declarations"
|
|
33
|
-
)
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def sanitize_unicode_for_llm(text: str) -> str:
|
|
38
|
-
"""Remove or replace problematic Unicode characters that increase token consumption.
|
|
39
|
-
|
|
40
|
-
Characters outside the Basic Multilingual Plane (BMP) like emoji and special symbols
|
|
41
|
-
get escaped as \\U sequences when sent to LLMs, dramatically increasing token count
|
|
42
|
-
and processing time.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
text: The text to sanitize
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
Text with problematic Unicode characters replaced with placeholders
|
|
49
|
-
"""
|
|
50
|
-
|
|
51
|
-
# Replace characters outside BMP (U+10000 and above) with a placeholder
|
|
52
|
-
# These are typically emoji, special symbols, or rare characters
|
|
53
|
-
def replace_high_unicode(match):
|
|
54
|
-
char = match.group(0)
|
|
55
|
-
codepoint = ord(char)
|
|
56
|
-
# Return a descriptive placeholder
|
|
57
|
-
return f"[U+{codepoint:X}]"
|
|
58
|
-
|
|
59
|
-
# Pattern matches characters with codepoints >= U+10000
|
|
60
|
-
pattern = re.compile(r"[\U00010000-\U0010FFFF]")
|
|
61
|
-
sanitized = pattern.sub(replace_high_unicode, text)
|
|
62
|
-
|
|
63
|
-
return sanitized
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
async def extract_figma_assets(design_context_code: str) -> ExtractedAssets:
|
|
67
|
-
"""Extract asset URLs from Figma design context code.
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
design_context_code: The React/TypeScript code from get_design_context
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
List of dictionaries containing variable_name, url, and extension
|
|
74
|
-
"""
|
|
75
|
-
system_message = Template(
|
|
76
|
-
Path(__file__).parent.joinpath("extract_figma_assets.md").read_text(encoding="utf-8")
|
|
77
|
-
).render()
|
|
78
|
-
|
|
79
|
-
sanitized_code = sanitize_unicode_for_llm(design_context_code)
|
|
80
|
-
|
|
81
|
-
messages: list[BaseMessage] = [
|
|
82
|
-
SystemMessage(content=system_message),
|
|
83
|
-
HumanMessage(
|
|
84
|
-
content=f"Here is the code to analyze:\n\n```typescript\n{sanitized_code}\n```"
|
|
85
|
-
),
|
|
86
|
-
]
|
|
87
|
-
|
|
88
|
-
llm = get_minitap_llm(
|
|
89
|
-
model="openai/gpt-5",
|
|
90
|
-
temperature=0,
|
|
91
|
-
trace_id=str(uuid.uuid4()),
|
|
92
|
-
remote_tracing=True,
|
|
93
|
-
).with_structured_output(ExtractedAssets)
|
|
94
|
-
result: ExtractedAssets = await llm.ainvoke(messages) # type: ignore
|
|
95
|
-
|
|
96
|
-
return result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|