fix(adapters): anchor emitted stdio MCP entries with AGENT_BUNDLE_PLUGIN_ROOT and restore claude cwd - #49
Merged
Conversation
…GIN_ROOT and restore claude cwd
Every adapter now injects a well-known AGENT_BUNDLE_PLUGIN_ROOT env entry
pointing at the plugin install root in its native spelling (claude
${CLAUDE_PLUGIN_ROOT}, portable ${PLUGIN_ROOT}, cursor ${CURSOR_PLUGIN_ROOT},
codex ./ against its plugin-root cwd), with user-declared keys winning, so
plugin runtimes stop fragmenting state across host launch directories on
hosts that do not anchor cwd — Claude Code silently ignores stdio cwd at
runtime. The claude adapter also stops dropping cwd for source-built servers,
emitting the documented schema-valid field again, and all adapter revisions
advance to 1.1.0 so stale artifacts revalidate as AB6010 instead of passing.
Closes #47
…CP documents and note the anchor in the root artifact contract
🦋 Changeset detectedLatest commit: a24dcf8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
This was referenced Aug 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #47
What
Every adapter now injects a well-known
AGENT_BUNDLE_PLUGIN_ROOTenvironment variable into emitted stdio MCP server entries, holding the plugin install root in the target's native spelling, and the claude adapter stops droppingcwdfor source-built servers. This hoists the consumer workaround from the movie-library port into the framework: plugin runtimes get a working-directory-independent install-root anchor on every host, including Claude Code, which silently ignores stdiocwdat runtime (anthropics/claude-code#17565, #42883, #54786).Per-adapter before/after (source-built
entry:serverdemo)claude (
.mcp.json) — before droppedcwdand emitted no env; after:{"args":["${CLAUDE_PLUGIN_ROOT}/mcp/demo.mjs"],"command":"node","cwd":"${CLAUDE_PLUGIN_ROOT}","env":{"AGENT_BUNDLE_PLUGIN_ROOT":"${CLAUDE_PLUGIN_ROOT}"},"type":"stdio"}The absolute
args[0]stays as the hedge against the upstream cwd-ignoring bugs;cwdis documented and schema-valid, so it is emitted as future-proofing and the env anchor carries the guarantee today.portable (
mcp.json) — before:cwd: "${PLUGIN_ROOT}", no env; after adds:{"env":{"AGENT_BUNDLE_PLUGIN_ROOT":"${PLUGIN_ROOT}"}}codex (
.mcp.json) — before:cwd: "./"with./-relative args, no env; after adds:{"env":{"AGENT_BUNDLE_PLUGIN_ROOT":"./"}}Codex has no path-token interpolation, so
./is only meaningful resolved against the entry's plugin-rootcwd. A codex stdio entry without a plugin-root cwd omits the anchor rather than emitting a misleading value (consistent with the existing hard diagnostics for plugin-root tokens on such entries). Source-built servers always have a plugin-root cwd, so they always carry the anchor.cursor (
mcp.json) — before: no env; after adds:{"env":{"AGENT_BUNDLE_PLUGIN_ROOT":"${CURSOR_PLUGIN_ROOT}"}}plugin (unified bundle) — reuses the three planners, so
.mcp.json,.codex-plugin/mcp.json, and.cursor-plugin/mcp.jsoneach carry their host's native anchor (pinned by a new bundle regression test).Merge semantics
withPluginRootEnvAnchorspreads declaredenventries after the injected anchor, so a user-declaredAGENT_BUNDLE_PLUGIN_ROOTkey always wins. Documented on the configenvfield, in the package README, and in the root README's artifact contract. The anchor name ships as the publicpluginRootEnvAnchorexport.Staleness
All adapter revisions advance
1.0.0→1.1.0, so artifacts built before this change revalidate as stale (AB6010, "Rebuild the artifact with the current target registry") instead of silently passing with the old emission shape. Capability tables and pinned schemas are untouched, so all pinned hashes inadapter-metadata.test.tshold; only the revision pins moved.Tests
host-adapters.test.ts: updated exact-content pins; claude source-built entries now assertcwd+ anchor (replacing the oldnot.toHaveProperty('cwd')); new regressions for user-declared-anchor-wins (codex + claude) and codex anchor omission without a plugin-root cwd.portable-adapter.test.ts,cursor-adapter.test.ts: anchor pins with native tokens.plugin-bundle.test.ts: per-host anchors pinned on all three bundle MCP documents.adapter-metadata.test.ts: revision pins1.1.0; hashes unchanged.Gates
pnpm build✓,pnpm typecheck✓,pnpm lint✓ (0 errors/warnings, 620 files)pnpm test:unit✓ (117 files, 1654 passed / 4 skipped)pnpm test:packed✓ (release-audit, packed-consumer, dev-workbench-packaging, public-api-packed, rsc-runtime-optional-packaging, packed-native-smoke, workbench packed-release e2e)Consumer note
The movie-library port (
agent-plugins/movie-library, commitaf0ab2a) works around this per-server today withenv: { MOVIE_LIBRARY_ROOT: pathTokens.pluginRoot }. That splice keeps working (user-declared keys win) but is unnecessary for new consumers: runtime code can readprocess.env.AGENT_BUNDLE_PLUGIN_ROOT(resolving it againstprocess.cwd()to absorb Codex's relative form) on every target.