Metadata-Version: 2.4
Name: kl-mcp-client
Version: 2.4.2
Summary: MCP Client for Python
Author-email: Kyle <hngan.it@gmail.com>
License: MIT
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.32.5
Requires-Dist: httpx>=0.28.1
Provides-Extra: camoufox
Requires-Dist: camoufox; extra == "camoufox"
Requires-Dist: playwright; extra == "camoufox"

# kl-mcp-client (Python)

Thư viện Python Client dùng để điều khiển trình duyệt Web thông qua Model Context Protocol (MCP). Hỗ trợ Camoufox anti-detect browser với persistent profile, fingerprint spoofing và proxy.

## Cài đặt

```bash
# Core SDK
pip install kl-mcp-client

# Với Camoufox anti-detect browser
pip install kl-mcp-client[camoufox]
python -m camoufox fetch
```

---

## Hướng dẫn Bắt đầu Nhanh

### Chế độ Đồng bộ (Synchronous)
```python
from kl_mcp_client.tools import MCPTools

tools = MCPTools()
tools.connect_mcp("http://localhost:8080/mcp")
sid = tools.create_session("ws://browser-host:9222")["sessionId"]
tools.open_page(sid, "https://google.com")
tools.screenshot(sid)
tools.close_session(sid)
```

### Chế độ Bất đồng bộ (Asynchronous)
```python
import asyncio
from kl_mcp_client.asyncio.tools import MCPTools

async def main():
    tools = MCPTools()
    tools.connect_mcp("http://localhost:8080/mcp")
    res = await tools.create_session("ws://browser-host:9222")
    sid = res["sessionId"]
    await tools.open_page(sid, "https://github.com")
    await tools.close_session(sid)

asyncio.run(main())
```

---

## Camoufox Anti-Detect Browser

Module `kl_mcp_client.camoufox` quản lý Camoufox browser (Firefox-based) với khả năng chống phát hiện bot.

### Local Mode — Persistent Profile

Dùng cho tự động hóa cần giữ session (cookies, localStorage, fingerprint) qua nhiều lần chạy.

```python
from kl_mcp_client.camoufox import CamoufoxManager, CamoufoxConfig

cfg = CamoufoxConfig(
    profile_dir="~/.camoufox-profiles/account-1",
    proxy={
        "server": "http://proxy.example.com:8080",
        "username": "user",
        "password": "pass",
    },
    headless=True,
    locale="vi-VN",
    os_name="windows",       # Fingerprint giả lập Windows
    block_webrtc=True,        # Chặn WebRTC leak IP
)

with CamoufoxManager(cfg) as mgr:
    page = mgr.context.new_page()
    page.goto("https://example.com")

    # Cookies & localStorage tự động persist trong profile_dir
    print(page.title())
    print(page.evaluate("navigator.userAgent"))

    # Anti-detect verification
    assert page.evaluate("navigator.webdriver") == False
```

### Server Mode — WS Endpoint cho MCP Server

Dùng cho Docker deployment hoặc kết nối remote.

```python
from kl_mcp_client.camoufox import CamoufoxManager, CamoufoxConfig

cfg = CamoufoxConfig(
    mode="server",
    headless=True,
    host="0.0.0.0",       # Bind tất cả interface (cần cho Docker)
)

with CamoufoxManager(cfg) as mgr:
    ws_endpoint = mgr.ws_endpoint
    # ws://127.0.0.1:RANDOM_PORT/TOKEN
    print(f"WS: {ws_endpoint}")
```

### Tích hợp Camoufox + MCP Server (Full Flow)

Mở Camoufox ở chế độ server, truyền WS endpoint vào MCP Server, rồi dùng MCPTools điều khiển browser.

**Cách 1: MCP Server đọc WS endpoint từ biến môi trường**

MCP Server hỗ trợ env `BROWSER_ENGINE` và `BROWSER_PLAYWRIGHT_WS`. Khi set hai biến này, mọi session tạo qua `create_session` sẽ tự động dùng Camoufox.

```bash
# 1. Mở Camoufox server (terminal 1)
python -c "
from kl_mcp_client.camoufox import CamoufoxManager, CamoufoxConfig
cfg = CamoufoxConfig(mode='server', headless=True)
mgr = CamoufoxManager(cfg)
mgr.start()
print(f'WS: {mgr.ws_endpoint}')
input('Enter để tắt...')
mgr.stop()
"

# 2. Khởi động MCP Server với Camoufox engine (terminal 2)
export BROWSER_ENGINE=camoufox
export BROWSER_PLAYWRIGHT_WS=ws://127.0.0.1:XXXXX/TOKEN   # WS từ bước 1
./mcp-server
```

