RioShiina commited on
Commit
97ac1ad
·
1 Parent(s): b959715

layout.py: Support High-Level MCP

Browse files
README.md CHANGED
@@ -150,13 +150,15 @@ models:
150
  - krea/Krea-2-Turbo
151
  - lodestones/Chroma1-HD
152
  - lodestones/Chroma1-Radiance
 
 
 
 
 
 
153
  - meituan-longcat/LongCat-Image
154
  - microsoft/Lens
155
  - microsoft/Lens-Turbo
156
- - microsoft/Mage-Flow
157
- - microsoft/Mage-Flow-Edit
158
- - microsoft/Mage-Flow-Edit-Turbo
159
- - microsoft/Mage-Flow-Turbo
160
  - NewBie-AI/NewBie-image-Exp0.1
161
  - nvidia/PiD
162
  - nvidia/PixelDiT-1300M-1024px
 
150
  - krea/Krea-2-Turbo
151
  - lodestones/Chroma1-HD
152
  - lodestones/Chroma1-Radiance
153
+ - mage-flow-community/Mage-Flow
154
+ - mage-flow-community/Mage-Flow-Base
155
+ - mage-flow-community/Mage-Flow-Edit
156
+ - mage-flow-community/Mage-Flow-Edit-Base
157
+ - mage-flow-community/Mage-Flow-Edit-Turbo
158
+ - mage-flow-community/Mage-Flow-Turbo
159
  - meituan-longcat/LongCat-Image
160
  - microsoft/Lens
161
  - microsoft/Lens-Turbo
 
 
 
 
162
  - NewBie-AI/NewBie-image-Exp0.1
163
  - nvidia/PiD
164
  - nvidia/PixelDiT-1300M-1024px
mcp_tools/__init__.py CHANGED
@@ -1,47 +1,47 @@
1
- def __getattr__(name):
2
- if name in ("types", "server", "client", "shared"):
3
- raise ImportError(f"No module named 'mcp.{name}' in local mcp package")
4
- raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
5
-
6
- from .get_task_list import handle_get_task_list
7
- from .get_model_architecture_list import handle_get_model_architecture_list
8
- from .get_model_list import handle_get_model_list
9
- from .get_feature_list import handle_get_feature_list
10
- from .get_model_features import handle_get_model_features
11
- from .run import handle_run
12
- from .get_task_status import handle_get_task_status
13
- from .error_schema import make_error, make_validation_error, make_not_found_error
14
- from .mcp_gradio_integration import (
15
- register_high_level_mcp_apis,
16
- cleanup_dependencies_api_names,
17
- patch_gradio_api_suppression,
18
- HIGH_LEVEL_MCP_API_NAMES,
19
- )
20
-
21
- MCP_FUNCTIONS = [
22
- handle_get_task_list,
23
- handle_get_model_architecture_list,
24
- handle_get_model_list,
25
- handle_get_feature_list,
26
- handle_get_model_features,
27
- handle_run,
28
- handle_get_task_status,
29
- ]
30
-
31
- __all__ = [
32
- "handle_get_task_list",
33
- "handle_get_model_architecture_list",
34
- "handle_get_model_list",
35
- "handle_get_feature_list",
36
- "handle_get_model_features",
37
- "handle_run",
38
- "handle_get_task_status",
39
- "make_error",
40
- "make_validation_error",
41
- "make_not_found_error",
42
- "register_high_level_mcp_apis",
43
- "cleanup_dependencies_api_names",
44
- "patch_gradio_api_suppression",
45
- "HIGH_LEVEL_MCP_API_NAMES",
46
- "MCP_FUNCTIONS",
47
- ]
 
1
+ def __getattr__(name):
2
+ if name in ("types", "server", "client", "shared"):
3
+ raise ImportError(f"No module named 'mcp.{name}' in local mcp package")
4
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
5
+
6
+ from .get_task_list import handle_get_task_list
7
+ from .get_model_architecture_list import handle_get_model_architecture_list
8
+ from .get_model_list import handle_get_model_list
9
+ from .get_feature_list import handle_get_feature_list
10
+ from .get_model_features import handle_get_model_features
11
+ from .run import handle_run
12
+ from .get_task_status import handle_get_task_status
13
+ from .error_schema import make_error, make_validation_error, make_not_found_error
14
+ from .mcp_gradio_integration import (
15
+ register_high_level_mcp_apis,
16
+ cleanup_dependencies_api_names,
17
+ patch_gradio_api_suppression,
18
+ HIGH_LEVEL_MCP_API_NAMES,
19
+ )
20
+
21
+ MCP_FUNCTIONS = [
22
+ handle_get_task_list,
23
+ handle_get_model_architecture_list,
24
+ handle_get_model_list,
25
+ handle_get_feature_list,
26
+ handle_get_model_features,
27
+ handle_run,
28
+ handle_get_task_status,
29
+ ]
30
+
31
+ __all__ = [
32
+ "handle_get_task_list",
33
+ "handle_get_model_architecture_list",
34
+ "handle_get_model_list",
35
+ "handle_get_feature_list",
36
+ "handle_get_model_features",
37
+ "handle_run",
38
+ "handle_get_task_status",
39
+ "make_error",
40
+ "make_validation_error",
41
+ "make_not_found_error",
42
+ "register_high_level_mcp_apis",
43
+ "cleanup_dependencies_api_names",
44
+ "patch_gradio_api_suppression",
45
+ "HIGH_LEVEL_MCP_API_NAMES",
46
+ "MCP_FUNCTIONS",
47
+ ]
mcp_tools/error_schema.py CHANGED
@@ -1,85 +1,85 @@
1
- """
2
- Unified MCP tool error response format.
3
-
4
- Error code enumeration:
5
- - INVALID_PARAMS: Parameter validation failed (missing required fields, type errors, value out of range)
6
- - MODEL_NOT_FOUND: The specified model name does not exist
7
- - ARCHITECTURE_NOT_FOUND: The specified architecture name does not exist
8
- - CHAIN_TYPE_NOT_FOUND: The specified chain/injector type is invalid
9
- - FEATURE_NOT_SUPPORTED: The current model does not support the requested feature
10
- - TASK_NOT_FOUND: The async task ID does not exist
11
- - MODEL_OOM: GPU out of memory
12
- - INTERNAL_ERROR: Internal server error
13
- """
14
-
15
-
16
- def make_error(code: str, message: str, details: dict = None) -> dict:
17
- """
18
- Construct a unified MCP tool error response.
19
-
20
- Args:
21
- code: Error code (UPPER_SNAKE_CASE format)
22
- message: Human-readable error description
23
- details: Optional details dictionary
24
-
25
- Returns:
26
- Standardized error response dictionary
27
- """
28
- error = {
29
- "error": {
30
- "code": code,
31
- "message": message,
32
- }
33
- }
34
- if details:
35
- error["error"]["details"] = details
36
- return error
37
-
38
-
39
- def make_validation_error(
40
- message: str = "Request validation failed.",
41
- missing_fields: list = None,
42
- invalid_fields: dict = None,
43
- ) -> dict:
44
- """
45
- Construct a parameter validation failure error response.
46
-
47
- Args:
48
- message: Error description
49
- missing_fields: List of missing required field names
50
- invalid_fields: Key-value pairs of invalid fields, key=field name, value=reason description
51
-
52
- Returns:
53
- Standardized INVALID_PARAMS error response
54
- """
55
- details = {}
56
- if missing_fields:
57
- details["missing_fields"] = missing_fields
58
- if invalid_fields:
59
- details["invalid_fields"] = invalid_fields
60
- return make_error("INVALID_PARAMS", message, details if details else None)
61
-
62
-
63
- def make_not_found_error(resource_type: str, resource_id: str) -> dict:
64
- """
65
- Construct a resource-not-found error response.
66
-
67
- Args:
68
- resource_type: Resource type (e.g., "model", "architecture", "chain_type", "task")
69
- resource_id: Resource identifier
70
-
71
- Returns:
72
- Standardized *_NOT_FOUND error response
73
- """
74
- code_map = {
75
- "model": "MODEL_NOT_FOUND",
76
- "architecture": "ARCHITECTURE_NOT_FOUND",
77
- "chain_type": "CHAIN_TYPE_NOT_FOUND",
78
- "task": "TASK_NOT_FOUND",
79
- }
80
- code = code_map.get(resource_type, f"{resource_type.upper()}_NOT_FOUND")
81
- return make_error(
82
- code,
83
- f"The specified {resource_type} '{resource_id}' was not found.",
84
- {"resource_type": resource_type, "resource_id": resource_id},
85
- )
 
1
+ """
2
+ Unified MCP tool error response format.
3
+
4
+ Error code enumeration:
5
+ - INVALID_PARAMS: Parameter validation failed (missing required fields, type errors, value out of range)
6
+ - MODEL_NOT_FOUND: The specified model name does not exist
7
+ - ARCHITECTURE_NOT_FOUND: The specified architecture name does not exist
8
+ - CHAIN_TYPE_NOT_FOUND: The specified chain/injector type is invalid
9
+ - FEATURE_NOT_SUPPORTED: The current model does not support the requested feature
10
+ - TASK_NOT_FOUND: The async task ID does not exist
11
+ - MODEL_OOM: GPU out of memory
12
+ - INTERNAL_ERROR: Internal server error
13
+ """
14
+
15
+
16
+ def make_error(code: str, message: str, details: dict = None) -> dict:
17
+ """
18
+ Construct a unified MCP tool error response.
19
+
20
+ Args:
21
+ code: Error code (UPPER_SNAKE_CASE format)
22
+ message: Human-readable error description
23
+ details: Optional details dictionary
24
+
25
+ Returns:
26
+ Standardized error response dictionary
27
+ """
28
+ error = {
29
+ "error": {
30
+ "code": code,
31
+ "message": message,
32
+ }
33
+ }
34
+ if details:
35
+ error["error"]["details"] = details
36
+ return error
37
+
38
+
39
+ def make_validation_error(
40
+ message: str = "Request validation failed.",
41
+ missing_fields: list = None,
42
+ invalid_fields: dict = None,
43
+ ) -> dict:
44
+ """
45
+ Construct a parameter validation failure error response.
46
+
47
+ Args:
48
+ message: Error description
49
+ missing_fields: List of missing required field names
50
+ invalid_fields: Key-value pairs of invalid fields, key=field name, value=reason description
51
+
52
+ Returns:
53
+ Standardized INVALID_PARAMS error response
54
+ """
55
+ details = {}
56
+ if missing_fields:
57
+ details["missing_fields"] = missing_fields
58
+ if invalid_fields:
59
+ details["invalid_fields"] = invalid_fields
60
+ return make_error("INVALID_PARAMS", message, details if details else None)
61
+
62
+
63
+ def make_not_found_error(resource_type: str, resource_id: str) -> dict:
64
+ """
65
+ Construct a resource-not-found error response.
66
+
67
+ Args:
68
+ resource_type: Resource type (e.g., "model", "architecture", "chain_type", "task")
69
+ resource_id: Resource identifier
70
+
71
+ Returns:
72
+ Standardized *_NOT_FOUND error response
73
+ """
74
+ code_map = {
75
+ "model": "MODEL_NOT_FOUND",
76
+ "architecture": "ARCHITECTURE_NOT_FOUND",
77
+ "chain_type": "CHAIN_TYPE_NOT_FOUND",
78
+ "task": "TASK_NOT_FOUND",
79
+ }
80
+ code = code_map.get(resource_type, f"{resource_type.upper()}_NOT_FOUND")
81
+ return make_error(
82
+ code,
83
+ f"The specified {resource_type} '{resource_id}' was not found.",
84
+ {"resource_type": resource_type, "resource_id": resource_id},
85
+ )
mcp_tools/get_feature_list.py CHANGED
@@ -1,127 +1,127 @@
1
- import os
2
- from copy import deepcopy
3
- from .common import _load_yaml, _CHAIN_FEATURES_PATH, _YAML_DIR
4
- from .error_schema import make_not_found_error
5
-
6
-
7
- def _build_feature_entry(chain_name: str, chain_data: dict, include_schema: bool = False) -> dict:
8
- entry = {
9
- "feature_name": chain_name,
10
- "chains": chain_data.get("chains", chain_name),
11
- "display_name": chain_data.get("display_name", chain_name),
12
- "description": chain_data.get("description", ""),
13
- "supported_tasks": chain_data.get("supported_tasks", []),
14
- "max_count": chain_data.get("max_count", 1),
15
- "usage_guideline": chain_data.get("usage_guideline", ""),
16
- }
17
- if include_schema:
18
- schema = deepcopy(chain_data.get("parameters_schema", {}))
19
- if chain_name in ("krea2_controlnet", "diffsynth_controlnet", "controlnet", "anima_controlnet_lllite"):
20
- config_key = (
21
- "Krea2_ControlNet" if chain_name == "krea2_controlnet"
22
- else "DiffSynth_ControlNet" if chain_name == "diffsynth_controlnet"
23
- else "Anima_ControlNet_Lllite" if chain_name == "anima_controlnet_lllite"
24
- else "ControlNet"
25
- )
26
- yaml_filename = f"{chain_name}_models.yaml"
27
- model_path = os.path.join(_YAML_DIR, yaml_filename)
28
- raw_models = _load_yaml(model_path).get(config_key, [])
29
- models_list = []
30
- if isinstance(raw_models, dict):
31
- for val in raw_models.values():
32
- if isinstance(val, list):
33
- models_list.extend(val)
34
- elif isinstance(val, dict):
35
- models_list.append(val)
36
- elif isinstance(raw_models, list):
37
- models_list = raw_models
38
-
39
- types_set = set()
40
- for m in models_list:
41
- t_val = m.get("Type", [])
42
- if isinstance(t_val, list):
43
- types_set.update(t_val)
44
- elif isinstance(t_val, str):
45
- types_set.add(t_val)
46
- types = sorted(list(types_set))
47
- series = sorted(list(set(m.get("Series") for m in models_list if m.get("Series"))))
48
- if "properties" in schema:
49
- if "type" in schema["properties"] and types:
50
- schema["properties"]["type"]["enum"] = types
51
- if "series" in schema["properties"] and series:
52
- schema["properties"]["series"]["enum"] = series
53
- if chain_name == "controlnet" and isinstance(raw_models, dict):
54
- schema["architectures"] = raw_models
55
- elif chain_name == "ipadapter":
56
- from .common import _get_ipadapter_presets_by_arch
57
- presets_by_arch = _get_ipadapter_presets_by_arch()
58
- schema["presets_by_architecture"] = presets_by_arch
59
- all_presets = sorted(list(set(presets_by_arch.get("SD1.5", []) + presets_by_arch.get("SDXL", []))))
60
- if "properties" in schema and "preset" in schema["properties"]:
61
- schema["properties"]["preset"]["enum"] = all_presets
62
- entry["parameters_schema"] = schema
63
- return entry
64
-
65
-
66
- def handle_get_feature_list(feature_name: str | list[str] = "") -> list | dict:
67
- """
68
- Dynamically load supported advanced features from chain_features.yaml.
69
-
70
- - If feature_name is empty: returns a summary list of ALL features (excluding parameters_schema)
71
- to optimize response size and token usage.
72
- - If feature_name is specified (single feature name, comma-separated string, or list of strings):
73
- returns complete feature details INCLUDING parameters_schema for the requested feature(s).
74
- """
75
- chain_features = _load_yaml(_CHAIN_FEATURES_PATH)
76
-
77
- targets = []
78
- is_single_string_query = False
79
-
80
- if isinstance(feature_name, list):
81
- targets = [str(x).strip() for x in feature_name if str(x).strip()]
82
- elif isinstance(feature_name, str) and feature_name.strip():
83
- raw_str = feature_name.strip()
84
- parts = [x.strip() for x in raw_str.split(",") if x.strip()]
85
- targets = parts
86
- if len(parts) == 1 and "," not in raw_str:
87
- is_single_string_query = True
88
-
89
- # Case 1: Empty input -> return summary list of all features (without parameters_schema)
90
- if not targets:
91
- return [
92
- _build_feature_entry(name, data, include_schema=False)
93
- for name, data in chain_features.items()
94
- ]
95
-
96
- # Helper function to resolve feature target by key or chains alias
97
- def _resolve_target(target_name: str) -> str | None:
98
- if target_name in chain_features:
99
- return target_name
100
- for feat_key, feat_data in chain_features.items():
101
- feat_chains = feat_data.get("chains")
102
- if isinstance(feat_chains, str) and feat_chains == target_name:
103
- return feat_key
104
- elif isinstance(feat_chains, list) and target_name in feat_chains:
105
- return feat_key
106
- return None
107
-
108
- resolved_targets = []
109
- # Case 2: Specific feature(s) requested -> validate existence
110
- for target in targets:
111
- resolved = _resolve_target(target)
112
- if not resolved:
113
- return make_not_found_error("feature_name", target)
114
- resolved_targets.append(resolved)
115
-
116
- # Case 3: Return full info including parameters_schema
117
- results = [
118
- _build_feature_entry(target, chain_features[target], include_schema=True)
119
- for target in resolved_targets
120
- ]
121
-
122
- if is_single_string_query and len(results) == 1:
123
- return results[0]
124
-
125
- return results
126
-
127
-
 
