Skip to content

feat(mcp): models registry and hash-versioned template cache pipeline#956

Merged
comfyui-wiki merged 9 commits into
mainfrom
feat/models-registry-and-mcp-index
Jun 24, 2026
Merged

feat(mcp): models registry and hash-versioned template cache pipeline#956
comfyui-wiki merged 9 commits into
mainfrom
feat/models-registry-and-mcp-index

Conversation

@comfyui-wiki

Copy link
Copy Markdown
Member

Summary

  • Move MCP index pipeline from scripts/sync/sync_mcp_index.py into scripts/mcp/ with a two-step workflow: deterministic sync (sync_index.py) then optional AI enhancement (enhance_models_registry.py, enhance_descriptions.py).
  • Add scripts/data/mcp/models_registry.json for model profiles (summary, strengths, capabilities) and scripts/data/mcp/template_cache.json for per-template AI copy versioned by workflow JSON source_hash.
  • Introduce shared OpenAI-compatible AI client (scripts/lib/ai/) and .env.example for local configuration; refresh templates/index.mcp.json with compact io format and cache merge on sync.

Architecture

Layer File Purpose
Models models_registry.json Model profiles for AI context
Templates template_cache.json description + io, keyed by workflow hash
Output index.mcp.json MCP-readable template index

Notes / follow-ups

  • template_cache.json currently seeds from existing index.mcp.json (PR feat: add index.mcp.json - MCP-readable template index with descriptions #932 copy); most entries are legacy, not freshly AI-generated. Plan to regenerate incrementally via enhance_descriptions.py.
  • Krea snapshot files and maintenance scripts included for one-off registry seeding; can be removed after seeding is complete.
  • Draft — feedback welcome on cache seeding strategy and whether to trim legacy template cache entries before merge.

Test plan

  • python3 scripts/mcp/sync_index.py --check
  • python3 scripts/mcp/enhance_descriptions.py --check
  • python3 scripts/mcp/enhance_models_registry.py --check
  • Verify index.mcp.json diff looks correct for MCP consumers

Replace JSON \b escape sequences that parsed as backspace with correct v2/v3 labels across all locale index files.
…line

Isolate MCP index tooling under scripts/mcp/ with deterministic sync,
AI enhancement scripts, and dedicated data files for model profiles
and template copy keyed by workflow JSON source hash.
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR replaces scripts/sync/sync_mcp_index.py with a full multi-step MCP index pipeline under scripts/mcp/, including deterministic sync, AI-driven template description and model-registry enrichment, SHA-256 hash-versioned template caching, ComfyUI API node scanning, shared Python libraries (ai/, env, json_format, paths), Krea model registry maintenance tools, seeded data files, environment config, and comprehensive documentation. Separately, embedded \b escape characters are removed from Depth Anything model name strings across all locale index files, and a GLB mime type is corrected.

Changes

MCP Index Pipeline

Layer / File(s) Summary
Shared AI/env/path/JSON libraries
scripts/lib/env.py, scripts/lib/ai/__init__.py, scripts/lib/ai/config.py, scripts/lib/ai/client.py, scripts/lib/json_format.py, scripts/lib/paths.py
Adds .env loader, frozen AISettings dataclass with load_ai_settings(), stdlib-only OpenAI-compatible chat completion client (chat_completion, chat_json_completion, parse_json_response), compact-array JSON formatter, and MCP data path constants (MCP_DATA_DIR, MODELS_REGISTRY_FILE, TEMPLATE_CACHE_FILE, etc.) with MODELS_CAPABILITIES_FILE deprecated as alias.
MCP lib helpers: scoring, cache, overrides, API node scanning, ComfyUI paths
scripts/mcp/lib/freshness_score.py, scripts/mcp/lib/recommend_score.py, scripts/mcp/lib/template_overrides.py, scripts/mcp/lib/template_cache.py, scripts/mcp/lib/comfyui_paths.py, scripts/mcp/lib/scan_api_node_models.py
Adds date→freshness label conversion, usage→recommend tier scoring, override load/save/resolve with category floors, SHA-256 hash-versioned template cache (load/save/overlay/stale detection/seeding/migration), ComfyUI checkout path resolution, and static AST+regex scanning of nodes_*.py files to extract API node model dropdown options.
MCP lib AI context helpers
scripts/mcp/lib/ai_context.py
Adds shared data loaders for index/MCP/registry JSON, registry profile lookup with alias and case-insensitive fallback, per-model template usage aggregation, registry staleness checks, and is_auto_description heuristic.
Bootstrap, data files, and .env config
scripts/mcp/bootstrap.py, scripts/data/mcp/*, scripts/data/krea_video_models.json, .env.example, .gitignore
Adds install_paths() bootstrap for sys.path wiring; seeds models_registry.json (757 lines), api_node_model_options.json (89 nodes), registry_aliases.json, example cache/override files, template_overrides.json; adds Krea video model snapshot; populates .env.example with COMFYUI_REPO_PATH and AI provider presets.
sync_index.py: deterministic MCP index sync
scripts/mcp/sync_index.py, scripts/sync/sync_mcp_index.py (deleted)
Replaces the old sync script with a 840-line deterministic pipeline: category/tag mapping, IO normalization, freshness/recommend resolution, API node model-options refresh, per-template entry building with cache overlay, --check dry-run, and log output to scripts/.output/sync_index.log.
scan_api_nodes.py CLI
scripts/mcp/scan_api_nodes.py
CLI entry point that scans the ComfyUI comfy_api_nodes/ directory, writes api_node_model_options.json, or prints per-workflow model options in --workflow mode.
import_template_cache.py and apply_template_cache.py
scripts/mcp/import_template_cache.py, scripts/mcp/apply_template_cache.py
Seeds template_cache.json from index.mcp.json with workflow hashes (import), and overlays cached description/io back onto index.mcp.json when hashes match (apply), both supporting --check mode.
enhance_descriptions.py: AI template description generation
scripts/mcp/enhance_descriptions.py
Step 2b: selects stale/targeted templates, builds category-aware prompts with model registry context (special handling for "Use Cases"), calls AI per template, stores results in template_cache.json, and writes index.mcp.json after each success.
enhance_models_registry.py: AI model registry enrichment
scripts/mcp/enhance_models_registry.py
Step 2a: selects registry entries needing update, builds structured prompts with profile and usage examples, calls chat_json_completion, normalizes AI response into summary/strengths/capabilities, and writes models_registry.json.
Krea registry maintenance
scripts/maintenance/krea_registry_sync.py, scripts/maintenance/sync_registry_from_krea.py, scripts/data/krea_video_models.json
One-off tooling to merge scraped Krea image/video model metadata into models_registry.json via alias/fuzzy key resolution, tier ranking, and deduped strength rebuilding.
npm scripts, READMEs, AGENTS.md, CLAUDE.md, SKILL.md
package.json, scripts/README.md, scripts/mcp/README.md, scripts/mcp/docs/MCP_AI_ENHANCEMENT.md, scripts/data/mcp/README.md, AGENTS.md, CLAUDE.md, .claude/skills/managing-mcp-index/SKILL.md
Adds i18n, mcp, mcp:check, mcp:ai, mcp:models npm scripts; updates all developer docs to reflect the new scripts/mcp/ directory, path migrations, environment variables, and agent skill reference.

Template Data Fixes

Layer / File(s) Summary
Depth Anything model name and mime_type fixes
templates/index.json, templates/index.*.json (11 locales), workflow_template_input_files.json
Removes embedded \b backspace escape from Depth Anything v2/v3 model name strings in the primary and all locale index files; corrects input/toy.glb mime_type from application/octet-stream to model/gltf-binary.

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant sync_index.py
  participant enhance_models_registry.py
  participant enhance_descriptions.py
  participant AI_Endpoint
  participant index.mcp.json

  Developer->>sync_index.py: npm run mcp (or --check)
  sync_index.py->>sync_index.py: load index.json, template_cache, overrides, models_registry
  sync_index.py->>sync_index.py: scan ComfyUI API nodes → api_node_model_options.json
  sync_index.py->>index.mcp.json: write deterministic output

  Developer->>enhance_models_registry.py: npm run mcp:models
  enhance_models_registry.py->>AI_Endpoint: chat_json_completion (model profile prompt)
  AI_Endpoint-->>enhance_models_registry.py: {summary, strengths, capabilities}
  enhance_models_registry.py->>enhance_models_registry.py: write models_registry.json

  Developer->>enhance_descriptions.py: npm run mcp:ai
  enhance_descriptions.py->>AI_Endpoint: chat_completion (template description prompt)
  AI_Endpoint-->>enhance_descriptions.py: description text
  enhance_descriptions.py->>enhance_descriptions.py: update template_cache.json (source_hash keyed)
  enhance_descriptions.py->>index.mcp.json: apply cache overlay and write
Loading

Possibly Related PRs

  • Comfy-Org/workflow_templates#955: Modifies the same scripts/lib/paths.py module that this PR extends with MCP_DATA_DIR and all MCP file path constants — the two changes are directly complementary in that shared file. (A path well traveled, it seems — pun intended!)
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/models-registry-and-mcp-index
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/models-registry-and-mcp-index

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

🔤 Spellcheck Results

Check Status
templates/index.json (titles & descriptions) ✅ No issues found
Workflow JSON notes (MarkdownNote / Note nodes) ✅ No issues found

All spellchecks passed! 🎉

@github-actions

Copy link
Copy Markdown
Contributor

recheck

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

recheck

@github-actions

Copy link
Copy Markdown
Contributor

Upload JSON updated - 596 assets

Introduce template_overrides.json for persistent recommend/freshness pins,
enforce Use Cases minimum recommend of low, and refresh index.mcp.json with
three new templates plus AI-enhanced descriptions in template_cache.
@github-actions

Copy link
Copy Markdown
Contributor

recheck

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

recheck

Add new npm commands for MCP index synchronization and AI enhancements, including `mcp`, `mcp:check`, `mcp:ai`, and `mcp:models`. Update documentation in AGENTS.md, CLAUDE.md, and scripts/README.md to reflect these changes and clarify the MCP index pipeline. Introduce template overrides in template_overrides.json for improved recommendations.
Add Boogu and HappyHorse 1.1 registry entries, introduce registry_aliases.json
with lookup_registry_profile for AI description generation, and normalize
strengths tier labels from Krea-specific to generic Type labels.
@github-actions

Copy link
Copy Markdown
Contributor

recheck

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

recheck

Refactor the enhance_descriptions.py and enhance_models_registry.py scripts to ensure that successful enhancements are immediately written to their respective cache files. This change allows for progress retention during interrupted runs and clarifies the output messages upon completion.
Delete krea_image_models.json and krea_registry_aliases.json as they are no longer needed. Update template descriptions in template_cache.json and index.mcp.json for improved clarity and accuracy, ensuring they align with the latest model capabilities and workflows.
@github-actions

Copy link
Copy Markdown
Contributor

recheck

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

recheck

@comfyui-wiki comfyui-wiki marked this pull request as ready for review June 24, 2026 16:41

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 24

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLAUDE.md`:
- Around line 32-33: Update the stale MCP data-file examples in CLAUDE.md so
they match the current MCP flow: replace references to models_capabilities.json
with models_registry.json, and make sure the surrounding data/ and MCP
documentation examples stay consistent with the files used by the relevant MCP
modules and cache flow. Check the sections around the data directory listing and
the later MCP examples so the filenames align with the current registry naming.

In `@scripts/data/krea_video_models.json`:
- Around line 1-433: This is generated scrape output and should not live under
scripts/data/. Move the krea_video_models snapshot (including scrapedAt and
triggerElement metadata) to scripts/.output/ or a repo-root report location, and
keep scripts/data/ reserved for stable hand-maintained config only. Update
whichever generation/export step produces this artifact so the saved path
matches the repo’s generated-output convention, using the krea_video_models.json
artifact as the target to relocate.

In `@scripts/data/mcp/api_node_model_options.json`:
- Around line 1-629: This scan cache JSON should not live under scripts/data/mcp
because it is regenerated from a local ComfyUI checkout and causes cross-machine
churn. Move the generated output path used by the sync/scan code so the live
cache is written to scripts/.output/ instead, and keep only a checked-in example
fixture if needed. Update the code that produces api_node_model_options.json and
any references to this artifact so they point to the new generated location,
using the existing scan/sync entrypoints that populate the MCP node model
options cache.

In `@scripts/data/mcp/models_registry.json`:
- Around line 92-100: Collapse the case-variant duplicate entries in the MCP
registry so each model name has only one canonical key. In the registry JSON,
deduplicate the repeated pairs like Kling O1/Kling o1, Kling O3/Kling o3, and
None/none by keeping a single normalized entry and merging the correct summary,
strengths, and capabilities into it. Update the affected registry objects in the
same model groups so the lookup layer’s case-insensitive fallback cannot resolve
to ambiguous or conflicting profiles.

In `@scripts/data/mcp/README.md`:
- Line 17: The docs link in README.md points to the wrong relative location,
resolving under scripts/data/mcp/docs instead of the intended scripts/mcp/docs.
Update the markdown link target in the README so it correctly references the
MCP_AI_ENHANCEMENT.md document from the current file’s location, using the
existing README link text and adjusting only the relative path.

In `@scripts/lib/ai/client.py`:
- Around line 51-67: The type annotations in parse_json_response and
chat_json_completion use Any, but it is not imported in this module, causing
Ruff F821. Update the imports in client.py to bring Any in from typing so both
function signatures resolve cleanly.
- Around line 38-43: Wrap all non-HTTP request failures in the AI client so
callers can handle them consistently. Update the request path in the client
function that uses urllib.request.urlopen and json.load to catch
URLError/timeout-style exceptions alongside HTTPError, and re-raise them as
RuntimeError with a clear message. Make sure
scripts/mcp/enhance_models_registry.py can rely on this behavior so a single
flaky model request is skipped and the batch continues.

In `@scripts/maintenance/krea_registry_sync.py`:
- Around line 30-36: The Krea registry sync currently hard-indexes required
fields in the loop, so a single malformed category or model can crash the whole
run. Update the record handling in krea_registry_sync.py around the data
iteration to safely skip entries missing category["name"] or model["name"],
while keeping the rest of the sync processing intact. Use the existing data loop
that builds entries to add the guard/validation before accessing those keys.

In `@scripts/maintenance/sync_registry_from_krea.py`:
- Around line 41-43: The registry merge in sync_registry_from_krea currently
assumes both REGISTRY_FILE and ALIASES_FILE contain object-shaped JSON, so add
early top-level type validation immediately after json.loads in
sync_registry_from_krea. Check that registry is a dict and aliases is a dict
before continuing, and raise a clear failure if either file contains a
list/string or any non-object value; keep the rest of the merge logic unchanged.

In `@scripts/mcp/bootstrap.py`:
- Around line 1-17: The shared bootstrap helper currently lives alongside MCP
CLI entrypoints, but it should be moved into scripts/lib/ as an import-only
module. Relocate install_paths() and the module-level path constants from
bootstrap.py into a shared library module under scripts/lib/, then update any
MCP scripts that import install_paths() to use the new location while keeping
the function behavior unchanged.

In `@scripts/mcp/docs/MCP_AI_ENHANCEMENT.md`:
- Around line 243-250: The table in MCP_AI_ENHANCEMENT.md has a duplicated entry
for scripts/data/mcp/models_registry.json with conflicting descriptions; remove
the redundant row or merge the two descriptions into one authoritative entry.
Update the table around the models registry references so only one
scripts/data/mcp/models_registry.json line remains, and make sure the
surrounding script entries in the MCP documentation section still clearly map
each script to its role.

In `@scripts/mcp/enhance_descriptions.py`:
- Around line 172-178: The `enhance_descriptions.py` startup path loads
`REGISTRY_FILE` without checking it exists first, so a missing
`models_registry.json` can crash instead of exiting cleanly. Add the same
prerequisite guard used in `enhance_models_registry.py` before the
`load_json(REGISTRY_FILE)` call in the main flow, and return a normal CLI error
when the file is absent; use the existing `MCP_FILE`, `REGISTRY_FILE`, and
`load_json` flow to place the check correctly.

In `@scripts/mcp/enhance_models_registry.py`:
- Around line 86-106: The normalize_profile function is treating
raw["strengths"] and raw["capabilities"] as iterable without validating they are
arrays first, which can cause strings or objects to be normalized into nonsense
before persistence. Update normalize_profile to explicitly verify both fields
are lists/arrays before building the strengths and capabilities lists, and raise
a ValueError when either field is the wrong type. Keep the fix localized to
normalize_profile and preserve the existing summary validation and output shape.

In `@scripts/mcp/import_template_cache.py`:
- Around line 40-49: The dry-run summary in import_templates_from_mcp is
under-counting work because it only compares template keys, so refreshed entries
with changed source_hash are missed. Update the counting logic in
import_template_cache.py to compare full template records before and after
migrate_legacy_cache(import_templates_from_mcp(...)) rather than just set
differences on templates keys. Use the existing cache/template structures in the
main import flow so the “Would add/update” total and the printed sample names
include both newly added and refreshed entries.

In `@scripts/mcp/lib/ai_context.py`:
- Around line 86-111: The model usage aggregation in model_template_usage
currently groups templates by the raw template model string, which can miss
registry lookups that expect canonical model keys. Normalize or canonicalize the
model name before adding entries to usage so aliases resolve to the same
registry key, and keep the existing sorting/truncation behavior intact in
model_template_usage and the downstream usage.get(name, []) consumer in
enhance_models_registry.py.

In `@scripts/mcp/lib/template_cache.py`:
- Around line 41-50: The load_template_cache function currently trusts
cache["templates"] after loading, but callers expect it to be a mapping and will
break if the JSON contains a non-dict value. Update load_template_cache to
validate the templates field during load, normalizing any non-dict value back to
an empty mapping before returning, alongside the existing schema_version and
legacy models cleanup. Keep the fix scoped to load_template_cache and the cache
shape it returns so downstream .get(name) lookups remain safe.
- Around line 141-147: The cache seeding logic in template_cache.py is only
persisting entries when description exists, which drops templates that have io
but no description. Update the entry filter in the seeding path so that
cache["templates"][name] is written whenever either description or io is
present, using the existing entry assembly around tpl, entry, and
cache["templates"].

In `@scripts/mcp/lib/template_overrides.py`:
- Around line 42-50: `load_template_overrides` currently only validates the root
JSON object, but `templates` can still be a non-mapping and later break
`sync_index.py` when it calls `.get()` on it. Update `load_template_overrides`
in `template_overrides.py` to validate or normalize the `templates` entry before
returning, alongside the existing `schema_version` and `empty_overrides()`
handling, so `templates` is always a dict (or the function falls back to safe
defaults) regardless of the override file contents.

In `@scripts/mcp/README.md`:
- Around line 9-23: The fenced code block in the README is missing a language
tag, which triggers markdownlint MD040. Update the opening fence in the section
that lists scripts/mcp and scripts/lib/ai to use a specific lexer such as text,
keeping the content unchanged and ensuring the fenced block is consistently
formatted.

In `@scripts/mcp/scan_api_nodes.py`:
- Around line 70-75: The emitted payload in scan_api_nodes.py currently includes
the absolute api_nodes_dir value under source, which leaks workstation-specific
paths into the shared JSON. Update the payload construction in the
scan/serialization flow to remove that absolute source field or replace it with
a stable non-local identifier, while keeping node_count and nodes intact, so
OUTPUT_FILE.write_text only writes portable data.

In `@scripts/mcp/sync_index.py`:
- Around line 537-544: The payload built in sync_index.py is writing the
caller’s absolute ComfyUI path into the shared cache via source in the JSON.
Update the payload construction in the sync logic that writes
API_NODE_OPTIONS_FILE so it does not serialize str(api_nodes_dir); use a stable,
non-local identifier or omit the field entirely if it is only used for
provenance, and keep the rest of the index generation unchanged.
- Around line 316-350: `infer_task_type()` is only deriving the task type from
the workflow name, so tagged workflows like Image to Image or Image to Video can
be misclassified when the filename lacks a matching token. Update
`infer_task_type` in `sync_index.py` to also consult template metadata/tags (as
`infer_task()` already does) before falling back to filename heuristics, and
ensure the task type written into `index.mcp.json` reflects the tag-based
contract for `infer_task`, `infer_task_type`, and the downstream `io` mapping.
- Around line 368-389: The _normalize_io_side function is coercing untrusted
slot["count"] values with int(slot.get("count", 1)), which can abort sync on
null, empty, or invalid text. Update _normalize_io_side to validate and safely
coerce count before using _encode_slot, skipping or defaulting bad entries
instead of raising, and apply the same defensive handling in the other io.count
normalization path referenced by the review.

In `@scripts/README.md`:
- Line 85: The README entry for Krea alias snapshots points to the wrong alias
file path, so update the documentation in the script guide to reference the MCP
alias location used by this rollout. In the affected markdown list item, replace
the `data/krea_registry_aliases.json` reference with
`data/mcp/registry_aliases.json` while keeping the rest of the Krea snapshot
note aligned with the existing seeding docs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 42593f21-ad16-41db-924d-50200291d0df

📥 Commits

Reviewing files that changed from the base of the PR and between cf4932e and 400a8ec.

📒 Files selected for processing (57)
  • .claude/skills/managing-mcp-index/SKILL.md
  • .env.example
  • .gitignore
  • AGENTS.md
  • CLAUDE.md
  • package.json
  • scripts/README.md
  • scripts/data/krea_video_models.json
  • scripts/data/mcp/README.md
  • scripts/data/mcp/api_node_model_options.json
  • scripts/data/mcp/models_registry.json
  • scripts/data/mcp/registry_aliases.json
  • scripts/data/mcp/template_cache.example.json
  • scripts/data/mcp/template_cache.json
  • scripts/data/mcp/template_overrides.example.json
  • scripts/data/mcp/template_overrides.json
  • scripts/lib/ai/__init__.py
  • scripts/lib/ai/client.py
  • scripts/lib/ai/config.py
  • scripts/lib/env.py
  • scripts/lib/json_format.py
  • scripts/lib/paths.py
  • scripts/maintenance/krea_registry_sync.py
  • scripts/maintenance/sync_registry_from_krea.py
  • scripts/mcp/README.md
  • scripts/mcp/__init__.py
  • scripts/mcp/apply_template_cache.py
  • scripts/mcp/bootstrap.py
  • scripts/mcp/docs/MCP_AI_ENHANCEMENT.md
  • scripts/mcp/enhance_descriptions.py
  • scripts/mcp/enhance_models_registry.py
  • scripts/mcp/import_template_cache.py
  • scripts/mcp/lib/__init__.py
  • scripts/mcp/lib/ai_context.py
  • scripts/mcp/lib/comfyui_paths.py
  • scripts/mcp/lib/freshness_score.py
  • scripts/mcp/lib/recommend_score.py
  • scripts/mcp/lib/scan_api_node_models.py
  • scripts/mcp/lib/template_cache.py
  • scripts/mcp/lib/template_overrides.py
  • scripts/mcp/scan_api_nodes.py
  • scripts/mcp/sync_index.py
  • scripts/sync/sync_mcp_index.py
  • templates/index.ar.json
  • templates/index.es.json
  • templates/index.fa.json
  • templates/index.fr.json
  • templates/index.ja.json
  • templates/index.json
  • templates/index.ko.json
  • templates/index.mcp.json
  • templates/index.pt-BR.json
  • templates/index.ru.json
  • templates/index.tr.json
  • templates/index.zh-TW.json
  • templates/index.zh.json
  • workflow_template_input_files.json
💤 Files with no reviewable changes (2)
  • scripts/sync/sync_mcp_index.py
  • .gitignore

Comment thread CLAUDE.md
Comment on lines 32 to +33
│ ├── data/ # i18n.json, whitelist.json, models_capabilities.json
│ ├── lib/ # Shared modules (locale_index_files, paths)
│ ├── lib/ # Shared modules (paths, locale_index_files, ai/)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update stale MCP data-file examples (old name sneaks in, like a ghost in the host).

Line 32 and Line 99 still reference models_capabilities.json, but this PR’s MCP flow documents/uses data/mcp/models_registry.json (+ cache files). Keeping the old filename here can misroute maintenance work.

Suggested doc fix
-| `scripts/data/`               # i18n.json, whitelist.json, models_capabilities.json
+| `scripts/data/`               # i18n.json, whitelist.json, mcp/models_registry.json, mcp/template_cache.json
...
-| `scripts/data/` | Static config JSON | `i18n.json`, `whitelist.json`, `models_capabilities.json` |
+| `scripts/data/` | Static config JSON | `i18n.json`, `whitelist.json`, `mcp/models_registry.json`, `mcp/template_cache.json` |

Also applies to: 99-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` around lines 32 - 33, Update the stale MCP data-file examples in
CLAUDE.md so they match the current MCP flow: replace references to
models_capabilities.json with models_registry.json, and make sure the
surrounding data/ and MCP documentation examples stay consistent with the files
used by the relevant MCP modules and cache flow. Check the sections around the
data directory listing and the later MCP examples so the filenames align with
the current registry naming.

Comment on lines +1 to +433
{
"source": "https://www.krea.ai/video",
"scrapedAt": "2026-06-22T11:31:26.393Z",
"triggerElement": {
"note": "ID is dynamically generated by bits-ui; at scrape time it was bits-c15 (user reported bits-c13)",
"selector": "[data-dropdown-menu-trigger]",
"action": "click opens model gallery dialog"
},
"totalCategories": 4,
"totalModels": 41,
"categories": [
{
"name": "Fast Models",
"description": "Affordable models for fast creative exploration.",
"models": [
{
"name": "Krea Realtime",
"slug": "krea_rtv_14b",
"description": "Real-time video generation model. Instant results at very low cost and quality.",
"capabilities": [],
"credits": 10
},
{
"name": "Hailuo 2.3 Fast",
"slug": "minimax_hailuo23_fast",
"description": "Cheapest medium-quality model. Best for most use cases.",
"capabilities": [
"Start frame"
],
"credits": 150
},
{
"name": "LTX-2.3 22B",
"slug": "ltx-23-22b",
"description": "High-quality Lightricks video generation model with native audio and start and end frame support.",
"capabilities": [
"Start frame",
"End frame",
"Lora"
],
"credits": 150
},
{
"name": "Seedance 2.0 Fast",
"slug": "seedance-2-fast",
"description": "Faster ByteDance Seedance 2 variant with cinematic motion, optional synchronized audio, tagged image/video/audio references, and support for animating between start and end frames.",
"capabilities": [
"Start frame",
"End frame",
"References"
],
"credits": 900
},
{
"name": "Veo 3.1 Lite",
"slug": "veo31-lite",
"description": "Faster and more affordable version of the powerful Veo 3.1 model.",
"capabilities": [
"Start frame"
],
"credits": 200
},
{
"name": "Grok Imagine",
"slug": "grok",
"description": "Fast, high-quality video generation by xAI.",
"capabilities": [
"Start frame",
"References"
],
"credits": 300
},
{
"name": "LTX-2",
"slug": "ltx-2-19b",
"description": "Affordable medium-quality audio-video model from Lightricks with native sound generation.",
"capabilities": [
"Start frame"
],
"credits": 35
},
{
"name": "Seedance Pro Fast",
"slug": "seedance-1-0-pro-fast",
"description": "Fast and cheap model. Up to 12 seconds.",
"capabilities": [
"Start frame"
],
"credits": 85
},
{
"name": "Veo 3.1 Fast",
"slug": "veo31-fast",
"description": "Faster and more affordable version of the powerful Veo 3.1 model with audio.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 450
}
]
},
{
"name": "Intelligent Models",
"description": "Frontier models that think deeply to visualize complex ideas.",
"models": [
{
"name": "Kling 3.0",
"slug": "kling_30",
"description": "Latest frontier model from Kling with native audio and extended durations up to 15 seconds.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 600
},
{
"name": "Runway Gen-4.5",
"slug": "runwaygen45",
"description": "Latest frontier model from Runway with native text-to-video.",
"capabilities": [
"Start frame"
],
"credits": 450
},
{
"name": "Seedance 2.0",
"slug": "seedance-2",
"description": "ByteDance frontier video model with cinematic motion, optional synchronized audio, tagged image/video/audio references, and support for animating between start and end frames.",
"capabilities": [
"Start frame",
"End frame",
"References"
],
"credits": 1100
},
{
"name": "HappyHorse",
"slug": "happy-horse",
"description": "HappyHorse generates synchronized audio-video clips from text, image references, or a source video edit instruction.",
"capabilities": [
"Start frame",
"References"
],
"credits": 500
},
{
"name": "Kling o3",
"slug": "kling_o3",
"description": "Advanced reasoning video model (720p). Supports image, element, and video references for precise creative control.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 300
},
{
"name": "Kling o3 Pro",
"slug": "kling_o3_pro",
"description": "Advanced reasoning video model (1080p). Supports image, element, and video references for precise creative control.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 400
},
{
"name": "Veo 3.1",
"slug": "veo31",
"description": "Best video model. Highest-quality frontier model with audio and reference images.",
"capabilities": [
"Start frame",
"End frame",
"References"
],
"credits": 1200
},
{
"name": "Veo 3",
"slug": "veo3",
"description": "Older version of the highest-quality frontier model Veo 3.1.",
"capabilities": [
"Start frame"
],
"credits": 1200
},
{
"name": "Veo 3 Fast",
"slug": "veo3-fast",
"description": "Older, faster and more affordable version of the leading Veo 3 model with audio.",
"capabilities": [
"Start frame"
],
"credits": 600
}
]
},
{
"name": "Quality Models",
"description": "Explore a wide range of affordable models from around the world.",
"models": [
{
"name": "Hailuo 2.3",
"slug": "minimax_hailuo23",
"description": "Frontier model with dynamic motion.",
"capabilities": [
"Start frame"
],
"credits": 200
},
{
"name": "Seedance 1.5 Pro",
"slug": "seedance-1-5-pro",
"description": "Latest medium quality model from ByteDance with audio generation and end frame support.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 300
},
{
"name": "Kling o1",
"slug": "kling_omni",
"description": "Intelligent video model that thinks before generating. Supports image, element, and video references for precise creative control.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 400
},
{
"name": "Wan 2.6",
"slug": "wan26",
"description": "Medium-quality model from Alibaba with improved quality and multi-shot support.",
"capabilities": [
"Start frame"
],
"credits": 350
},
{
"name": "Wan 2.5",
"slug": "wan25",
"description": "Latest medium quality model from Alibaba.",
"capabilities": [
"Start frame"
],
"credits": 350
},
{
"name": "Kling 2.6",
"slug": "kling_26",
"description": "Frontier model from Kling with native audio. Highest quality at a moderate price point.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 250
},
{
"name": "Kling 2.5",
"slug": "kling_25",
"description": "Next-gen model with improved dynamics and enhanced style adaptation from Kling.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 250
},
{
"name": "Kling 2.5 Turbo",
"slug": "kling_25_turbo",
"description": "Top-tier text-to-video generation with unparalleled motion fluidity and cinematic visuals.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 250
},
{
"name": "Vidu Q2",
"slug": "vidu_q2",
"description": "High-quality model with reference images support.",
"capabilities": [
"Start frame",
"References"
],
"credits": 200
},
{
"name": "Vidu Q3",
"slug": "vidu_q3",
"description": "New model excelling at anime.",
"capabilities": [
"Start frame"
],
"credits": 550
},
{
"name": "Hailuo 02",
"slug": "minimax_hailuo02",
"description": "Frontier model with dynamic motion.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 200
},
{
"name": "Seedance Pro",
"slug": "seedance-1-0-pro",
"description": "Fast, high-quality model from ByteDance.",
"capabilities": [
"Start frame",
"End frame",
"References"
],
"credits": 200
}
]
},
{
"name": "Legacy Models",
"description": "Blasts from the past. Try out older models from various providers.",
"models": [
{
"name": "Wan 2.1",
"slug": "wan",
"description": "Fastest low-quality model with video Lora support.",
"capabilities": [
"Start frame",
"End frame",
"Lora"
],
"credits": 250
},
{
"name": "Wan 2.2",
"slug": "wan22",
"description": "Fast, lower-quality model from Alibaba.",
"capabilities": [
"Start frame"
],
"credits": 300
},
{
"name": "Kling 2.1",
"slug": "kling_21",
"description": "Frontier model with 1080p resolution.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": 200
},
{
"name": "Runway Gen-4",
"slug": "runwaygen4",
"description": "Medium quality model with a focus on cinematic visuals but weaker structure and motion.",
"capabilities": [
"Start frame"
],
"credits": 200
},
{
"name": "Runway Gen-3",
"slug": "runway",
"description": "Old generation cinematic model with higher consistency.",
"capabilities": [
"Start frame"
],
"credits": 200
},
{
"name": "Kling 1.6",
"slug": "kling_16",
"description": "Previous generation high-quality model for complex scenes.",
"capabilities": [
"Start frame"
],
"credits": 150
},
{
"name": "Kling 2.0",
"slug": "kling_2",
"description": "High-quality model with great aesthetics.",
"capabilities": [
"Start frame"
],
"credits": 1000
},
{
"name": "Hailuo",
"slug": "minimax",
"description": "High-quality model with camera control.",
"capabilities": [
"Start frame",
"Camera",
"Character"
],
"credits": 300
},
{
"name": "01-Live",
"slug": "minimax_live",
"description": "High-quality model for animating people.",
"capabilities": [
"Start frame"
],
"credits": 300
},
{
"name": "Ray 2",
"slug": "ray2",
"description": "Older medium model with natural motion from Luma Labs.",
"capabilities": [
"Start frame"
],
"credits": 300
},
{
"name": "Kling 1.0 (Pro)",
"slug": "klingPro",
"description": "Slow model with high control and 10s duration.",
"capabilities": [
"Start frame",
"End frame"
],
"credits": null
}
]
}
]
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Do not commit generated scrape output under scripts/data/.

This file is generated snapshot data (e.g., scrapedAt, DOM trigger metadata) and violates the scripts/data/*.json rule. Please move generated artifacts to scripts/.output/ (or a repo-root report path) and keep only stable hand-maintained config in scripts/data/.

As per coding guidelines: “Generated JSON must not be committed under scripts/data/; generated output should go to scripts/.output/ or repo-root reports.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/data/krea_video_models.json` around lines 1 - 433, This is generated
scrape output and should not live under scripts/data/. Move the
krea_video_models snapshot (including scrapedAt and triggerElement metadata) to
scripts/.output/ or a repo-root report location, and keep scripts/data/ reserved
for stable hand-maintained config only. Update whichever generation/export step
produces this artifact so the saved path matches the repo’s generated-output
convention, using the krea_video_models.json artifact as the target to relocate.

Source: Coding guidelines

Comment on lines +1 to +629
{
"source": "/Users/linmoumou/Documents/Github/ComfyUI/comfy_api_nodes",
"node_count": 89,
"nodes": {
"Flux2ImageNode": {
"node_id": "Flux2ImageNode",
"class_name": "Flux2ImageNode",
"display_name": "Flux.2 Image",
"model_options": ["Flux.2 [pro]", "Flux.2 [max]"],
"source_file": "nodes_bfl.py"
},
"BriaImageEditNode": {
"node_id": "BriaImageEditNode",
"class_name": "BriaImageEditNode",
"display_name": "Bria FIBO Image Edit",
"model_options": ["FIBO"],
"source_file": "nodes_bria.py"
},
"ByteDanceImageNode": {
"node_id": "ByteDanceImageNode",
"class_name": "ByteDanceImageNode",
"display_name": "ByteDance Image",
"model_options": ["seedream-3-0-t2i-250415"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceSeedreamNode": {
"node_id": "ByteDanceSeedreamNode",
"class_name": "ByteDanceSeedreamNode",
"display_name": "ByteDance Seedream 4.5 & 5.0",
"model_options": ["seedream 5.0 lite", "seedream-4-5-251128", "seedream-4-0-250828"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceSeedreamNodeV2": {
"node_id": "ByteDanceSeedreamNodeV2",
"class_name": "ByteDanceSeedreamNodeV2",
"display_name": "ByteDance Seedream 4.5 & 5.0",
"model_options": ["seedream 5.0 lite", "seedream-4-5-251128", "seedream-4-0-250828"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceTextToVideoNode": {
"node_id": "ByteDanceTextToVideoNode",
"class_name": "ByteDanceTextToVideoNode",
"display_name": "ByteDance Text to Video",
"model_options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-t2v-250428", "seedance-1-0-pro-fast-251015"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceImageToVideoNode": {
"node_id": "ByteDanceImageToVideoNode",
"class_name": "ByteDanceImageToVideoNode",
"display_name": "ByteDance Image to Video",
"model_options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428", "seedance-1-0-pro-fast-251015"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceFirstLastFrameNode": {
"node_id": "ByteDanceFirstLastFrameNode",
"class_name": "ByteDanceFirstLastFrameNode",
"display_name": "ByteDance First-Last-Frame to Video",
"model_options": ["seedance-1-5-pro-251215", "seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"],
"source_file": "nodes_bytedance.py"
},
"ByteDanceImageReferenceNode": {
"node_id": "ByteDanceImageReferenceNode",
"class_name": "ByteDanceImageReferenceNode",
"display_name": "ByteDance Reference Images to Video",
"model_options": ["seedance-1-0-pro-250528", "seedance-1-0-lite-i2v-250428"],
"source_file": "nodes_bytedance.py"
},
"ByteDance2TextToVideoNode": {
"node_id": "ByteDance2TextToVideoNode",
"class_name": "ByteDance2TextToVideoNode",
"display_name": "ByteDance Seedance 2.0 Text to Video",
"model_options": ["Seedance 2.0", "Seedance 2.0 Fast"],
"source_file": "nodes_bytedance.py"
},
"ByteDance2FirstLastFrameNode": {
"node_id": "ByteDance2FirstLastFrameNode",
"class_name": "ByteDance2FirstLastFrameNode",
"display_name": "ByteDance Seedance 2.0 First-Last-Frame to Video",
"model_options": ["Seedance 2.0", "Seedance 2.0 Fast"],
"source_file": "nodes_bytedance.py"
},
"ByteDance2ReferenceNode": {
"node_id": "ByteDance2ReferenceNode",
"class_name": "ByteDance2ReferenceNode",
"display_name": "ByteDance Seedance 2.0 Reference to Video",
"model_options": ["Seedance 2.0", "Seedance 2.0 Fast"],
"source_file": "nodes_bytedance.py"
},
"ElevenLabsSpeechToText": {
"node_id": "ElevenLabsSpeechToText",
"class_name": "ElevenLabsSpeechToText",
"display_name": "ElevenLabs Speech to Text",
"model_options": ["scribe_v2"],
"source_file": "nodes_elevenlabs.py"
},
"ElevenLabsTextToSpeech": {
"node_id": "ElevenLabsTextToSpeech",
"class_name": "ElevenLabsTextToSpeech",
"display_name": "ElevenLabs Text to Speech",
"model_options": ["eleven_multilingual_v2", "eleven_v3"],
"source_file": "nodes_elevenlabs.py"
},
"ElevenLabsTextToSoundEffects": {
"node_id": "ElevenLabsTextToSoundEffects",
"class_name": "ElevenLabsTextToSoundEffects",
"display_name": "ElevenLabs Text to Sound Effects",
"model_options": ["eleven_sfx_v2"],
"source_file": "nodes_elevenlabs.py"
},
"ElevenLabsSpeechToSpeech": {
"node_id": "ElevenLabsSpeechToSpeech",
"class_name": "ElevenLabsSpeechToSpeech",
"display_name": "ElevenLabs Speech to Speech",
"model_options": ["eleven_multilingual_sts_v2", "eleven_english_sts_v2"],
"source_file": "nodes_elevenlabs.py"
},
"ElevenLabsTextToDialogue": {
"node_id": "ElevenLabsTextToDialogue",
"class_name": "ElevenLabsTextToDialogue",
"display_name": "ElevenLabs Text to Dialogue",
"model_options": ["eleven_v3"],
"source_file": "nodes_elevenlabs.py"
},
"GeminiNode": {
"node_id": "GeminiNode",
"class_name": "GeminiNode",
"display_name": "Google Gemini",
"model_options": ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-3-pro-preview", "gemini-3-1-pro", "gemini-3-1-flash-lite"],
"source_file": "nodes_gemini.py"
},
"GeminiNodeV2": {
"node_id": "GeminiNodeV2",
"class_name": "GeminiNodeV2",
"display_name": "Google Gemini",
"model_options": ["Gemini 3.1 Pro", "Gemini 3.1 Flash-Lite"],
"source_file": "nodes_gemini.py"
},
"GeminiImageNode": {
"node_id": "GeminiImageNode",
"class_name": "GeminiImage",
"display_name": "Nano Banana (Google Gemini Image)",
"model_options": ["gemini-2.5-flash-image"],
"source_file": "nodes_gemini.py"
},
"GeminiImage2Node": {
"node_id": "GeminiImage2Node",
"class_name": "GeminiImage2",
"display_name": "Nano Banana Pro (Google Gemini Image)",
"model_options": ["gemini-3-pro-image-preview", "Nano Banana 2 (Gemini 3.1 Flash Image)"],
"source_file": "nodes_gemini.py"
},
"GeminiNanoBanana2": {
"node_id": "GeminiNanoBanana2",
"class_name": "GeminiNanoBanana2",
"display_name": "Nano Banana 2",
"model_options": ["Nano Banana 2 (Gemini 3.1 Flash Image)"],
"source_file": "nodes_gemini.py"
},
"GeminiNanoBanana2V2": {
"node_id": "GeminiNanoBanana2V2",
"class_name": "GeminiNanoBanana2V2",
"display_name": "Nano Banana 2",
"model_options": ["Nano Banana 2 (Gemini 3.1 Flash Image)"],
"source_file": "nodes_gemini.py"
},
"GrokImageNode": {
"node_id": "GrokImageNode",
"class_name": "GrokImageNode",
"display_name": "Grok Image",
"model_options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"],
"source_file": "nodes_grok.py"
},
"GrokImageEditNode": {
"node_id": "GrokImageEditNode",
"class_name": "GrokImageEditNode",
"display_name": "Grok Image Edit",
"model_options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"],
"source_file": "nodes_grok.py"
},
"GrokImageEditNodeV2": {
"node_id": "GrokImageEditNodeV2",
"class_name": "GrokImageEditNodeV2",
"display_name": "Grok Image Edit",
"model_options": ["grok-imagine-image-quality", "grok-imagine-image-pro", "grok-imagine-image"],
"source_file": "nodes_grok.py"
},
"GrokVideoNode": {
"node_id": "GrokVideoNode",
"class_name": "GrokVideoNode",
"display_name": "Grok Video",
"model_options": ["grok-imagine-video", "grok-imagine-video-1.5"],
"source_file": "nodes_grok.py"
},
"GrokVideoEditNode": {
"node_id": "GrokVideoEditNode",
"class_name": "GrokVideoEditNode",
"display_name": "Grok Video Edit",
"model_options": ["grok-imagine-video"],
"source_file": "nodes_grok.py"
},
"GrokVideoReferenceNode": {
"node_id": "GrokVideoReferenceNode",
"class_name": "GrokVideoReferenceNode",
"display_name": "Grok Reference-to-Video",
"model_options": ["grok-imagine-video"],
"source_file": "nodes_grok.py"
},
"GrokVideoExtendNode": {
"node_id": "GrokVideoExtendNode",
"class_name": "GrokVideoExtendNode",
"display_name": "Grok Video Extend",
"model_options": ["grok-imagine-video"],
"source_file": "nodes_grok.py"
},
"HitPawGeneralImageEnhance": {
"node_id": "HitPawGeneralImageEnhance",
"class_name": "HitPawGeneralImageEnhance",
"display_name": "HitPaw General Image Enhance",
"model_options": ["generative_portrait", "generative"],
"source_file": "nodes_hitpaw.py"
},
"HitPawVideoEnhance": {
"node_id": "HitPawVideoEnhance",
"class_name": "HitPawVideoEnhance",
"display_name": "HitPaw Video Enhance",
"model_options": ["Portrait Restore Model (1x)", "Portrait Restore Model (2x)", "General Restore Model (1x)", "General Restore Model (2x)", "General Restore Model (4x)", "Ultra HD Model (2x)", "Generative Model (1x)"],
"source_file": "nodes_hitpaw.py"
},
"TencentTextToModelNode": {
"node_id": "TencentTextToModelNode",
"class_name": "TencentTextToModelNode",
"display_name": "Hunyuan3D: Text to Model",
"model_options": ["3.0", "3.1"],
"source_file": "nodes_hunyuan3d.py"
},
"TencentImageToModelNode": {
"node_id": "TencentImageToModelNode",
"class_name": "TencentImageToModelNode",
"display_name": "Hunyuan3D: Image(s) to Model",
"model_options": ["3.0", "3.1"],
"source_file": "nodes_hunyuan3d.py"
},
"KlingMotionControl": {
"node_id": "KlingMotionControl",
"class_name": "MotionControl",
"display_name": "Kling Motion Control",
"model_options": ["kling-v3", "kling-v2-6"],
"source_file": "nodes_kling.py"
},
"KlingVideoNode": {
"node_id": "KlingVideoNode",
"class_name": "KlingVideoNode",
"display_name": "Kling 3.0 Video",
"model_options": ["kling-v3", "kling-3.0-turbo"],
"source_file": "nodes_kling.py"
},
"KlingFirstLastFrameNode": {
"node_id": "KlingFirstLastFrameNode",
"class_name": "KlingFirstLastFrameNode",
"display_name": "Kling 3.0 First-Last-Frame to Video",
"model_options": ["kling-v3"],
"source_file": "nodes_kling.py"
},
"LtxvApiTextToVideo": {
"node_id": "LtxvApiTextToVideo",
"class_name": "TextToVideoNode",
"display_name": "LTXV Text To Video",
"model_options": ["LTX-2 (Pro)", "LTX-2 (Fast)"],
"source_file": "nodes_ltxv.py"
},
"LtxvApiImageToVideo": {
"node_id": "LtxvApiImageToVideo",
"class_name": "ImageToVideoNode",
"display_name": "LTXV Image To Video",
"model_options": ["LTX-2 (Pro)", "LTX-2 (Fast)"],
"source_file": "nodes_ltxv.py"
},
"LumaImageNode2": {
"node_id": "LumaImageNode2",
"class_name": "LumaImageNode",
"display_name": "Luma UNI-1 Image",
"model_options": ["uni-1", "uni-1-max"],
"source_file": "nodes_luma.py"
},
"LumaImageEditNode2": {
"node_id": "LumaImageEditNode2",
"class_name": "LumaImageEditNode",
"display_name": "Luma UNI-1 Image Edit",
"model_options": ["uni-1", "uni-1-max"],
"source_file": "nodes_luma.py"
},
"MeshyTextToModelNode": {
"node_id": "MeshyTextToModelNode",
"class_name": "MeshyTextToModelNode",
"display_name": "Meshy: Text to Model",
"model_options": ["latest"],
"source_file": "nodes_meshy.py"
},
"MeshyRefineNode": {
"node_id": "MeshyRefineNode",
"class_name": "MeshyRefineNode",
"display_name": "Meshy: Refine Draft Model",
"model_options": ["latest"],
"source_file": "nodes_meshy.py"
},
"MeshyImageToModelNode": {
"node_id": "MeshyImageToModelNode",
"class_name": "MeshyImageToModelNode",
"display_name": "Meshy: Image to Model",
"model_options": ["latest"],
"source_file": "nodes_meshy.py"
},
"MeshyMultiImageToModelNode": {
"node_id": "MeshyMultiImageToModelNode",
"class_name": "MeshyMultiImageToModelNode",
"display_name": "Meshy: Multi-Image to Model",
"model_options": ["latest"],
"source_file": "nodes_meshy.py"
},
"MeshyTextureNode": {
"node_id": "MeshyTextureNode",
"class_name": "MeshyTextureNode",
"display_name": "Meshy: Texture Model",
"model_options": ["latest"],
"source_file": "nodes_meshy.py"
},
"MinimaxTextToVideoNode": {
"node_id": "MinimaxTextToVideoNode",
"class_name": "MinimaxTextToVideoNode",
"display_name": "MiniMax Text to Video",
"model_options": ["T2V-01", "T2V-01-Director"],
"source_file": "nodes_minimax.py"
},
"MinimaxImageToVideoNode": {
"node_id": "MinimaxImageToVideoNode",
"class_name": "MinimaxImageToVideoNode",
"display_name": "MiniMax Image to Video",
"model_options": ["I2V-01-Director", "I2V-01", "I2V-01-live"],
"source_file": "nodes_minimax.py"
},
"MinimaxSubjectToVideoNode": {
"node_id": "MinimaxSubjectToVideoNode",
"class_name": "MinimaxSubjectToVideoNode",
"display_name": "MiniMax Subject to Video",
"model_options": ["S2V-01"],
"source_file": "nodes_minimax.py"
},
"OpenAIGPTImage1": {
"node_id": "OpenAIGPTImage1",
"class_name": "OpenAIGPTImage1",
"display_name": "OpenAI GPT Image 2",
"model_options": ["gpt-image-1", "gpt-image-1.5", "gpt-image-2"],
"source_file": "nodes_openai.py"
},
"OpenAIGPTImageNodeV2": {
"node_id": "OpenAIGPTImageNodeV2",
"class_name": "OpenAIGPTImageNodeV2",
"display_name": "OpenAI GPT Image 2",
"model_options": ["gpt-image-2", "gpt-image-1.5", "gpt-image-1"],
"source_file": "nodes_openai.py"
},
"RecraftV4TextToImageNode": {
"node_id": "RecraftV4TextToImageNode",
"class_name": "RecraftV4TextToImageNode",
"display_name": "Recraft V4 Text to Image",
"model_options": ["recraftv4", "recraftv4_pro"],
"source_file": "nodes_recraft.py"
},
"RecraftV4TextToVectorNode": {
"node_id": "RecraftV4TextToVectorNode",
"class_name": "RecraftV4TextToVectorNode",
"display_name": "Recraft V4 Text to Vector",
"model_options": ["recraftv4", "recraftv4_pro"],
"source_file": "nodes_recraft.py"
},
"OpenAIVideoSora2": {
"node_id": "OpenAIVideoSora2",
"class_name": "OpenAIVideoSora2",
"display_name": "OpenAI Sora - Video (DEPRECATED)",
"model_options": ["sora-2", "sora-2-pro"],
"source_file": "nodes_sora.py"
},
"StabilityTextToAudio": {
"node_id": "StabilityTextToAudio",
"class_name": "StabilityTextToAudio",
"display_name": "Stability AI Text To Audio",
"model_options": ["stable-audio-2.5"],
"source_file": "nodes_stability.py"
},
"StabilityAudioToAudio": {
"node_id": "StabilityAudioToAudio",
"class_name": "StabilityAudioToAudio",
"display_name": "Stability AI Audio To Audio",
"model_options": ["stable-audio-2.5"],
"source_file": "nodes_stability.py"
},
"StabilityAudioInpaint": {
"node_id": "StabilityAudioInpaint",
"class_name": "StabilityAudioInpaint",
"display_name": "Stability AI Audio Inpaint",
"model_options": ["stable-audio-2.5"],
"source_file": "nodes_stability.py"
},
"TopazImageEnhance": {
"node_id": "TopazImageEnhance",
"class_name": "TopazImageEnhance",
"display_name": "Topaz Image Enhance",
"model_options": ["Reimagine"],
"source_file": "nodes_topaz.py"
},
"VeoVideoGenerationNode": {
"node_id": "VeoVideoGenerationNode",
"class_name": "VeoVideoGenerationNode",
"display_name": "Google Veo 2 Video Generation",
"model_options": ["veo-2.0-generate-001"],
"source_file": "nodes_veo2.py"
},
"Veo3VideoGenerationNode": {
"node_id": "Veo3VideoGenerationNode",
"class_name": "Veo3VideoGenerationNode",
"display_name": "Google Veo 3 Video Generation",
"model_options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite", "veo-3.0-generate-001", "veo-3.0-fast-generate-001"],
"source_file": "nodes_veo2.py"
},
"Veo3FirstLastFrameNode": {
"node_id": "Veo3FirstLastFrameNode",
"class_name": "Veo3FirstLastFrameNode",
"display_name": "Google Veo 3 First-Last-Frame to Video",
"model_options": ["veo-3.1-generate", "veo-3.1-fast-generate", "veo-3.1-lite"],
"source_file": "nodes_veo2.py"
},
"ViduTextToVideoNode": {
"node_id": "ViduTextToVideoNode",
"class_name": "ViduTextToVideoNode",
"display_name": "Vidu Text To Video Generation",
"model_options": ["viduq1"],
"source_file": "nodes_vidu.py"
},
"ViduImageToVideoNode": {
"node_id": "ViduImageToVideoNode",
"class_name": "ViduImageToVideoNode",
"display_name": "Vidu Image To Video Generation",
"model_options": ["viduq1"],
"source_file": "nodes_vidu.py"
},
"ViduReferenceVideoNode": {
"node_id": "ViduReferenceVideoNode",
"class_name": "ViduReferenceVideoNode",
"display_name": "Vidu Reference To Video Generation",
"model_options": ["viduq1"],
"source_file": "nodes_vidu.py"
},
"ViduStartEndToVideoNode": {
"node_id": "ViduStartEndToVideoNode",
"class_name": "ViduStartEndToVideoNode",
"display_name": "Vidu Start End To Video Generation",
"model_options": ["viduq1"],
"source_file": "nodes_vidu.py"
},
"Vidu2TextToVideoNode": {
"node_id": "Vidu2TextToVideoNode",
"class_name": "Vidu2TextToVideoNode",
"display_name": "Vidu2 Text-to-Video Generation",
"model_options": ["viduq2"],
"source_file": "nodes_vidu.py"
},
"Vidu2ImageToVideoNode": {
"node_id": "Vidu2ImageToVideoNode",
"class_name": "Vidu2ImageToVideoNode",
"display_name": "Vidu2 Image-to-Video Generation",
"model_options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"],
"source_file": "nodes_vidu.py"
},
"Vidu2ReferenceVideoNode": {
"node_id": "Vidu2ReferenceVideoNode",
"class_name": "Vidu2ReferenceVideoNode",
"display_name": "Vidu2 Reference-to-Video Generation",
"model_options": ["viduq2"],
"source_file": "nodes_vidu.py"
},
"Vidu2StartEndToVideoNode": {
"node_id": "Vidu2StartEndToVideoNode",
"class_name": "Vidu2StartEndToVideoNode",
"display_name": "Vidu2 Start/End Frame-to-Video Generation",
"model_options": ["viduq2-pro-fast", "viduq2-pro", "viduq2-turbo"],
"source_file": "nodes_vidu.py"
},
"ViduExtendVideoNode": {
"node_id": "ViduExtendVideoNode",
"class_name": "ViduExtendVideoNode",
"display_name": "Vidu Video Extension",
"model_options": ["viduq2-pro", "viduq2-turbo"],
"source_file": "nodes_vidu.py"
},
"ViduMultiFrameVideoNode": {
"node_id": "ViduMultiFrameVideoNode",
"class_name": "ViduMultiFrameVideoNode",
"display_name": "Vidu Multi-Frame Video Generation",
"model_options": ["viduq2-pro", "viduq2-turbo"],
"source_file": "nodes_vidu.py"
},
"Vidu3TextToVideoNode": {
"node_id": "Vidu3TextToVideoNode",
"class_name": "Vidu3TextToVideoNode",
"display_name": "Vidu Q3 Text-to-Video Generation",
"model_options": ["viduq3-pro", "viduq3-turbo"],
"source_file": "nodes_vidu.py"
},
"Vidu3ImageToVideoNode": {
"node_id": "Vidu3ImageToVideoNode",
"class_name": "Vidu3ImageToVideoNode",
"display_name": "Vidu Q3 Image-to-Video Generation",
"model_options": ["viduq3-pro", "viduq3-turbo"],
"source_file": "nodes_vidu.py"
},
"Vidu3StartEndToVideoNode": {
"node_id": "Vidu3StartEndToVideoNode",
"class_name": "Vidu3StartEndToVideoNode",
"display_name": "Vidu Q3 Start/End Frame-to-Video Generation",
"model_options": ["viduq3-pro", "viduq3-turbo"],
"source_file": "nodes_vidu.py"
},
"WanTextToImageApi": {
"node_id": "WanTextToImageApi",
"class_name": "WanTextToImageApi",
"display_name": "Wan Text to Image",
"model_options": ["wan2.5-t2i-preview"],
"source_file": "nodes_wan.py"
},
"WanImageToImageApi": {
"node_id": "WanImageToImageApi",
"class_name": "WanImageToImageApi",
"display_name": "Wan Image to Image",
"model_options": ["wan2.5-i2i-preview"],
"source_file": "nodes_wan.py"
},
"WanTextToVideoApi": {
"node_id": "WanTextToVideoApi",
"class_name": "WanTextToVideoApi",
"display_name": "Wan Text to Video",
"model_options": ["wan2.5-t2v-preview", "wan2.6-t2v"],
"source_file": "nodes_wan.py"
},
"WanImageToVideoApi": {
"node_id": "WanImageToVideoApi",
"class_name": "WanImageToVideoApi",
"display_name": "Wan Image to Video",
"model_options": ["wan2.5-i2v-preview", "wan2.6-i2v"],
"source_file": "nodes_wan.py"
},
"WanReferenceVideoApi": {
"node_id": "WanReferenceVideoApi",
"class_name": "WanReferenceVideoApi",
"display_name": "Wan Reference to Video",
"model_options": ["wan2.6-r2v"],
"source_file": "nodes_wan.py"
},
"Wan2TextToVideoApi": {
"node_id": "Wan2TextToVideoApi",
"class_name": "Wan2TextToVideoApi",
"display_name": "Wan 2.7 Text to Video",
"model_options": ["wan2.7-t2v"],
"source_file": "nodes_wan.py"
},
"Wan2ImageToVideoApi": {
"node_id": "Wan2ImageToVideoApi",
"class_name": "Wan2ImageToVideoApi",
"display_name": "Wan 2.7 Image to Video",
"model_options": ["wan2.7-i2v"],
"source_file": "nodes_wan.py"
},
"Wan2VideoContinuationApi": {
"node_id": "Wan2VideoContinuationApi",
"class_name": "Wan2VideoContinuationApi",
"display_name": "Wan 2.7 Video Continuation",
"model_options": ["wan2.7-i2v"],
"source_file": "nodes_wan.py"
},
"Wan2VideoEditApi": {
"node_id": "Wan2VideoEditApi",
"class_name": "Wan2VideoEditApi",
"display_name": "Wan 2.7 Video Edit",
"model_options": ["wan2.7-videoedit"],
"source_file": "nodes_wan.py"
},
"Wan2ReferenceVideoApi": {
"node_id": "Wan2ReferenceVideoApi",
"class_name": "Wan2ReferenceVideoApi",
"display_name": "Wan 2.7 Reference to Video",
"model_options": ["wan2.7-r2v"],
"source_file": "nodes_wan.py"
},
"HappyHorseTextToVideoApi": {
"node_id": "HappyHorseTextToVideoApi",
"class_name": "HappyHorseTextToVideoApi",
"display_name": "HappyHorse Text to Video",
"model_options": ["happyhorse-1.0-t2v"],
"source_file": "nodes_wan.py"
},
"HappyHorseImageToVideoApi": {
"node_id": "HappyHorseImageToVideoApi",
"class_name": "HappyHorseImageToVideoApi",
"display_name": "HappyHorse Image to Video",
"model_options": ["happyhorse-1.0-i2v"],
"source_file": "nodes_wan.py"
},
"HappyHorseVideoEditApi": {
"node_id": "HappyHorseVideoEditApi",
"class_name": "HappyHorseVideoEditApi",
"display_name": "HappyHorse Video Edit",
"model_options": ["happyhorse-1.0-video-edit"],
"source_file": "nodes_wan.py"
},
"HappyHorseReferenceVideoApi": {
"node_id": "HappyHorseReferenceVideoApi",
"class_name": "HappyHorseReferenceVideoApi",
"display_name": "HappyHorse Reference to Video",
"model_options": ["happyhorse-1.0-r2v"],
"source_file": "nodes_wan.py"
},
"WavespeedImageUpscaleNode": {
"node_id": "WavespeedImageUpscaleNode",
"class_name": "WavespeedImageUpscaleNode",
"display_name": "WaveSpeed Image Upscale",
"model_options": ["SeedVR2", "Ultimate"],
"source_file": "nodes_wavespeed.py"
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Move this generated scan cache out of scripts/data/.

This file is regenerated from a local ComfyUI checkout during sync, so checking it into scripts/data/mcp/ violates the repo policy for generated JSON and invites cross-machine churn. Keep an example fixture if you need one, but write the live cache to scripts/.output/ instead. As per coding guidelines, "Generated JSON must not be committed under scripts/data/; generated output should go to scripts/.output/ or repo-root reports instead."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/data/mcp/api_node_model_options.json` around lines 1 - 629, This scan
cache JSON should not live under scripts/data/mcp because it is regenerated from
a local ComfyUI checkout and causes cross-machine churn. Move the generated
output path used by the sync/scan code so the live cache is written to
scripts/.output/ instead, and keep only a checked-in example fixture if needed.
Update the code that produces api_node_model_options.json and any references to
this artifact so they point to the new generated location, using the existing
scan/sync entrypoints that populate the MCP node model options cache.

Source: Coding guidelines

Comment on lines +92 to +100
"Kling O3": {
"summary": "Video generation with outpainting, image editing, and character reference features.",
"strengths": [],
"capabilities": []
},
"Kling O1": {
"summary": "Kling Omni image model with support for up to 10 reference images with tags.",
"strengths": ["Type: Quality"],
"capabilities": []

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Collapse the case-variant duplicate registry keys.

This file contains multiple case-folding duplicates (Kling O1/Kling o1, Kling O3/Kling o3, None/none). The MCP registry lookup layer is described as doing case-insensitive fallback, so these doppelgängers make profile resolution ambiguous and can bind the wrong summary to a template.

Also applies to: 247-250, 262-265, 677-680, 747-750

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/data/mcp/models_registry.json` around lines 92 - 100, Collapse the
case-variant duplicate entries in the MCP registry so each model name has only
one canonical key. In the registry JSON, deduplicate the repeated pairs like
Kling O1/Kling o1, Kling O3/Kling o3, and None/none by keeping a single
normalized entry and merging the correct summary, strengths, and capabilities
into it. Update the affected registry objects in the same model groups so the
lookup layer’s case-insensitive fallback cannot resolve to ambiguous or
conflicting profiles.


**Template overrides:** edit `template_overrides.json` to pin `recommend` or `freshness` for specific templates. Use Cases category never syncs below `low` (no `not_recommended`).

See [`../mcp/docs/MCP_AI_ENHANCEMENT.md`](../mcp/docs/MCP_AI_ENHANCEMENT.md).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the relative docs link target.

Line 17 currently points to scripts/data/mcp/docs/... instead of scripts/mcp/docs/...—a tiny path that does a big oopsie.

Suggested fix
-See [`../mcp/docs/MCP_AI_ENHANCEMENT.md`](../mcp/docs/MCP_AI_ENHANCEMENT.md).
+See [`../../mcp/docs/MCP_AI_ENHANCEMENT.md`](../../mcp/docs/MCP_AI_ENHANCEMENT.md).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
See [`../mcp/docs/MCP_AI_ENHANCEMENT.md`](../mcp/docs/MCP_AI_ENHANCEMENT.md).
See [`../../mcp/docs/MCP_AI_ENHANCEMENT.md`](../../mcp/docs/MCP_AI_ENHANCEMENT.md).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/data/mcp/README.md` at line 17, The docs link in README.md points to
the wrong relative location, resolving under scripts/data/mcp/docs instead of
the intended scripts/mcp/docs. Update the markdown link target in the README so
it correctly references the MCP_AI_ENHANCEMENT.md document from the current
file’s location, using the existing README link text and adjusting only the
relative path.

Comment on lines +70 to +75
payload = {
"source": str(api_nodes_dir),
"node_count": len(index),
"nodes": index,
}
OUTPUT_FILE.write_text(dumps_compact_arrays(payload), encoding="utf-8")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Drop the absolute source path from the emitted payload.

This CLI writes the local api_nodes_dir into the shared JSON output, so it can reintroduce the same workstation-path leak on every run. A stable identifier is fine; a home-directory breadcrumb is not.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/mcp/scan_api_nodes.py` around lines 70 - 75, The emitted payload in
scan_api_nodes.py currently includes the absolute api_nodes_dir value under
source, which leaks workstation-specific paths into the shared JSON. Update the
payload construction in the scan/serialization flow to remove that absolute
source field or replace it with a stable non-local identifier, while keeping
node_count and nodes intact, so OUTPUT_FILE.write_text only writes portable
data.

Comment thread scripts/mcp/sync_index.py
Comment on lines +316 to +350
def infer_task_type(name: str) -> str:
name_l = name.lower()
if any(x in name_l for x in ["t2v", "txt2vid", "text_to_video", "text-to-video"]):
return "t2v"
if any(x in name_l for x in ["i2v", "img2vid", "img_to_vid", "image_to_video", "image-to-video", "r2v", "reference_to_video"]):
return "i2v"
if any(x in name_l for x in ["t2i", "text_to_image", "text-to-image"]):
return "t2i"
if any(x in name_l for x in ["i2i", "img_edit", "img2img"]):
return "i2i"
if any(x in name_l for x in ["segment", "matting"]):
return "seg"
if "upscale" in name_l:
return "upscale"
if "depth" in name_l:
return "depth"
if "remove" in name_l:
return "remove"
if any(x in name_l for x in ["frame", "film", "rife", "slowmo", "gimm"]):
return "frame"
if "text_to_3d" in name_l or "text-to-3d" in name_l:
return "t2-3d"
if any(x in name_l for x in ["img2_3d", "img2-3d", "image_to_3d", "image-to-3d"]):
return "i2-3d"
if any(x in name_l for x in ["text_to_audio", "text-to-audio", "text_to_music", "text-to-music"]):
return "t2a"
if any(x in name_l for x in ["text_gen", "llm", "chat"]):
return "llm"
if any(x in name_l for x in ["rembg", "birefnet", "bi-refnet", "background"]):
return "remove"
if "gaussian" in name_l or "splat" in name_l:
return "3d"
if "perspective" in name_l:
return "perspective"
return ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Derive task_type from template metadata, not just the filename.

infer_task() already trusts tags, but infer_task_type() only parses name. If a workflow is tagged Image to Image or Image to Video without an i2i/i2v-style filename token, this falls back to generic text IO and writes the wrong io contract to index.mcp.json—when the name is coy, the IO goes awry.

Also applies to: 617-622

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/mcp/sync_index.py` around lines 316 - 350, `infer_task_type()` is
only deriving the task type from the workflow name, so tagged workflows like
Image to Image or Image to Video can be misclassified when the filename lacks a
matching token. Update `infer_task_type` in `sync_index.py` to also consult
template metadata/tags (as `infer_task()` already does) before falling back to
filename heuristics, and ensure the task type written into `index.mcp.json`
reflects the tag-based contract for `infer_task`, `infer_task_type`, and the
downstream `io` mapping.

Comment thread scripts/mcp/sync_index.py
Comment on lines +368 to +389
def _normalize_io_side(slots: list | dict | None) -> list[str]:
"""Normalize legacy object/dict slots to string array."""
if not slots:
return []
if isinstance(slots, dict):
return [
_encode_slot(typ, "", int(count))
for typ, count in slots.items()
if typ and int(count) > 0
]
result: list[str] = []
for slot in slots:
if isinstance(slot, str):
result.append(slot)
continue
typ = slot.get("type", "")
if not typ:
continue
role = (slot.get("role") or slot.get("purpose") or "").strip()
count = int(slot.get("count", 1))
result.append(_encode_slot(typ, role, count))
return result

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate cached io.count values before coercing them.

template_cache.json is AI-populated in this pipeline, so slot["count"] is untrusted input. int(slot.get("count", 1)) will raise on null, "", or non-numeric text and abort the entire sync for one bad cache row.

Also applies to: 646-649

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/mcp/sync_index.py` around lines 368 - 389, The _normalize_io_side
function is coercing untrusted slot["count"] values with int(slot.get("count",
1)), which can abort sync on null, empty, or invalid text. Update
_normalize_io_side to validate and safely coerce count before using
_encode_slot, skipping or defaulting bad entries instead of raising, and apply
the same defensive handling in the other io.count normalization path referenced
by the review.

Comment thread scripts/mcp/sync_index.py
Comment on lines +537 to +544
payload = {
"source": str(api_nodes_dir),
"node_count": len(index),
"nodes": index,
}
API_NODE_OPTIONS_FILE.write_text(
dumps_compact_arrays(payload),
encoding="utf-8",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Don’t serialize the caller’s absolute ComfyUI path into the shared cache.

Writing source: str(api_nodes_dir) bakes a maintainer-local filesystem path into the generated JSON. That leaks workstation details and guarantees noisy diffs whenever someone else runs the sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/mcp/sync_index.py` around lines 537 - 544, The payload built in
sync_index.py is writing the caller’s absolute ComfyUI path into the shared
cache via source in the JSON. Update the payload construction in the sync logic
that writes API_NODE_OPTIONS_FILE so it does not serialize str(api_nodes_dir);
use a stable, non-local identifier or omit the field entirely if it is only used
for provenance, and keep the rest of the index generation unchanged.

Comment thread scripts/README.md
- **`data/mcp/api_node_model_options.json`** — Generated cache of API node `model` dropdown options (from ComfyUI source).
- **`data/mcp/models_registry.json`** — Model profiles (summary, strengths, capabilities) for AI description generation.
- **`data/mcp/template_cache.json`** — Per-template AI copy, versioned by workflow JSON hash.
- **`data/krea_registry_aliases.json`**, **`data/krea_*_models.json`** — Temporary Krea snapshots for one-off registry seeding (delete when seeding is complete).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix Krea alias path in docs (right file, right aisle).

Line 85 lists data/krea_registry_aliases.json, but MCP aliases are documented/seeded under data/mcp/registry_aliases.json in this rollout. This path mismatch will send maintainers to the wrong file.

Suggested doc fix
-- **`data/krea_registry_aliases.json`**, **`data/krea_*_models.json`** — Temporary Krea snapshots for one-off registry seeding (delete when seeding is complete).
+- **`data/mcp/registry_aliases.json`**, **`data/krea_*_models.json`** — Temporary Krea snapshot/alias inputs for one-off registry seeding (delete snapshot files when seeding is complete).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **`data/krea_registry_aliases.json`**, **`data/krea_*_models.json`** — Temporary Krea snapshots for one-off registry seeding (delete when seeding is complete).
**`data/mcp/registry_aliases.json`**, **`data/krea_*_models.json`** — Temporary Krea snapshot/alias inputs for one-off registry seeding (delete snapshot files when seeding is complete).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/README.md` at line 85, The README entry for Krea alias snapshots
points to the wrong alias file path, so update the documentation in the script
guide to reference the MCP alias location used by this rollout. In the affected
markdown list item, replace the `data/krea_registry_aliases.json` reference with
`data/mcp/registry_aliases.json` while keeping the rest of the Krea snapshot
note aligned with the existing seeding docs.

@comfyui-wiki comfyui-wiki merged commit 51fc600 into main Jun 24, 2026
15 checks passed
@comfyui-wiki comfyui-wiki deleted the feat/models-registry-and-mcp-index branch June 24, 2026 17:22
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant