Investigate re-evaluating workspace scope when the MCP client adds a working directory mid-run #416
Labels
No labels
breaking
bug
documentation
enhancement
epic
good first issue
help wanted
refactoring
resolution/duplicate
resolution/invalid
resolution/wontfix
security
severity/critical
severity/high
severity/low
severity/medium
status/abandoned
status/blocked
status/needs-decision
status/needs-info
status/needs-verification
testing
upstream
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
sixfold-space/madtea#416
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happens now
The MCP server resolves its working directory once, at launch. Everything downstream of that (in-scope vs foreign, the primary-checkout guards, the fail-closed multi-repo behaviour) is decided against that single fixed path.
Some MCP clients let you add a working directory after startup. When I do that, madtea has no idea. A repo under the newly-added directory is still classified foreign, so
branch_create,commit, andpullagainst its primary checkout are all refused, and the only way through is the worktree flow.I hit this standing up a brand-new repo. I created it, cloned it, explicitly added its directory to the running workspace so I could work in it, and madtea still (correctly, given what it knew) treated it as someone else's shared state. Paraphrasing the refusal:
The refusal is well written and the worktree flow works fine, so this is friction rather than breakage. But the mental model diverges: I had just told the client "this directory is part of my workspace", and madtea's answer was "I have never heard of it."
The mechanism that might exist
MCP has a
rootscapability. Clients declare workspace roots, and there is aroots/list_changednotification for exactly the case where that set changes at runtime. If a client advertisesrootsand sends that notification, the server could in principle re-derive scope instead of trusting a launch-time snapshot.I have not verified what clients actually send in practice, and that is most of the investigation.
What I want out of this
Not a patch yet. A decision with evidence behind it.
rootsand emitroots/list_changedwhen a directory is added? If nobody sends it, this dies here.Not in scope
Changing the worktree flow, or relaxing the foreign-primary guard for repos that were never added as roots. Both should stay exactly as they are.
The gating fact is empirical: do the MCP clients in real use advertise the
rootscapability, and do they emitroots/list_changedwhen a directory is added mid-run? If none send it, this dies there, and no design work is needed.The safety half is the open question I have to settle, and I am not settling it on argument alone: is an explicitly-added root a strong enough ownership signal to relax the foreign-primary guard for that path? My lean is yes, but opt-in only, behind a flag or config key, and only after a client is shown to send the notification. The guard has already paid for itself, so it does not get widened by default.
Next step when I pick this up: gather the client-behavior evidence first, record what each client advertises and sends, and report that before any code lands.
Decided: honor a working directory I add mid-session as in-session scope, including writes to that dir's own origin.
The agent cannot add a working directory.
/add-dir,/cd,--add-dir, andadditionalDirectoriesare all mine to run, not the agent's. Claude Code implementsroots/listand emitsroots/list_changed(since v2.1.203, and on/cdsince v2.1.246). So a root arriving viaroots/list_changedis a directory I authorized, never one the agent granted itself. Blocking writes in a directory I explicitly added defeats the purpose of/add-dir.Decision:
roots/list_changed. A directory I add is in-session scope: reads and writes to that dir's own origin, without the foreign-primary worktree-forcing block, for that session./cdviaroots/list_changed(v2.1.246+), closing the "server cannot follow the cd" gap.Trust assumption: madtea trusts the client's guarantee that roots reflect directories I granted. Claude Code enforces this - the agent cannot add a root. A client that let its agent add roots would not carry the guarantee, but the threat model already treats the client as chosen, trusted infrastructure, and these guards are accident-detectors (ADR 0007), not defenses against a compromised client, so this sits where the line already is.
This is a posture change and wants an ADR amendment (0019 / 0027). Implementation relies on the roots signal, whose successor (SEP-2322) is tracked in #428; roots is fully functional into 2027.
Recorded in the design of record: ADR 0019 and ADR 0027 amendments (2026-09-08), merged in PR #471. This issue stays open for the implementation - roots re-derivation and the operator-added-root write path.