How to Share State Between Skills Within a Claude Plugin: The Complete MCP Guide
Use the Managed-Context Provider (MCP) key-value store via mcp.set_state() and mcp.get_state() to share data between skills within the same Claude plugin instance.
Claude plugins in the anthropics/claude-plugins-community repository rely on a Managed-Context Provider (MCP) to coordinate multi-step workflows. When you need to share state between skills within a plugin, the MCP exposes a persistent, per-plugin key-value store that all skills in the same plugin instance can access during an active user session.
How the MCP State Store Works
The MCP state store acts as the single source of truth for runtime data across all skills in a plugin. According to the architecture defined in .claude-plugin/plugin.json, each plugin receives a unique namespace that automatically isolates its keys from other plugins. State persists for the duration of the user conversation and is atomically cleared when the session terminates.
Core Methods for State Management
Storing Data with set_state
To write data that subsequent skills can retrieve, invoke the asynchronous set_state method on the MCP object. This pattern appears in tres-finance-plugin/skills/tres-rollup-rules/SKILL.md for sharing sub-transaction identifiers across workflow steps:
await mcp.set_state("my_key", value)
Retrieving Data with get_state
Skills read shared state using the get_state method. As implemented in tres-finance-plugin/skills/tres-ledger-link/SKILL.md, subsequent skills access wallet, asset, or status information stored by earlier steps:
value = await mcp.get_state("my_key")
Updating and Clearing State
When workflows progress, skills can mutate existing keys or remove them entirely. The MCP interface supports both overwrite operations and explicit deletion:
await mcp.set_state("my_key", new_value) # Atomic update
await mcp.delete_state("my_key") # Complete removal
Implementation Examples from the Repository
Sharing Report IDs Across Finance Skills
In tres-finance-plugin/skills/tres-rollup-rules/SKILL.md, a "Create Report" skill persists transaction identifiers for later retrieval. The Python implementation follows this pattern:
# skill: tres-report-create/SKILL.py
async def run(mcp, input):
# ... create report, get report_id ...
await mcp.set_state("latest_report_id", report_id)
return f"Report created with ID {report_id}."
A subsequent analyzer skill retrieves this identifier to fetch the correct resource:
# skill: tres-report-analyzer/scripts/analyze_report.py
async def run(mcp, input):
report_id = await mcp.get_state("latest_report_id")
if not report_id:
return "No report has been created yet."
# ... fetch and analyze report using report_id ...
return f"Analysis for report {report_id} complete."
Persisting User Selections
The tres-ledger-link skill demonstrates sharing user-selected wallets across multiple finance operations. One skill stores the selection:
await mcp.set_state("selected_wallet", wallet_id)
Downstream skills access this value without re-prompting the user:
wallet_id = await mcp.get_state("selected_wallet")
Managing Design Workflows
The quickdesign/skills/quickdesign/SKILL.md implementation persists job IDs and result URLs in MCP so that subsequent steps in the design generation workflow can retrieve processing status without maintaining external databases.
Architectural Guarantees and Limitations
Session-Scoped Persistence
State stored via MCP exists only during the active user conversation. When a user abandons the chat or the session expires, the platform automatically purges all MCP entries for that plugin instance, preventing data leakage between unrelated interactions.
Atomic Operations and Namespace Isolation
All MCP operations are atomic—skills always observe the most recent value written by any concurrent skill. Namespace isolation ensures that keys in one plugin cannot collide with keys in another, even if both plugins use identical key names like "user_id" or "config".
Versioning Strategies for Complex Data
For workflows requiring historical tracking (such as generating multiple reports), store lists under single keys or implement versioned key patterns:
# Append to history
history = await mcp.get_state("report_history") or []
history.append(new_report_id)
await mcp.set_state("report_history", history)
Alternatively, use prefixed keys like report_1, report_2 to maintain discrete snapshots without overwriting previous state.
Summary
- Use
mcp.set_state()andmcp.get_state()to share data between skills within the same Claude plugin instance. - State is scoped per-plugin via namespaces defined in
.claude-plugin/plugin.json, ensuring strict isolation between different plugins. - Session-only persistence guarantees that data exists only during the active user conversation and is automatically cleaned up afterward.
- Atomic operations ensure that all skills read the most current values without race conditions.
- Reference implementations are available in
tres-finance-plugin/skills/tres-rollup-rules/SKILL.md,tres-finance-plugin/skills/tres-ledger-link/SKILL.md, andquickdesign/skills/quickdesign/SKILL.mdwithin theanthropics/claude-plugins-communityrepository.
Frequently Asked Questions
How long does shared state persist in a Claude plugin?
Shared state persists only for the duration of the user session. When the user abandons the conversation or the session terminates, the MCP platform automatically clears all stored entries for that specific plugin instance.
Can different Claude plugins access the same MCP state?
No. MCP state is strictly isolated per-plugin. Each plugin operates within its own namespace determined by the internal identifier in the plugin manifest (.claude-plugin/plugin.json), ensuring that two different plugins cannot read or overwrite each other's data even if they use identical key names.
What data types can be stored in MCP state?
The MCP key-value store accepts standard JSON-serializable values including strings, numbers, booleans, lists, and dictionaries. For complex objects, ensure they are serializable before calling set_state(), or store unique identifiers that reference external data stores rather than the full objects themselves.
How do I handle concurrent state modifications?
MCP read and write operations are inherently atomic, meaning set_state and get_state execute without interference from other skills. However, for workflows requiring transaction-like integrity across multiple related keys, implement optimistic locking by storing version numbers alongside your data and validating them before updates.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →