Skip to content

UV: Slice G — CLI/MCP parity for UV editor tools (#465) - #777

Merged
fernandotonon merged 2 commits into
masterfrom
feature/uv-cli-mcp-465
Jun 29, 2026
Merged

UV: Slice G — CLI/MCP parity for UV editor tools (#465)#777
fernandotonon merged 2 commits into
masterfrom
feature/uv-cli-mcp-465

Conversation

@fernandotonon

@fernandotonon fernandotonon commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add UvPipeline as the shared headless layer for UV info, geometric projection, seam marking, and partial xatlas unwrap.
  • Extend qtmesh uv with --info (islands + overlap), --project, and --set-seams; add MCP tools uv_info, uv_project, uv_set_seams, and uv_unwrap_selection.
  • Add unit tests and document the UV Editor architecture + CLI examples in CLAUDE.md.

Closes #465.

Test plan

  • ./build_local/bin/UnitTests --gtest_filter="UvPipeline*:CLIPipelineCmdUvCoverage*" (23 tests pass)
  • CI: Linux unit tests + build matrix
  • Manual: qtmesh uv model.fbx --info --json
  • Manual: qtmesh uv model.fbx --project box -o out.glb
  • Manual: MCP uv_info / uv_project on a loaded mesh

Made with Cursor

Summary by CodeRabbit

  • New Features

    • Added richer UV tools in the CLI and editor workflows, including UV analysis, projection options, seam marking, and unwrap actions.
    • Expanded support in the AI/automation interface for viewing UV details and performing UV edits consistently across entry points.
  • Bug Fixes

    • Improved validation for UV commands so required options and mode selection are enforced more reliably.
    • Added coverage for missing-file and invalid-usage cases to make UV operations behave more predictably.

Centralize headless UV info, projection, seam marking, and partial unwrap
in UvPipeline and wire qtmesh uv plus MCP uv_* tools with tests and docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@fernandotonon, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 11 minutes and 47 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e87303f4-6e0a-45ae-b2dd-d5a10f9c3c1b

📥 Commits

Reviewing files that changed from the base of the PR and between 9b1bbb0 and 883fdea.

📒 Files selected for processing (4)
  • src/CLIPipeline_cmduv_coverage_test.cpp
  • src/MCPServer.cpp
  • src/UvPipeline.cpp
  • src/UvPipeline_test.cpp
📝 Walkthrough

Walkthrough

Introduces UvPipeline, a new static-method facade centralizing UV analysis, projection, seam management, and unwrapping. It is wired into CLIPipeline::cmdUv (adding --project and --set-seams modes) and into MCPServer (four new tool handlers). Unit tests and CLI coverage tests are added, with CMake and docs updated throughout.

Changes

UvPipeline CLI/MCP Parity

Layer / File(s) Summary
UvPipeline interface and implementation
src/UvPipeline.h, src/UvPipeline.cpp
Defines InfoReport/SeamEdge structs and all static method declarations; implements internal UV-overlap/UV-load helpers, parseProjectMode, analyzeEntity, infoToJson/infoToText, projectEntity, parseSeamEdgeList, setSeamsOnEntity, unwrapEntity, and unwrapTriangles.
CLIPipeline::cmdUv extended modes
src/CLIPipeline.cpp
Adds --project <mode> and --set-seams argument parsing with --axis/--scale; centralizes mode-count validation and -o enforcement; updates Sentry breadcrumb to modeLabel; routes --info/--project/--set-seams through UvPipeline and switches --unwrap to UvPipeline::unwrapEntity.
MCPServer UV tool handlers
src/MCPServer.h, src/MCPServer.cpp
Declares and implements toolUvInfo, toolUvProject, toolUvSetSeams, toolUvUnwrapSelection; registers them in toolHandlers(); migrates toolAutoUvUnwrap to UvPipeline::unwrapEntity; advertises all tools in buildToolsList() schema.
Tests and build wiring
src/UvPipeline_test.cpp, src/CLIPipeline_cmduv_coverage_test.cpp, src/CMakeLists.txt, tests/CMakeLists.txt
Adds unit tests for parseProjectMode, parseSeamEdgeList, and infoToJson/infoToText; expands CLI coverage for no-mode, multiple-mode, missing-output, and missing-file cases; registers UvPipeline.cpp/.h in both build targets.
Docs
CLAUDE.md
Extends qtmesh UV CLI examples with --info overlap metrics and --project/--set-seams usage; adds a UV Editor section describing UvPipeline and updates the UvUnwrap Sentry breadcrumb category.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as qtmesh CLI / MCP Client
  participant cmdUv as CLIPipeline::cmdUv / MCPServer::toolUv*
  participant UvPipeline
  participant UvProject
  participant UvUnwrap
  participant OgreEntity as Ogre::Entity

  CLI->>cmdUv: --project box / uv_project{mode:"box"}
  cmdUv->>UvPipeline: parseProjectMode("box")
  cmdUv->>UvPipeline: projectEntity(entity, Box, uvChannel, opts)
  UvPipeline->>OgreEntity: load into EditableMesh, preload UVs
  UvPipeline->>UvProject: project(editableMesh, Box, opts)
  UvPipeline->>OgreEntity: commit updated UVs
  UvPipeline-->>cmdUv: UvProject::Report {vertsChanged}
  cmdUv-->>CLI: JSON result

  CLI->>cmdUv: --set-seams "0:1-2,0:3-4" / uv_set_seams{edges:...}
  cmdUv->>UvPipeline: parseSeamEdgeList(spec)
  cmdUv->>UvPipeline: setSeamsOnEntity(entity, edges)
  UvPipeline->>OgreEntity: load, validate, UvSeamData::setSeam, write back
  UvPipeline-->>cmdUv: bool ok
  cmdUv-->>CLI: JSON result

  CLI->>cmdUv: uv_unwrap_selection{submesh, triangles}
  cmdUv->>UvPipeline: unwrapTriangles(entity, subMeshIndex, triangleIndices, opts)
  UvPipeline->>OgreEntity: build faceMask, load seamEdgeKeys
  UvPipeline->>UvUnwrap: unwrapEntity(entity, opts+faceMask)
  UvPipeline-->>cmdUv: UvUnwrapReport
  cmdUv-->>CLI: JSON result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #465 (UV: Slice G — CLI/MCP parity, polish, docs): This PR directly implements the CLI subcommands (--project, --set-seams, --info), MCP tools (uv_info, uv_project, uv_set_seams, uv_unwrap_selection), Sentry breadcrumbs, tests, and CLAUDE.md docs specified in the acceptance criteria.
  • #458 (UV editor epic): UvPipeline is the headless parity pipeline referenced as the parent epic's shared infrastructure.

Possibly related PRs

  • fernandotonon/QtMeshEditor#776: Both PRs introduce UV projection modes (box/cylinder/sphere/reset) through overlapping APIs — the retrieved PR wires UvProject into the UV editor controller, while this PR routes the same projections through UvPipeline::projectEntity for CLI/MCP.

Poem

🐇 Hopping through the mesh today,
I painted UVs every way—
Box and cylinder, seams set right,
CLI and MCP, all in sight!
The pipeline hops without a hitch,
No overlapping UV glitch. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has a summary and test plan, but it omits required template sections like Technical Details, PS1 checklist, and features/bugfixes. Fill in the repository template: add Technical Details, the PS1 runtime checklist if applicable, and the features/bugfixes sections.
Linked Issues check ⚠️ Warning The PR covers info/project/seams and MCP parity, but it does not show the required --pack/uv_pack work or the full --info metrics from #465. Add the missing --pack/uv_pack support and confirm --info includes the requested metrics, or update the issue scope if intentionally deferred.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.63% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly reflects the PR's main focus on UV editor CLI/MCP parity and references the relevant issue.
Out of Scope Changes check ✅ Passed The changes are centered on the UV editor pipeline, CLI/MCP parity, tests, and docs, with no clear unrelated additions.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/uv-cli-mcp-465

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b1bbb0536

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/UvPipeline.cpp Outdated
if (ti >= 0 && ti < triCount)
mask.includeTriangle[static_cast<size_t>(ti)] = true;
}
runOpts.faceMasks.push_back(mask);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Mask non-target submeshes during selection unwrap

When uv_unwrap_selection is used on a multi-submesh entity, only the target submesh gets a FaceMask; UvUnwrap::unwrapEntity treats submeshes with no mask as fully included, so every other submesh is xatlas-unwrapped even though the caller selected triangles on one submesh. This can silently replace unrelated UVs; add all-false masks for non-target submeshes or otherwise restrict the unwrap to the requested submesh.

Useful? React with 👍 / 👎.

Comment thread src/MCPServer.cpp Outdated
Comment on lines +1555 to +1557
SelectionSet* sel = SelectionSet::getSingleton();
if (!sel || sel->getEntitiesCount() == 0)
return makeErrorResult("No selected entity.");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use resolved selections for UV MCP tools

hasSelectedEntities() already accepts scene-node and sub-entity selections via getResolvedEntities(), but this gate then rejects them by checking the raw entity list. The normal MCP load_mesh flow leaves the imported object selected as a scene node, so uv_info (and the same repeated check in uv_project, uv_set_seams, and uv_unwrap_selection) returns "No selected entity" immediately after loading a mesh instead of operating on the resolved entity.

Useful? React with 👍 / 👎.

Comment thread src/UvPipeline.cpp Outdated
Comment on lines +159 to +160
if (uvChannel != 0)
applyUvChannelFromEntity(mesh, const_cast<Ogre::Entity*>(entity), uvChannel);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not fall back to UV0 for missing info channels

For --info --channel N / uv_info with a channel that is absent on some or all submeshes, applyUvChannelFromEntity simply leaves the EditableMesh UVs that loadFromEntity populated from UV0. The subsequent island and overlap report is therefore computed from UV0 while the caller asked about channel N, which gives false coverage/overlap results for missing lightmap channels; clear hasUV or report N/A when the requested channel cannot be read.

Useful? React with 👍 / 👎.

@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: 8

🧹 Nitpick comments (2)
src/UvPipeline_test.cpp (1)

5-29: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover the accepted projection aliases and normalization here.

parseProjectMode() also accepts trimmed/case-insensitive inputs plus cyl, sph, reset_box, and resetbox. These tests only pin the canonical spellings, so a regression in the CLI/MCP input variants added by this PR would still pass.

Example coverage
 TEST(UvPipelineParseProjectMode, AcceptsKnownModes)
 {
     bool ok = false;
+    EXPECT_EQ(UvPipeline::parseProjectMode(QStringLiteral("  CYL "), &ok),
+              UvProject::Mode::Cylinder);
+    EXPECT_TRUE(ok);
+    EXPECT_EQ(UvPipeline::parseProjectMode(QStringLiteral("sph"), &ok),
+              UvProject::Mode::Sphere);
+    EXPECT_TRUE(ok);
+    EXPECT_EQ(UvPipeline::parseProjectMode(QStringLiteral("reset_box"), &ok),
+              UvProject::Mode::ResetBox);
+    EXPECT_TRUE(ok);
🤖 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 `@src/UvPipeline_test.cpp` around lines 5 - 29, Expand the
UvPipeline::parseProjectMode test coverage to include the accepted alias and
normalization inputs, not just the canonical spellings. Update
UvPipelineParseProjectMode::AcceptsKnownModes and related checks to verify
trimmed and case-insensitive values, plus the additional accepted forms cly,
sph, reset_box, and resetbox, so regressions in the CLI/MCP parsing path are
caught.
src/CLIPipeline_cmduv_coverage_test.cpp (1)

96-100: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise gate 4 with one of the new mode flags.

MultipleModesSpecified still uses only --info and --unwrap. Since this PR extends the parser with --project and --set-seams, a bug where either new flag is not counted by the “one mode only” check would slip past this test.

Example tweak
 TEST(CLIPipelineCmdUvCoverageError, MultipleModesSpecified)
 {
-    UvTestArgv args({"qtmesh", "uv", "model.fbx", "--info", "--unwrap", "-o", "out.glb"});
+    UvTestArgv args({"qtmesh", "uv", "model.fbx", "--info", "--project", "box",
+                     "-o", "out.glb"});
     EXPECT_EQ(CLIPipeline::cmdUv(args.argc(), args.argv()), 2);
 }
🤖 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 `@src/CLIPipeline_cmduv_coverage_test.cpp` around lines 96 - 100, The
MultipleModesSpecified coverage test only exercises --info and --unwrap, so it
misses the new parser modes added in cmdUv. Update the test in
CLIPipelineCmdUvCoverageError to include either --project or --set-seams
alongside an existing mode flag, and keep asserting CLIPipeline::cmdUv returns
the same “multiple modes” error so the one-mode-only check is validated for the
new flags too.
🤖 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 `@src/CLIPipeline.cpp`:
- Around line 7928-7933: The UV command parser/usage in CLIPipeline’s `uv` mode
currently only recognizes `--info`, `--unwrap`, `--project`, and `--set-seams`,
so the required `--pack` workflow is missing. Update the parsing/validation and
help text around the `inputPath`, `outputPath`, `projectMode`, and `seamSpec`
handling to accept `--pack` with the required margin control options, and make
sure the mode dispatch path treats it as a first-class UV mode rather than
rejecting it or leaving it undocumented.

In `@src/MCPServer.cpp`:
- Around line 583-586: The MCP UV tool registry is missing the required uv_pack
entry, so MCP parity is incomplete. Add a uv_pack handler in MCPServer, register
it alongside toolUvInfo/toolUvProject/toolUvSetSeams/toolUvUnwrapSelection in
the UV tools map, and update the tool schema/advertised objectives so uv_pack is
exposed consistently; if the implementation is not ready, do not mark the `#465`
objective as fully closed.
- Around line 1591-1595: The MCP uv projection path is not matching the CLI
because uv_project in MCPServer.cpp forwards invalid scale values directly while
cmdUv normalizes non-positive scale to 1.0. Update the uv_project handling
around UvProject::Options opts so args["scale"] is clamped or rejected
consistently with the CLI before assigning opts.boxScale, and keep the behavior
aligned with cmdUv and the existing MCP argument parsing.
- Around line 6865-6903: The MCP tool schemas for uv_set_seams and
uv_unwrap_selection are missing required-field declarations even though the
handlers expect edges and triangles to always be present. Update the JSON schema
objects built in MCPServer’s tool registration blocks for appendTool so that
uv_set_seams marks edges as required and uv_unwrap_selection marks triangles as
required, matching the expectations of toolUvSetSeams and toolUvUnwrapSelection.
- Around line 1662-1669: The submesh/triangles parsing in the MCPServer request
handler is silently coercing non-integer JSON values to 0 via toInt(), which can
accept malformed input as valid. Update the logic around the args["submesh"] and
args["triangles"] handling to explicitly validate that submesh is a JSON integer
and that every triangles entry is an integer within the expected range before
converting, otherwise return a makeErrorResult failure instead of defaulting to
0.

In `@src/UvPipeline.cpp`:
- Around line 330-354: Validate the selection inputs in UvPipeline before
mutating runOpts: in the submesh index check, reject values that cannot be
represented safely instead of casting subMeshIndex to unsigned short, and use
the same validated index consistently when calling getSubMesh. Also, in the
triangleIndices loop, detect any out-of-range triangle IDs and return a failure
immediately rather than silently skipping them, so UvUnwrapOptions::FaceMask is
only built from fully valid input.
- Around line 62-78: The overlap ratio in the UvPipeline overlap scan only
counts the first triangle in each overlapping pair, so it underreports the
fraction of triangles with overlapping UV AABBs. Update the overlap counting
logic in the loop over order/boxes so both triangles in a detected overlap are
counted, and make the final ratio reflect triangles with at least one overlap
rather than pair starts.
- Around line 95-110: The UV extraction in UvPipeline.cpp assumes every
VES_TEXTURE_COORDINATES element is a 2-float layout before reading p[1]. Update
the loop around baseVertexPointerToElement() to detect the element’s actual type
and only read as Ogre::Vector2 for VET_FLOAT2-compatible data; for VET_FLOAT1
and packed short/ubyte encodings, either skip the channel or convert it safely
before assigning to uvs. Keep the fix localized to the texture-coordinate read
path that uses elem, vbuf, and base.

---

Nitpick comments:
In `@src/CLIPipeline_cmduv_coverage_test.cpp`:
- Around line 96-100: The MultipleModesSpecified coverage test only exercises
--info and --unwrap, so it misses the new parser modes added in cmdUv. Update
the test in CLIPipelineCmdUvCoverageError to include either --project or
--set-seams alongside an existing mode flag, and keep asserting
CLIPipeline::cmdUv returns the same “multiple modes” error so the one-mode-only
check is validated for the new flags too.

In `@src/UvPipeline_test.cpp`:
- Around line 5-29: Expand the UvPipeline::parseProjectMode test coverage to
include the accepted alias and normalization inputs, not just the canonical
spellings. Update UvPipelineParseProjectMode::AcceptsKnownModes and related
checks to verify trimmed and case-insensitive values, plus the additional
accepted forms cly, sph, reset_box, and resetbox, so regressions in the CLI/MCP
parsing path are caught.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: e5bea19c-1932-416d-8241-11983e7d14ba

📥 Commits

Reviewing files that changed from the base of the PR and between 9c3a03e and 9b1bbb0.

📒 Files selected for processing (10)
  • CLAUDE.md
  • src/CLIPipeline.cpp
  • src/CLIPipeline_cmduv_coverage_test.cpp
  • src/CMakeLists.txt
  • src/MCPServer.cpp
  • src/MCPServer.h
  • src/UvPipeline.cpp
  • src/UvPipeline.h
  • src/UvPipeline_test.cpp
  • tests/CMakeLists.txt

Comment thread src/CLIPipeline.cpp
Comment on lines +7928 to +7933
// Parse:
// uv <file> --info [--json] [--channel N]
// uv <file> --unwrap [--resolution N] [--padding P] [--channel C] [--no-backup] -o out
// uv <file> --project box|cylinder|sphere|reset [--axis N] [--scale S] [--channel C] -o out [--json]
// uv <file> --set-seams "0:1-2,0:2-3" -o out
QString inputPath, outputPath, projectMode, seamSpec;

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 | 🏗️ Heavy lift

Wire the required --pack UV mode before closing Slice G.

The parser/usage/mode validation only accepts --info, --unwrap, --project, and --set-seams, but the linked objectives require qtmesh uv --pack with margin control. Add the pack mode here or keep the issue open/defer it explicitly.

Also applies to: 7981-8001

🤖 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 `@src/CLIPipeline.cpp` around lines 7928 - 7933, The UV command parser/usage in
CLIPipeline’s `uv` mode currently only recognizes `--info`, `--unwrap`,
`--project`, and `--set-seams`, so the required `--pack` workflow is missing.
Update the parsing/validation and help text around the `inputPath`,
`outputPath`, `projectMode`, and `seamSpec` handling to accept `--pack` with the
required margin control options, and make sure the mode dispatch path treats it
as a first-class UV mode rather than rejecting it or leaving it undocumented.

Comment thread src/MCPServer.cpp
Comment on lines +583 to +586
{QStringLiteral("uv_info"), &MCPServer::toolUvInfo},
{QStringLiteral("uv_project"), &MCPServer::toolUvProject},
{QStringLiteral("uv_set_seams"), &MCPServer::toolUvSetSeams},
{QStringLiteral("uv_unwrap_selection"), &MCPServer::toolUvUnwrapSelection},

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 | 🏗️ Heavy lift

Add the missing uv_pack MCP tool.

The new UV registry/schema advertises four UV tools, but the linked objectives require uv_pack as part of MCP parity. Add the handler, registration, and tool schema, or avoid claiming #465 is fully closed.

Also applies to: 6833-6904

🤖 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 `@src/MCPServer.cpp` around lines 583 - 586, The MCP UV tool registry is
missing the required uv_pack entry, so MCP parity is incomplete. Add a uv_pack
handler in MCPServer, register it alongside
toolUvInfo/toolUvProject/toolUvSetSeams/toolUvUnwrapSelection in the UV tools
map, and update the tool schema/advertised objectives so uv_pack is exposed
consistently; if the implementation is not ready, do not mark the `#465` objective
as fully closed.

Comment thread src/MCPServer.cpp
Comment thread src/MCPServer.cpp Outdated
Comment thread src/MCPServer.cpp
Comment thread src/UvPipeline.cpp Outdated
Comment thread src/UvPipeline.cpp
Comment thread src/UvPipeline.cpp Outdated
Use resolved MCP selections, mask non-target submeshes on partial unwrap,
validate triangle/submesh indices, fix overlap counting and non-zero channel
info, and align MCP scale handling with the CLI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@fernandotonon

Copy link
Copy Markdown
Owner Author

Review follow-up in 883fdea:

Fixed

  • Partial unwrap (uv_unwrap_selection / unwrapTriangles) now installs all-false face masks on non-target submeshes so xatlas does not touch unrelated UVs.
  • MCP UV tools use getResolvedEntities() (scene-node selections after load_mesh work).
  • --info / uv_info on non-zero channels clears UV0 fallback before island/overlap analysis.
  • Overlap ratio counts any triangle participating in an AABB overlap (not just pair starts).
  • MCP scale clamped to match CLI; triangle/submesh JSON args validated; tool schemas mark required fields.

Intentionally deferred (Slice F rejected)

@sonarqubecloud

Copy link
Copy Markdown

@fernandotonon
fernandotonon merged commit bd34380 into master Jun 29, 2026
21 checks passed
@fernandotonon
fernandotonon deleted the feature/uv-cli-mcp-465 branch June 29, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UV: Slice G — CLI/MCP parity, polish, docs

1 participant