1
+ import os
2
+ from copy import deepcopy
3
+ from .common import _load_yaml, _CHAIN_FEATURES_PATH, _YAML_DIR
4
+ from .error_schema import make_not_found_error
5
+
6
+
7
+ def _build_feature_entry(chain_name: str, chain_data: dict, include_schema: bool = False) -> dict:
8
+ entry = {
9
+ "feature_name": chain_name,
10
+ "chains": chain_data.get("chains", chain_name),
11
+ "display_name": chain_data.get("display_name", chain_name),
12
+ "description": chain_data.get("description", ""),
13
+ "supported_tasks": chain_data.get("supported_tasks", []),
14
+ "max_count": chain_data.get("max_count", 1),
15
+ "usage_guideline": chain_data.get("usage_guideline", ""),
16
+ }
17
+ if include_schema:
18
+ schema = deepcopy(chain_data.get("parameters_schema", {}))
19
+ if chain_name in ("krea2_controlnet", "diffsynth_controlnet", "controlnet", "anima_controlnet_lllite"):
20
+ config_key = (
21
+ "Krea2_ControlNet" if chain_name == "krea2_controlnet"
22
+ else "DiffSynth_ControlNet" if chain_name == "diffsynth_controlnet"
23
+ else "Anima_ControlNet_Lllite" if chain_name == "anima_controlnet_lllite"
24
+ else "ControlNet"
25
+ )
26
+ yaml_filename = f"{chain_name}_models.yaml"
27
+ model_path = os.path.join(_YAML_DIR, yaml_filename)
28
+ raw_models = _load_yaml(model_path).get(config_key, [])
29
+ models_list = []
30
+ if isinstance(raw_models, dict):
31
+ for val in raw_models.values():
32
+ if isinstance(val, list):
33
+ models_list.extend(val)
34
+ elif isinstance(val, dict):
35
+ models_list.append(val)
36
+ elif isinstance(raw_models, list):
37
+ models_list = raw_models
38
+
39
+ types_set = set()
40
+ for m in models_list:
41
+ t_val = m.get("Type", [])
42
+ if isinstance(t_val, list):
43
+ types_set.update(t_val)
44
+ elif isinstance(t_val, str):
45
+ types_set.add(t_val)
46
+ types = sorted(list(types_set))
47
+ series = sorted(list(set(m.get("Series") for m in models_list if m.get("Series"))))
48
+ if "properties" in schema:
49
+ if "type" in schema["properties"] and types:
50
+ schema["properties"]["type"]["enum"] = types
51
+ if "series" in schema["properties"] and series:
52
+ schema["properties"]["series"]["enum"] = series
53
+ if chain_name == "controlnet" and isinstance(raw_models, dict):
54
+ schema["architectures"] = raw_models
55
+ elif chain_name == "ipadapter":
56
+ from .common import _get_ipadapter_presets_by_arch
57
+ presets_by_arch = _get_ipadapter_presets_by_arch()
58
+ schema["presets_by_architecture"] = presets_by_arch
59
+ all_presets = sorted(list(set(presets_by_arch.get("SD1.5", []) + presets_by_arch.get("SDXL", []))))
60
+ if "properties" in schema and "preset" in schema["properties"]:
61
+ schema["properties"]["preset"]["enum"] = all_presets
62
+ entry["parameters_schema"] = schema
63
+ return entry
64
+
65
+
66
+ def handle_get_feature_list(feature_name: str | list[str] = "") -> list | dict:
67
+ """
68
+ Dynamically load supported advanced features from chain_features.yaml.
69
+
70
+ - If feature_name is empty: returns a summary list of ALL features (excluding parameters_schema)
71
+ to optimize response size and token usage.
72
+ - If feature_name is specified (single feature name, comma-separated string, or list of strings):
73
+ returns complete feature details INCLUDING parameters_schema for the requested feature(s).
74
+ """
75
+ chain_features = _load_yaml(_CHAIN_FEATURES_PATH)
76
+
77
+ targets = []
78
+ is_single_string_query = False
79
+
80
+ if isinstance(feature_name, list):
81
+ targets = [str(x).strip() for x in feature_name if str(x).strip()]
82
+ elif isinstance(feature_name, str) and feature_name.strip():
83
+ raw_str = feature_name.strip()
84
+ parts = [x.strip() for x in raw_str.split(",") if x.strip()]
85
+ targets = parts
86
+ if len(parts) == 1 and "," not in raw_str:
87
+ is_single_string_query = True
88
+
89
+ # Case 1: Empty input -> return summary list of all features (without parameters_schema)
90
+ if not targets:
91
+ return [
92
+ _build_feature_entry(name, data, include_schema=False)
93
+ for name, data in chain_features.items()
94
+ ]
95
+
96
+ # Helper function to resolve feature target by key or chains alias
97
+ def _resolve_target(target_name: str) -> str | None:
98
+ if target_name in chain_features:
99
+ return target_name
100
+ for feat_key, feat_data in chain_features.items():
101
+ feat_chains = feat_data.get("chains")
102
+ if isinstance(feat_chains, str) and feat_chains == target_name:
103
+ return feat_key
104
+ elif isinstance(feat_chains, list) and target_name in feat_chains:
105
+ return feat_key
106
+ return None
107
+
108
+ resolved_targets = []
109
+ # Case 2: Specific feature(s) requested -> validate existence
110
+ for target in targets:
111
+ resolved = _resolve_target(target)
112
+ if not resolved:
113
+ return make_not_found_error("feature_name", target)
114
+ resolved_targets.append(resolved)
115
+
116
+ # Case 3: Return full info including parameters_schema
117
+ results = [
118
+ _build_feature_entry(target, chain_features[target], include_schema=True)
119
+ for target in resolved_targets
120
+ ]
121
+
122
+ if is_single_string_query and len(results) == 1:
123
+ return results[0]
124
+
125
+ return results
126
+
127
+
mcp_tools/get_model_architecture_list.py CHANGED
@@ -1,36 +1,36 @@
1
- """
2
- MCP Tool: get_model_architecture_list
3
- Get all supported model architectures and their corresponding default resolutions.
4
- """
5
-
6
- from .common import _load_yaml, _MODEL_ARCHITECTURES_PATH, _CONSTANTS_PATH
7
-
8
-
9
- def handle_get_model_architecture_list() -> list:
10
- """Dynamically load all supported model architectures from model_architectures.yaml."""
11
- arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
12
- constants = _load_yaml(_CONSTANTS_PATH)
13
- resolution_map = constants.get("RESOLUTION_MAP", {})
14
- architectures = arch_config.get("architectures", {})
15
- architecture_order = arch_config.get("architecture_order", list(architectures.keys()))
16
-
17
- result = []
18
- for arch_name in architecture_order:
19
- if arch_name not in architectures:
20
- continue
21
- arch_data = architectures[arch_name]
22
- model_type = arch_data.get("model_type", arch_name.lower())
23
-
24
- default_res = [1024, 1024]
25
- if model_type in resolution_map:
26
- resolutions = resolution_map[model_type]
27
- if resolutions:
28
- first_key = next(iter(resolutions))
29
- default_res = resolutions[first_key]
30
-
31
- result.append({
32
- "model_architecture": arch_name,
33
- "default_resolution": default_res,
34
- })
35
-
36
- return result
 
1
+ """
2
+ MCP Tool: get_model_architecture_list
3
+ Get all supported model architectures and their corresponding default resolutions.
4
+ """
5
+
6
+ from .common import _load_yaml, _MODEL_ARCHITECTURES_PATH, _CONSTANTS_PATH
7
+
8
+
9
+ def handle_get_model_architecture_list() -> list:
10
+ """Dynamically load all supported model architectures from model_architectures.yaml."""
11
+ arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
12
+ constants = _load_yaml(_CONSTANTS_PATH)
13
+ resolution_map = constants.get("RESOLUTION_MAP", {})
14
+ architectures = arch_config.get("architectures", {})
15
+ architecture_order = arch_config.get("architecture_order", list(architectures.keys()))
16
+
17
+ result = []
18
+ for arch_name in architecture_order:
19
+ if arch_name not in architectures:
20
+ continue
21
+ arch_data = architectures[arch_name]
22
+ model_type = arch_data.get("model_type", arch_name.lower())
23
+
24
+ default_res = [1024, 1024]
25
+ if model_type in resolution_map:
26
+ resolutions = resolution_map[model_type]
27
+ if resolutions:
28
+ first_key = next(iter(resolutions))
29
+ default_res = resolutions[first_key]
30
+
31
+ result.append({
32
+ "model_architecture": arch_name,
33
+ "default_resolution": default_res,
34
+ })
35
+
36
+ return result
mcp_tools/get_model_features.py CHANGED
@@ -1,102 +1,102 @@
1
- """
2
- MCP Tool: get_model_features
3
- Query metadata for a specified model, including supported task types, extended features, and default inference parameters.
4
- """
5
-
6
- from .common import (
7
- _load_yaml,
8
- _MODEL_LIST_PATH,
9
- _MODEL_DEFAULTS_PATH,
10
- _IMAGE_GEN_FEATURES_PATH,
11
- _MODEL_ARCHITECTURES_PATH,
12
- _CHAIN_FEATURES_PATH,
13
- _TASK_DEFINITIONS,
14
- )
15
- from .error_schema import make_validation_error, make_not_found_error
16
-
17
-
18
- def handle_get_model_features(model: str) -> dict:
19
- """Query metadata for a specified model: supported task types, extended features, and default inference parameters."""
20
- if not model:
21
- return make_validation_error(
22
- "Parameter 'model' is required.",
23
- missing_fields=["model"],
24
- )
25
-
26
- model_list = _load_yaml(_MODEL_LIST_PATH)
27
- model_defaults = _load_yaml(_MODEL_DEFAULTS_PATH)
28
- features_config = _load_yaml(_IMAGE_GEN_FEATURES_PATH)
29
- arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
30
- chain_features = _load_yaml(_CHAIN_FEATURES_PATH)
31
-
32
- found_arch = None
33
- checkpoints = model_list.get("Checkpoint", {})
34
- for arch_name, arch_data in checkpoints.items():
35
- if not isinstance(arch_data, dict):
36
- continue
37
- for m in arch_data.get("models", []):
38
- if m.get("display_name") == model:
39
- found_arch = arch_name
40
- break
41
- if found_arch:
42
- break
43
-
44
- if not found_arch:
45
- return make_not_found_error("model", model)
46
-
47
- architectures = arch_config.get("architectures", {})
48
- arch_info = architectures.get(found_arch, {})
49
- model_type = arch_info.get("model_type", found_arch.lower())
50
-
51
- arch_features = features_config.get(model_type, features_config.get("default", {}))
52
- enabled_chains = arch_features.get("enabled_chains", [])
53
-
54
- supported_features = []
55
- for feat_name, feat_data in chain_features.items():
56
- feat_chains = feat_data.get("chains")
57
- if feat_chains is None:
58
- feat_chains = [feat_name]
59
- elif isinstance(feat_chains, str):
60
- feat_chains = [feat_chains]
61
-
62
- if any(c in enabled_chains for c in feat_chains):
63
- supported_features.append(feat_name)
64
-
65
- arch_defaults_section = model_defaults.get(found_arch, {})
66
- arch_level_defaults = arch_defaults_section.get("_defaults", {})
67
- model_specific_defaults = arch_defaults_section.get(model, {})
68
- global_defaults = model_defaults.get("Default", {})
69
-
70
- merged_defaults = {**global_defaults, **arch_level_defaults, **model_specific_defaults}
71
-
72
- default_parameter = {
73
- "sampler": merged_defaults.get("sampler_name", "euler"),
74
- "scheduler": merged_defaults.get("scheduler", "simple"),
75
- "steps": merged_defaults.get("steps", 20),
76
- "cfg": merged_defaults.get("cfg", 1.0),
77
- }
78
-
79
- supported_tasks = [t["task_type"] for t in _TASK_DEFINITIONS]
80
-
81
- result = {
82
- "name": model,
83
- "model_architecture": found_arch,
84
- "supported_tasks": supported_tasks,
85
- "supported_features": supported_features,
86
- "default_parameter": default_parameter,
87
- }
88
-
89
- default_pos = model_specific_defaults.get(
90
- "positive_prompt",
91
- arch_level_defaults.get("positive_prompt", ""),
92
- )
93
- default_neg = model_specific_defaults.get(
94
- "negative_prompt",
95
- arch_level_defaults.get("negative_prompt", ""),
96
- )
97
- if default_pos:
98
- result["default_positive_prompt"] = default_pos
99
- if default_neg:
100
- result["default_negative_prompt"] = default_neg
101
-
102
- return result
 
