androidviewclient 24.0.0__tar.gz → 25.0.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.
Files changed (56) hide show
  1. androidviewclient-25.0.0/PKG-INFO +40 -0
  2. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/README.md +75 -0
  3. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/setup.py +30 -5
  4. androidviewclient-25.0.0/src/androidviewclient.egg-info/PKG-INFO +40 -0
  5. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/androidviewclient.egg-info/SOURCES.txt +6 -0
  6. androidviewclient-25.0.0/src/androidviewclient.egg-info/entry_points.txt +2 -0
  7. androidviewclient-25.0.0/src/androidviewclient.egg-info/requires.txt +12 -0
  8. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/adb/adbclient.py +1 -1
  9. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/adb/dumpsys.py +1 -1
  10. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/code_generator.py +1 -1
  11. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/common.py +1 -1
  12. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/concertina.py +1 -1
  13. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/controlpanel.py +1 -1
  14. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/culebron.py +2 -7
  15. androidviewclient-25.0.0/src/com/dtmilano/android/mcp/__init__.py +33 -0
  16. androidviewclient-25.0.0/src/com/dtmilano/android/mcp/object_store.py +139 -0
  17. androidviewclient-25.0.0/src/com/dtmilano/android/mcp/server.py +111 -0
  18. androidviewclient-25.0.0/src/com/dtmilano/android/mcp/tools.py +721 -0
  19. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/plot.py +1 -1
  20. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/robotframework/viewclientwrapper.py +1 -1
  21. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py +38 -8
  22. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/viewclient.py +3 -3
  23. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/tools/culebra +1 -1
  24. androidviewclient-25.0.0/tools/culebra-mcp +35 -0
  25. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/tools/dump +1 -1
  26. androidviewclient-24.0.0/PKG-INFO +0 -18
  27. androidviewclient-24.0.0/src/androidviewclient.egg-info/PKG-INFO +0 -18
  28. androidviewclient-24.0.0/src/androidviewclient.egg-info/requires.txt +0 -5
  29. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/LICENSE +0 -0
  30. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/setup.cfg +0 -0
  31. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/androidviewclient.egg-info/dependency_links.txt +0 -0
  32. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/androidviewclient.egg-info/top_level.txt +0 -0
  33. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/__init__.py +0 -0
  34. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/__init__.py +0 -0
  35. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/__init__.py +0 -0
  36. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/adb/__init__.py +0 -0
  37. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/adb/androidkeymap.py +0 -0
  38. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/distance.py +0 -0
  39. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/kato/__init__.py +0 -0
  40. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/kato/kato.py +0 -0
  41. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/keyevent.py +0 -0
  42. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/robotframework/__init__.py +0 -0
  43. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/uiautomator/__init__.py +0 -0
  44. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/uiautomator/utils.py +0 -0
  45. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/com/dtmilano/android/window.py +0 -0
  46. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/__init__.py +0 -0
  47. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/__init__.py +0 -0
  48. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/culebra.png +0 -0
  49. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/__init__.py +0 -0
  50. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/__init__.py +0 -0
  51. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/__init__.py +0 -0
  52. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/__init__.py +0 -0
  53. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/__init__.py +0 -0
  54. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_back.png +0 -0
  55. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_fore.png +0 -0
  56. {androidviewclient-24.0.0 → androidviewclient-25.0.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_shadow.png +0 -0
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: androidviewclient
3
+ Version: 25.0.0
4
+ Summary: AndroidViewClient is a 100% pure python library and tools
5
+ Home-page: https://github.com/dtmilano/AndroidViewClient/
6
+ Author: Diego Torres Milano
7
+ Author-email: dtmilano@gmail.com
8
+ License: Apache
9
+ Keywords: android uiautomator viewclient monkeyrunner test automation mcp
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.9
18
+ License-File: LICENSE
19
+ Requires-Dist: setuptools
20
+ Requires-Dist: requests
21
+ Requires-Dist: numpy
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: culebratester-client>=2.0.73
24
+ Requires-Dist: mcp>=0.9.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
28
+ Requires-Dist: hypothesis>=6.0.0; extra == "dev"
29
+ Requires-Dist: responses>=0.23.0; extra == "dev"
30
+ Dynamic: author
31
+ Dynamic: author-email
32
+ Dynamic: classifier
33
+ Dynamic: home-page
34
+ Dynamic: keywords
35
+ Dynamic: license
36
+ Dynamic: license-file
37
+ Dynamic: provides-extra
38
+ Dynamic: requires-dist
39
+ Dynamic: requires-python
40
+ Dynamic: summary
@@ -39,6 +39,81 @@ pip3 install androidviewclient --upgrade
39
39
  ```
40
40
  Or check the wiki for more alternatives.
41
41
 
42
+ # AI-Powered Testing with MCP
43
+
44
+ **NEW!** AndroidViewClient now includes a Model Context Protocol (MCP) server that enables AI assistants like Kiro to interact with Android devices through natural language.
45
+
46
+ ## Quick Start with MCP
47
+
48
+ 1. **Install with MCP support:**
49
+ ```bash
50
+ pip3 install androidviewclient --upgrade
51
+ ```
52
+
53
+ 2. **Start CulebraTester2 on your device:**
54
+
55
+ Check the details at [How to run CulebraTester2 ?](https://github.com/dtmilano/CulebraTester2-public?tab=readme-ov-file#how-to-run-culebratester2-)
56
+
57
+
58
+ 4. **Configure your AI assistant:**
59
+
60
+ Add to `.kiro/settings/mcp.json` or `~/.kiro/settings/mcp.json`:
61
+ ```json
62
+ {
63
+ "mcpServers": {
64
+ "culebratester2": {
65
+ "command": "culebra-mcp",
66
+ "env": {
67
+ "CULEBRATESTER2_URL": "http://localhost:9987"
68
+ }
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ 5. **Start testing with natural language:**
75
+ - "Get the device screen size"
76
+ - "Launch the Calculator app"
77
+ - "Find the button with text Submit and click it"
78
+ - "Take a screenshot"
79
+ - "Swipe up to scroll"
80
+
81
+ ## MCP Tools Available
82
+
83
+ The MCP server provides 20 tools for Android automation:
84
+
85
+ **Element-based interactions:**
86
+ - Find elements by text or resource ID
87
+ - Click, long-click, enter text, clear text
88
+ - Navigate with back/home buttons
89
+ - Launch applications
90
+
91
+ **Coordinate-based interactions:**
92
+ - Click/long-click at coordinates
93
+ - Swipe gestures
94
+
95
+ **Device actions:**
96
+ - Wake/sleep device
97
+ - Get current app
98
+ - Force stop apps
99
+ - Take screenshots
100
+
101
+ ## Configuration
102
+
103
+ For detailed MCP configuration options, see the [MCP Configuration Guide](docs/MCP_CONFIGURATION.md).
104
+
105
+ Quick reference:
106
+ - **User-level config** (kiro-cli): `~/.kiro/settings/mcp.json`
107
+ - **Workspace config** (Kiro IDE): `.kiro/settings/mcp.json`
108
+ - **Examples:** `examples/mcp_config.json`
109
+ - **Usage examples:** `examples/test_calculator_mcp.py`
110
+
111
+ ## Environment Variables
112
+
113
+ - `CULEBRATESTER2_URL`: Base URL for CulebraTester2 (default: `http://localhost:9987`)
114
+ - `CULEBRATESTER2_TIMEOUT`: HTTP timeout in seconds (default: `30`)
115
+ - `CULEBRATESTER2_DEBUG`: Enable debug logging (`1`, `true`, or `yes`)
116
+
42
117
  # Want to learn more?
43
118
 
44
119
  > 🚀 Check [Examples](https://github.com/dtmilano/AndroidViewClient/wiki/Resources#examples) and [Screencasts and videos](https://github.com/dtmilano/AndroidViewClient/wiki/Resources#screencasts-and-videos) page to see it in action.
@@ -3,14 +3,14 @@
3
3
  from setuptools import setup, find_packages
4
4
 
5
5
  setup(name='androidviewclient',
6
- version='24.0.0',
6
+ version='25.0.0',
7
7
  description='''AndroidViewClient is a 100% pure python library and tools
8
8
  that simplifies test script creation providing higher level
9
9
  operations and the ability of obtaining the tree of Views present at
10
10
  any given moment on the device or emulator screen.
11
11
  ''',
12
12
  license='Apache',
13
- keywords='android uiautomator viewclient monkeyrunner test automation',
13
+ keywords='android uiautomator viewclient monkeyrunner test automation mcp',
14
14
  author='Diego Torres Milano',
15
15
  author_email='dtmilano@gmail.com',
16
16
  url='https://github.com/dtmilano/AndroidViewClient/',
@@ -18,9 +18,34 @@ setup(name='androidviewclient',
18
18
  package_dir={'': 'src'},
19
19
  package_data={'': ['*.png']},
20
20
  include_package_data=True,
21
- scripts=['tools/culebra', 'tools/dump'],
21
+ scripts=['tools/culebra', 'tools/dump', 'tools/culebra-mcp'],
22
+ entry_points={
23
+ 'console_scripts': [
24
+ 'culebra-mcp=com.dtmilano.android.mcp.server:main',
25
+ ],
26
+ },
27
+ python_requires='>=3.9',
22
28
  classifiers=['Development Status :: 5 - Production/Stable',
23
29
  'Intended Audience :: Developers',
24
- 'License :: OSI Approved :: Apache Software License'],
25
- install_requires=['setuptools', 'requests', 'numpy', 'matplotlib', 'culebratester-client >= 2.0.70'],
30
+ 'License :: OSI Approved :: Apache Software License',
31
+ 'Programming Language :: Python :: 3.9',
32
+ 'Programming Language :: Python :: 3.10',
33
+ 'Programming Language :: Python :: 3.11',
34
+ 'Programming Language :: Python :: 3.12'],
35
+ install_requires=[
36
+ 'setuptools',
37
+ 'requests',
38
+ 'numpy',
39
+ 'matplotlib',
40
+ 'culebratester-client >= 2.0.73',
41
+ 'mcp >= 0.9.0',
42
+ ],
43
+ extras_require={
44
+ 'dev': [
45
+ 'pytest >= 7.0.0',
46
+ 'pytest-asyncio >= 0.21.0',
47
+ 'hypothesis >= 6.0.0',
48
+ 'responses >= 0.23.0',
49
+ ],
50
+ },
26
51
  )
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: androidviewclient
3
+ Version: 25.0.0
4
+ Summary: AndroidViewClient is a 100% pure python library and tools
5
+ Home-page: https://github.com/dtmilano/AndroidViewClient/
6
+ Author: Diego Torres Milano
7
+ Author-email: dtmilano@gmail.com
8
+ License: Apache
9
+ Keywords: android uiautomator viewclient monkeyrunner test automation mcp
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.9
18
+ License-File: LICENSE
19
+ Requires-Dist: setuptools
20
+ Requires-Dist: requests
21
+ Requires-Dist: numpy
22
+ Requires-Dist: matplotlib
23
+ Requires-Dist: culebratester-client>=2.0.73
24
+ Requires-Dist: mcp>=0.9.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
27
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
28
+ Requires-Dist: hypothesis>=6.0.0; extra == "dev"
29
+ Requires-Dist: responses>=0.23.0; extra == "dev"
30
+ Dynamic: author
31
+ Dynamic: author-email
32
+ Dynamic: classifier
33
+ Dynamic: home-page
34
+ Dynamic: keywords
35
+ Dynamic: license
36
+ Dynamic: license-file
37
+ Dynamic: provides-extra
38
+ Dynamic: requires-dist
39
+ Dynamic: requires-python
40
+ Dynamic: summary
@@ -4,6 +4,7 @@ setup.py
4
4
  src/androidviewclient.egg-info/PKG-INFO
5
5
  src/androidviewclient.egg-info/SOURCES.txt
6
6
  src/androidviewclient.egg-info/dependency_links.txt
7
+ src/androidviewclient.egg-info/entry_points.txt
7
8
  src/androidviewclient.egg-info/requires.txt
8
9
  src/androidviewclient.egg-info/top_level.txt
9
10
  src/com/__init__.py
@@ -25,6 +26,10 @@ src/com/dtmilano/android/adb/androidkeymap.py
25
26
  src/com/dtmilano/android/adb/dumpsys.py
26
27
  src/com/dtmilano/android/kato/__init__.py
27
28
  src/com/dtmilano/android/kato/kato.py
29
+ src/com/dtmilano/android/mcp/__init__.py
30
+ src/com/dtmilano/android/mcp/object_store.py
31
+ src/com/dtmilano/android/mcp/server.py
32
+ src/com/dtmilano/android/mcp/tools.py
28
33
  src/com/dtmilano/android/robotframework/__init__.py
29
34
  src/com/dtmilano/android/robotframework/viewclientwrapper.py
30
35
  src/com/dtmilano/android/uiautomator/__init__.py
@@ -42,4 +47,5 @@ src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_back.
42
47
  src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_fore.png
43
48
  src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_shadow.png
44
49
  tools/culebra
50
+ tools/culebra-mcp
45
51
  tools/dump
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ culebra-mcp = com.dtmilano.android.mcp.server:main
@@ -0,0 +1,12 @@
1
+ setuptools
2
+ requests
3
+ numpy
4
+ matplotlib
5
+ culebratester-client>=2.0.73
6
+ mcp>=0.9.0
7
+
8
+ [dev]
9
+ pytest>=7.0.0
10
+ pytest-asyncio>=0.21.0
11
+ hypothesis>=6.0.0
12
+ responses>=0.23.0
@@ -27,7 +27,7 @@ from typing import Optional
27
27
 
28
28
  from com.dtmilano.android.adb.dumpsys import Dumpsys
29
29
 
30
- __version__ = '24.0.0'
30
+ __version__ = '25.0.0'
31
31
 
32
32
  import sys
33
33
  import warnings
@@ -23,7 +23,7 @@ import re
23
23
  import sys
24
24
  from _warnings import warn
25
25
 
26
- __version__ = '24.0.0'
26
+ __version__ = '25.0.0'
27
27
 
28
28
  DEBUG = False
29
29
 
@@ -3,7 +3,7 @@ import textwrap
3
3
  from abc import ABC
4
4
  from datetime import date
5
5
 
6
- __version__ = '24.0.0'
6
+ __version__ = '25.0.0'
7
7
 
8
8
  from typing import TextIO, Union, Dict, List
9
9
 
@@ -20,7 +20,7 @@ limitations under the License.
20
20
 
21
21
  from __future__ import print_function
22
22
 
23
- __version__ = '24.0.0'
23
+ __version__ = '25.0.0'
24
24
 
25
25
  import ast
26
26
  import os
@@ -22,7 +22,7 @@ import json
22
22
  import random
23
23
 
24
24
  __author__ = 'diego'
25
- __version__ = '24.0.0'
25
+ __version__ = '25.0.0'
26
26
 
27
27
  DEBUG = True
28
28
 
@@ -20,7 +20,7 @@
20
20
  '''
21
21
  import platform
22
22
 
23
- __version__ = '24.0.0'
23
+ __version__ = '25.0.0'
24
24
 
25
25
  import tkinter
26
26
  import tkinter.ttk
@@ -38,7 +38,7 @@ from com.dtmilano.android.keyevent import KEY_EVENT
38
38
  from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper
39
39
  from com.dtmilano.android.viewclient import ViewClient, View, VERSION_SDK_PROPERTY
40
40
 
41
- __version__ = '24.0.0'
41
+ __version__ = '25.0.0'
42
42
 
43
43
  import sys
44
44
  import threading
@@ -240,13 +240,8 @@ On Ubuntu install
240
240
 
241
241
  $ sudo apt-get install python-imaging python-imaging-tk
242
242
 
243
- On OSX install
243
+ On macOS install
244
244
 
245
- $ brew install homebrew/python/pillow
246
-
247
- or, preferred since El Capitan
248
-
249
- $ sudo easy_install pip
250
245
  $ sudo pip install pillow
251
246
 
252
247
  ''')
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ AndroidViewClient MCP Server Module
5
+
6
+ This module provides a Model Context Protocol (MCP) server that exposes
7
+ CulebraTester2 functionality to AI assistants, enabling AI-powered Android
8
+ test automation.
9
+
10
+ The MCP server acts as a bridge between MCP-compatible AI tools (like Kiro)
11
+ and Android devices running the CulebraTester2 service.
12
+
13
+ Example usage:
14
+ # Start the MCP server
15
+ $ culebra-mcp
16
+
17
+ # Or with custom URL
18
+ $ culebra-mcp --url http://192.168.1.100:9987
19
+
20
+ For more information, see:
21
+ https://github.com/dtmilano/AndroidViewClient/
22
+ """
23
+
24
+ __version__ = '25.0.0'
25
+ __author__ = 'Diego Torres Milano'
26
+ __email__ = 'dtmilano@gmail.com'
27
+
28
+ __all__ = [
29
+ 'server',
30
+ 'client',
31
+ 'object_store',
32
+ 'tools',
33
+ ]
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Object Store for MCP Server
5
+
6
+ This module provides an in-memory storage mechanism for UI element references
7
+ returned by CulebraTester2 find operations. The object store allows MCP tools
8
+ to cache and reuse object identifiers across multiple operations.
9
+
10
+ Copyright (C) 2012-2024 Diego Torres Milano
11
+ Created on 2024-12-20 by Culebra
12
+
13
+ Licensed under the Apache License, Version 2.0 (the "License");
14
+ you may not use this file except in compliance with the License.
15
+ You may obtain a copy of the License at
16
+
17
+ http://www.apache.org/licenses/LICENSE-2.0
18
+
19
+ Unless required by applicable law or agreed to in writing, software
20
+ distributed under the License is distributed on an "AS IS" BASIS,
21
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ See the License for the specific language governing permissions and
23
+ limitations under the License.
24
+ """
25
+
26
+ from typing import Dict, Any, Optional
27
+
28
+ __version__ = '25.0.0'
29
+
30
+
31
+ class ObjectStore:
32
+ """
33
+ In-memory storage for UI element references.
34
+
35
+ The ObjectStore maintains a mapping between object IDs (returned by
36
+ CulebraTester2) and metadata about those objects (such as the selector
37
+ used to find them). This allows MCP tools to validate object IDs before
38
+ performing operations and to retrieve information about cached objects.
39
+
40
+ Example:
41
+ >>> store = ObjectStore()
42
+ >>> store.store(123, {"selector": {"text": "Login"}, "type": "text"})
43
+ >>> store.exists(123)
44
+ True
45
+ >>> store.get(123)
46
+ {'selector': {'text': 'Login'}, 'type': 'text'}
47
+ >>> store.remove(123)
48
+ >>> store.exists(123)
49
+ False
50
+ """
51
+
52
+ def __init__(self):
53
+ """Initialize an empty object store."""
54
+ self._objects: Dict[int, Dict[str, Any]] = {}
55
+
56
+ def store(self, oid: int, metadata: Dict[str, Any]) -> None:
57
+ """
58
+ Store an object reference with associated metadata.
59
+
60
+ Args:
61
+ oid: The object ID returned by CulebraTester2
62
+ metadata: Dictionary containing information about the object,
63
+ typically including the selector used to find it
64
+
65
+ Example:
66
+ >>> store.store(456, {
67
+ ... "selector": {"resourceId": "com.example:id/button"},
68
+ ... "type": "resourceId"
69
+ ... })
70
+ """
71
+ self._objects[oid] = metadata
72
+
73
+ def get(self, oid: int) -> Optional[Dict[str, Any]]:
74
+ """
75
+ Retrieve metadata for a stored object.
76
+
77
+ Args:
78
+ oid: The object ID to look up
79
+
80
+ Returns:
81
+ Dictionary containing the object's metadata, or None if the
82
+ object ID is not found in the store
83
+
84
+ Example:
85
+ >>> metadata = store.get(456)
86
+ >>> if metadata:
87
+ ... print(metadata['selector'])
88
+ {'resourceId': 'com.example:id/button'}
89
+ """
90
+ return self._objects.get(oid)
91
+
92
+ def exists(self, oid: int) -> bool:
93
+ """
94
+ Check if an object ID exists in the store.
95
+
96
+ Args:
97
+ oid: The object ID to check
98
+
99
+ Returns:
100
+ True if the object ID exists, False otherwise
101
+
102
+ Example:
103
+ >>> if store.exists(456):
104
+ ... print("Object found")
105
+ Object found
106
+ """
107
+ return oid in self._objects
108
+
109
+ def remove(self, oid: int) -> None:
110
+ """
111
+ Remove an object from the store.
112
+
113
+ This method is idempotent - removing a non-existent object ID
114
+ does not raise an error.
115
+
116
+ Args:
117
+ oid: The object ID to remove
118
+
119
+ Example:
120
+ >>> store.remove(456)
121
+ >>> store.exists(456)
122
+ False
123
+ """
124
+ if oid in self._objects:
125
+ del self._objects[oid]
126
+
127
+ def clear(self) -> None:
128
+ """
129
+ Clear all objects from the store.
130
+
131
+ This removes all cached object references, effectively resetting
132
+ the store to its initial empty state.
133
+
134
+ Example:
135
+ >>> store.clear()
136
+ >>> len(store._objects)
137
+ 0
138
+ """
139
+ self._objects.clear()
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ MCP Server Core for CulebraTester2
5
+
6
+ This module implements the main MCP server that exposes CulebraTester2
7
+ functionality to AI assistants via the Model Context Protocol.
8
+
9
+ Copyright (C) 2012-2024 Diego Torres Milano
10
+ Created on 2024-12-20 by Culebra
11
+
12
+ Licensed under the Apache License, Version 2.0 (the "License");
13
+ you may not use this file except in compliance with the License.
14
+ You may obtain a copy of the License at
15
+
16
+ http://www.apache.org/licenses/LICENSE-2.0
17
+
18
+ Unless required by applicable law or agreed to in writing, software
19
+ distributed under the License is distributed on an "AS IS" BASIS,
20
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ See the License for the specific language governing permissions and
22
+ limitations under the License.
23
+ """
24
+
25
+ import os
26
+ import sys
27
+ import logging
28
+ from mcp.server import FastMCP
29
+
30
+ from culebratester_client import ApiClient, Configuration
31
+ from culebratester_client.api import DefaultApi
32
+ from com.dtmilano.android.mcp.object_store import ObjectStore
33
+
34
+ __version__ = '25.0.0'
35
+
36
+ # Configure logging
37
+ DEBUG = os.environ.get('CULEBRATESTER2_DEBUG', '').lower() in ('1', 'true', 'yes')
38
+ logging.basicConfig(
39
+ level=logging.DEBUG if DEBUG else logging.INFO,
40
+ format='[%(asctime)s] %(levelname)s [%(name)s] %(message)s',
41
+ stream=sys.stderr
42
+ )
43
+ logger = logging.getLogger('culebratester2-mcp')
44
+
45
+ # Get configuration from environment variables
46
+ BASE_URL = os.environ.get('CULEBRATESTER2_URL', 'http://localhost:9987')
47
+ TIMEOUT = int(os.environ.get('CULEBRATESTER2_TIMEOUT', '30'))
48
+
49
+ logger.info("Starting CulebraTester2 MCP Server")
50
+ logger.info(" Base URL: {}".format(BASE_URL))
51
+ logger.info(" Timeout: {}s".format(TIMEOUT))
52
+ logger.info(" Debug mode: {}".format(DEBUG))
53
+
54
+ # Create FastMCP server instance
55
+ mcp = FastMCP(
56
+ name="culebratester2-mcp-server",
57
+ instructions="MCP server for Android UI automation using CulebraTester2. "
58
+ "Provides tools to interact with Android devices through the CulebraTester2 backend."
59
+ )
60
+
61
+ # Initialize official CulebraTester2 client
62
+ # Note: The official client's OpenAPI spec doesn't include /v2 prefix in paths,
63
+ # so we add it to the host URL
64
+ configuration = Configuration()
65
+ configuration.host = "{}/v2".format(BASE_URL)
66
+ api_client = ApiClient(configuration)
67
+ api_client.rest_client.pool_manager.connection_pool_kw['timeout'] = TIMEOUT
68
+ client = DefaultApi(api_client)
69
+
70
+ # Initialize object store (shared across all tool calls)
71
+ objectStore = ObjectStore()
72
+
73
+
74
+ def validateConnection():
75
+ """Validate connection to CulebraTester2 server."""
76
+ try:
77
+ logger.debug("Validating connection to CulebraTester2...")
78
+ # Use the info endpoint to check service health and version
79
+ info = client.culebra_info_get()
80
+ logger.info("Connected to CulebraTester2 at {}".format(BASE_URL))
81
+ logger.info(" Version: {} (code: {})".format(
82
+ info.version_name if hasattr(info, 'version_name') else 'unknown',
83
+ info.version_code if hasattr(info, 'version_code') else 'unknown'
84
+ ))
85
+ print("Connected to CulebraTester2 at {}".format(BASE_URL), file=sys.stderr)
86
+ print(" Version: {} (code: {})".format(
87
+ info.version_name if hasattr(info, 'version_name') else 'unknown',
88
+ info.version_code if hasattr(info, 'version_code') else 'unknown'
89
+ ), file=sys.stderr)
90
+ return True
91
+ except Exception as e:
92
+ logger.error("Could not connect to CulebraTester2 at {}: {}".format(BASE_URL, e))
93
+ print("Warning: Could not connect to CulebraTester2 at {}: {}".format(BASE_URL, e), file=sys.stderr)
94
+ print("Server will start but tools may fail until connection is established.", file=sys.stderr)
95
+ return False
96
+
97
+
98
+ # Import tools after mcp instance is created (tools will register themselves)
99
+ from com.dtmilano.android.mcp import tools # noqa: F401, E402
100
+
101
+
102
+ def main():
103
+ """Main entry point for the MCP server."""
104
+ logger.info("Initializing MCP server...")
105
+ validateConnection()
106
+ logger.info("MCP server ready, starting event loop...")
107
+ mcp.run()
108
+
109
+
110
+ if __name__ == "__main__":
111
+ main()