```python
# 3. Client SDK kết nối MCP Server và dùng browser (không cần biết engine bên dưới)
from kl_mcp_client.tools import MCPTools

tools = MCPTools()
tools.connect_mcp("http://localhost:8080/mcp")

# create_session không cần truyền cdpUrl khi server đã có BROWSER_PLAYWRIGHT_WS
sid = tools.create_session("")["sessionId"]
tools.open_page(sid, "https://example.com")
tools.screenshot(sid)
tools.close_session(sid)
```

**Cách 2: Tự quản lý Camoufox trong code Python**

Mở Camoufox server mode trong cùng script, lấy WS endpoint, rồi truyền trực tiếp khi tạo session.

```python
from kl_mcp_client.tools import MCPTools
from kl_mcp_client.camoufox import CamoufoxManager, CamoufoxConfig

# Mở Camoufox anti-detect browser ở server mode
cfg = CamoufoxConfig(
    mode="server",
    headless=True,
    proxy={"server": "http://proxy:8080"},   # tuỳ chọn
    os_name="windows",                        # giả lập Windows fingerprint
    block_webrtc=True,                        # chặn WebRTC leak IP
)

with CamoufoxManager(cfg) as mgr:
    ws = mgr.ws_endpoint  # ws://127.0.0.1:XXXXX/TOKEN

    # Kết nối MCP Server (server phải chạy engine=playwright hoặc camoufox)
    tools = MCPTools()
    tools.connect_mcp("http://localhost:8080/mcp")

    # Tạo session với Camoufox WS endpoint
    sid = tools.create_session(ws)["sessionId"]

    # Dùng như bình thường — browser bên dưới là Camoufox anti-detect
    tools.open_page(sid, "https://example.com")
    result = tools.screenshot(sid)
    tools.close_session(sid)

# Camoufox tự tắt khi thoát with block
```

**Cách 3: Docker — Camoufox container + MCP Server**

```bash
# 1. Chạy Camoufox container
docker run -d --name camoufox -p 42019:42019 mcp-server-camoufox:latest

# 2. MCP Server kết nối Camoufox container
export BROWSER_ENGINE=camoufox
export BROWSER_PLAYWRIGHT_WS=ws://localhost:42019/TOKEN
./mcp-server
```

```python
# 3. Client SDK — hoàn toàn giống nhau, không cần biết browser ở đâu
from kl_mcp_client.tools import MCPTools

tools = MCPTools()
tools.connect_mcp("http://localhost:8080/mcp")
sid = tools.create_session("")["sessionId"]
tools.open_page(sid, "https://example.com")
tools.screenshot(sid)
tools.close_session(sid)
```

> **Lưu ý:** MCP Server nhận biết engine qua env `BROWSER_ENGINE`:
> - `chromedp` (mặc định): Chrome/Chromium qua CDP
> - `camoufox`: Camoufox Firefox anti-detect
> - `playwright`: Firefox qua Playwright
>
> Khi `BROWSER_PLAYWRIGHT_WS` được set, server kết nối tới browser WS đã chạy sẵn thay vì tự mở browser mới.

### CamoufoxConfig Options

| Option | Type | Default | Mô tả |
|---|---|---|---|
| `mode` | `"local" \| "server"` | `"local"` | Local = Playwright trực tiếp. Server = WS endpoint |
| `profile_dir` | `str \| None` | `None` | Thư mục profile Firefox. `None` = tạm thời |
| `proxy` | `dict \| None` | `None` | `{"server": "...", "username": "...", "password": "..."}` |
| `headless` | `bool` | `True` | Chạy headless |
| `geoip` | `bool` | `False` | Tự detect geolocation từ proxy IP |
| `fingerprint` | `dict \| None` | `None` | Custom fingerprint. `None` = tự tạo random |
| `fingerprint_preset` | `bool \| dict \| None` | `None` | Dùng fingerprint thật thay vì random |
| `locale` | `str \| None` | `None` | Locale: `"en-US"`, `"vi-VN"` |
| `os_name` | `str \| None` | `None` | OS giả lập: `"windows"`, `"macos"`, `"linux"` |
| `block_images` | `bool` | `False` | Chặn hình ảnh |
| `block_webrtc` | `bool` | `False` | Chặn WebRTC leak |
| `block_webgl` | `bool` | `False` | Chặn WebGL fingerprint |
| `addons` | `list[str] \| None` | `None` | Đường dẫn tới Firefox extension XPI |
| `humanize` | `bool \| float \| None` | `None` | Mô phỏng di chuyển chuột con người |
| `enable_cache` | `bool \| None` | `None` | Browser disk cache |
| `port` | `int` | `0` | Port (server mode). `0` = random high port |
| `host` | `str` | `"127.0.0.1"` | Bind host (server mode) |

