Bug
mcpc connect and mcpc restart fail with ENOENT on the bridge socket when macOS Keychain access requires user password confirmation (interactive Keychain dialog).
Root cause
In dist/bridge/index.js:185-186, the bridge waits only 5 seconds for auth credentials:
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout waiting for auth credentials')), 5000);
});
await Promise.race([this.authCredentialsReceived, timeout]);
But credentials are read from macOS Keychain after the bridge starts (dist/lib/bridge-manager.js:61-72):
// 1. Bridge spawned, socket created
await waitForFile(socketPath, { timeoutMs: 5000 }); // ← bridge is ready
// 2. NOW read Keychain (triggers macOS password dialog!)
await sendAuthCredentialsToBridge(socketPath, ...);
// └── readKeychainOAuthTokenInfo() ← macOS prompt
// └── readKeychainOAuthClientInfo() ← macOS prompt
Timeline:
- Bridge starts, creates socket, starts 5s credential timer
- Main process detects socket ✓
- Main process calls
readKeychainOAuthTokenInfo() → macOS dialog appears
- User reads dialog, types password → 5-15 seconds
- Bridge 5s timer fires → bridge shuts down → socket removed
- Main process gets Keychain value, tries
connect(socket) → ENOENT
Why "Always Allow" works
When user clicks "Always Allow" in macOS Keychain dialog, node is added to the Keychain entry ACL permanently. Subsequent getPassword() calls return instantly (~1ms) with no dialog → credentials reach bridge well within 5s.
Steps to reproduce
- Clear Keychain access for
node to mcpc entries: Keychain Access.app → find mcpc entries → Get Info → Access Control → remove node
- Run
mcpc mcp.apify.com connect @session
- When macOS prompts for password, wait a few seconds before entering → ENOENT
Suggested fixes (in order of preference)
Option A: Read credentials before starting bridge (best)
Read Keychain in the main process before spawning the bridge, then pass credentials immediately after socket is ready. Zero delay.
// In startBridge():
const credentials = await readCredentialsFromKeychain(...); // ← prompts happen HERE
const bridgeProcess = spawn('node', [bridgeExecutable, ...args], ...);
await waitForFile(socketPath, { timeoutMs: 5000 });
await sendCredentialsToBridge(socketPath, credentials); // ← instant, no Keychain
Option B: Increase credential timeout
Change 5000ms to 60000ms in bridge/index.js:186. Simple but doesn't address the architectural issue.
Option C: Bridge waits indefinitely
Remove the timeout — bridge waits for credentials until main process sends them or bridge is killed.
Environment
- mcpc: 0.1.10
- OS: macOS 26.3 (arm64)
- Keychain:
@napi-rs/keyring → macOS Keychain
- Context: Claude Code plugin running mcpc commands
Updated: Original report incorrectly identified ensureBridgeReady as the cause. After deeper analysis, the actual issue is the 5s credential timeout in the bridge process vs macOS Keychain interactive prompts.
Bug
mcpc connectandmcpc restartfail withENOENTon the bridge socket when macOS Keychain access requires user password confirmation (interactive Keychain dialog).Root cause
In
dist/bridge/index.js:185-186, the bridge waits only 5 seconds for auth credentials:But credentials are read from macOS Keychain after the bridge starts (
dist/lib/bridge-manager.js:61-72):Timeline:
readKeychainOAuthTokenInfo()→ macOS dialog appearsconnect(socket)→ ENOENTWhy "Always Allow" works
When user clicks "Always Allow" in macOS Keychain dialog,
nodeis added to the Keychain entry ACL permanently. SubsequentgetPassword()calls return instantly (~1ms) with no dialog → credentials reach bridge well within 5s.Steps to reproduce
nodetomcpcentries: Keychain Access.app → findmcpcentries → Get Info → Access Control → removenodemcpc mcp.apify.com connect @sessionSuggested fixes (in order of preference)
Option A: Read credentials before starting bridge (best)
Read Keychain in the main process before spawning the bridge, then pass credentials immediately after socket is ready. Zero delay.
Option B: Increase credential timeout
Change 5000ms to 60000ms in
bridge/index.js:186. Simple but doesn't address the architectural issue.Option C: Bridge waits indefinitely
Remove the timeout — bridge waits for credentials until main process sends them or bridge is killed.
Environment
@napi-rs/keyring→ macOS KeychainUpdated: Original report incorrectly identified
ensureBridgeReadyas the cause. After deeper analysis, the actual issue is the 5s credential timeout in the bridge process vs macOS Keychain interactive prompts.