quash-mcp 0.2.3__tar.gz → 0.2.5__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.
Files changed (25) hide show
  1. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/PKG-INFO +1 -1
  2. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/pyproject.toml +1 -1
  3. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/backend_client.py +7 -6
  4. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/execute_v3.py +39 -1
  5. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/.gitignore +0 -0
  6. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/README.md +0 -0
  7. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/SETUP_CLAUDE_CODE.md +0 -0
  8. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/__init__.py +0 -0
  9. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/__main__.py +0 -0
  10. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/device/__init__.py +0 -0
  11. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/device/adb_tools.py +0 -0
  12. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/device/portal.py +0 -0
  13. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/device/state_capture.py +0 -0
  14. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/server.py +0 -0
  15. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/state.py +0 -0
  16. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/__init__.py +0 -0
  17. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/build.py +0 -0
  18. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/build_old.py +0 -0
  19. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/configure.py +0 -0
  20. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/connect.py +0 -0
  21. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/execute.py +0 -0
  22. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/execute_v2_backup.py +0 -0
  23. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/runsuite.py +0 -0
  24. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/quash_mcp/tools/usage.py +0 -0
  25. {quash_mcp-0.2.3 → quash_mcp-0.2.5}/test_backend_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quash-mcp
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Model Context Protocol server for Quash - AI-powered mobile automation agent
5
5
  Project-URL: Homepage, https://quashbugs.com
6
6
  Project-URL: Repository, https://github.com/quash/quash-mcp
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "quash-mcp"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Model Context Protocol server for Quash - AI-powered mobile automation agent"
5
5
  readme = "README.md"
6
6
  license = {text = "MIT"}
@@ -245,19 +245,20 @@ class BackendClient:
245
245
  # Convert to JSON string
246
246
  data_json = json.dumps(data_dict)
247
247
 
248
- # Prepare files dict
249
- files = {
250
- "data": ("data.json", data_json, "application/json")
251
- }
248
+ # Prepare form data (data field as string)
249
+ form_data = {"data": data_json}
252
250
 
253
- # Add screenshot if provided
251
+ # Prepare files dict (only screenshot if provided)
252
+ files = {}
254
253
  if screenshot_bytes:
255
254
  files["screenshot"] = ("screenshot.png", screenshot_bytes, "image/png")
256
255
 
257
256
  async with httpx.AsyncClient(timeout=self.timeout) as client:
257
+ # Send both form data and files (multipart/form-data)
258
258
  response = await client.post(
259
259
  f"{self.base_url}/api/agent/step",
260
- files=files
260
+ data=form_data,
261
+ files=files if files else None
261
262
  )
262
263
 
263
264
  if response.status_code == 200:
@@ -7,12 +7,25 @@ This hybrid approach keeps proprietary code private while allowing local device
7
7
 
8
8
  import time
9
9
  import uuid
10
+ import asyncio
10
11
  from typing import Dict, Any, Callable, Optional
11
12
  from ..state import get_state
12
13
  from ..backend_client import get_backend_client
13
14
  from ..device.state_capture import get_device_state
14
15
  from ..device.adb_tools import AdbTools
15
16
 
17
+ # Import mahoraga components for tool descriptions
18
+ try:
19
+ from mahoraga.tools import Tools, describe_tools
20
+ from mahoraga.agent.context.personas import DEFAULT
21
+ from mahoraga.agent.utils.async_utils import async_to_sync
22
+ except ImportError as e:
23
+ print(f"Warning: Could not import mahoraga components: {e}")
24
+ Tools = None
25
+ describe_tools = None
26
+ DEFAULT = None
27
+ async_to_sync = None
28
+
16
29
 
17
30
  async def execute_v3(
18
31
  task: str,
@@ -114,11 +127,36 @@ async def execute_v3(
114
127
  # Initialize local ADB tools for code execution
115
128
  adb_tools = AdbTools(serial=state.device_serial, use_tcp=True)
116
129
 
117
- # Code executor namespace
130
+ # Code executor namespace - add tool functions so generated code can call them
118
131
  executor_globals = {
119
132
  "__builtins__": __builtins__,
120
133
  "adb_tools": adb_tools
121
134
  }
135
+
136
+ # Add tool functions to executor namespace (like start_app, swipe, etc.)
137
+ if describe_tools and DEFAULT:
138
+ try:
139
+ # Get all tool functions from AdbTools instance
140
+ tool_list = describe_tools(adb_tools, exclude_tools=None)
141
+
142
+ # Filter by allowed tools from DEFAULT persona
143
+ allowed_tool_names = DEFAULT.allowed_tools if hasattr(DEFAULT, 'allowed_tools') else []
144
+ filtered_tools = {name: func for name, func in tool_list.items() if name in allowed_tool_names}
145
+
146
+ # Add each tool function to executor globals
147
+ for tool_name, tool_function in filtered_tools.items():
148
+ # Convert async functions to sync if needed
149
+ if asyncio.iscoroutinefunction(tool_function):
150
+ if async_to_sync:
151
+ tool_function = async_to_sync(tool_function)
152
+
153
+ # Add to globals so code can call it directly
154
+ executor_globals[tool_name] = tool_function
155
+
156
+ log_progress(f"🔧 Loaded {len(filtered_tools)} tool functions: {list(filtered_tools.keys())}")
157
+ except Exception as e:
158
+ log_progress(f"⚠️ Warning: Could not load tool functions: {e}")
159
+
122
160
  executor_locals = {}
123
161
 
124
162
  try:
File without changes
File without changes
File without changes
File without changes