---

## Tài liệu API

### Session & Navigation

| Method | Mô tả | MCP Server |
|---|---|---|
| `connect_mcp(url)` | Kết nối tới MCP server | v1.0.0+ |
| `create_session(cdpUrl)` | Tạo phiên browser | v1.0.0+ |
| `close_session(sid)` | Đóng phiên | v1.0.0+ |
| `open_page(sid, url)` | Mở URL | v1.0.0+ |
| `get_html(sid)` | Lấy HTML | v1.0.0+ |
| `get_clean_text(sid)` | Lấy text đã lọc tag | v1.0.0+ |
| `screenshot(sid)` | Chụp màn hình (Base64) | v1.0.0+ |
| `get_cookies(sid)` | Lấy cookies | v1.0.0+ |
| `import_cookies(sid, cookies)` | Import cookies | v1.0.0+ |

### AI Interaction

| Method | Mô tả | MCP Server |
|---|---|---|
| `find_element_by_prompt(sid, prompt)` | Tìm phần tử bằng AI | v1.5.0+ |
| `find_elements_by_prompt(sid, prompt)` | Tìm nhiều phần tử bằng AI | v1.6.1+ |
| `find_element_context(sid, prompt)` | Tìm phần tử bằng context analysis | v1.6.1+ |
| `click_by_prompt(sid, prompt)` | AI tìm và click | v1.6.1+ |
| `extract_structured(sid, prompt)` | Trích xuất dữ liệu thành JSON | v1.6.1+ |
| `parse_html_by_prompt(html, prompt)` | Parse HTML bằng AI | v1.6.1+ |

### Input & Controls

| Method | Mô tả | MCP Server |
|---|---|---|
| `click(sid, selector)` | Click phần tử | v1.0.0+ |
| `click_to_text(sid, text)` | Click theo text | v1.0.0+ |
| `type(sid, selector, text)` | Nhập text vào input | v1.0.0+ |
| `send_text(sid, text, interval)` | Gõ phím human-like | v1.0.0+ |
| `send_combo(sid, text)` | Tổ hợp phím (Ctrl+A) | v1.0.0+ |
| `send_keys(sid, text)` | Gửi keystrokes | v1.0.0+ |
| `scroll(sid, x, y)` | Cuộn trang | v1.0.0+ |
| `drag_and_drop(sid, fx, fy, tx, ty)` | Kéo thả | v1.0.0+ |
| `hover(sid, x, y)` | Di chuột | v1.0.0+ |

### Tab Management

| Method | Mô tả | MCP Server |
|---|---|---|
| `list_tabs(sid)` | Liệt kê tabs | v1.0.0+ |
| `new_tab(sid, url)` | Mở tab mới | v1.0.0+ |
| `switch_tab(sid, tabId)` | Chuyển tab | v1.0.0+ |
| `close_tab(sid, tabId)` | Đóng tab | v1.0.0+ |
| `current_tab(sid)` | Tab hiện tại | v1.0.0+ |
| `get_current_url(sid)` | URL hiện tại | v1.0.0+ |

### DOM & Element

| Method | Mô tả | MCP Server |
|---|---|---|
| `get_dom_tree(sid)` | DOM tree | v1.0.0+ |
| `get_clickable(sid)` | Các phần tử clickable | v1.0.0+ |
| `find_element(sid, selector)` | Tìm 1 phần tử | v1.0.0+ |
| `find_all(sid, selector)` | Tìm tất cả phần tử | v1.0.0+ |
| `find_element_by_xpath(sid, xpath)` | Tìm bằng XPath | v1.0.0+ |
| `find_element_by_text(sid, text)` | Tìm bằng text | v1.0.0+ |

### Data Streaming

| Method | Mô tả | MCP Server |
|---|---|---|
| `evaluate(sid, expression)` | Chạy JavaScript | v1.0.0+ |
| `evaluate_stream_all(sid, expr, chunk, max)` | Stream dữ liệu lớn | v1.6.0+ |

### File Upload

| Method | Mô tả | MCP Server |
|---|---|---|
| `upload_file(sid, selector, file_path)` | Upload file (all-in-one) | v1.0.0+ |
| `upload_file_to_server(file_path)` | Upload file lên server | v1.0.0+ |
| `set_file_for_input(sid, selector, uploadId)` | Gắn file vào input | v1.0.0+ |

---

## Ví dụ

Xem thư mục [`kl_mcp_client/examples/`](./kl_mcp_client/examples/).

## License
MIT