1
+ """
2
+ MCP Tool: get_model_features
3
+ Query metadata for a specified model, including supported task types, extended features, and default inference parameters.
4
+ """
5
+
6
+ from .common import (
7
+ _load_yaml,
8
+ _MODEL_LIST_PATH,
9
+ _MODEL_DEFAULTS_PATH,
10
+ _IMAGE_GEN_FEATURES_PATH,
11
+ _MODEL_ARCHITECTURES_PATH,
12
+ _CHAIN_FEATURES_PATH,
13
+ _TASK_DEFINITIONS,
14
+ )
15
+ from .error_schema import make_validation_error, make_not_found_error
16
+
17
+
18
+ def handle_get_model_features(model: str) -> dict:
19
+ """Query metadata for a specified model: supported task types, extended features, and default inference parameters."""
20
+ if not model:
21
+ return make_validation_error(
22
+ "Parameter 'model' is required.",
23
+ missing_fields=["model"],
24
+ )
25
+
26
+ model_list = _load_yaml(_MODEL_LIST_PATH)
27
+ model_defaults = _load_yaml(_MODEL_DEFAULTS_PATH)
28
+ features_config = _load_yaml(_IMAGE_GEN_FEATURES_PATH)
29
+ arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
30
+ chain_features = _load_yaml(_CHAIN_FEATURES_PATH)
31
+
32
+ found_arch = None
33
+ checkpoints = model_list.get("Checkpoint", {})
34
+ for arch_name, arch_data in checkpoints.items():
35
+ if not isinstance(arch_data, dict):
36
+ continue
37
+ for m in arch_data.get("models", []):
38
+ if m.get("display_name") == model:
39
+ found_arch = arch_name
40
+ break
41
+ if found_arch:
42
+ break
43
+
44
+ if not found_arch:
45
+ return make_not_found_error("model", model)
46
+
47
+ architectures = arch_config.get("architectures", {})
48
+ arch_info = architectures.get(found_arch, {})
49
+ model_type = arch_info.get("model_type", found_arch.lower())
50
+
51
+ arch_features = features_config.get(model_type, features_config.get("default", {}))
52
+ enabled_chains = arch_features.get("enabled_chains", [])
53
+
54
+ supported_features = []
55
+ for feat_name, feat_data in chain_features.items():
56
+ feat_chains = feat_data.get("chains")
57
+ if feat_chains is None:
58
+ feat_chains = [feat_name]
59
+ elif isinstance(feat_chains, str):
60
+ feat_chains = [feat_chains]
61
+
62
+ if any(c in enabled_chains for c in feat_chains):
63
+ supported_features.append(feat_name)
64
+
65
+ arch_defaults_section = model_defaults.get(found_arch, {})
66
+ arch_level_defaults = arch_defaults_section.get("_defaults", {})
67
+ model_specific_defaults = arch_defaults_section.get(model, {})
68
+ global_defaults = model_defaults.get("Default", {})
69
+
70
+ merged_defaults = {**global_defaults, **arch_level_defaults, **model_specific_defaults}
71
+
72
+ default_parameter = {
73
+ "sampler": merged_defaults.get("sampler_name", "euler"),
74
+ "scheduler": merged_defaults.get("scheduler", "simple"),
75
+ "steps": merged_defaults.get("steps", 20),
76
+ "cfg": merged_defaults.get("cfg", 1.0),
77
+ }
78
+
79
+ supported_tasks = [t["task_type"] for t in _TASK_DEFINITIONS]
80
+
81
+ result = {
82
+ "name": model,
83
+ "model_architecture": found_arch,
84
+ "supported_tasks": supported_tasks,
85
+ "supported_features": supported_features,
86
+ "default_parameter": default_parameter,
87
+ }
88
+
89
+ default_pos = model_specific_defaults.get(
90
+ "positive_prompt",
91
+ arch_level_defaults.get("positive_prompt", ""),
92
+ )
93
+ default_neg = model_specific_defaults.get(
94
+ "negative_prompt",
95
+ arch_level_defaults.get("negative_prompt", ""),
96
+ )
97
+ if default_pos:
98
+ result["default_positive_prompt"] = default_pos
99
+ if default_neg:
100
+ result["default_negative_prompt"] = default_neg
101
+
102
+ return result
mcp_tools/get_model_list.py CHANGED
@@ -1,64 +1,64 @@
1
- """
2
- MCP Tool: get_model_list
3
- Query the list of available image generation models, with optional filtering by model architecture.
4
- """
5
-
6
- from .common import _load_yaml, _MODEL_LIST_PATH, _MODEL_DEFAULTS_PATH, _MODEL_ARCHITECTURES_PATH
7
- from .error_schema import make_not_found_error
8
-
9
-
10
- def handle_get_model_list(model_architecture: str = None) -> list | dict:
11
- """Dynamically load the list of available image generation models from model_list.yaml."""
12
- model_list = _load_yaml(_MODEL_LIST_PATH)
13
- model_defaults = _load_yaml(_MODEL_DEFAULTS_PATH)
14
- arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
15
- valid_architectures = set(arch_config.get("architectures", {}).keys())
16
-
17
- if model_architecture and model_architecture not in valid_architectures:
18
- return make_not_found_error("architecture", model_architecture)
19
-
20
- result = []
21
- checkpoints = model_list.get("Checkpoint", {})
22
-
23
- for arch_name, arch_data in checkpoints.items():
24
- if model_architecture and arch_name != model_architecture:
25
- continue
26
- if not isinstance(arch_data, dict):
27
- continue
28
-
29
- models = arch_data.get("models", [])
30
- if not isinstance(models, list):
31
- continue
32
-
33
- arch_defaults = model_defaults.get(arch_name, {})
34
- arch_level_defaults = arch_defaults.get("_defaults", {})
35
-
36
- for model in models:
37
- display_name = model.get("display_name", "")
38
- category = model.get("category", None)
39
-
40
- model_specific_defaults = arch_defaults.get(display_name, {})
41
-
42
- default_pos = model_specific_defaults.get(
43
- "positive_prompt",
44
- arch_level_defaults.get("positive_prompt", ""),
45
- )
46
- default_neg = model_specific_defaults.get(
47
- "negative_prompt",
48
- arch_level_defaults.get("negative_prompt", ""),
49
- )
50
-
51
- entry = {
52
- "name": display_name,
53
- "model_architecture": arch_name,
54
- }
55
- if category:
56
- entry["category"] = category
57
- if default_pos:
58
- entry["default_positive_prompt"] = default_pos
59
- if default_neg:
60
- entry["default_negative_prompt"] = default_neg
61
-
62
- result.append(entry)
63
-
64
- return result
 
1
+ """
2
+ MCP Tool: get_model_list
3
+ Query the list of available image generation models, with optional filtering by model architecture.
4
+ """
5
+
6
+ from .common import _load_yaml, _MODEL_LIST_PATH, _MODEL_DEFAULTS_PATH, _MODEL_ARCHITECTURES_PATH
7
+ from .error_schema import make_not_found_error
8
+
9
+
10
+ def handle_get_model_list(model_architecture: str = None) -> list | dict:
11
+ """Dynamically load the list of available image generation models from model_list.yaml."""
12
+ model_list = _load_yaml(_MODEL_LIST_PATH)
13
+ model_defaults = _load_yaml(_MODEL_DEFAULTS_PATH)
14
+ arch_config = _load_yaml(_MODEL_ARCHITECTURES_PATH)
15
+ valid_architectures = set(arch_config.get("architectures", {}).keys())
16
+
17
+ if model_architecture and model_architecture not in valid_architectures:
18
+ return make_not_found_error("architecture", model_architecture)
19
+
20
+ result = []
21
+ checkpoints = model_list.get("Checkpoint", {})
22
+
23
+ for arch_name, arch_data in checkpoints.items():
24
+ if model_architecture and arch_name != model_architecture:
25
+ continue
26
+ if not isinstance(arch_data, dict):
27
+ continue
28
+
29
+ models = arch_data.get("models", [])
30
+ if not isinstance(models, list):
31
+ continue
32
+
33
+ arch_defaults = model_defaults.get(arch_name, {})
34
+ arch_level_defaults = arch_defaults.get("_defaults", {})
35
+
36
+ for model in models:
37
+ display_name = model.get("display_name", "")
38
+ category = model.get("category", None)
39
+
40
+ model_specific_defaults = arch_defaults.get(display_name, {})
41
+
42
+ default_pos = model_specific_defaults.get(
43
+ "positive_prompt",
44
+ arch_level_defaults.get("positive_prompt", ""),
45
+ )
46
+ default_neg = model_specific_defaults.get(
47
+ "negative_prompt",
48
+ arch_level_defaults.get("negative_prompt", ""),
49
+ )
50
+
51
+ entry = {
52
+ "name": display_name,
53
+ "model_architecture": arch_name,
54
+ }
55
+ if category:
56
+ entry["category"] = category
57
+ if default_pos:
58
+ entry["default_positive_prompt"] = default_pos
59
+ if default_neg:
60
+ entry["default_negative_prompt"] = default_neg
61
+
62
+ result.append(entry)
63
+
64
+ return result
mcp_tools/get_task_list.py CHANGED
@@ -1,11 +1,11 @@
1
- """
2
- MCP Tool: get_task_list
3
- Get a list of all supported image generation task types along with their required/optional parameter lists.
4
- """
5
-
6
- from .common import _TASK_DEFINITIONS
7
-
8
-
9
- def handle_get_task_list() -> list:
10
- """Get a list of all supported image generation task types along with their required/optional parameter lists."""
11
- return _TASK_DEFINITIONS
 
1
+ """
2
+ MCP Tool: get_task_list
3
+ Get a list of all supported image generation task types along with their required/optional parameter lists.
4
+ """
5
+
6
+ from .common import _TASK_DEFINITIONS
7
+
8
+
9
+ def handle_get_task_list() -> list:
10
+ """Get a list of all supported image generation task types along with their required/optional parameter lists."""
11
+ return _TASK_DEFINITIONS
mcp_tools/get_task_status.py CHANGED
@@ -1,21 +1,21 @@
1
- """
2
- MCP Tool: get_task_status
3
- Query the processing progress and final results of an async image generation task.
4
- """
5
-
6
- from .common import _TASKS_DB
7
- from .error_schema import make_validation_error, make_not_found_error
8
-
9
-
10
- def handle_get_task_status(task_id: str) -> dict:
11
- """Query the processing progress and final results of an async image generation task."""
12
- if not task_id:
13
- return make_validation_error(
14
- "Parameter 'task_id' is required.",
15
- missing_fields=["task_id"],
16
- )
17
-
18
- if task_id not in _TASKS_DB:
19
- return make_not_found_error("task", task_id)
20
-
21
- return _TASKS_DB[task_id]
 
