kl-mcp-client 2.0.4__py3-none-any.whl → 2.1.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.
@@ -46,7 +46,7 @@ class MCPTools:
46
46
 
47
47
  async def screenshot(self, sessionId: str) -> Dict[str, Any]:
48
48
  """
49
- ADK Web expects this structure:
49
+ ADK Web expects:
50
50
  {
51
51
  "type": "image",
52
52
  "mimeType": "image/png",
@@ -121,7 +121,7 @@ class MCPTools:
121
121
  ) -> Dict[str, Any]:
122
122
  args = {"sessionId": sessionId, "selector": selector}
123
123
  if timeoutMs is not None:
124
- args["timeoutMs"] = timeoutMs
124
+ args["timeoutMs"] = int(timeoutMs)
125
125
 
126
126
  res = await self.client.call_tool("waitForSelector", args)
127
127
  return res.get("structuredContent", {})
@@ -145,10 +145,10 @@ class MCPTools:
145
145
  return res.get("structuredContent", {})
146
146
 
147
147
  # ======================================================
148
- # ADVANCED
148
+ # ADVANCED ACTIONS
149
149
  # ======================================================
150
150
 
151
- async def click_to_text(self, sessionId: str, text: str) -> dict:
151
+ async def click_to_text(self, sessionId: str, text: str) -> Dict[str, Any]:
152
152
  res = await self.client.call_tool(
153
153
  "clickToText", {"sessionId": sessionId, "text": text}
154
154
  )
@@ -178,25 +178,97 @@ class MCPTools:
178
178
  )
179
179
  return res.get("structuredContent", {})
180
180
 
181
+ async def get_dom_tree(self, sessionId: str, args: Optional[dict] = None):
182
+ return await self.client.call_tool(
183
+ "getDomTree", {"sessionId": sessionId, "args": args or {}}
184
+ )
185
+
186
+ async def get_clickable(self, sessionId: str, args: Optional[dict] = None):
187
+ return await self.client.call_tool(
188
+ "getClickable", {"sessionId": sessionId, "args": args or {}}
189
+ )
190
+
191
+ async def selector_map(
192
+ self, sessionId: str, selector: str, args: Optional[dict] = None
193
+ ):
194
+ return await self.client.call_tool(
195
+ "selectorMap",
196
+ {"sessionId": sessionId, "selector": selector, "args": args or {}},
197
+ )
198
+
199
+ # ======================================================
200
+ # AI / CONTENT PARSING
201
+ # ======================================================
202
+
181
203
  async def parse_html_by_prompt(self, html: str, prompt: str) -> Dict[str, Any]:
204
+ res = await self.client.call_tool(
205
+ "parseHTMLByPrompt",
206
+ {"html": html, "prompt": prompt},
207
+ )
208
+ return res.get("structuredContent", {})
209
+
210
+ # ======================================================
211
+ # MOUSE / PERFORM ACTIONS
212
+ # ======================================================
213
+
214
+ async def perform_click_xy(
215
+ self,
216
+ sessionId: str,
217
+ x: float,
218
+ y: float,
219
+ ) -> Dict[str, Any]:
220
+ """
221
+ Move mouse smoothly to (x, y) and left click.
182
222
  """
183
- Parse HTML content using AI with dynamic prompt-defined structure.
223
+ res = await self.client.call_tool(
224
+ "perform",
225
+ {
226
+ "sessionId": sessionId,
227
+ "action": "click",
228
+ "x": float(x),
229
+ "y": float(y),
230
+ },
231
+ )
232
+ return res.get("structuredContent", {})
184
233
 
185
- Args:
186
- html: Raw HTML string (client-provided)
187
- prompt: Instruction that defines what to extract and output structure
188
- Example:
189
- - "Hãy lấy nội dung bài viết, struct trả về { content }"
190
- - "Hãy lấy số lượng like, share, comment, trả JSON { like, share, comment }"
234
+ async def perform_drag(
235
+ self,
236
+ sessionId: str,
237
+ from_x: float,
238
+ from_y: float,
239
+ to_x: float,
240
+ to_y: float,
241
+ ) -> Dict[str, Any]:
242
+ """
243
+ Drag mouse from (from_x, from_y) to (to_x, to_y).
244
+ """
245
+ res = await self.client.call_tool(
246
+ "perform",
247
+ {
248
+ "sessionId": sessionId,
249
+ "action": "drag",
250
+ "from": {"x": float(from_x), "y": float(from_y)},
251
+ "to": {"x": float(to_x), "y": float(to_y)},
252
+ },
253
+ )
254
+ return res.get("structuredContent", {})
191
255
 
192
- Returns:
193
- structuredContent (dynamic JSON defined by prompt)
256
+ async def perform_hover(
257
+ self,
258
+ sessionId: str,
259
+ x: float,
260
+ y: float,
261
+ ) -> Dict[str, Any]:
262
+ """
263
+ Move mouse smoothly to (x, y) without clicking.
194
264
  """
195
265
  res = await self.client.call_tool(
196
- "parseHTMLByPrompt",
266
+ "perform",
197
267
  {
198
- "html": html,
199
- "prompt": prompt,
268
+ "sessionId": sessionId,
269
+ "action": "hover",
270
+ "x": float(x),
271
+ "y": float(y),
200
272
  },
201
273
  )
202
274
  return res.get("structuredContent", {})
kl_mcp_client/tools.py CHANGED
@@ -126,63 +126,27 @@ class MCPTools:
126
126
 
127
127
  @_ensure_client
128
128
  def upload_file(
129
- self,
130
- sessionId: str,
131
- selector: str,
132
- file_path: str,
129
+ self, sessionId: str, selector: str, filename: str, base64data: str
133
130
  ) -> Dict[str, Any]:
134
131
  """
