mcp-hcaptcha 2026.10.8.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.
@@ -0,0 +1,6 @@
1
+ ACEDATACLOUD_API_TOKEN=
2
+ ACEDATACLOUD_API_BASE_URL=https://api.acedata.cloud
3
+ HCAPTCHA_REQUEST_TIMEOUT=120
4
+ MCP_TRANSPORT=stdio
5
+ MCP_SERVER_NAME=hcaptcha
6
+ LOG_LEVEL=INFO
@@ -0,0 +1,2 @@
1
+ __pycache__/
2
+ *.py[cod]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AceDataCloud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-hcaptcha
3
+ Version: 2026.10.8.0
4
+ Summary: MCP server for AceDataCloud hCaptcha captcha APIs
5
+ Project-URL: Homepage, https://github.com/AceDataCloud/MCPs
6
+ Project-URL: Documentation, https://platform.acedata.cloud/services/018c653e-4f1b-433f-82f9-732ef2767040?utm_source=pypi&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_package_quick_start
7
+ Project-URL: Repository, https://github.com/AceDataCloud/MCPs
8
+ Project-URL: Issues, https://github.com/AceDataCloud/MCPs/issues
9
+ Author-email: AceDataCloud <support@acedata.cloud>
10
+ Maintainer-email: AceDataCloud <support@acedata.cloud>
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: acedata,captcha,hcaptcha,mcp,model-context-protocol
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: cryptography>=42.0.0
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: loguru>=0.7.0
28
+ Requires-Dist: mcp<2,>=1.2.0
29
+ Requires-Dist: pydantic>=2.0.0
30
+ Requires-Dist: python-dotenv>=1.0.0
31
+ Requires-Dist: redis<7,>=5.0.0
32
+ Provides-Extra: all
33
+ Requires-Dist: build>=1.2.0; extra == 'all'
34
+ Requires-Dist: mypy>=1.10.0; extra == 'all'
35
+ Requires-Dist: pre-commit>=3.7.0; extra == 'all'
36
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
37
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'all'
38
+ Requires-Dist: pytest>=8.0.0; extra == 'all'
39
+ Requires-Dist: respx>=0.21.0; extra == 'all'
40
+ Requires-Dist: ruff>=0.4.0; extra == 'all'
41
+ Requires-Dist: twine>=5.0.0; extra == 'all'
42
+ Provides-Extra: dev
43
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
44
+ Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
45
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
46
+ Provides-Extra: release
47
+ Requires-Dist: build>=1.2.0; extra == 'release'
48
+ Requires-Dist: twine>=5.0.0; extra == 'release'
49
+ Provides-Extra: test
50
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
51
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
52
+ Requires-Dist: pytest>=8.0.0; extra == 'test'
53
+ Requires-Dist: respx>=0.21.0; extra == 'test'
54
+ Description-Content-Type: text/markdown
55
+
56
+ <!-- Generated by scripts/marketing_readmes.py from README.md; do not edit. -->
57
+ # MCP HCaptcha Server
58
+
59
+ A Model Context Protocol (MCP) server for AceDataCloud's hCaptcha captcha-solving APIs.
60
+
61
+ ## Features
62
+ - Solve hCaptcha image challenges and retrieve hCaptcha site tokens.
63
+ - Shared async task polling via `/captcha/tasks`
64
+ - Bearer-token authentication through AceDataCloud
65
+
66
+ ## Connect locally
67
+
68
+ Use the local stdio package and an AceDataCloud API token. The public hosted HTTPS endpoint could not be verified, so this README does not offer it as a connection option. The local MCP process still calls AceDataCloud's API; it does not run the underlying service offline.
69
+
70
+ Get an API credential through [AceDataCloud Platform](https://platform.acedata.cloud?utm_source=pypi&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_package_platform), keep it out of committed files, and review current pricing before a billable call.
71
+
72
+ ### Local stdio
73
+
74
+ Install the package and give the local process an API token:
75
+
76
+ ```bash
77
+ python -m pip install mcp-hcaptcha
78
+ export ACEDATACLOUD_API_TOKEN='YOUR_API_TOKEN'
79
+ mcp-hcaptcha
80
+ ```
81
+
82
+ For Claude Desktop local MCP, merge this entry into the file opened by its developer settings (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS). `uvx` requires [uv](https://docs.astral.sh/uv/) on `PATH`:
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ "hcaptcha": {
88
+ "command": "uvx",
89
+ "args": ["mcp-hcaptcha"],
90
+ "env": {"ACEDATACLOUD_API_TOKEN": "YOUR_API_TOKEN"}
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ Keep this user-level file private. Self-hosted HTTP uses `mcp-hcaptcha --transport http --port 8000`; expose it only with suitable network and TLS controls. Local execution still calls the AceDataCloud API.
97
+
98
+ ### Check the connection
99
+
100
+ Confirm that the MCP client loads its tools. `hcaptcha_get_usage_guide` returns reference information; it does not prove downstream API access or balance. A real service request can be billed. If it returns 401, check the API token; if it returns 403 or an account/balance error, read that response before retrying.
101
+
102
+ ## Tools
103
+ - `hcaptcha_recognize` — Recognize hCaptcha image challenges
104
+ - `hcaptcha_get_token` — Get an hCaptcha token for a website, optionally with `rqdata`
105
+ - `hcaptcha_get_task` — Poll a captcha task result
106
+ - `hcaptcha_get_usage_guide` — Get hCaptcha usage guide
107
+ - `hcaptcha_get_api_info` — Get hCaptcha API information
108
+
109
+ ## Service details
110
+
111
+ <!-- canonical-documentation -->
112
+ [Service details](https://platform.acedata.cloud/services/018c653e-4f1b-433f-82f9-732ef2767040?utm_source=pypi&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_package_quick_start)
@@ -0,0 +1,56 @@
1
+ # MCP HCaptcha Server
2
+
3
+ A Model Context Protocol (MCP) server for AceDataCloud's hCaptcha captcha-solving APIs.
4
+
5
+ ## Features
6
+ - Solve hCaptcha image challenges and retrieve hCaptcha site tokens.
7
+ - Shared async task polling via `/captcha/tasks`
8
+ - Bearer-token authentication through AceDataCloud
9
+
10
+ ## Connect locally
11
+
12
+ Use the local stdio package and an AceDataCloud API token. The public hosted HTTPS endpoint could not be verified, so this README does not offer it as a connection option. The local MCP process still calls AceDataCloud's API; it does not run the underlying service offline.
13
+
14
+ Get an API credential through [AceDataCloud Platform](https://platform.acedata.cloud?utm_source=github&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_readme_platform), keep it out of committed files, and review current pricing before a billable call.
15
+
16
+ ### Local stdio
17
+
18
+ Install the package and give the local process an API token:
19
+
20
+ ```bash
21
+ python -m pip install mcp-hcaptcha
22
+ export ACEDATACLOUD_API_TOKEN='YOUR_API_TOKEN'
23
+ mcp-hcaptcha
24
+ ```
25
+
26
+ For Claude Desktop local MCP, merge this entry into the file opened by its developer settings (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS). `uvx` requires [uv](https://docs.astral.sh/uv/) on `PATH`:
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "hcaptcha": {
32
+ "command": "uvx",
33
+ "args": ["mcp-hcaptcha"],
34
+ "env": {"ACEDATACLOUD_API_TOKEN": "YOUR_API_TOKEN"}
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ Keep this user-level file private. Self-hosted HTTP uses `mcp-hcaptcha --transport http --port 8000`; expose it only with suitable network and TLS controls. Local execution still calls the AceDataCloud API.
41
+
42
+ ### Check the connection
43
+
44
+ Confirm that the MCP client loads its tools. `hcaptcha_get_usage_guide` returns reference information; it does not prove downstream API access or balance. A real service request can be billed. If it returns 401, check the API token; if it returns 403 or an account/balance error, read that response before retrying.
45
+
46
+ ## Tools
47
+ - `hcaptcha_recognize` — Recognize hCaptcha image challenges
48
+ - `hcaptcha_get_token` — Get an hCaptcha token for a website, optionally with `rqdata`
49
+ - `hcaptcha_get_task` — Poll a captcha task result
50
+ - `hcaptcha_get_usage_guide` — Get hCaptcha usage guide
51
+ - `hcaptcha_get_api_info` — Get hCaptcha API information
52
+
53
+ ## Service details
54
+
55
+ <!-- canonical-documentation -->
56
+ [Service details](https://platform.acedata.cloud/services/018c653e-4f1b-433f-82f9-732ef2767040?utm_source=github&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_readme_quick_start)
@@ -0,0 +1,57 @@
1
+ <!-- Generated by scripts/marketing_readmes.py from README.md; do not edit. -->
2
+ # MCP HCaptcha Server
3
+
4
+ A Model Context Protocol (MCP) server for AceDataCloud's hCaptcha captcha-solving APIs.
5
+
6
+ ## Features
7
+ - Solve hCaptcha image challenges and retrieve hCaptcha site tokens.
8
+ - Shared async task polling via `/captcha/tasks`
9
+ - Bearer-token authentication through AceDataCloud
10
+
11
+ ## Connect locally
12
+
13
+ Use the local stdio package and an AceDataCloud API token. The public hosted HTTPS endpoint could not be verified, so this README does not offer it as a connection option. The local MCP process still calls AceDataCloud's API; it does not run the underlying service offline.
14
+
15
+ Get an API credential through [AceDataCloud Platform](https://platform.acedata.cloud?utm_source=pypi&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_package_platform), keep it out of committed files, and review current pricing before a billable call.
16
+
17
+ ### Local stdio
18
+
19
+ Install the package and give the local process an API token:
20
+
21
+ ```bash
22
+ python -m pip install mcp-hcaptcha
23
+ export ACEDATACLOUD_API_TOKEN='YOUR_API_TOKEN'
24
+ mcp-hcaptcha
25
+ ```
26
+
27
+ For Claude Desktop local MCP, merge this entry into the file opened by its developer settings (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS). `uvx` requires [uv](https://docs.astral.sh/uv/) on `PATH`:
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "hcaptcha": {
33
+ "command": "uvx",
34
+ "args": ["mcp-hcaptcha"],
35
+ "env": {"ACEDATACLOUD_API_TOKEN": "YOUR_API_TOKEN"}
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ Keep this user-level file private. Self-hosted HTTP uses `mcp-hcaptcha --transport http --port 8000`; expose it only with suitable network and TLS controls. Local execution still calls the AceDataCloud API.
42
+
43
+ ### Check the connection
44
+
45
+ Confirm that the MCP client loads its tools. `hcaptcha_get_usage_guide` returns reference information; it does not prove downstream API access or balance. A real service request can be billed. If it returns 401, check the API token; if it returns 403 or an account/balance error, read that response before retrying.
46
+
47
+ ## Tools
48
+ - `hcaptcha_recognize` — Recognize hCaptcha image challenges
49
+ - `hcaptcha_get_token` — Get an hCaptcha token for a website, optionally with `rqdata`
50
+ - `hcaptcha_get_task` — Poll a captcha task result
51
+ - `hcaptcha_get_usage_guide` — Get hCaptcha usage guide
52
+ - `hcaptcha_get_api_info` — Get hCaptcha API information
53
+
54
+ ## Service details
55
+
56
+ <!-- canonical-documentation -->
57
+ [Service details](https://platform.acedata.cloud/services/018c653e-4f1b-433f-82f9-732ef2767040?utm_source=pypi&utm_medium=referral&utm_campaign=evergreen&utm_content=hcaptcha_mcp_package_quick_start)
@@ -0,0 +1,15 @@
1
+ """Core module for MCP HCaptcha server."""
2
+
3
+ from core.client import HCaptchaClient
4
+ from core.config import settings
5
+ from core.exceptions import HCaptchaAPIError, HCaptchaAuthError, HCaptchaValidationError
6
+ from core.server import mcp
7
+
8
+ __all__ = [
9
+ "HCaptchaClient",
10
+ "settings",
11
+ "mcp",
12
+ "HCaptchaAPIError",
13
+ "HCaptchaAuthError",
14
+ "HCaptchaValidationError",
15
+ ]
@@ -0,0 +1,144 @@
1
+ """HTTP client for HCaptcha API."""
2
+
3
+ import contextvars
4
+ import json
5
+ from typing import Any
6
+
7
+ import httpx
8
+ from loguru import logger
9
+
10
+ from core.config import settings
11
+ from core.exceptions import HCaptchaAPIError, HCaptchaAuthError, HCaptchaError, HCaptchaTimeoutError
12
+
13
+ _request_api_token: contextvars.ContextVar[str | None] = contextvars.ContextVar(
14
+ "_request_api_token", default=None
15
+ )
16
+
17
+
18
+ def set_request_api_token(token: str | None) -> None:
19
+ _request_api_token.set(token)
20
+
21
+
22
+ def get_request_api_token() -> str | None:
23
+ return _request_api_token.get()
24
+
25
+
26
+ def _apply_async_flag(payload: dict[str, Any], async_: bool | None) -> None:
27
+ if async_ is not None:
28
+ payload["async"] = async_
29
+
30
+
31
+ class HCaptchaClient:
32
+ """Async HTTP client for the AceDataCloud HCaptcha API."""
33
+
34
+ def __init__(self, api_token: str | None = None, base_url: str | None = None):
35
+ self.api_token = api_token if api_token is not None else settings.api_token
36
+ self.base_url = base_url or settings.api_base_url
37
+ self.timeout = settings.request_timeout
38
+ logger.info(f"HCaptchaClient initialized with base_url: {self.base_url}")
39
+
40
+ def _get_headers(self) -> dict[str, str]:
41
+ token = get_request_api_token() or self.api_token
42
+ if not token:
43
+ raise HCaptchaAuthError("API token not configured")
44
+ return {
45
+ "accept": "application/json",
46
+ "authorization": "******",
47
+ "content-type": "application/json",
48
+ }
49
+
50
+ def _handle_error_response(self, response: httpx.Response) -> None:
51
+ status = response.status_code
52
+ try:
53
+ body = response.json()
54
+ except Exception:
55
+ body = {}
56
+ error_obj = body.get("error", {}) if isinstance(body, dict) else {}
57
+ code = error_obj.get("code", f"http_{status}")
58
+ message = (
59
+ error_obj.get("message")
60
+ or (body.get("detail") if isinstance(body, dict) else None)
61
+ or response.text
62
+ or f"HTTP {status}"
63
+ )
64
+ if status in (401, 403):
65
+ raise HCaptchaAuthError(message)
66
+ raise HCaptchaAPIError(message=message, code=code, status_code=status)
67
+
68
+ async def request(
69
+ self,
70
+ method: str,
71
+ endpoint: str,
72
+ *,
73
+ payload: dict[str, Any] | None = None,
74
+ timeout: float | None = None,
75
+ allowed_error_statuses: set[int] | None = None,
76
+ ) -> dict[str, Any]:
77
+ method_upper = method.upper()
78
+ url = f"{self.base_url}{endpoint}"
79
+ request_timeout = timeout or self.timeout
80
+ if payload is not None:
81
+ logger.debug(f"Request payload: {json.dumps(payload, ensure_ascii=False, indent=2)}")
82
+ async with httpx.AsyncClient() as http_client:
83
+ try:
84
+ response = await http_client.request(
85
+ method_upper,
86
+ url,
87
+ json=payload,
88
+ headers=self._get_headers(),
89
+ timeout=request_timeout,
90
+ )
91
+ if response.status_code >= 400 and response.status_code not in (
92
+ allowed_error_statuses or set()
93
+ ):
94
+ self._handle_error_response(response)
95
+ return response.json() # type: ignore[no-any-return]
96
+ except httpx.TimeoutException as e:
97
+ raise HCaptchaTimeoutError(
98
+ f"Request to {endpoint} timed out after {request_timeout}s"
99
+ ) from e
100
+ except HCaptchaError:
101
+ raise
102
+ except Exception as e:
103
+ raise HCaptchaAPIError(message=str(e)) from e
104
+
105
+ async def recognize(
106
+ self,
107
+ queries: list[str] | None = None,
108
+ question: str | None = None,
109
+ async_: bool | None = None,
110
+ ) -> dict[str, Any]:
111
+ payload: dict[str, Any] = {}
112
+ if queries is not None:
113
+ payload["queries"] = queries
114
+ if question is not None:
115
+ payload["question"] = question
116
+ _apply_async_flag(payload, async_)
117
+ return await self.request("POST", "/captcha/recognition/hcaptcha", payload=payload)
118
+
119
+ async def get_token(
120
+ self,
121
+ website_key: str,
122
+ website_url: str,
123
+ rqdata: str | None = None,
124
+ proxy: str | None = None,
125
+ async_: bool | None = None,
126
+ ) -> dict[str, Any]:
127
+ payload: dict[str, Any] = {"website_key": website_key, "website_url": website_url}
128
+ if rqdata is not None:
129
+ payload["rqdata"] = rqdata
130
+ if proxy is not None:
131
+ payload["proxy"] = proxy
132
+ _apply_async_flag(payload, async_)
133
+ return await self.request("POST", "/captcha/token/hcaptcha", payload=payload)
134
+
135
+ async def get_task(self, task_id: str) -> dict[str, Any]:
136
+ return await self.request(
137
+ "POST",
138
+ "/captcha/tasks",
139
+ payload={"task_id": task_id},
140
+ allowed_error_statuses={504},
141
+ )
142
+
143
+
144
+ client = HCaptchaClient()
@@ -0,0 +1,53 @@
1
+ """Configuration management for MCP HCaptcha server."""
2
+
3
+ import os
4
+ from dataclasses import dataclass, field
5
+ from pathlib import Path
6
+
7
+ from dotenv import load_dotenv
8
+
9
+ _env_path = Path(__file__).parent.parent / ".env"
10
+ load_dotenv(dotenv_path=_env_path)
11
+
12
+
13
+ @dataclass
14
+ class Settings:
15
+ """Application settings loaded from environment variables."""
16
+
17
+ api_base_url: str = field(
18
+ default_factory=lambda: os.getenv("ACEDATACLOUD_API_BASE_URL", "https://api.acedata.cloud")
19
+ )
20
+ api_token: str = field(default_factory=lambda: os.getenv("ACEDATACLOUD_API_TOKEN", ""))
21
+ request_timeout: float = field(
22
+ default_factory=lambda: float(os.getenv("HCAPTCHA_REQUEST_TIMEOUT", "120"))
23
+ )
24
+ server_name: str = field(default_factory=lambda: os.getenv("MCP_SERVER_NAME", "hcaptcha"))
25
+ transport: str = field(default_factory=lambda: os.getenv("MCP_TRANSPORT", "stdio"))
26
+ log_level: str = field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO"))
27
+ server_url: str = field(default_factory=lambda: os.getenv("MCP_SERVER_URL", ""))
28
+ auth_base_url: str = field(
29
+ default_factory=lambda: os.getenv(
30
+ "ACEDATACLOUD_AUTH_BASE_URL", "https://auth.acedata.cloud"
31
+ )
32
+ )
33
+ platform_base_url: str = field(
34
+ default_factory=lambda: os.getenv(
35
+ "ACEDATACLOUD_PLATFORM_BASE_URL", "https://platform.acedata.cloud"
36
+ )
37
+ )
38
+ oauth_client_id: str = field(
39
+ default_factory=lambda: os.getenv("ACEDATACLOUD_OAUTH_CLIENT_ID", "")
40
+ )
41
+
42
+ def validate(self) -> None:
43
+ if not self.api_token:
44
+ raise ValueError(
45
+ "ACEDATACLOUD_API_TOKEN environment variable is required. Get your token from https://platform.acedata.cloud"
46
+ )
47
+
48
+ @property
49
+ def is_configured(self) -> bool:
50
+ return bool(self.api_token)
51
+
52
+
53
+ settings = Settings()
@@ -0,0 +1,29 @@
1
+ """Custom exceptions for MCP HCaptcha server."""
2
+
3
+
4
+ class HCaptchaError(Exception):
5
+ def __init__(self, message: str, code: str = "unknown"):
6
+ self.message = message
7
+ self.code = code
8
+ super().__init__(self.message)
9
+
10
+
11
+ class HCaptchaAuthError(HCaptchaError):
12
+ def __init__(self, message: str = "Authentication failed"):
13
+ super().__init__(message, code="auth_error")
14
+
15
+
16
+ class HCaptchaAPIError(HCaptchaError):
17
+ def __init__(self, message: str, code: str = "api_error", status_code: int | None = None):
18
+ self.status_code = status_code
19
+ super().__init__(message, code)
20
+
21
+
22
+ class HCaptchaValidationError(HCaptchaError):
23
+ def __init__(self, message: str):
24
+ super().__init__(message, code="validation_error")
25
+
26
+
27
+ class HCaptchaTimeoutError(HCaptchaError):
28
+ def __init__(self, message: str = "Request timed out"):
29
+ super().__init__(message, code="timeout_error")