mcp-face-transform 2026.5.31.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,16 @@
1
+ # Environment template - copy to .env and fill in your values
2
+ # Get your API token from https://platform.acedata.cloud
3
+
4
+ # AceDataCloud API Configuration (REQUIRED)
5
+ ACEDATACLOUD_API_TOKEN=your_api_token_here
6
+ ACEDATACLOUD_API_BASE_URL=https://api.acedata.cloud
7
+
8
+ # Face Configuration (Optional)
9
+ FACE_REQUEST_TIMEOUT=180
10
+
11
+ # MCP Server Configuration (Optional)
12
+ MCP_SERVER_NAME=face
13
+ MCP_TRANSPORT=stdio
14
+
15
+ # Logging (Optional)
16
+ LOG_LEVEL=INFO
@@ -0,0 +1,82 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .nox/
39
+ .coverage
40
+ .coverage.*
41
+ .cache
42
+ nosetests.xml
43
+ coverage.xml
44
+ *.cover
45
+ *.py,cover
46
+ .hypothesis/
47
+ .pytest_cache/
48
+
49
+ # Translations
50
+ *.mo
51
+ *.pot
52
+
53
+ # Environments
54
+ .env
55
+ .venv
56
+ env/
57
+ venv/
58
+ ENV/
59
+ env.bak/
60
+ venv.bak/
61
+
62
+ # IDE
63
+ .idea/
64
+ .vscode/
65
+ *.swp
66
+ *.swo
67
+ *~
68
+
69
+ # Ruff
70
+ .ruff_cache/
71
+
72
+ # mypy
73
+ .mypy_cache/
74
+ .dmypy.json
75
+ dmypy.json
76
+
77
+ # OS
78
+ .DS_Store
79
+ Thumbs.db
80
+
81
+ # Project specific
82
+ *.log
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Calendar Versioning](https://calver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - Initial release of MCP Face Transform Server.
13
+ - Seven face tools wrapping the AceDataCloud Face Transform API:
14
+ - `face_detect_keypoints` — `POST /face/analyze` (90+ keypoints per face)
15
+ - `face_beautify` — `POST /face/beautify`
16
+ - `face_change_age` — `POST /face/change-age`
17
+ - `face_change_gender` — `POST /face/change-gender`
18
+ - `face_swap` — `POST /face/swap` (optional async `callback_url`)
19
+ - `face_cartoonize` — `POST /face/cartoon`
20
+ - `face_detect_liveness` — `POST /face/detect-live`
21
+ - `face_get_usage_guide` — concise tool reference
22
+ - Two MCP prompts: `face_guide`, `face_workflow_examples`.
23
+ - stdio and Streamable HTTP transports.
24
+ - OAuth 2.1 (PKCE) support for hosted Claude.ai deployment.
25
+ - Bearer-token authentication for direct HTTP access.
26
+ - JetBrains AI Assistant plugin scaffold and VS Code extension scaffold.
27
+ - GitHub Actions pipeline for PyPI / GitHub Release / MCP Registry / Smithery /
28
+ VS Code Marketplace / JetBrains Marketplace / Docker Hub publication.
@@ -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,175 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-face-transform
3
+ Version: 2026.5.31.0
4
+ Summary: MCP server for the AceDataCloud Face Transform API (keypoints, beautify, age/gender, swap, cartoon, liveness)
5
+ Project-URL: Homepage, https://github.com/AceDataCloud/FaceTransformMCP
6
+ Project-URL: Documentation, https://docs.acedata.cloud
7
+ Project-URL: Repository, https://github.com/AceDataCloud/FaceTransformMCP
8
+ Project-URL: Issues, https://github.com/AceDataCloud/FaceTransformMCP/issues
9
+ Project-URL: Changelog, https://github.com/AceDataCloud/FaceTransformMCP/blob/main/CHANGELOG.md
10
+ Author-email: AceDataCloud <support@acedata.cloud>
11
+ Maintainer-email: AceDataCloud <support@acedata.cloud>
12
+ License: MIT
13
+ License-File: LICENSE
14
+ Keywords: acedata,beautify,claude,face,face-swap,face-transform,liveness-detection,llm,mcp,model-context-protocol
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Multimedia :: Graphics
24
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
25
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: httpx>=0.27.0
28
+ Requires-Dist: loguru>=0.7.0
29
+ Requires-Dist: mcp>=1.2.0
30
+ Requires-Dist: pydantic>=2.0.0
31
+ Requires-Dist: python-dotenv>=1.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
+ # MCP Face Transform Server
57
+
58
+ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
59
+ exposes the AceDataCloud Face Transform API — face keypoint detection,
60
+ beautification, age/gender transform, face swap, cartoonization, and liveness
61
+ detection.
62
+
63
+ > **Status:** All Face APIs are currently in **Alpha**. Interfaces may evolve.
64
+
65
+ ## Features
66
+
67
+ - **Keypoint detection** — 90+ landmarks per face, multi-face supported
68
+ - **Beautification** — smoothing, whitening, face slimming, eye enlarging
69
+ - **Age transform** — age or de-age a portrait
70
+ - **Gender transform** — swap perceived facial gender characteristics
71
+ - **Face swap** — move a source face onto a target image (with optional async webhook)
72
+ - **Cartoonize** — render a portrait in animated / cartoon style
73
+ - **Liveness detection** — distinguish live captures from printed / screen photos
74
+
75
+ ## Installation
76
+
77
+ ```bash
78
+ pip install mcp-face-transform
79
+ ```
80
+
81
+ ## Configuration
82
+
83
+ Set your AceDataCloud API token:
84
+
85
+ ```bash
86
+ export ACEDATACLOUD_API_TOKEN=your_token_here
87
+ ```
88
+
89
+ Get your token from [https://platform.acedata.cloud](https://platform.acedata.cloud).
90
+
91
+ ## Usage
92
+
93
+ ### stdio mode (default)
94
+
95
+ ```bash
96
+ mcp-face-transform
97
+ ```
98
+
99
+ ### HTTP mode
100
+
101
+ ```bash
102
+ mcp-face-transform --transport http --port 8000
103
+ ```
104
+
105
+ ## Available Tools
106
+
107
+ | Tool | Endpoint | Purpose |
108
+ |------|----------|---------|
109
+ | `face_detect_keypoints` | `POST /face/analyze` | Detect 90+ keypoints per face |
110
+ | `face_beautify` | `POST /face/beautify` | Smoothing / whitening / slimming / eye enlarging |
111
+ | `face_change_age` | `POST /face/change-age` | Age or de-age a portrait |
112
+ | `face_change_gender` | `POST /face/change-gender` | Swap perceived facial gender characteristics |
113
+ | `face_swap` | `POST /face/swap` | Move source face onto target image |
114
+ | `face_cartoonize` | `POST /face/cartoon` | Convert portrait to cartoon style |
115
+ | `face_detect_liveness` | `POST /face/detect-live` | Detect live vs printed/screen face |
116
+ | `face_get_usage_guide` | _client-side_ | Concise tool usage reference |
117
+
118
+ ## Example
119
+
120
+ ```text
121
+ "Detect all faces in https://example.com/group.jpg and return their keypoints."
122
+ → face_detect_keypoints(image_url="https://example.com/group.jpg")
123
+
124
+ "Lighten and smooth my portrait."
125
+ → face_beautify(image_url="https://example.com/me.jpg", smoothing=15, whitening=25)
126
+
127
+ "Replace the face in the scene with the headshot."
128
+ → face_swap(
129
+ source_image_url="https://example.com/headshot.jpg",
130
+ target_image_url="https://example.com/scene.jpg",
131
+ )
132
+ ```
133
+
134
+ ## Configuration in Claude Desktop / Claude Code
135
+
136
+ ```json
137
+ {
138
+ "mcpServers": {
139
+ "face-transform": {
140
+ "command": "uvx",
141
+ "args": ["mcp-face-transform"],
142
+ "env": {
143
+ "ACEDATACLOUD_API_TOKEN": "your_api_token_here"
144
+ }
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ Or use the hosted endpoint with bearer auth:
151
+
152
+ ```json
153
+ {
154
+ "mcpServers": {
155
+ "face-transform": {
156
+ "url": "https://face.mcp.acedata.cloud/mcp",
157
+ "headers": {
158
+ "Authorization": "Bearer your_api_token_here"
159
+ }
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ## Development
166
+
167
+ ```bash
168
+ pip install -e ".[dev,test]"
169
+ pytest --cov=core --cov=tools
170
+ ruff check .
171
+ ```
172
+
173
+ ## License
174
+
175
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,120 @@
1
+ # MCP Face Transform Server
2
+
3
+ A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
4
+ exposes the AceDataCloud Face Transform API — face keypoint detection,
5
+ beautification, age/gender transform, face swap, cartoonization, and liveness
6
+ detection.
7
+
8
+ > **Status:** All Face APIs are currently in **Alpha**. Interfaces may evolve.
9
+
10
+ ## Features
11
+
12
+ - **Keypoint detection** — 90+ landmarks per face, multi-face supported
13
+ - **Beautification** — smoothing, whitening, face slimming, eye enlarging
14
+ - **Age transform** — age or de-age a portrait
15
+ - **Gender transform** — swap perceived facial gender characteristics
16
+ - **Face swap** — move a source face onto a target image (with optional async webhook)
17
+ - **Cartoonize** — render a portrait in animated / cartoon style
18
+ - **Liveness detection** — distinguish live captures from printed / screen photos
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install mcp-face-transform
24
+ ```
25
+
26
+ ## Configuration
27
+
28
+ Set your AceDataCloud API token:
29
+
30
+ ```bash
31
+ export ACEDATACLOUD_API_TOKEN=your_token_here
32
+ ```
33
+
34
+ Get your token from [https://platform.acedata.cloud](https://platform.acedata.cloud).
35
+
36
+ ## Usage
37
+
38
+ ### stdio mode (default)
39
+
40
+ ```bash
41
+ mcp-face-transform
42
+ ```
43
+
44
+ ### HTTP mode
45
+
46
+ ```bash
47
+ mcp-face-transform --transport http --port 8000
48
+ ```
49
+
50
+ ## Available Tools
51
+
52
+ | Tool | Endpoint | Purpose |
53
+ |------|----------|---------|
54
+ | `face_detect_keypoints` | `POST /face/analyze` | Detect 90+ keypoints per face |
55
+ | `face_beautify` | `POST /face/beautify` | Smoothing / whitening / slimming / eye enlarging |
56
+ | `face_change_age` | `POST /face/change-age` | Age or de-age a portrait |
57
+ | `face_change_gender` | `POST /face/change-gender` | Swap perceived facial gender characteristics |
58
+ | `face_swap` | `POST /face/swap` | Move source face onto target image |
59
+ | `face_cartoonize` | `POST /face/cartoon` | Convert portrait to cartoon style |
60
+ | `face_detect_liveness` | `POST /face/detect-live` | Detect live vs printed/screen face |
61
+ | `face_get_usage_guide` | _client-side_ | Concise tool usage reference |
62
+
63
+ ## Example
64
+
65
+ ```text
66
+ "Detect all faces in https://example.com/group.jpg and return their keypoints."
67
+ → face_detect_keypoints(image_url="https://example.com/group.jpg")
68
+
69
+ "Lighten and smooth my portrait."
70
+ → face_beautify(image_url="https://example.com/me.jpg", smoothing=15, whitening=25)
71
+
72
+ "Replace the face in the scene with the headshot."
73
+ → face_swap(
74
+ source_image_url="https://example.com/headshot.jpg",
75
+ target_image_url="https://example.com/scene.jpg",
76
+ )
77
+ ```
78
+
79
+ ## Configuration in Claude Desktop / Claude Code
80
+
81
+ ```json
82
+ {
83
+ "mcpServers": {
84
+ "face-transform": {
85
+ "command": "uvx",
86
+ "args": ["mcp-face-transform"],
87
+ "env": {
88
+ "ACEDATACLOUD_API_TOKEN": "your_api_token_here"
89
+ }
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ Or use the hosted endpoint with bearer auth:
96
+
97
+ ```json
98
+ {
99
+ "mcpServers": {
100
+ "face-transform": {
101
+ "url": "https://face.mcp.acedata.cloud/mcp",
102
+ "headers": {
103
+ "Authorization": "Bearer your_api_token_here"
104
+ }
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ pip install -e ".[dev,test]"
114
+ pytest --cov=core --cov=tools
115
+ ruff check .
116
+ ```
117
+
118
+ ## License
119
+
120
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,15 @@
1
+ """Core module for MCP Face Transform server."""
2
+
3
+ from core.client import FaceClient
4
+ from core.config import settings
5
+ from core.exceptions import FaceAPIError, FaceAuthError, FaceValidationError
6
+ from core.server import mcp
7
+
8
+ __all__ = [
9
+ "FaceClient",
10
+ "settings",
11
+ "mcp",
12
+ "FaceAPIError",
13
+ "FaceAuthError",
14
+ "FaceValidationError",
15
+ ]
@@ -0,0 +1,160 @@
1
+ """HTTP client for Face Transform 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 FaceAPIError, FaceAuthError, FaceError, FaceTimeoutError
12
+
13
+ # Context variable for per-request API token (used in HTTP/remote mode).
14
+ _request_api_token: contextvars.ContextVar[str | None] = contextvars.ContextVar(
15
+ "_request_api_token", default=None
16
+ )
17
+
18
+
19
+ def set_request_api_token(token: str | None) -> None:
20
+ """Set the API token for the current request context (HTTP mode)."""
21
+ _request_api_token.set(token)
22
+
23
+
24
+ def get_request_api_token() -> str | None:
25
+ """Get the API token from the current request context."""
26
+ return _request_api_token.get()
27
+
28
+
29
+ class FaceClient:
30
+ """Async HTTP client for the AceDataCloud Face Transform API."""
31
+
32
+ def __init__(self, api_token: str | None = None, base_url: str | None = None):
33
+ self.api_token = api_token if api_token is not None else settings.api_token
34
+ self.base_url = base_url or settings.api_base_url
35
+ self.timeout = settings.request_timeout
36
+
37
+ logger.info(f"FaceClient initialized with base_url: {self.base_url}")
38
+ logger.debug(f"API token configured: {'Yes' if self.api_token else 'No'}")
39
+ logger.debug(f"Request timeout: {self.timeout}s")
40
+
41
+ def _get_headers(self) -> dict[str, str]:
42
+ token = get_request_api_token() or self.api_token
43
+ if not token:
44
+ logger.error("API token not configured!")
45
+ raise FaceAuthError("API token not configured")
46
+
47
+ return {
48
+ "accept": "application/json",
49
+ "authorization": f"Bearer {token}",
50
+ "content-type": "application/json",
51
+ }
52
+
53
+ def _handle_error_response(self, response: httpx.Response) -> None:
54
+ status = response.status_code
55
+ try:
56
+ body = response.json()
57
+ except Exception:
58
+ body = {}
59
+
60
+ error_obj = body.get("error", {}) if isinstance(body, dict) else {}
61
+ code = error_obj.get("code", f"http_{status}")
62
+ message = (
63
+ error_obj.get("message")
64
+ or (body.get("detail") if isinstance(body, dict) else None)
65
+ or response.text
66
+ or f"HTTP {status}"
67
+ )
68
+
69
+ logger.error(f"API error {status} [{code}]: {message}")
70
+
71
+ if status in (401, 403):
72
+ raise FaceAuthError(message)
73
+ raise FaceAPIError(message=message, code=code, status_code=status)
74
+
75
+ async def request(
76
+ self,
77
+ method: str,
78
+ endpoint: str,
79
+ *,
80
+ payload: dict[str, Any] | None = None,
81
+ params: dict[str, Any] | None = None,
82
+ timeout: float | None = None,
83
+ ) -> dict[str, Any]:
84
+ method_upper = method.upper()
85
+ url = f"{self.base_url}{endpoint}"
86
+ request_timeout = timeout or self.timeout
87
+
88
+ logger.info(f"🚀 {method_upper} {url}")
89
+ if payload is not None:
90
+ logger.debug(f"Request payload: {json.dumps(payload, ensure_ascii=False, indent=2)}")
91
+ if params is not None:
92
+ logger.debug(f"Request params: {json.dumps(params, ensure_ascii=False, indent=2)}")
93
+ logger.debug(f"Timeout: {request_timeout}s")
94
+
95
+ async with httpx.AsyncClient() as http_client:
96
+ try:
97
+ response = await http_client.request(
98
+ method_upper,
99
+ url,
100
+ json=payload,
101
+ params=params,
102
+ headers=self._get_headers(),
103
+ timeout=request_timeout,
104
+ )
105
+ logger.info(f"📥 Response status: {response.status_code}")
106
+
107
+ if response.status_code >= 400:
108
+ self._handle_error_response(response)
109
+
110
+ result = response.json()
111
+ logger.success("✅ Request successful")
112
+ return result # type: ignore[no-any-return]
113
+
114
+ except httpx.TimeoutException as e:
115
+ logger.error(f"⏰ Request timeout after {request_timeout}s: {e}")
116
+ raise FaceTimeoutError(
117
+ f"Request to {endpoint} timed out after {request_timeout}s"
118
+ ) from e
119
+
120
+ except FaceError:
121
+ raise
122
+
123
+ except Exception as e:
124
+ logger.error(f"❌ Request error: {e}")
125
+ raise FaceAPIError(message=str(e)) from e
126
+
127
+ async def analyze(self, **kwargs: Any) -> dict[str, Any]:
128
+ logger.info(f"🔍 Analyzing face keypoints for: {kwargs.get('image_url', '')}")
129
+ return await self.request("POST", "/face/analyze", payload=kwargs)
130
+
131
+ async def beautify(self, **kwargs: Any) -> dict[str, Any]:
132
+ logger.info(f"✨ Beautifying face for: {kwargs.get('image_url', '')}")
133
+ return await self.request("POST", "/face/beautify", payload=kwargs)
134
+
135
+ async def change_age(self, **kwargs: Any) -> dict[str, Any]:
136
+ logger.info(f"🕰️ Transforming age for: {kwargs.get('image_url', '')}")
137
+ return await self.request("POST", "/face/change-age", payload=kwargs)
138
+
139
+ async def change_gender(self, **kwargs: Any) -> dict[str, Any]:
140
+ logger.info(f"🔁 Swapping gender for: {kwargs.get('image_url', '')}")
141
+ return await self.request("POST", "/face/change-gender", payload=kwargs)
142
+
143
+ async def swap(self, **kwargs: Any) -> dict[str, Any]:
144
+ logger.info(
145
+ f"🔄 Swapping face: source={kwargs.get('source_image_url', '')} "
146
+ f"target={kwargs.get('target_image_url', '')}"
147
+ )
148
+ return await self.request("POST", "/face/swap", payload=kwargs)
149
+
150
+ async def cartoon(self, **kwargs: Any) -> dict[str, Any]:
151
+ logger.info(f"🎨 Cartoonizing face for: {kwargs.get('image_url', '')}")
152
+ return await self.request("POST", "/face/cartoon", payload=kwargs)
153
+
154
+ async def detect_live(self, **kwargs: Any) -> dict[str, Any]:
155
+ logger.info(f"🛡️ Detecting liveness for: {kwargs.get('image_url', '')}")
156
+ return await self.request("POST", "/face/detect-live", payload=kwargs)
157
+
158
+
159
+ # Global client instance
160
+ client = FaceClient()
@@ -0,0 +1,65 @@
1
+ """Configuration management for MCP Face Transform 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
+ # Load .env file from project root
10
+ _env_path = Path(__file__).parent.parent / ".env"
11
+ load_dotenv(dotenv_path=_env_path)
12
+
13
+
14
+ @dataclass
15
+ class Settings:
16
+ """Application settings loaded from environment variables."""
17
+
18
+ # API Configuration
19
+ api_base_url: str = field(
20
+ default_factory=lambda: os.getenv("ACEDATACLOUD_API_BASE_URL", "https://api.acedata.cloud")
21
+ )
22
+ api_token: str = field(default_factory=lambda: os.getenv("ACEDATACLOUD_API_TOKEN", ""))
23
+
24
+ # Request Configuration — face endpoints are synchronous; default 180s.
25
+ request_timeout: float = field(
26
+ default_factory=lambda: float(os.getenv("FACE_REQUEST_TIMEOUT", "180"))
27
+ )
28
+
29
+ # Server Configuration
30
+ server_name: str = field(default_factory=lambda: os.getenv("MCP_SERVER_NAME", "face"))
31
+ transport: str = field(default_factory=lambda: os.getenv("MCP_TRANSPORT", "stdio"))
32
+ log_level: str = field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO"))
33
+
34
+ # OAuth / Remote Auth Configuration
35
+ server_url: str = field(default_factory=lambda: os.getenv("MCP_SERVER_URL", ""))
36
+ auth_base_url: str = field(
37
+ default_factory=lambda: os.getenv(
38
+ "ACEDATACLOUD_AUTH_BASE_URL", "https://auth.acedata.cloud"
39
+ )
40
+ )
41
+ platform_base_url: str = field(
42
+ default_factory=lambda: os.getenv(
43
+ "ACEDATACLOUD_PLATFORM_BASE_URL", "https://platform.acedata.cloud"
44
+ )
45
+ )
46
+ oauth_client_id: str = field(
47
+ default_factory=lambda: os.getenv("ACEDATACLOUD_OAUTH_CLIENT_ID", "")
48
+ )
49
+
50
+ def validate(self) -> None:
51
+ """Validate required settings."""
52
+ if not self.api_token:
53
+ raise ValueError(
54
+ "ACEDATACLOUD_API_TOKEN environment variable is required."
55
+ "Get your token from https://platform.acedata.cloud"
56
+ )
57
+
58
+ @property
59
+ def is_configured(self) -> bool:
60
+ """Check if the API token is configured."""
61
+ return bool(self.api_token)
62
+
63
+
64
+ # Global settings instance
65
+ settings = Settings()