135
- Upload file (kể cả video lớn) vào input[type=file] theo luồng mới:
136
- 1. Multipart upload file lên MCP server
137
- 2. Nhận uploadId
138
- 3. Gọi MCP tool uploadFile với uploadId
139
-
132
+ Upload file vào input[type=file]
140
133
  Args:
141
134
  sessionId: MCP browser session
142
135
  selector: CSS selector, ví dụ 'input[type=file]'
143
- file_path: đường dẫn file local (video, pdf, doc, ...)
136
+ filename: tên file trên browser side
137
+ base64data: dữ liệu base64 (không kèm header)
138
+ Returns:
139
+ structured result từ server
144
140
  """
145
-
146
- if not file_path:
147
- return {"ok": False, "error": "file_path is required"}
148
-
149
- # --------------------------------------------------
150
- # 1️⃣ Multipart upload file lên MCP server
151
- # --------------------------------------------------
152
- try:
153
- with open(file_path, "rb") as f:
154
- resp = self.client.http.post(
155
- "/upload",
156
- files={"file": f},
157
- timeout=300, # upload file lớn
158
- )
159
- except Exception as e:
160
- return {"ok": False, "error": f"upload http failed: {e}"}
161
-
162
- if resp.status_code != 200:
163
- return {
164
- "ok": False,
165
- "error": f"upload http error {resp.status_code}: {resp.text}",
166
- }
167
-
168
- data = resp.json()
169
- upload_id = data.get("uploadId")
170
- if not upload_id:
171
- return {"ok": False, "error": "uploadId not returned from server"}
172
-
173
- # --------------------------------------------------
174
- # 2️⃣ Gọi MCP tool uploadFile (PATH MODE)
175
- # --------------------------------------------------
176
- result = self.client.call_tool(
141
+ return self.client.call_tool(
177
142
  "uploadFile",
178
143
  {
179
144
  "sessionId": sessionId,
180
145
  "selector": selector,
181
- "uploadId": upload_id,
146
+ "filename": filename,
147
+ "data": base64data,
182
148
  },
183
- )
184
-
185
- return result.get("structuredContent", {})
149
+ ).get("structuredContent", {})
186
150
 
187
151
  @_ensure_client
188
152
  def wait_for_selector(
@@ -265,16 +229,6 @@ class MCPTools:
265
229
  {"sessionId": sessionId, "selector": selector, "args": args or {}},
266
230
  )
267
231
 
268
- @_ensure_client
269
- def find_element_by_prompt(self, sessionId: str, prompt: str) -> Dict[str, Any]:
270
- """
271
- Gọi tool findElementByPrompt trên MCP server.
272
- Trả về structuredContent gồm: html, nodeId.
273
- """
274
- return self.client.call_tool(
275
- "findElementByPrompt", {"sessionId": sessionId, "prompt": prompt}
276
- ).get("structuredContent", {})
277
-
278
232
  # ======================================================
279
233
  # AI / CONTENT PARSING
280
234
  # ======================================================
@@ -300,3 +254,65 @@ class MCPTools:
300
254
  "prompt": prompt,
301
255
  },
302
256
  ).get("structuredContent", {})
257
+ # ======================================================
258
+ # MOUSE / PERFORM ACTIONS
259
+ # ======================================================
260
+ @_ensure_client
261
+ def perform_click_xy(
262
+ self,
263
+ sessionId: str,
264
+ x: float,
265
+ y: float,
266
+ ) -> Dict[str, Any]:
267
+ """
268
+ Move mouse smoothly to (x, y) and left click.
269
+ """
270
+ return self.client.call_tool(
271
+ "perform",
272
+ {
273
+ "sessionId": sessionId,
274
+ "action": "click",
275
+ "x": float(x),
276
+ "y": float(y),
277
+ },
278
+ ).get("structuredContent", {})
279
+ @_ensure_client
280
+ def perform_drag(
281
+ self,
282
+ sessionId: str,
283
+ from_x: float,
284
+ from_y: float,
285
+ to_x: float,
286
+ to_y: float,
287
+ ) -> Dict[str, Any]:
288
+ """
289
+ Drag mouse from (from_x, from_y) to (to_x, to_y).
290
+ """
291
+ return self.client.call_tool(
292
+ "perform",
293
+ {
294
+ "sessionId": sessionId,
295
+ "action": "drag",
296
+ "from": {"x": float(from_x), "y": float(from_y)},
297
+ "to": {"x": float(to_x), "y": float(to_y)},
298
+ },
299
+ ).get("structuredContent", {})
300
+ @_ensure_client
301
+ def perform_hover(
302
+ self,
303
+ sessionId: str,
304
+ x: float,
305
+ y: float,
306
+ ) -> Dict[str, Any]:
307
+ """
308
+ Move mouse smoothly to (x, y) without clicking.
309
+ """
310
+ return self.client.call_tool(
311
+ "perform",
312
+ {
313
+ "sessionId": sessionId,
314
+ "action": "hover",
315
+ "x": float(x),
316
+ "y": float(y),
317
+ },
318
+ ).get("structuredContent", {})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kl-mcp-client
3
- Version: 2.0.4
3
+ Version: 2.1.0
4
4
  Summary: MCP Client for Python
5
5
  Author-email: Kyle <hngan.it@gmail.com>
6
6
  License: MIT
@@ -1,11 +1,11 @@
1
1
  kl_mcp_client/__init__.py,sha256=pdJdBcEH5HaRuHSe2B7VUyRgH5ad3u1dDc4euZMDRMY,106
2
2
  kl_mcp_client/__version__.py,sha256=CCYQUt19bi0kfo0Q8q8snnwgw_c9F3s6FFxTMsX1yDE,22
3
3
  kl_mcp_client/client.py,sha256=ujhRp0zC5GJKnBYziIPMdKZqrhv8K2t6tBAuwYw7q_k,4513
4
- kl_mcp_client/tools.py,sha256=yJ8eTZrIPCyAwLm462e1eZOz6yaPk39J4gd13BzYXbw,10974
4
+ kl_mcp_client/tools.py,sha256=5lI8eoAaZQuB__IfcAzgJh_J7VLw--NMO1rqcc9X6Qw,11083
5
5
  kl_mcp_client/asyncio/__init__.py,sha256=pdJdBcEH5HaRuHSe2B7VUyRgH5ad3u1dDc4euZMDRMY,106
6
6
  kl_mcp_client/asyncio/client.py,sha256=bgooGIzdU-BKAo0f2wHZKkuIHlKrj5GJ8vxAuwU6Xn4,4409
7
- kl_mcp_client/asyncio/tools.py,sha256=tCeHUc4ao99Hu4ck0BmvDo95vmTtG1ChvwHamaIx_zE,7655
8
- kl_mcp_client-2.0.4.dist-info/METADATA,sha256=95PHfR0WCTh4FcvCc6F9a1HLkGYAaZpdJd9N1lGPGWI,4443
9
- kl_mcp_client-2.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
- kl_mcp_client-2.0.4.dist-info/top_level.txt,sha256=wd_HFFyGjiKavwACuj8Ny0svtVyNsrxCSVU48EkoQ7c,14
11
- kl_mcp_client-2.0.4.dist-info/RECORD,,
7
+ kl_mcp_client/asyncio/tools.py,sha256=82zwDC_N0spi_DIPbOq6HgG6qxgpBM2PtBkzUZGDxAo,9658
8
+ kl_mcp_client-2.1.0.dist-info/METADATA,sha256=L1ezxu5mRFgD10rsX668ebKhe8dFGmVoIyP2wvzqqo8,4443
9
+ kl_mcp_client-2.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ kl_mcp_client-2.1.0.dist-info/top_level.txt,sha256=wd_HFFyGjiKavwACuj8Ny0svtVyNsrxCSVU48EkoQ7c,14
11
+ kl_mcp_client-2.1.0.dist-info/RECORD,,