modelcontextprotocol / modelcontextprotocol/ext-apps
Proposal: Slot-based updateModelContext() for independent context channels
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 387
- Avg merge
- 3h 21m
- Merged PRs (30d)
- 6
Description
Problem
updateModelContext() is replacement-based — each call overwrites all previous context. This forces developers to re-bundle all context dimensions into every single update, even when only one dimension changed.
In practice, an MCP App maintains several independent context channels:
| Channel | Update frequency | Content |
|---|---|---|
| Current state | On every edit (debounced) | Full artifact code/data |
| Selection | On selection change (debounced) | Which elements the user is pointing at |
| Change history | Accumulated over time | Semantic deltas (rename, add, delete) |
| Metadata | Rarely | Diagram type, view mode, etc. |
Today, updating selection requires re-sending the full artifact code + change history + metadata, because any updateModelContext() call replaces everything. This creates:
- Redundant data transmission — re-sending unchanged state on every update
- Timing coupling — all context dimensions must be synchronized at the same debounce interval
- Code complexity — developers must maintain a "context assembler" that merges all dimensions before every update
Proposal
Support named slots that update independently:
// Each slot is independently replaceable
app.updateModelContext({ content: [...] }, { slot: "state" }); // current code
app.updateModelContext({ content: [...] }, { slot: "selection" }); // selected elements
app.updateModelContext({ content: [...] }, { slot: "history" }); // change log
// Updating one slot does NOT affect other slots
// Model sees the merged result of all slots
Semantics
- Each slot is independently replacement-based (updating
"selection"only replaces the previous"selection"content) - The model sees the concatenation of all active slots (ordering: by slot creation time, or alphabetical, or developer-specified priority)
- A call without
slotbehaves as today (replaces everything) for backward compatibility - Clearing a slot:
app.updateModelContext({ content: [] }, { slot: "selection" })orapp.clearModelContext({ slot: "selection" })
Alternative: Append mode
A simpler variant would be append-mode:
app.updateModelContext({ content: [...] }, { mode: "append" });
This is less flexible (can't independently update/clear specific dimensions) but simpler to implement.
Real-world context
We build MCP Apps (Mermaid diagrams, PlantUML, Music composer) and documented our context design patterns. The key insight: effective AI context has four independent layers (current state, user focus/selection, change history, user intent), each with different update frequencies and lifecycles. The current single-replacement API forces them into one monolithic blob.
This is especially painful combined with debouncing — selection changes (1.5s debounce) and code edits (500ms debounce) happen at different rates, but both must trigger a full context rebuild because any update overwrites the other.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the TypeScript SDK's updateModelContext() entry point and trace how replacement-based context is represented and exposed. Compare the proposed independent slot, clearing, ordering, and no-slot backward-compatibility semantics, then define acceptance checks showing that updating one slot preserves the others.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100