1
+ """
2
+ MCP Tool: get_task_status
3
+ Query the processing progress and final results of an async image generation task.
4
+ """
5
+
6
+ from .common import _TASKS_DB
7
+ from .error_schema import make_validation_error, make_not_found_error
8
+
9
+
10
+ def handle_get_task_status(task_id: str) -> dict:
11
+ """Query the processing progress and final results of an async image generation task."""
12
+ if not task_id:
13
+ return make_validation_error(
14
+ "Parameter 'task_id' is required.",
15
+ missing_fields=["task_id"],
16
+ )
17
+
18
+ if task_id not in _TASKS_DB:
19
+ return make_not_found_error("task", task_id)
20
+
21
+ return _TASKS_DB[task_id]
mcp_tools/mcp_gradio_integration.py CHANGED
@@ -1,130 +1,130 @@
1
- """
2
- MCP & Gradio Integration Module
3
-
4
- Provides:
5
- 1. register_high_level_mcp_apis: Expose only 7 high-level abstract API/MCP endpoints (using gr.api without polluting the visual UI structure)
6
- 2. cleanup_dependencies_api_names: Force cleanup of show_api attribute for non-high-level APIs in dependencies
7
- 3. patch_gradio_api_suppression: No-op implementation retained for backward compatibility
8
- """
9
-
10
- import json
11
- import gradio as gr
12
-
13
- from .get_task_list import handle_get_task_list
14
- from .get_model_architecture_list import handle_get_model_architecture_list
15
- from .get_model_list import handle_get_model_list
16
- from .get_feature_list import handle_get_feature_list
17
- from .get_model_features import handle_get_model_features
18
- from .run import handle_run
19
- from .get_task_status import handle_get_task_status
20
-
21
- HIGH_LEVEL_MCP_API_NAMES = {
22
- "get_task_list",
23
- "get_model_architecture_list",
24
- "get_model_list",
25
- "get_feature_list",
26
- "get_model_features",
27
- "run",
28
- "get_task_status",
29
- }
30
-
31
-
32
- def sanitize_keys(obj):
33
- """Recursively ensure all dictionary keys are converted to str type to avoid Gradio 5 orjson TypeError: Dict key must be str."""
34
- if isinstance(obj, dict):
35
- return {str(k): sanitize_keys(v) for k, v in obj.items()}
36
- elif isinstance(obj, list):
37
- return [sanitize_keys(x) for x in obj]
38
- elif isinstance(obj, tuple):
39
- return tuple(sanitize_keys(x) for x in obj)
40
- return obj
41
-
42
-
43
- def patch_gradio_api_suppression():
44
- """Retained for backward compatibility (no-op)."""
45
- pass
46
-
47
-
48
- def cleanup_dependencies_api_names(demo):
49
- """
50
- Clean up residual auto-generated API names in demo.fns and demo.dependencies.
51
- Force only the 7 high-level abstract MCP APIs to be exposed as public endpoints.
52
- """
53
- for fn in demo.fns.values():
54
- api_name = getattr(fn, "api_name", None)
55
- if api_name not in HIGH_LEVEL_MCP_API_NAMES:
56
- fn.show_api = False
57
-
58
- deps = getattr(demo, "dependencies", None)
59
- if deps is None and hasattr(demo, "config") and isinstance(demo.config, dict):
60
- deps = demo.config.get("dependencies", [])
61
-
62
- if deps:
63
- for dep in deps:
64
- if isinstance(dep, dict):
65
- api_name = dep.get("api_name")
66
- if api_name not in HIGH_LEVEL_MCP_API_NAMES:
67
- dep["show_api"] = False
68
-
69
- print("[MCP Protection] Cleaned up demo dependencies. Suppressed atomic API endpoints.")
70
-
71
-
72
- def register_high_level_mcp_apis(demo):
73
- """
74
- Explicitly register 7 high-level abstract MCP API endpoints on the Gradio demo using gr.api.
75
- Using gr.api() never adds any visual UI components (such as Row, Textbox, Button, etc.), avoiding duplicate interface rendering.
76
- """
77
- def get_task_list() -> list:
78
- """[Recommended Discovery Flow Step 1] Get a list of all supported image generation task types (txt2img, img2img, inpaint, outpaint, hires_fix) along with their required and optional parameter lists. Recommended flow: get_task_list -> get_model_architecture_list -> get_model_list -> [Path 1: Call run directly (pass only required params) | Path 2: Call get_model_features to get official default hyperparams -> run]."""
79
- return sanitize_keys(handle_get_task_list())
80
-
81
- def get_model_architecture_list() -> list:
82
- """[Recommended Discovery Flow Step 2] Get a list of all supported model architectures (e.g., SD1.5, SDXL, FLUX, etc.) along with their default resolutions. It is recommended to call this tool before get_model_list to obtain valid model_architecture parameters for precise model filtering."""
83
- return sanitize_keys(handle_get_model_architecture_list())
84
-
85
- def get_model_list(model_architecture: str = "") -> list | dict:
86
- """[Recommended Discovery Flow Step 3] Query the list of available image generation models. After obtaining models, choose one of two paths: 1. [Path 1 (Recommended - Minimal Mode)] Call run directly with only required parameters. Do NOT guess steps/cfg/sampler/scheduler from experience; the server will automatically apply the model's optimal default hyperparameters. 2. [Path 2 (Explicit Alignment Mode)] First call get_model_features to query the model's officially recommended hyperparameters, then pass them to run."""
87
- arch = model_architecture.strip() if model_architecture else None
88
- return sanitize_keys(handle_get_model_list(arch))
89
-
90
- def get_feature_list(feature_name: str = "") -> list | dict:
91
- """Get supported advanced features. If feature_name is empty, returns a summary list of ALL features (excluding parameters_schema to save tokens). Pass a specific feature_name (single name like 'lora', or comma-separated like 'lora, ipadapter') to retrieve complete details INCLUDING parameters_schema for requested feature(s)."""
92
- return sanitize_keys(handle_get_feature_list(feature_name.strip() if isinstance(feature_name, str) else feature_name))
93
-
94
- def get_model_features(model: str = "") -> dict:
95
- """Query metadata for the specified model, including supported task types, extended features, and official default inference parameters (steps, cfg, sampler, scheduler). This tool MUST be called when explicitly obtaining a model's optimal default hyperparameters (Path 2). Guessing or fabricating hyperparameters without querying is strictly prohibited."""
96
- return sanitize_keys(handle_get_model_features(model.strip()))
97
-
98
- def run(json_params: str = "{}") -> dict:
99
- """[Recommended Discovery Flow Step 4] Unified image generation task execution interface. Supports txt2img, img2img, and other tasks with chainable extended features. [IMPORTANT PARAMETER RULES] Do NOT guess or fabricate inference hyperparameters such as steps, cfg, sampler, scheduler! Path 1 (Recommended): Pass only required parameters (task_type, model, prompt, width, height), leave optional hyperparams empty (server uses optimal defaults). Path 2: If explicit hyperparams are needed, you MUST first call get_model_features to obtain official defaults before passing them."""
100
- try:
101
- if isinstance(json_params, dict):
102
- params = json_params
103
- else:
104
- params = json.loads(json_params or "{}")
105
- except Exception as e:
106
- return {"error": {"code": "INVALID_JSON", "message": f"Failed to parse JSON params: {e}"}}
107
- return sanitize_keys(handle_run(params))
108
-
109
- def get_task_status(task_id: str = "") -> dict:
110
- """Query the progress, status, and final generated results of an async image generation task."""
111
- return sanitize_keys(handle_get_task_status(task_id.strip()))
112
-
113
- funcs = [
114
- get_task_list,
115
- get_model_architecture_list,
116
- get_model_list,
117
- get_feature_list,
118
- get_model_features,
119
- run,
120
- get_task_status,
121
- ]
122
-
123
- for func in funcs:
124
- gr.api(func)
125
-
126
- for fn in demo.fns.values():
127
- if getattr(fn, "api_name", None) in HIGH_LEVEL_MCP_API_NAMES:
128
- fn.show_api = True
129
-
130
- print("[MCP Integration] Successfully registered 7 High-Level Abstract MCP APIs via gr.api().")
 
1
+ """
2
+ MCP & Gradio Integration Module
3
+
4
+ Provides:
5
+ 1. register_high_level_mcp_apis: Expose only 7 high-level abstract API/MCP endpoints (using gr.api without polluting the visual UI structure)
6
+ 2. cleanup_dependencies_api_names: Force cleanup of show_api attribute for non-high-level APIs in dependencies
7
+ 3. patch_gradio_api_suppression: No-op implementation retained for backward compatibility
8
+ """
9
+
10
+ import json
11
+ import gradio as gr
12
+
13
+ from .get_task_list import handle_get_task_list
14
+ from .get_model_architecture_list import handle_get_model_architecture_list
15
+ from .get_model_list import handle_get_model_list
16
+ from .get_feature_list import handle_get_feature_list
17
+ from .get_model_features import handle_get_model_features
18
+ from .run import handle_run
19
+ from .get_task_status import handle_get_task_status
20
+
21
+ HIGH_LEVEL_MCP_API_NAMES = {
22
+ "get_task_list",
23
+ "get_model_architecture_list",
24
+ "get_model_list",
25
+ "get_feature_list",
26
+ "get_model_features",
27
+ "run",
28
+ "get_task_status",
29
+ }
30
+
31
+
32
+ def sanitize_keys(obj):
33
+ """Recursively ensure all dictionary keys are converted to str type to avoid Gradio 5 orjson TypeError: Dict key must be str."""
34
+ if isinstance(obj, dict):
35
+ return {str(k): sanitize_keys(v) for k, v in obj.items()}
36
+ elif isinstance(obj, list):
37
+ return [sanitize_keys(x) for x in obj]
38
+ elif isinstance(obj, tuple):
39
+ return tuple(sanitize_keys(x) for x in obj)
40
+ return obj
41
+
42
+
43
+ def patch_gradio_api_suppression():
44
+ """Retained for backward compatibility (no-op)."""
45
+ pass
46
+
47
+
48
+ def cleanup_dependencies_api_names(demo):
49
+ """
50
+ Clean up residual auto-generated API names in demo.fns and demo.dependencies.
51
+ Force only the 7 high-level abstract MCP APIs to be exposed as public endpoints.
52
+ """
53
+ for fn in demo.fns.values():
54
+ api_name = getattr(fn, "api_name", None)
55
+ if api_name not in HIGH_LEVEL_MCP_API_NAMES:
56
+ fn.show_api = False
57
+
58
+ deps = getattr(demo, "dependencies", None)
59
+ if deps is None and hasattr(demo, "config") and isinstance(demo.config, dict):
60
+ deps = demo.config.get("dependencies", [])
61
+
62
+ if deps:
63
+ for dep in deps:
64
+ if isinstance(dep, dict):
65
+ api_name = dep.get("api_name")
66
+ if api_name not in HIGH_LEVEL_MCP_API_NAMES:
67
+ dep["show_api"] = False
68
+
69
+ print("[MCP Protection] Cleaned up demo dependencies. Suppressed atomic API endpoints.")
70
+
71
+
72
+ def register_high_level_mcp_apis(demo):
73
+ """
74
+ Explicitly register 7 high-level abstract MCP API endpoints on the Gradio demo using gr.api.
75
+ Using gr.api() never adds any visual UI components (such as Row, Textbox, Button, etc.), avoiding duplicate interface rendering.
76
+ """
77
+ def get_task_list() -> list:
78
+ """[Recommended Discovery Flow Step 1] Get a list of all supported image generation task types (txt2img, img2img, inpaint, outpaint, hires_fix) along with their required and optional parameter lists. Recommended flow: get_task_list -> get_model_architecture_list -> get_model_list -> [Path 1: Call run directly (pass only required params) | Path 2: Call get_model_features to get official default hyperparams -> run]."""
79
+ return sanitize_keys(handle_get_task_list())
80
+
81
+ def get_model_architecture_list() -> list:
82
+ """[Recommended Discovery Flow Step 2] Get a list of all supported model architectures (e.g., SD1.5, SDXL, FLUX, etc.) along with their default resolutions. It is recommended to call this tool before get_model_list to obtain valid model_architecture parameters for precise model filtering."""
83
+ return sanitize_keys(handle_get_model_architecture_list())
84
+
85
+ def get_model_list(model_architecture: str = "") -> list | dict:
86
+ """[Recommended Discovery Flow Step 3] Query the list of available image generation models. After obtaining models, choose one of two paths: 1. [Path 1 (Recommended - Minimal Mode)] Call run directly with only required parameters. Do NOT guess steps/cfg/sampler/scheduler from experience; the server will automatically apply the model's optimal default hyperparameters. 2. [Path 2 (Explicit Alignment Mode)] First call get_model_features to query the model's officially recommended hyperparameters, then pass them to run."""
87
+ arch = model_architecture.strip() if model_architecture else None
88
+ return sanitize_keys(handle_get_model_list(arch))
89
+
90
+ def get_feature_list(feature_name: str = "") -> list | dict:
91
+ """Get supported advanced features. If feature_name is empty, returns a summary list of ALL features (excluding parameters_schema to save tokens). Pass a specific feature_name (single name like 'lora', or comma-separated like 'lora, ipadapter') to retrieve complete details INCLUDING parameters_schema for requested feature(s)."""
92
+ return sanitize_keys(handle_get_feature_list(feature_name.strip() if isinstance(feature_name, str) else feature_name))
93
+
94
+ def get_model_features(model: str = "") -> dict:
95
+ """Query metadata for the specified model, including supported task types, extended features, and official default inference parameters (steps, cfg, sampler, scheduler). This tool MUST be called when explicitly obtaining a model's optimal default hyperparameters (Path 2). Guessing or fabricating hyperparameters without querying is strictly prohibited."""
96
+ return sanitize_keys(handle_get_model_features(model.strip()))
97
+
98
+ def run(json_params: str = "{}") -> dict:
99
+ """[Recommended Discovery Flow Step 4] Unified image generation task execution interface. Supports txt2img, img2img, and other tasks with chainable extended features. [IMPORTANT PARAMETER RULES] Do NOT guess or fabricate inference hyperparameters such as steps, cfg, sampler, scheduler! Path 1 (Recommended): Pass only required parameters (task_type, model, prompt, width, height), leave optional hyperparams empty (server uses optimal defaults). Path 2: If explicit hyperparams are needed, you MUST first call get_model_features to obtain official defaults before passing them."""
100
+ try:
101
+ if isinstance(json_params, dict):
102
+ params = json_params
103
+ else:
104
+ params = json.loads(json_params or "{}")
105
+ except Exception as e:
106
+ return {"error": {"code": "INVALID_JSON", "message": f"Failed to parse JSON params: {e}"}}
107
+ return sanitize_keys(handle_run(params))
108
+
109
+ def get_task_status(task_id: str = "") -> dict:
110
+ """Query the progress, status, and final generated results of an async image generation task."""
111
+ return sanitize_keys(handle_get_task_status(task_id.strip()))
112
+
113
+ funcs = [
114
+ get_task_list,
115
+ get_model_architecture_list,
116
+ get_model_list,
117
+ get_feature_list,
118
+ get_model_features,
119
+ run,
120
+ get_task_status,
121
+ ]
122
+
123
+ for func in funcs:
124
+ gr.api(func)
125
+
126
+ for fn in demo.fns.values():
127
+ if getattr(fn, "api_name", None) in HIGH_LEVEL_MCP_API_NAMES:
128
+ fn.show_api = True
129
+
130
+ print("[MCP Integration] Successfully registered 7 High-Level Abstract MCP APIs via gr.api().")
mcp_tools/run.py CHANGED
@@ -1,76 +1,76 @@
1
- """
2
- MCP Tool: run
3
- Unified image generation task submission and execution interface.
4
- """
5
-
6
- import time
7
- import uuid
8
- import threading
9
- from .common import (
10
- _load_yaml,
11
- _MODEL_LIST_PATH,
12
- _TASK_DEFINITIONS,
13
- _TASKS_DB,
14
- _execute_imagegen_pipeline,
15
- )
16
- from .error_schema import make_validation_error, make_not_found_error
17
-
18
-
19
- def handle_run(params: dict) -> dict:
20
- """Unified image generation task execution interface."""
21
- if not isinstance(params, dict):
22
- return make_validation_error("Request params must be an object.")
23
-
24
- missing = []
25
- for req_field in ["task_type", "model", "prompt"]:
26
- if req_field not in params or not params[req_field]:
27
- missing.append(req_field)
28
- if missing:
29
- return make_validation_error(
30
- f"Missing required parameter(s): {', '.join(missing)}",
31
- missing_fields=missing,
32
- )
33
-
34
- task_type = params["task_type"]
35
- valid_tasks = [t["task_type"] for t in _TASK_DEFINITIONS]
36
- if task_type not in valid_tasks:
37
- return make_validation_error(
38
- f"Invalid task_type '{task_type}'. Must be one of {valid_tasks}.",
39
- invalid_fields={"task_type": f"Must be in {valid_tasks}"},
40
- )
41
-
42
- model_list = _load_yaml(_MODEL_LIST_PATH)
43
- checkpoints = model_list.get("Checkpoint", {})
44
- all_models = set()
45
- for arch_name, arch_data in checkpoints.items():
46
- if isinstance(arch_data, dict):
47
- for m in arch_data.get("models", []):
48
- all_models.add(m.get("display_name"))
49
-
50
- if params["model"] not in all_models:
51
- return make_not_found_error("model", params["model"])
52
-
53
- task_id = f"img_task_{uuid.uuid4().hex[:10]}"
54
- created_at = int(time.time())
55
-
56
- _TASKS_DB[task_id] = {
57
- "task_id": task_id,
58
- "status": "queued",
59
- "progress": 0,
60
- "created_at": created_at,
61
- }
62
-
63
- async_exec = params.get("async_execution", False)
64
-
65
- if async_exec:
66
- t = threading.Thread(target=_execute_imagegen_pipeline, args=(task_id, params), daemon=True)
67
- t.start()
68
- return {
69
- "status": "queued",
70
- "task_id": task_id,
71
- "poll_interval_ms": 2000,
72
- "message": "Task queued successfully. Poll get_task_status for results.",
73
- }
74
- else:
75
- _execute_imagegen_pipeline(task_id, params)
76
- return _TASKS_DB[task_id]
 
