kl-mcp-client 1.0.3__tar.gz → 1.0.4__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.
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/PKG-INFO +1 -1
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/tools.py +44 -6
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client.egg-info/PKG-INFO +1 -1
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/pyproject.toml +1 -1
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/README.md +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/__init__.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/__version__.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/asyncio/__init__.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/asyncio/client.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/asyncio/tools.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client/client.py +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client.egg-info/SOURCES.txt +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client.egg-info/dependency_links.txt +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client.egg-info/requires.txt +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/kl_mcp_client.egg-info/top_level.txt +0 -0
- {kl_mcp_client-1.0.3 → kl_mcp_client-1.0.4}/setup.cfg +0 -0
|
@@ -1,8 +1,24 @@
|
|
|
1
|
+
from functools import wraps
|
|
1
2
|
from typing import Any, Dict, Optional
|
|
2
3
|
|
|
3
4
|
from .client import MCPClient
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
def _ensure_client(func):
|
|
8
|
+
"""Decorator kiểm tra self.client != None trước khi gọi tool."""
|
|
9
|
+
|
|
10
|
+
@wraps(func)
|
|
11
|
+
def wrapper(self, *args, **kwargs):
|
|
12
|
+
if self.client is None:
|
|
13
|
+
return {
|
|
14
|
+
"ok": False,
|
|
15
|
+
"error": "MCP client not connected. Call connect mcp server first.",
|
|
16
|
+
}
|
|
17
|
+
return func(self, *args, **kwargs)
|
|
18
|
+
|
|
19
|
+
return wrapper
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
class MCPTools:
|
|
7
23
|
"""
|
|
8
24
|
Wrapper chuẩn cho Google ADK + MCP Server.
|
|
@@ -10,38 +26,47 @@ class MCPTools:
|
|
|
10
26
|
- Tool screenshot → trả đúng content để ADK Web hiển thị image
|
|
11
27
|
"""
|
|
12
28
|
|
|
13
|
-
def __init__(self
|
|
14
|
-
self.client =
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self.client = None
|
|
15
31
|
|
|
16
32
|
# ======================================================
|
|
17
33
|
# SESSION MANAGEMENT
|
|
18
34
|
# ======================================================
|
|
35
|
+
def connect_mcp(self, mcpUrl: str) -> Dict[str, Any]:
|
|
36
|
+
# sid = self.client.create_session(mcpUrl)
|
|
37
|
+
self.client = MCPClient(base_url=mcpUrl, headers=None, timeout=30, retries=2)
|
|
38
|
+
return {"ok": True, "cdpUrl": "http://127.0.0.1:9222"}
|
|
19
39
|
|
|
40
|
+
@_ensure_client
|
|
20
41
|
def create_session(self, cdpUrl: str) -> Dict[str, Any]:
|
|
21
42
|
sid = self.client.create_session(cdpUrl)
|
|
22
43
|
return {"sessionId": sid}
|
|
23
44
|
|
|
45
|
+
@_ensure_client
|
|
24
46
|
def close_session(self, sessionId: str) -> Dict[str, Any]:
|
|
25
47
|
ok = self.client.close_session(sessionId)
|
|
26
48
|
return {"ok": bool(ok)}
|
|
27
49
|
|
|
50
|
+
@_ensure_client
|
|
28
51
|
def list_sessions(self) -> Dict[str, Any]:
|
|
29
52
|
return {"sessions": self.client.list_local_sessions()}
|
|
30
53
|
|
|
31
54
|
# ======================================================
|
|
32
55
|
# NAVIGATION & DOM
|
|
33
56
|
# ======================================================
|
|
34
|
-
|
|
57
|
+
@_ensure_client
|
|
35
58
|
def open_page(self, sessionId: str, url: str) -> Dict[str, Any]:
|
|
36
59
|
return self.client.call_tool(
|
|
37
60
|
"openPage", {"sessionId": sessionId, "url": url}
|
|
38
61
|
).get("structuredContent", {})
|
|
39
62
|
|
|
63
|
+
@_ensure_client
|
|
40
64
|
def get_html(self, sessionId: str) -> Dict[str, Any]:
|
|
41
65
|
return self.client.call_tool("getHTML", {"sessionId": sessionId}).get(
|
|
42
66
|
"structuredContent", {}
|
|
43
67
|
)
|
|
44
68
|
|
|
69
|
+
@_ensure_client
|
|
45
70
|
def screenshot(self, sessionId: str) -> Dict[str, Any]:
|
|
46
71
|
"""
|
|
47
72
|
Trả về đúng phần IMAGE content:
|
|
@@ -54,16 +79,19 @@ class MCPTools:
|
|
|
54
79
|
full = self.client.call_tool("screenshot", {"sessionId": sessionId})
|
|
55
80
|
return full["content"][0]
|
|
56
81
|
|
|
82
|
+
@_ensure_client
|
|
57
83
|
def click(self, sessionId: str, selector: str) -> Dict[str, Any]:
|
|
58
84
|
return self.client.call_tool(
|
|
59
85
|
"click", {"sessionId": sessionId, "selector": selector}
|
|
60
86
|
).get("structuredContent", {})
|
|
61
87
|
|
|
88
|
+
@_ensure_client
|
|
62
89
|
def type(self, sessionId: str, selector: str, text: str) -> Dict[str, Any]:
|
|
63
90
|
return self.client.call_tool(
|
|
64
91
|
"type", {"sessionId": sessionId, "selector": selector, "text": text}
|
|
65
92
|
).get("structuredContent", {})
|
|
66
93
|
|
|
94
|
+
@_ensure_client
|
|
67
95
|
def evaluate(self, sessionId: str, expression: str) -> Dict[str, Any]:
|
|
68
96
|
return self.client.call_tool(
|
|
69
97
|
"evaluate", {"sessionId": sessionId, "expression": expression}
|
|
@@ -72,27 +100,31 @@ class MCPTools:
|
|
|
72
100
|
# ======================================================
|
|
73
101
|
# ELEMENT UTILITIES
|
|
74
102
|
# ======================================================
|
|
75
|
-
|
|
103
|
+
@_ensure_client
|
|
76
104
|
def find_element(self, sessionId: str, selector: str) -> Dict[str, Any]:
|
|
77
105
|
return self.client.call_tool(
|
|
78
106
|
"findElement", {"sessionId": sessionId, "selector": selector}
|
|
79
107
|
).get("structuredContent", {})
|
|
80
108
|
|
|
109
|
+
@_ensure_client
|
|
81
110
|
def find_all(self, sessionId: str, selector: str) -> Dict[str, Any]:
|
|
82
111
|
return self.client.call_tool(
|
|
83
112
|
"findAll", {"sessionId": sessionId, "selector": selector}
|
|
84
113
|
).get("structuredContent", {})
|
|
85
114
|
|
|
115
|
+
@_ensure_client
|
|
86
116
|
def get_bounding_box(self, sessionId: str, selector: str) -> Dict[str, Any]:
|
|
87
117
|
return self.client.call_tool(
|
|
88
118
|
"getBoundingBox", {"sessionId": sessionId, "selector": selector}
|
|
89
119
|
).get("structuredContent", {})
|
|
90
120
|
|
|
121
|
+
@_ensure_client
|
|
91
122
|
def click_bounding_box(self, sessionId: str, selector: str) -> Dict[str, Any]:
|
|
92
123
|
return self.client.call_tool(
|
|
93
124
|
"clickBoundingBox", {"sessionId": sessionId, "selector": selector}
|
|
94
125
|
).get("structuredContent", {})
|
|
95
126
|
|
|
127
|
+
@_ensure_client
|
|
96
128
|
def upload_file(
|
|
97
129
|
self, sessionId: str, selector: str, filename: str, base64data: str
|
|
98
130
|
) -> Dict[str, Any]:
|
|
@@ -116,6 +148,7 @@ class MCPTools:
|
|
|
116
148
|
},
|
|
117
149
|
).get("structuredContent", {})
|
|
118
150
|
|
|
151
|
+
@_ensure_client
|
|
119
152
|
def wait_for_selector(
|
|
120
153
|
self, sessionId: str, selector: str, timeoutMs: Optional[int] = None
|
|
121
154
|
) -> Dict[str, Any]:
|
|
@@ -130,7 +163,7 @@ class MCPTools:
|
|
|
130
163
|
# ======================================================
|
|
131
164
|
# TAB MANAGEMENT
|
|
132
165
|
# ======================================================
|
|
133
|
-
|
|
166
|
+
@_ensure_client
|
|
134
167
|
def new_tab(
|
|
135
168
|
self, sessionId: str, url: Optional[str] = "about:blank"
|
|
136
169
|
) -> Dict[str, Any]:
|
|
@@ -138,6 +171,7 @@ class MCPTools:
|
|
|
138
171
|
"newTab", {"sessionId": sessionId, "url": url}
|
|
139
172
|
).get("structuredContent", {})
|
|
140
173
|
|
|
174
|
+
@_ensure_client
|
|
141
175
|
def switch_tab(self, sessionId: str, targetId: str) -> Dict[str, Any]:
|
|
142
176
|
return self.client.call_tool(
|
|
143
177
|
"switchTab", {"sessionId": sessionId, "targetId": targetId}
|
|
@@ -146,27 +180,31 @@ class MCPTools:
|
|
|
146
180
|
# ======================================================
|
|
147
181
|
# ADVANCED ACTIONS
|
|
148
182
|
# ======================================================
|
|
149
|
-
|
|
183
|
+
@_ensure_client
|
|
150
184
|
def click_to_text(self, sessionId: str, text: str) -> dict:
|
|
151
185
|
return self.client.call_tool(
|
|
152
186
|
"clickToText", {"sessionId": sessionId, "text": text}
|
|
153
187
|
).get("structuredContent", {})
|
|
154
188
|
|
|
189
|
+
@_ensure_client
|
|
155
190
|
def find_element_xpath(self, sessionId: str, xpath: str) -> Dict[str, Any]:
|
|
156
191
|
return self.client.call_tool(
|
|
157
192
|
"findElementByXPath", {"sessionId": sessionId, "xpath": xpath}
|
|
158
193
|
).get("structuredContent", {})
|
|
159
194
|
|
|
195
|
+
@_ensure_client
|
|
160
196
|
def find_element_by_text(self, sessionId: str, text: str) -> Dict[str, Any]:
|
|
161
197
|
return self.client.call_tool(
|
|
162
198
|
"findElementByText", {"sessionId": sessionId, "text": text}
|
|
163
199
|
).get("structuredContent", {})
|
|
164
200
|
|
|
201
|
+
@_ensure_client
|
|
165
202
|
def click_by_node_id(self, sessionId: str, nodeId: int) -> Dict[str, Any]:
|
|
166
203
|
return self.client.call_tool(
|
|
167
204
|
"clickByNodeId", {"sessionId": sessionId, "nodeId": nodeId}
|
|
168
205
|
).get("structuredContent", {})
|
|
169
206
|
|
|
207
|
+
@_ensure_client
|
|
170
208
|
def import_cookies(self, sessionId: str, cookies: dict) -> Dict[str, Any]:
|
|
171
209
|
return self.client.call_tool(
|
|
172
210
|
"importCookies", {"sessionId": sessionId, "cookies": cookies}
|
|
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
|