-
Notifications
You must be signed in to change notification settings - Fork 30
Description
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 promptTimeline:
- 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
nodetomcpcentries: Keychain Access.app → findmcpcentries → Get Info → Access Control → removenode - 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 KeychainOption 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.