1
+ """
2
+ MCP Tool: run
3
+ Unified image generation task submission and execution interface.
4
+ """
5
+
6
+ import time
7
+ import uuid
8
+ import threading
9
+ from .common import (
10
+ _load_yaml,
11
+ _MODEL_LIST_PATH,
12
+ _TASK_DEFINITIONS,
13
+ _TASKS_DB,
14
+ _execute_imagegen_pipeline,
15
+ )
16
+ from .error_schema import make_validation_error, make_not_found_error
17
+
18
+
19
+ def handle_run(params: dict) -> dict:
20
+ """Unified image generation task execution interface."""
21
+ if not isinstance(params, dict):
22
+ return make_validation_error("Request params must be an object.")
23
+
24
+ missing = []
25
+ for req_field in ["task_type", "model", "prompt"]:
26
+ if req_field not in params or not params[req_field]:
27
+ missing.append(req_field)
28
+ if missing:
29
+ return make_validation_error(
30
+ f"Missing required parameter(s): {', '.join(missing)}",
31
+ missing_fields=missing,
32
+ )
33
+
34
+ task_type = params["task_type"]
35
+ valid_tasks = [t["task_type"] for t in _TASK_DEFINITIONS]
36
+ if task_type not in valid_tasks:
37
+ return make_validation_error(
38
+ f"Invalid task_type '{task_type}'. Must be one of {valid_tasks}.",
39
+ invalid_fields={"task_type": f"Must be in {valid_tasks}"},
40
+ )
41
+
42
+ model_list = _load_yaml(_MODEL_LIST_PATH)
43
+ checkpoints = model_list.get("Checkpoint", {})
44
+ all_models = set()
45
+ for arch_name, arch_data in checkpoints.items():
46
+ if isinstance(arch_data, dict):
47
+ for m in arch_data.get("models", []):
48
+ all_models.add(m.get("display_name"))
49
+
50
+ if params["model"] not in all_models:
51
+ return make_not_found_error("model", params["model"])
52
+
53
+ task_id = f"img_task_{uuid.uuid4().hex[:10]}"
54
+ created_at = int(time.time())
55
+
56
+ _TASKS_DB[task_id] = {
57
+ "task_id": task_id,
58
+ "status": "queued",
59
+ "progress": 0,
60
+ "created_at": created_at,
61
+ }
62
+
63
+ async_exec = params.get("async_execution", False)
64
+
65
+ if async_exec:
66
+ t = threading.Thread(target=_execute_imagegen_pipeline, args=(task_id, params), daemon=True)
67
+ t.start()
68
+ return {
69
+ "status": "queued",
70
+ "task_id": task_id,
71
+ "poll_interval_ms": 2000,
72
+ "message": "Task queued successfully. Poll get_task_status for results.",
73
+ }
74
+ else:
75
+ _execute_imagegen_pipeline(task_id, params)
76
+ return _TASKS_DB[task_id]
mcp_tools/tool_handlers.py CHANGED
@@ -1,28 +1,28 @@
1
- """
2
- MCP Tool Handlers — Backward-compatible aggregation entry point.
3
- Core logic has been split into individual files (get_*.py and run.py).
4
- """
5
-
6
- from .get_task_list import handle_get_task_list
7
- from .get_model_architecture_list import handle_get_model_architecture_list
8
- from .get_model_list import handle_get_model_list
9
- from .get_feature_list import handle_get_feature_list
10
- from .get_model_features import handle_get_model_features
11
- from .run import handle_run
12
- from .get_task_status import handle_get_task_status
13
- from .common import (
14
- _TASK_DEFINITIONS,
15
- _TASKS_DB,
16
- _load_yaml,
17
- _execute_imagegen_pipeline,
18
- )
19
-
20
- __all__ = [
21
- "handle_get_task_list",
22
- "handle_get_model_architecture_list",
23
- "handle_get_model_list",
24
- "handle_get_feature_list",
25
- "handle_get_model_features",
26
- "handle_run",
27
- "handle_get_task_status",
28
- ]
 
1
+ """
2
+ MCP Tool Handlers — Backward-compatible aggregation entry point.
3
+ Core logic has been split into individual files (get_*.py and run.py).
4
+ """
5
+
6
+ from .get_task_list import handle_get_task_list
7
+ from .get_model_architecture_list import handle_get_model_architecture_list
8
+ from .get_model_list import handle_get_model_list
9
+ from .get_feature_list import handle_get_feature_list
10
+ from .get_model_features import handle_get_model_features
11
+ from .run import handle_run
12
+ from .get_task_status import handle_get_task_status
13
+ from .common import (
14
+ _TASK_DEFINITIONS,
15
+ _TASKS_DB,
16
+ _load_yaml,
17
+ _execute_imagegen_pipeline,
18
+ )
19
+
20
+ __all__ = [
21
+ "handle_get_task_list",
22
+ "handle_get_model_architecture_list",
23
+ "handle_get_model_list",
24
+ "handle_get_feature_list",
25
+ "handle_get_model_features",
26
+ "handle_run",
27
+ "handle_get_task_status",
28
+ ]
ui/layout.py CHANGED
@@ -12,7 +12,7 @@ def build_ui(event_handler_function):
12
  with gr.Blocks() as demo:
13
  gr.Markdown("# ImageGen")
14
  gr.Markdown(
15
- "This demo is a streamlined version of the [Comfy web UI](https://github.com/RioShiina47/comfy-webui)'s [ImageGen](https://huggingface.co/spaces/RioShiina/ImageGen) functionality."
16
  )
17
  with gr.Tabs(elem_id="tabs_container") as tabs:
18
  with gr.TabItem("Txt2Img", id=0):
 
12
  with gr.Blocks() as demo:
13
  gr.Markdown("# ImageGen")
14
  gr.Markdown(
15
+ "This demo is a streamlined version of the [Comfy web UI](https://github.com/RioShiina47/comfy-webui)'s [ImageGen](https://huggingface.co/spaces/RioShiina/ImageGen) functionality. Support [High-Level MCP](https://rioshiina-imagegen.hf.space/gradio_api/mcp/) 🤖"
16
  )
17
  with gr.Tabs(elem_id="tabs_container") as tabs:
18
  with gr.TabItem("Txt2Img", id=0):
