Skip to content

Emit MCP variants under their original server name - #9

Merged
llima merged 2 commits into
mainfrom
fix/mcp-variant-server-name
Sep 21, 2026
Merged

llima merged 2 commits into
mainfrom
fix/mcp-variant-server-name

Conversation

@llima

@llima llima commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Version bumped to 0.2.2 (patch). Merging publishes craftar@0.2.2 to npm once the release run is approved in the npm environment.
  • Fixes a bug that 0.2.1 made reachable. Both MCP emitters keyed the server map by the ingredient's name instead of outName — every other ingredient type already follows the rule that a variant emits under its original name. Since 0.2.1, import correctly turns a second workspace's differing MCP server into the variant mcp/srv--b. sync then wrote it into .mcp.json as "srv--b", so that workspace's own .mcp.json read as collision. The fix affects both targets: .mcp.json and .kiro/settings/mcp.json.
  • A shared mcpServers() helper replaces the two copies of the loop. When two ingredients write one server name, it now warns: <target>: two ingredients write the MCP server "<name>" into <file>: <a> and <b> (last wins). This mirrors the existing file-collision warning. Before this change the clash could not happen: the two names differed, so 0.2.1 wrote both servers.

Emitted bytes and the oracle

This changes emitted bytes for existing targets, but only for MCP variants:

  • Non-variant bytes did not move. For an ingredient that is not a variant, outName(m) === m.name, and the order is still resolution order. An old-versus-new comparison of plan() and status() on 8 synthetic Forges, across both targets, gave identical bytes and key order. The Forges covered several servers, recipe order and extends, names such as constructor, toString, 2 and 10, per-target scoping, and CRLF + BOM. The golden workspace acme-portal, which includes .mcp.json and .kiro/settings/mcp.json, passed with no regeneration.
  • Which workspaces see update: only those that sync an MCP variant.
    • A .mcp.json that 0.2.1 wrote with "<name>--<profile>" becomes update. The next sync rewrites it under the original name, and it is unchanged after that.
    • A workspace whose own .mcp.json was reported as collision becomes adopt.
  • The oracle suite was skipped (no fixture available). It also could not cover this path: it imports a single workspace into an empty Forge, which never produces a variant (as:).

Upgrade notes

  • Re-importing a workspace into a Forge built before 0.2.1 now recovers its .mcp.json as well (adopt). In 0.2.1 only the Forge side was repaired.
  • If a recipe still holds both mcp/<name> and mcp/<name>--<profile>, which can happen when the importer merged an existing suffixed recipe, sync now warns about the duplicate server name instead of writing both. Remove the stale mcp/<name> reference from that recipe.

Test plan

  • npm run typecheck: exit 0

  • npm test: 294 passed / 27 skipped

  • New tests failed for the right reason before the fix, and were re-checked against c410aee:

    • both emitters wrote srv--acme;
    • no warning was emitted;
    • the end-to-end import a → import b → status b reported .mcp.json as collision.

    Now: srv, the warning is emitted, and adopt.

  • Old/new byte comparison for non-variant MCP output: identical on 8 synthetic Forges, both targets.

  • Golden workspaces (test/golden.test.ts, including acme-portal's MCP files) and the golden unify Forge passed with no regeneration.

  • Oracle suite: skipped, no fixture available. It cannot reach the variant path (see above).

  • Linux CI

Both emitters keyed the MCP file by the ingredient name, so an MCP variant, which
import creates since 0.2.1, was written as "srv--b" and the workspace's own file
read as a collision. Two ingredients writing one server name now warn.
0.2.2: patch, for the MCP emitter fix.
@llima
llima merged commit 3faf5e9 into main Sep 21, 2026
8 checks passed
@llima
llima deleted the fix/mcp-variant-server-name branch September 21, 2026 21:49
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.

1 participant