Chat
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data โ all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v1344View latest version
The affordance manager was previously being created before MCP clients were fully connected, leading to potential race conditions and multiple instances being created. This has been fixed to ensure:
- Single Instance: Only one affordance manager instance is created
- Proper Timing: Creation happens only after MCP clients are connected (or when no MCP servers are configured)
- Reliable Restoration: Persistent affordances are restored only when the system is ready
Before:
- Created affordance manager when
clientPool
existed (regardless of connection status) - Used timeout-based restoration (unreliable)
- Could create multiple instances
After:
- Creates affordance manager only when:
- No existing instance exists
- Client pool is available
- Either MCP clients are connected OR no MCP servers are configured (offline usage)
- Restoration happens immediately when conditions are met (no timeout)
- Proper cleanup on unmount
Client Tools:
- All affordance tool handlers now provide clear error messages when the manager isn't ready
- Consistent error message: "AffordanceManager is not available. Please wait for the system to initialize."
- Removed unnecessary MCP client pool checks (affordance manager handles this internally)
Affordance Manager:
- Better logging of initialization state
- Graceful handling when MCP clients aren't available
- Clear error messages when components can't be loaded
Added to shared/types.ts:
declare global {
interface Window {
mcpClientPool?: any;
affordanceManager?: any;
}
}
1. App starts โ MCP clients begin connecting
2. useMCPClients hook manages connection lifecycle
3. When clients connect (or no servers configured):
โ AffordanceManager is created (once)
โ Manager is made globally available
โ Persistent affordances are restored
4. On unmount:
โ Manager cleanup is called
โ Global reference is cleared
- Reliable Startup: Affordances always work when the system is ready
- No Race Conditions: Components load only when dependencies are available
- Better Error Messages: Clear feedback when system isn't ready
- Predictable Lifecycle: Manager creation follows clear rules
- Single Source of Truth: One manager instance per app lifecycle
- Clean Separation: MCP connection logic separate from affordance logic
- Clear Interface: Tools provide helpful error messages when not ready
- Consistent Behavior: All affordance operations work the same way
- Reliable State: No confusion about whether the system is ready
- If affordance tools return "not available" errors, wait for system initialization
- Use
list_affordances
to check if the system is ready - Persistent affordances will be automatically restored when ready
- Don't create additional AffordanceManager instances
- Use the global
window.affordanceManager
reference if needed - Manager will be
null
until system is ready
- No MCP Clients: Manager still works for local components
- MCP Connection Failures: Manager logs warnings but continues
- Component Load Failures: Clear error messages with available methods
- Premature Tool Calls: Helpful "wait for initialization" messages
- Test with no MCP servers configured (offline mode)
- Test with MCP servers that fail to connect
- Test rapid component attachment/detachment
- Test page refresh with persistent affordances
- Test cleanup on navigation away from app
This implementation ensures the affordance system is robust, predictable, and provides clear feedback to both users and assistants about its readiness state.