yaml/chain_features.yaml CHANGED
@@ -1,652 +1,652 @@
1
- # Complete Feature & Chain Definitions Configuration for MCP Tools
2
- # Every chain injector in chain_injectors/ corresponds 1-to-1 with an entry here (21 injectors total).
3
-
4
- lora:
5
- chains: lora
6
- display_name: "LoRA Fine-tuning Injector"
7
- description: "Injects LoRA weights into UNet/DiT model and CLIP text encoder for custom style, character, or domain adaptation."
8
- supported_tasks:
9
- - txt2img
10
- - img2img
11
- - inpaint
12
- - outpaint
13
- - hires_fix
14
- max_count: 5
15
- usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), then provide the lora_value (Civitai Version ID or HF repo path), and a single scale value (0.0~2.0) that controls both model and clip strength simultaneously."
16
- parameters_schema:
17
- type: object
18
- properties:
19
- source:
20
- type: string
21
- enum: ["Civitai", "Hugging Face"]
22
- description: "Download source for the LoRA model. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo path."
23
- lora_value:
24
- type: string
25
- description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456). For Hugging Face: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., 'lightx2v/Qwen-Image-Lightning/Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors')."
26
- scale:
27
- type: number
28
- default: 1.0
29
- minimum: 0.0
30
- maximum: 2.0
31
- description: "Unified strength applied to both the UNet/DiT model and CLIP text encoder (0.0 to 2.0)."
32
- required:
33
- - source
34
- - lora_value
35
-
36
- ipadapter:
37
- chains: ipadapter
38
- display_name: "IP-Adapter Image Prompt"
39
- description: "Uses reference images to guide generation style, composition, structure, or face appearance without prompt text restrictions (SD1.5 & SDXL)."
40
- supported_tasks:
41
- - txt2img
42
- - img2img
43
- - inpaint
44
- - outpaint
45
- - hires_fix
46
- max_count: 5
47
- usage_guideline: "Supply global settings (preset, embeds_scaling, combine_method, final_weight) and up to 5 reference images with individual weights. Preset must match the target model architecture (SD1.5 or SDXL)."
48
- parameters_schema:
49
- type: object
50
- properties:
51
- image:
52
- type: string
53
- description: "Reference image encoded as Base64 Data URI (e.g., data:image/png;base64,...) or HTTP/HTTPS URL."
54
- weight:
55
- type: number
56
- default: 1.0
57
- minimum: 0.0
58
- maximum: 2.0
59
- description: "Influence weight of the individual image prompt (0.0 to 2.0)."
60
- preset:
61
- type: string
62
- default: "STANDARD (medium strength)"
63
- description: "IPAdapter preset model variant loaded from ipadapter.yaml. Must match model architecture (SD1.5 vs SDXL)."
64
- embeds_scaling:
65
- type: string
66
- default: "V only"
67
- enum:
68
- - "V only"
69
- - "K+V"
70
- - "K+V w/ C penalty"
71
- - "K+mean(V) w/ C penalty"
72
- description: "Embedding scaling method for IPAdapter."
73
- combine_method:
74
- type: string
75
- default: "concat"
76
- enum:
77
- - "concat"
78
- - "add"
79
- - "subtract"
80
- - "average"
81
- - "norm average"
82
- - "max"
83
- - "min"
84
- description: "Combination method for multiple reference images."
85
- final_weight:
86
- type: number
87
- default: 1.0
88
- minimum: 0.0
89
- maximum: 2.0
90
- description: "Global weight multiplier for IPAdapter conditioning (0.0 to 2.0)."
91
- lora_strength:
92
- type: number
93
- default: 0.6
94
- description: "LoRA weight strength for FaceID adapter variants."
95
- required:
96
- - image
97
-
98
- controlnet:
99
- chains: controlnet
100
- display_name: "ControlNet Spatial Guidance"
101
- description: "Applies structural and spatial conditioning (depth, pose, lineart, tile, scribble, canny) to guide output composition."
102
- supported_tasks:
103
- - txt2img
104
- - img2img
105
- - inpaint
106
- - outpaint
107
- - hires_fix
108
- max_count: 5
109
- usage_guideline: "Specify ControlNet type and series (must match requested model architecture e.g., SD1.5, SDXL, SD3.5, FLUX.1, Qwen-Image), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and guidance strength."
110
- parameters_schema:
111
- type: object
112
- properties:
113
- type:
114
- type: string
115
- description: "ControlNet conditioning type (must match model architecture)."
116
- series:
117
- type: string
118
- description: "ControlNet model series (must match model architecture)."
119
- image:
120
- type: string
121
- description: "Pre-processed control image (e.g., Depth, Canny, Pose, Lineart map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
122
- strength:
123
- type: number
124
- default: 1.0
125
- minimum: 0.0
126
- maximum: 2.0
127
- description: "Control influence strength (0.0 to 2.0)."
128
- required:
129
- - type
130
- - series
131
- - image
132
-
133
- conditioning:
134
- chains: conditioning
135
- display_name: "Regional Conditioning / Area Prompt"
136
- description: "Defines rectangular areas (X, Y, Width, Height) and assigns specific text prompts and conditioning strengths to them."
137
- supported_tasks:
138
- - txt2img
139
- - img2img
140
- - inpaint
141
- - outpaint
142
- - hires_fix
143
- max_count: 10
144
- usage_guideline: "Define rectangular spatial areas (X, Y, width, height) and assign specific prompts and strengths to them. Supports up to 10 area prompts."
145
- parameters_schema:
146
- type: object
147
- properties:
148
- prompt:
149
- type: string
150
- description: "Text prompt for this specific rectangular area."
151
- x:
152
- type: integer
153
- default: 0
154
- description: "Top-left X coordinate of the rectangular area."
155
- y:
156
- type: integer
157
- default: 0
158
- description: "Top-left Y coordinate of the rectangular area."
159
- width:
160
- type: integer
161
- default: 512
162
- description: "Width of the rectangular area."
163
- height:
164
- type: integer
165
- default: 512
166
- description: "Height of the rectangular area."
167
- strength:
168
- type: number
169
- default: 1.0
170
- minimum: 0.1
171
- maximum: 2.0
172
- description: "Conditioning strength for this area (0.1 to 2.0)."
173
- required:
174
- - prompt
175
-
176
- vae:
177
- chains: vae
178
- display_name: "Custom VAE Loader"
179
- description: "Overrides default VAE model used for latent space encoding and final image decoding."
180
- supported_tasks:
181
- - txt2img
182
- - img2img
183
- - inpaint
184
- - outpaint
185
- - hires_fix
186
- max_count: 1
187
- usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), then provide the vae_value (Civitai Version ID or HF file path)."
188
- parameters_schema:
189
- type: object
190
- properties:
191
- source:
192
- type: string
193
- enum: ["Civitai", "Hugging Face"]
194
- description: "Download source for the VAE model. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo path."
195
- vae_value:
196
- type: string
197
- description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456). For Hugging Face: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., 'madebyollin/sdxl-vae-fp16-fix/sdxl_vae.safetensors')."
198
- required:
199
- - source
200
- - vae_value
201
-
202
- pid:
203
- chains: pid
204
- display_name: "PiD High-Resolution Refinement"
205
- description: "Progressive Detail (PiD) upscale injector for fine detail enhancement and resolution upscaling."
206
- supported_tasks:
207
- - txt2img
208
- max_count: 1
209
- usage_guideline: "Enables PiD detail refinement pipeline using a boolean switch ('enabled': true/false)."
210
- parameters_schema:
211
- type: object
212
- properties:
213
- enabled:
214
- type: boolean
215
- default: true
216
- description: "Enable or disable PiD High-Resolution Refinement."
217
- required:
218
- - enabled
219
-
220
- flux1_style:
221
- chains: style
222
- display_name: "FLUX.1 Style Reference"
223
- description: "Applies artistic style conditioning from reference images onto FLUX.1 model generated outputs."
224
- supported_tasks:
225
- - txt2img
226
- - img2img
227
- - inpaint
228
- - outpaint
229
- - hires_fix
230
- max_count: 5
231
- usage_guideline: "Supply style reference image(s) (up to 5) encoded as Base64 Data URI or HTTP/HTTPS URL and optional strength."
232
- parameters_schema:
233
- type: object
234
- properties:
235
- image:
236
- type: string
237
- description: "Style reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
238
- strength:
239
- type: number
240
- default: 1.0
241
- minimum: 0.0
242
- maximum: 2.0
243
- description: "Style influence strength (0.0 to 2.0)."
244
- required:
245
- - image
246
-
247
- reference_edit:
248
- chains: reference_latent
249
- display_name: "Reference Edit"
250
- description: "For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
251
- supported_tasks:
252
- - txt2img
253
- - img2img
254
- - inpaint
255
- - outpaint
256
- - hires_fix
257
- max_count: 10
258
- usage_guideline: "Supply reference image(s) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images (up to 10) performs an Image Combine."
259
- parameters_schema:
260
- type: object
261
- properties:
262
- image:
263
- type: string
264
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
265
- required:
266
- - image
267
-
268
- mage_flow_reference_edit:
269
- chains: reference_image
270
- display_name: "Mage-Flow Reference Edit"
271
- description: " (Mage-Flow-Edit-Turbo/Mage-Flow-Edit recommended) For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
272
- supported_tasks:
273
- - txt2img
274
- - img2img
275
- - inpaint
276
- - outpaint
277
- - hires_fix
278
- max_count: 10
279
- usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
280
- parameters_schema:
281
- type: object
282
- properties:
283
- image:
284
- type: string
285
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
286
- required:
287
- - image
288
-
289
- krea2_identity_edit:
290
- chains: krea2_identity_edit
291
- display_name: "KREA2 Identity Edit"
292
- description: "Processed using the lbouaraba/comfyui-krea2edit node. (Krea-2-Turbo recommended, Krea-2-Raw need set ZeroGPU Duration (s) to 120 ) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
293
- supported_tasks:
294
- - txt2img
295
- - img2img
296
- - inpaint
297
- - outpaint
298
- - hires_fix
299
- max_count: 2
300
- usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
301
- parameters_schema:
302
- type: object
303
- properties:
304
- image:
305
- type: string
306
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
307
- required:
308
- - image
309
-
310
- krea2_style_reference:
311
- chains: krea2_style_reference
312
- display_name: "KREA2 Style Reference"
313
- description: "(Krea-2-Turbo recommended) Add style reference images to perform style reference editing."
314
- supported_tasks:
315
- - txt2img
316
- - img2img
317
- - inpaint
318
- - outpaint
319
- - hires_fix
320
- max_count: 3
321
- usage_guideline: "Supply style reference image as Base64 Data URI or HTTP/HTTPS URL."
322
- parameters_schema:
323
- type: object
324
- properties:
325
- image:
326
- type: string
327
- description: "Style reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
328
- required:
329
- - image
330
-
331
- diffsynth_controlnet:
332
- chains: diffsynth_controlnet
333
- display_name: "DiffSynth ControlNet"
334
- description: "DiffSynth optimized ControlNet injector for Z-Image models."
335
- supported_tasks:
336
- - txt2img
337
- - img2img
338
- - inpaint
339
- - outpaint
340
- - hires_fix
341
- max_count: 5
342
- usage_guideline: "Supply ControlNet type (e.g., 'Canny'), series (e.g., 'alibaba-pai Controlnet Union 2.1 8steps'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
343
- parameters_schema:
344
- type: object
345
- properties:
346
- type:
347
- type: string
348
- description: "ControlNet conditioning type."
349
- series:
350
- type: string
351
- description: "ControlNet model series name."
352
- image:
353
- type: string
354
- description: "Pre-processed control image (e.g., Depth map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
355
- strength:
356
- type: number
357
- default: 1.0
358
- description: "Control influence strength."
359
- required:
360
- - type
361
- - series
362
- - image
363
-
364
- boogu_image_edit:
365
- chains: boogu_image_edit
366
- display_name: "Boogu-Image Edit"
367
- description: " (Boogu-Image-Edit-Turbo/Boogu-Image-Edit recommended, Boogu-Image-Edit need set ZeroGPU Duration (s) to 120 ) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
368
- supported_tasks:
369
- - txt2img
370
- - img2img
371
- - inpaint
372
- - outpaint
373
- - hires_fix
374
- max_count: 2
375
- usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
376
- parameters_schema:
377
- type: object
378
- properties:
379
- image:
380
- type: string
381
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
382
- required:
383
- - image
384
-
385
- joyai_reference_edit:
386
- chains: joyai_image
387
- display_name: "JoyAI Reference Edit"
388
- description: " (JoyAI-Image-Edit recommended) For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit (JoyAI-Image-Edit recommended), while adding multiple images performs an Image Combine (JoyAI-Image-Edit-Plus recommended with ZeroGPU Duration (s) set to 120)."
389
- supported_tasks:
390
- - txt2img
391
- - img2img
392
- - inpaint
393
- - outpaint
394
- - hires_fix
395
- max_count: 2
396
- usage_guideline: "Supply JoyAI reference image as Base64 Data URI or HTTP/HTTPS URL."
397
- parameters_schema:
398
- type: object
399
- properties:
400
- image:
401
- type: string
402
- description: "Input reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
403
- required:
404
- - image
405
-
406
- qwen_image_edit:
407
- chains: qwen_image_edit
408
- display_name: "Qwen-Image Edit"
409
- description: " (lightx2v/Qwen-Image-Edit-2511-Lightning recommended) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
410
- supported_tasks:
411
- - txt2img
412
- - img2img
413
- - inpaint
414
- - outpaint
415
- - hires_fix
416
- max_count: 3
417
- usage_guideline: "Supply reference image(s) (up to 3) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images performs an Image Combine."
418
- parameters_schema:
419
- type: object
420
- properties:
421
- image:
422
- type: string
423
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
424
- required:
425
- - image
426
-
427
- hidream_o1_smoothing:
428
- chains: hidream_o1_smoothing
429
- display_name: "HiDream O1 Smoothing Injector"
430
- description: "HiDream O1 detail smoothing and artifact reduction injector."
431
- supported_tasks:
432
- - txt2img
433
- - img2img
434
- - inpaint
435
- - outpaint
436
- - hires_fix
437
- max_count: 1
438
- usage_guideline: "Configures smoothing factor for HiDream models."
439
- parameters_schema:
440
- type: object
441
- properties:
442
- factor:
443
- type: number
444
- default: 0.5
445
- description: "Smoothing intensity (0.0 to 1.0)."
446
- required: []
447
-
448
- krea2_controlnet:
449
- chains: krea2_controlnet
450
- display_name: "KREA2 ControlNet"
451
- description: "Processed using the facok/comfyui-krea2-controlnet node."
452
- supported_tasks:
453
- - txt2img
454
- - img2img
455
- - inpaint
456
- - outpaint
457
- - hires_fix
458
- max_count: 5
459
- usage_guideline: "Supply ControlNet type (e.g., 'Depth'), series (e.g., 'Patil'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
460
- parameters_schema:
461
- type: object
462
- properties:
463
- type:
464
- type: string
465
- enum:
466
- - "Depth"
467
- description: "ControlNet conditioning type."
468
- series:
469
- type: string
470
- enum:
471
- - "Patil"
472
- default: "Patil"
473
- description: "ControlNet model series."
474
- image:
475
- type: string
476
- description: "Pre-processed control image (e.g., Depth map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
477
- strength:
478
- type: number
479
- default: 1.0
480
- minimum: 0.0
481
- maximum: 2.0
482
- description: "Control influence strength (0.0 to 2.0)."
483
- required:
484
- - type
485
- - series
486
- - image
487
-
488
- anima_controlnet_lllite:
489
- chains: anima_controlnet_lllite
490
- display_name: "Anima ControlNet LLLite"
491
- description: "Anima model-specific lightweight ControlNet."
492
- supported_tasks:
493
- - txt2img
494
- - img2img
495
- - inpaint
496
- - outpaint
497
- - hires_fix
498
- max_count: 5
499
- usage_guideline: "Supply Anima ControlNet LLLite type (e.g., 'Depth'), series (e.g., 'kohya-ss'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
500
- parameters_schema:
501
- type: object
502
- properties:
503
- type:
504
- type: string
505
- description: "Anima ControlNet LLLite conditioning type."
506
- series:
507
- type: string
508
- description: "Anima ControlNet LLLite model series."
509
- image:
510
- type: string
511
- description: "Pre-processed control image (e.g., Depth, Lineart map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
512
- strength:
513
- type: number
514
- default: 1.0
515
- minimum: 0.0
516
- maximum: 2.0
517
- description: "Control influence strength (0.0 to 2.0)."
518
- required:
519
- - type
520
- - series
521
- - image
522
-
523
- hidream_o1_reference:
524
- chains: hidream_o1_reference
525
- display_name: "HiDream-O1 Reference Edit"
526
- description: " (HiDream-O1-Image-Dev recommended with resolution set to 4.0MP, e.g., 2048x2048) For HiDream-O1 models, this feature enables reference image editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
527
- supported_tasks:
528
- - txt2img
529
- - img2img
530
- - inpaint
531
- - outpaint
532
- - hires_fix
533
- max_count: 9
534
- usage_guideline: "Supply reference image(s) (up to 9) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images performs an Image Combine."
535
- parameters_schema:
536
- type: object
537
- properties:
538
- image:
539
- type: string
540
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
541
- required:
542
- - image
543
-
544
- flux1_ipadapter:
545
- chains: flux1_ipadapter
546
- display_name: "Flux1 IP-Adapter"
547
- description: "FLUX.1 model-specific IP-Adapter implementation."
548
- supported_tasks:
549
- - txt2img
550
- - img2img
551
- - inpaint
552
- - outpaint
553
- - hires_fix
554
- max_count: 5
555
- usage_guideline: "Supply reference image (Base64 Data URI or HTTP/HTTPS URL), optional weight (default 1.0), start_at (default 0.0), and end_at (default 1.0). Up to 5 images supported."
556
- parameters_schema:
557
- type: object
558
- properties:
559
- image:
560
- type: string
561
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
562
- weight:
563
- type: number
564
- default: 1.0
565
- description: "Influence weight of the image prompt (0.0 to 2.0)."
566
- start_at:
567
- type: number
568
- default: 0.0
569
- description: "Start step percentage for IP-Adapter application (0.0 to 1.0)."
570
- end_at:
571
- type: number
572
- default: 1.0
573
- description: "End step percentage for IP-Adapter application (0.0 to 1.0)."
574
- start_percent:
575
- type: number
576
- default: 0.0
577
- description: "Alias for start_at."
578
- end_percent:
579
- type: number
580
- default: 1.0
581
- description: "Alias for end_at."
582
- required:
583
- - image
584
-
585
- sd3_ipadapter:
586
- chains: sd3_ipadapter
587
- display_name: "SD3 IP-Adapter"
588
- description: "SD3/SD3.5 model-specific IP-Adapter implementation."
589
- supported_tasks:
590
- - txt2img
591
- - img2img
592
- - inpaint
593
- - outpaint
594
- - hires_fix
595
- max_count: 5
596
- usage_guideline: "Supply reference image (Base64 Data URI or HTTP/HTTPS URL), optional weight (default 1.0), start_at (default 0.0), and end_at (default 1.0). Up to 5 images supported."
597
- parameters_schema:
598
- type: object
599
- properties:
600
- image:
601
- type: string
602
- description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
603
- weight:
604
- type: number
605
- default: 1.0
606
- description: "Influence weight of the image prompt (0.0 to 2.0)."
607
- start_at:
608
- type: number
609
- default: 0.0
610
- description: "Start step percentage for IP-Adapter application (0.0 to 1.0)."
611
- end_at:
612
- type: number
613
- default: 1.0
614
- description: "End step percentage for IP-Adapter application (0.0 to 1.0)."
615
- start_percent:
616
- type: number
617
- default: 0.0
618
- description: "Alias for start_at."
619
- end_percent:
620
- type: number
621
- default: 1.0
622
- description: "Alias for end_at."
623
- required:
624
- - image
625
-
626
- embedding:
627
- chains: embedding
628
- display_name: "Textual Inversion Embedding Injector"
629
- description: "Downloads Textual Inversion embedding files from Civitai or Hugging Face to the server. Note: This feature ONLY handles file downloading/preparation. To activate the embedding, manually add 'embedding:<filename>' (e.g. 'embedding:civitai_456' for Civitai ID 456, or 'embedding:filename' for Hugging Face) into your prompt or negative_prompt."
630
- supported_tasks:
631
- - txt2img
632
- - img2img
633
- - inpaint
634
- - outpaint
635
- - hires_fix
636
- max_count: 5
637
- usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), and embedding_value (Civitai Version ID or HF repo file path). The file is downloaded to server; manually enter 'embedding:<filename>' in prompt or negative_prompt to activate."
638
- parameters_schema:
639
- type: object
640
- properties:
641
- source:
642
- type: string
643
- enum:
644
- - "Civitai"
645
- - "Hugging Face"
646
- description: "Download source for the Textual Inversion embedding file. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo file path."
647
- embedding_value:
648
- type: string
649
- description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456, saved as 'civitai_456.safetensors'). For Hugging Face: repo_id/filename.extension (e.g., 'ilikebigturtles/lazypos/lazypos.safetensors', saved as 'lazypos.safetensors'). Manually reference embedding:<filename> in prompt or negative_prompt."
650
- required:
651
- - source
652
- - embedding_value
 
