agent host: derive MCP customization id from ownership instead of publication position
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Follow-up cleanup from the scoped-enablement work (#330566, #330715).
## Problem
An MCP server currently carries three identifiers, and most of the hard bugs in this area were *mapping errors between them*:
| Identifier | Value | Depends on |
| --- | --- | --- |
| `id` | `mcp-top-level:::` **or** the plugin child id | publication position |
| `name` | server name | SDK operations |
| durable enablement key | `#mcp=` or `mcpServers#` | ownership |
Publication position is decided by a startup race in `McpCustomizationController._applyOne`: if a plugin's children are already published the server is nested, otherwise it is **promoted** to a bare top-level customization, and promotion is deliberately sticky because re-parenting mid-session would orphan an id the client has already rendered.
Because position leaked into identity, the same server keyed differently depending on whether it happened to be promoted that session — so "disable azure globally" written in one session was invisible in the next. That was the original reported bug.
It is currently fixed by threading an ownership map (`mcpServerOwners` / `pluginMcpServerSources`) so the durable key is position-independent. That works, but it means correctness now *depends on every provider remembering to supply the map* — and Codex did not, which is #330715.
## Suggestion
Mint the top-level customization id **from the durable key** rather than from provider/session/name. Then:
- nested and promoted publications are the same identity **by construction**;
- the ownership map stops being load-bearing for correctness and is only needed for display grouping;
- sticky promotion stops being an invariant contributors must preserve;
- the whole "should we gate publication on plugin parsing?" question becomes a pure UX decision rather than a correctness one.
Higher risk than the other follow-ups because it touches id minting, which clients render — worth checking whether any client persists these ids. But it deletes the bug class rather than guarding it.
## Constraint
`getCustomizationEnablementKey` output must not change for existing keys, or users' stored decisions silently orphan and disabled servers come back enabled.
Contributor guide
Assessment
This issue has not been assessed yet.