1
+ # Complete Feature & Chain Definitions Configuration for MCP Tools
2
+ # Every chain injector in chain_injectors/ corresponds 1-to-1 with an entry here (21 injectors total).
3
+
4
+ lora:
5
+ chains: lora
6
+ display_name: "LoRA Fine-tuning Injector"
7
+ description: "Injects LoRA weights into UNet/DiT model and CLIP text encoder for custom style, character, or domain adaptation."
8
+ supported_tasks:
9
+ - txt2img
10
+ - img2img
11
+ - inpaint
12
+ - outpaint
13
+ - hires_fix
14
+ max_count: 5
15
+ usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), then provide the lora_value (Civitai Version ID or HF repo path), and a single scale value (0.0~2.0) that controls both model and clip strength simultaneously."
16
+ parameters_schema:
17
+ type: object
18
+ properties:
19
+ source:
20
+ type: string
21
+ enum: ["Civitai", "Hugging Face"]
22
+ description: "Download source for the LoRA model. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo path."
23
+ lora_value:
24
+ type: string
25
+ description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456). For Hugging Face: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., 'lightx2v/Qwen-Image-Lightning/Qwen-Image-Lightning-4steps-V2.0-bf16.safetensors')."
26
+ scale:
27
+ type: number
28
+ default: 1.0
29
+ minimum: 0.0
30
+ maximum: 2.0
31
+ description: "Unified strength applied to both the UNet/DiT model and CLIP text encoder (0.0 to 2.0)."
32
+ required:
33
+ - source
34
+ - lora_value
35
+
36
+ ipadapter:
37
+ chains: ipadapter
38
+ display_name: "IP-Adapter Image Prompt"
39
+ description: "Uses reference images to guide generation style, composition, structure, or face appearance without prompt text restrictions (SD1.5 & SDXL)."
40
+ supported_tasks:
41
+ - txt2img
42
+ - img2img
43
+ - inpaint
44
+ - outpaint
45
+ - hires_fix
46
+ max_count: 5
47
+ usage_guideline: "Supply global settings (preset, embeds_scaling, combine_method, final_weight) and up to 5 reference images with individual weights. Preset must match the target model architecture (SD1.5 or SDXL)."
48
+ parameters_schema:
49
+ type: object
50
+ properties:
51
+ image:
52
+ type: string
53
+ description: "Reference image encoded as Base64 Data URI (e.g., data:image/png;base64,...) or HTTP/HTTPS URL."
54
+ weight:
55
+ type: number
56
+ default: 1.0
57
+ minimum: 0.0
58
+ maximum: 2.0
59
+ description: "Influence weight of the individual image prompt (0.0 to 2.0)."
60
+ preset:
61
+ type: string
62
+ default: "STANDARD (medium strength)"
63
+ description: "IPAdapter preset model variant loaded from ipadapter.yaml. Must match model architecture (SD1.5 vs SDXL)."
64
+ embeds_scaling:
65
+ type: string
66
+ default: "V only"
67
+ enum:
68
+ - "V only"
69
+ - "K+V"
70
+ - "K+V w/ C penalty"
71
+ - "K+mean(V) w/ C penalty"
72
+ description: "Embedding scaling method for IPAdapter."
73
+ combine_method:
74
+ type: string
75
+ default: "concat"
76
+ enum:
77
+ - "concat"
78
+ - "add"
79
+ - "subtract"
80
+ - "average"
81
+ - "norm average"
82
+ - "max"
83
+ - "min"
84
+ description: "Combination method for multiple reference images."
85
+ final_weight:
86
+ type: number
87
+ default: 1.0
88
+ minimum: 0.0
89
+ maximum: 2.0
90
+ description: "Global weight multiplier for IPAdapter conditioning (0.0 to 2.0)."
91
+ lora_strength:
92
+ type: number
93
+ default: 0.6
94
+ description: "LoRA weight strength for FaceID adapter variants."
95
+ required:
96
+ - image
97
+
98
+ controlnet:
99
+ chains: controlnet
100
+ display_name: "ControlNet Spatial Guidance"
101
+ description: "Applies structural and spatial conditioning (depth, pose, lineart, tile, scribble, canny) to guide output composition."
102
+ supported_tasks:
103
+ - txt2img
104
+ - img2img
105
+ - inpaint
106
+ - outpaint
107
+ - hires_fix
108
+ max_count: 5
109
+ usage_guideline: "Specify ControlNet type and series (must match requested model architecture e.g., SD1.5, SDXL, SD3.5, FLUX.1, Qwen-Image), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and guidance strength."
110
+ parameters_schema:
111
+ type: object
112
+ properties:
113
+ type:
114
+ type: string
115
+ description: "ControlNet conditioning type (must match model architecture)."
116
+ series:
117
+ type: string
118
+ description: "ControlNet model series (must match model architecture)."
119
+ image:
120
+ type: string
121
+ description: "Pre-processed control image (e.g., Depth, Canny, Pose, Lineart map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
122
+ strength:
123
+ type: number
124
+ default: 1.0
125
+ minimum: 0.0
126
+ maximum: 2.0
127
+ description: "Control influence strength (0.0 to 2.0)."
128
+ required:
129
+ - type
130
+ - series
131
+ - image
132
+
133
+ conditioning:
134
+ chains: conditioning
135
+ display_name: "Regional Conditioning / Area Prompt"
136
+ description: "Defines rectangular areas (X, Y, Width, Height) and assigns specific text prompts and conditioning strengths to them."
137
+ supported_tasks:
138
+ - txt2img
139
+ - img2img
140
+ - inpaint
141
+ - outpaint
142
+ - hires_fix
143
+ max_count: 10
144
+ usage_guideline: "Define rectangular spatial areas (X, Y, width, height) and assign specific prompts and strengths to them. Supports up to 10 area prompts."
145
+ parameters_schema:
146
+ type: object
147
+ properties:
148
+ prompt:
149
+ type: string
150
+ description: "Text prompt for this specific rectangular area."
151
+ x:
152
+ type: integer
153
+ default: 0
154
+ description: "Top-left X coordinate of the rectangular area."
155
+ y:
156
+ type: integer
157
+ default: 0
158
+ description: "Top-left Y coordinate of the rectangular area."
159
+ width:
160
+ type: integer
161
+ default: 512
162
+ description: "Width of the rectangular area."
163
+ height:
164
+ type: integer
165
+ default: 512
166
+ description: "Height of the rectangular area."
167
+ strength:
168
+ type: number
169
+ default: 1.0
170
+ minimum: 0.1
171
+ maximum: 2.0
172
+ description: "Conditioning strength for this area (0.1 to 2.0)."
173
+ required:
174
+ - prompt
175
+
176
+ vae:
177
+ chains: vae
178
+ display_name: "Custom VAE Loader"
179
+ description: "Overrides default VAE model used for latent space encoding and final image decoding."
180
+ supported_tasks:
181
+ - txt2img
182
+ - img2img
183
+ - inpaint
184
+ - outpaint
185
+ - hires_fix
186
+ max_count: 1
187
+ usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), then provide the vae_value (Civitai Version ID or HF file path)."
188
+ parameters_schema:
189
+ type: object
190
+ properties:
191
+ source:
192
+ type: string
193
+ enum: ["Civitai", "Hugging Face"]
194
+ description: "Download source for the VAE model. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo path."
195
+ vae_value:
196
+ type: string
197
+ description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456). For Hugging Face: repo_id/filename.extension or repo_id/folder_path/filename.extension (e.g., 'madebyollin/sdxl-vae-fp16-fix/sdxl_vae.safetensors')."
198
+ required:
199
+ - source
200
+ - vae_value
201
+
202
+ pid:
203
+ chains: pid
204
+ display_name: "PiD High-Resolution Refinement"
205
+ description: "Progressive Detail (PiD) upscale injector for fine detail enhancement and resolution upscaling."
206
+ supported_tasks:
207
+ - txt2img
208
+ max_count: 1
209
+ usage_guideline: "Enables PiD detail refinement pipeline using a boolean switch ('enabled': true/false)."
210
+ parameters_schema:
211
+ type: object
212
+ properties:
213
+ enabled:
214
+ type: boolean
215
+ default: true
216
+ description: "Enable or disable PiD High-Resolution Refinement."
217
+ required:
218
+ - enabled
219
+
220
+ flux1_style:
221
+ chains: style
222
+ display_name: "FLUX.1 Style Reference"
223
+ description: "Applies artistic style conditioning from reference images onto FLUX.1 model generated outputs."
224
+ supported_tasks:
225
+ - txt2img
226
+ - img2img
227
+ - inpaint
228
+ - outpaint
229
+ - hires_fix
230
+ max_count: 5
231
+ usage_guideline: "Supply style reference image(s) (up to 5) encoded as Base64 Data URI or HTTP/HTTPS URL and optional strength."
232
+ parameters_schema:
233
+ type: object
234
+ properties:
235
+ image:
236
+ type: string
237
+ description: "Style reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
238
+ strength:
239
+ type: number
240
+ default: 1.0
241
+ minimum: 0.0
242
+ maximum: 2.0
243
+ description: "Style influence strength (0.0 to 2.0)."
244
+ required:
245
+ - image
246
+
247
+ reference_edit:
248
+ chains: reference_latent
249
+ display_name: "Reference Edit"
250
+ description: "For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
251
+ supported_tasks:
252
+ - txt2img
253
+ - img2img
254
+ - inpaint
255
+ - outpaint
256
+ - hires_fix
257
+ max_count: 10
258
+ usage_guideline: "Supply reference image(s) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images (up to 10) performs an Image Combine."
259
+ parameters_schema:
260
+ type: object
261
+ properties:
262
+ image:
263
+ type: string
264
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
265
+ required:
266
+ - image
267
+
268
+ mage_flow_reference_edit:
269
+ chains: reference_image
270
+ display_name: "Mage-Flow Reference Edit"
271
+ description: " (Mage-Flow-Edit-Turbo/Mage-Flow-Edit recommended) For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
272
+ supported_tasks:
273
+ - txt2img
274
+ - img2img
275
+ - inpaint
276
+ - outpaint
277
+ - hires_fix
278
+ max_count: 10
279
+ usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
280
+ parameters_schema:
281
+ type: object
282
+ properties:
283
+ image:
284
+ type: string
285
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
286
+ required:
287
+ - image
288
+
289
+ krea2_identity_edit:
290
+ chains: krea2_identity_edit
291
+ display_name: "KREA2 Identity Edit"
292
+ description: "Processed using the lbouaraba/comfyui-krea2edit node. (Krea-2-Turbo recommended, Krea-2-Raw need set ZeroGPU Duration (s) to 120 ) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
293
+ supported_tasks:
294
+ - txt2img
295
+ - img2img
296
+ - inpaint
297
+ - outpaint
298
+ - hires_fix
299
+ max_count: 2
300
+ usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
301
+ parameters_schema:
302
+ type: object
303
+ properties:
304
+ image:
305
+ type: string
306
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
307
+ required:
308
+ - image
309
+
310
+ krea2_style_reference:
311
+ chains: krea2_style_reference
312
+ display_name: "KREA2 Style Reference"
313
+ description: "(Krea-2-Turbo recommended) Add style reference images to perform style reference editing."
314
+ supported_tasks:
315
+ - txt2img
316
+ - img2img
317
+ - inpaint
318
+ - outpaint
319
+ - hires_fix
320
+ max_count: 3
321
+ usage_guideline: "Supply style reference image as Base64 Data URI or HTTP/HTTPS URL."
322
+ parameters_schema:
323
+ type: object
324
+ properties:
325
+ image:
326
+ type: string
327
+ description: "Style reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
328
+ required:
329
+ - image
330
+
331
+ diffsynth_controlnet:
332
+ chains: diffsynth_controlnet
333
+ display_name: "DiffSynth ControlNet"
334
+ description: "DiffSynth optimized ControlNet injector for Z-Image models."
335
+ supported_tasks:
336
+ - txt2img
337
+ - img2img
338
+ - inpaint
339
+ - outpaint
340
+ - hires_fix
341
+ max_count: 5
342
+ usage_guideline: "Supply ControlNet type (e.g., 'Canny'), series (e.g., 'alibaba-pai Controlnet Union 2.1 8steps'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
343
+ parameters_schema:
344
+ type: object
345
+ properties:
346
+ type:
347
+ type: string
348
+ description: "ControlNet conditioning type."
349
+ series:
350
+ type: string
351
+ description: "ControlNet model series name."
352
+ image:
353
+ type: string
354
+ description: "Pre-processed control image (e.g., Depth map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
355
+ strength:
356
+ type: number
357
+ default: 1.0
358
+ description: "Control influence strength."
359
+ required:
360
+ - type
361
+ - series
362
+ - image
363
+
364
+ boogu_image_edit:
365
+ chains: boogu_image_edit
366
+ display_name: "Boogu-Image Edit"
367
+ description: " (Boogu-Image-Edit-Turbo/Boogu-Image-Edit recommended, Boogu-Image-Edit need set ZeroGPU Duration (s) to 120 ) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
368
+ supported_tasks:
369
+ - txt2img
370
+ - img2img
371
+ - inpaint
372
+ - outpaint
373
+ - hires_fix
374
+ max_count: 2
375
+ usage_guideline: "Supply reference image as Base64 Data URI or HTTP/HTTPS URL."
376
+ parameters_schema:
377
+ type: object
378
+ properties:
379
+ image:
380
+ type: string
381
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
382
+ required:
383
+ - image
384
+
385
+ joyai_reference_edit:
386
+ chains: joyai_image
387
+ display_name: "JoyAI Reference Edit"
388
+ description: " (JoyAI-Image-Edit recommended) For multimodal models, this feature enables powerful editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit (JoyAI-Image-Edit recommended), while adding multiple images performs an Image Combine (JoyAI-Image-Edit-Plus recommended with ZeroGPU Duration (s) set to 120)."
389
+ supported_tasks:
390
+ - txt2img
391
+ - img2img
392
+ - inpaint
393
+ - outpaint
394
+ - hires_fix
395
+ max_count: 2
396
+ usage_guideline: "Supply JoyAI reference image as Base64 Data URI or HTTP/HTTPS URL."
397
+ parameters_schema:
398
+ type: object
399
+ properties:
400
+ image:
401
+ type: string
402
+ description: "Input reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
403
+ required:
404
+ - image
405
+
406
+ qwen_image_edit:
407
+ chains: qwen_image_edit
408
+ display_name: "Qwen-Image Edit"
409
+ description: " (lightx2v/Qwen-Image-Edit-2511-Lightning recommended) In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
410
+ supported_tasks:
411
+ - txt2img
412
+ - img2img
413
+ - inpaint
414
+ - outpaint
415
+ - hires_fix
416
+ max_count: 3
417
+ usage_guideline: "Supply reference image(s) (up to 3) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images performs an Image Combine."
418
+ parameters_schema:
419
+ type: object
420
+ properties:
421
+ image:
422
+ type: string
423
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
424
+ required:
425
+ - image
426
+
427
+ hidream_o1_smoothing:
428
+ chains: hidream_o1_smoothing
429
+ display_name: "HiDream O1 Smoothing Injector"
430
+ description: "HiDream O1 detail smoothing and artifact reduction injector."
431
+ supported_tasks:
432
+ - txt2img
433
+ - img2img
434
+ - inpaint
435
+ - outpaint
436
+ - hires_fix
437
+ max_count: 1
438
+ usage_guideline: "Configures smoothing factor for HiDream models."
439
+ parameters_schema:
440
+ type: object
441
+ properties:
442
+ factor:
443
+ type: number
444
+ default: 0.5
445
+ description: "Smoothing intensity (0.0 to 1.0)."
446
+ required: []
447
+
448
+ krea2_controlnet:
449
+ chains: krea2_controlnet
450
+ display_name: "KREA2 ControlNet"
451
+ description: "Processed using the facok/comfyui-krea2-controlnet node."
452
+ supported_tasks:
453
+ - txt2img
454
+ - img2img
455
+ - inpaint
456
+ - outpaint
457
+ - hires_fix
458
+ max_count: 5
459
+ usage_guideline: "Supply ControlNet type (e.g., 'Depth'), series (e.g., 'Patil'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
460
+ parameters_schema:
461
+ type: object
462
+ properties:
463
+ type:
464
+ type: string
465
+ enum:
466
+ - "Depth"
467
+ description: "ControlNet conditioning type."
468
+ series:
469
+ type: string
470
+ enum:
471
+ - "Patil"
472
+ default: "Patil"
473
+ description: "ControlNet model series."
474
+ image:
475
+ type: string
476
+ description: "Pre-processed control image (e.g., Depth map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
477
+ strength:
478
+ type: number
479
+ default: 1.0
480
+ minimum: 0.0
481
+ maximum: 2.0
482
+ description: "Control influence strength (0.0 to 2.0)."
483
+ required:
484
+ - type
485
+ - series
486
+ - image
487
+
488
+ anima_controlnet_lllite:
489
+ chains: anima_controlnet_lllite
490
+ display_name: "Anima ControlNet LLLite"
491
+ description: "Anima model-specific lightweight ControlNet."
492
+ supported_tasks:
493
+ - txt2img
494
+ - img2img
495
+ - inpaint
496
+ - outpaint
497
+ - hires_fix
498
+ max_count: 5
499
+ usage_guideline: "Supply Anima ControlNet LLLite type (e.g., 'Depth'), series (e.g., 'kohya-ss'), pre-processed control image (Base64 Data URI or HTTP/HTTPS URL; system does NOT pre-process raw RGB images), and optional strength."
500
+ parameters_schema:
501
+ type: object
502
+ properties:
503
+ type:
504
+ type: string
505
+ description: "Anima ControlNet LLLite conditioning type."
506
+ series:
507
+ type: string
508
+ description: "Anima ControlNet LLLite model series."
509
+ image:
510
+ type: string
511
+ description: "Pre-processed control image (e.g., Depth, Lineart map) encoded as Base64 Data URI or HTTP/HTTPS URL. Note: System does NOT automatically pre-process raw RGB images."
512
+ strength:
513
+ type: number
514
+ default: 1.0
515
+ minimum: 0.0
516
+ maximum: 2.0
517
+ description: "Control influence strength (0.0 to 2.0)."
518
+ required:
519
+ - type
520
+ - series
521
+ - image
522
+
523
+ hidream_o1_reference:
524
+ chains: hidream_o1_reference
525
+ display_name: "HiDream-O1 Reference Edit"
526
+ description: " (HiDream-O1-Image-Dev recommended with resolution set to 4.0MP, e.g., 2048x2048) For HiDream-O1 models, this feature enables reference image editing and combining capabilities. In txt2img mode, adding a single reference image performs an Image Edit, while adding multiple images performs an Image Combine."
527
+ supported_tasks:
528
+ - txt2img
529
+ - img2img
530
+ - inpaint
531
+ - outpaint
532
+ - hires_fix
533
+ max_count: 9
534
+ usage_guideline: "Supply reference image(s) (up to 9) encoded as Base64 Data URI or HTTP/HTTPS URL. Passing a single reference image performs an Image Edit, while passing multiple images performs an Image Combine."
535
+ parameters_schema:
536
+ type: object
537
+ properties:
538
+ image:
539
+ type: string
540
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
541
+ required:
542
+ - image
543
+
544
+ flux1_ipadapter:
545
+ chains: flux1_ipadapter
546
+ display_name: "Flux1 IP-Adapter"
547
+ description: "FLUX.1 model-specific IP-Adapter implementation."
548
+ supported_tasks:
549
+ - txt2img
550
+ - img2img
551
+ - inpaint
552
+ - outpaint
553
+ - hires_fix
554
+ max_count: 5
555
+ usage_guideline: "Supply reference image (Base64 Data URI or HTTP/HTTPS URL), optional weight (default 1.0), start_at (default 0.0), and end_at (default 1.0). Up to 5 images supported."
556
+ parameters_schema:
557
+ type: object
558
+ properties:
559
+ image:
560
+ type: string
561
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
562
+ weight:
563
+ type: number
564
+ default: 1.0
565
+ description: "Influence weight of the image prompt (0.0 to 2.0)."
566
+ start_at:
567
+ type: number
568
+ default: 0.0
569
+ description: "Start step percentage for IP-Adapter application (0.0 to 1.0)."
570
+ end_at:
571
+ type: number
572
+ default: 1.0
573
+ description: "End step percentage for IP-Adapter application (0.0 to 1.0)."
574
+ start_percent:
575
+ type: number
576
+ default: 0.0
577
+ description: "Alias for start_at."
578
+ end_percent:
579
+ type: number
580
+ default: 1.0
581
+ description: "Alias for end_at."
582
+ required:
583
+ - image
584
+
585
+ sd3_ipadapter:
586
+ chains: sd3_ipadapter
587
+ display_name: "SD3 IP-Adapter"
588
+ description: "SD3/SD3.5 model-specific IP-Adapter implementation."
589
+ supported_tasks:
590
+ - txt2img
591
+ - img2img
592
+ - inpaint
593
+ - outpaint
594
+ - hires_fix
595
+ max_count: 5
596
+ usage_guideline: "Supply reference image (Base64 Data URI or HTTP/HTTPS URL), optional weight (default 1.0), start_at (default 0.0), and end_at (default 1.0). Up to 5 images supported."
597
+ parameters_schema:
598
+ type: object
599
+ properties:
600
+ image:
601
+ type: string
602
+ description: "Reference image encoded as Base64 Data URI or HTTP/HTTPS URL."
603
+ weight:
604
+ type: number
605
+ default: 1.0
606
+ description: "Influence weight of the image prompt (0.0 to 2.0)."
607
+ start_at:
608
+ type: number
609
+ default: 0.0
610
+ description: "Start step percentage for IP-Adapter application (0.0 to 1.0)."
611
+ end_at:
612
+ type: number
613
+ default: 1.0
614
+ description: "End step percentage for IP-Adapter application (0.0 to 1.0)."
615
+ start_percent:
616
+ type: number
617
+ default: 0.0
618
+ description: "Alias for start_at."
619
+ end_percent:
620
+ type: number
621
+ default: 1.0
622
+ description: "Alias for end_at."
623
+ required:
624
+ - image
625
+
626
+ embedding:
627
+ chains: embedding
628
+ display_name: "Textual Inversion Embedding Injector"
629
+ description: "Downloads Textual Inversion embedding files from Civitai or Hugging Face to the server. Note: This feature ONLY handles file downloading/preparation. To activate the embedding, manually add 'embedding:<filename>' (e.g. 'embedding:civitai_456' for Civitai ID 456, or 'embedding:filename' for Hugging Face) into your prompt or negative_prompt."
630
+ supported_tasks:
631
+ - txt2img
632
+ - img2img
633
+ - inpaint
634
+ - outpaint
635
+ - hires_fix
636
+ max_count: 5
637
+ usage_guideline: "Specify source ('Civitai' or 'Hugging Face'), and embedding_value (Civitai Version ID or HF repo file path). The file is downloaded to server; manually enter 'embedding:<filename>' in prompt or negative_prompt to activate."
638
+ parameters_schema:
639
+ type: object
640
+ properties:
641
+ source:
642
+ type: string
643
+ enum:
644
+ - "Civitai"
645
+ - "Hugging Face"
646
+ description: "Download source for the Textual Inversion embedding file. Use 'Civitai' to download by Version ID, or 'Hugging Face' to download by repo file path."
647
+ embedding_value:
648
+ type: string
649
+ description: "For Civitai: the Version ID (e.g., '456' from civitai.com/models/123?modelVersionId=456, saved as 'civitai_456.safetensors'). For Hugging Face: repo_id/filename.extension (e.g., 'ilikebigturtles/lazypos/lazypos.safetensors', saved as 'lazypos.safetensors'). Manually reference embedding:<filename> in prompt or negative_prompt."
650
+ required:
651
+ - source
652
+ - embedding_value