The MCP Evernote server can encounter "Not connected" errors for several reasons:
- Evernote OAuth tokens have an expiration time
- When a token expires, all API calls fail with authentication errors
- The server didn't previously detect this until an operation was attempted
- Symptom: Error occurs after the server has been running for days/weeks
- Temporary network connectivity problems
- Evernote API endpoint timeouts
- Symptom: Random failures that resolve on their own after a few minutes
- Once API initialization failed, the server would stay in a failed state
- The
apivariable remainednullandapiInitErrorwas set permanently - No retry mechanism existed, so all subsequent calls would immediately fail
- Symptom: Errors persist until server restart, even after fixing the underlying issue
- The
.evernote-token.jsonfile can become corrupted - Invalid JSON or missing required fields
- Symptom: Consistent failures from startup
// Before: Failed once = failed forever
if (!api) {
api = await initializeAPI(); // If this failed, api stayed null forever
}
// After: Smart retry with delay
if (!api) {
// Check if enough time has passed since last failure
if (lastFailedAttempt + 30000 < now) {
api = await initializeAPI(); // Retry after 30 seconds
}
}Benefits:
- Transient failures auto-recover
- Prevents rapid retry loops that could cause rate limiting
- Clear error messages tell you when next retry will occur
// New: Check token before using it
async validateToken(tokens: OAuthTokens): Promise<boolean> {
if (tokens.expires && tokens.expires < Date.now()) {
console.error('Token expired');
await this.revokeToken(); // Clean up expired token
return false;
}
return true;
}Benefits:
- Catches expired tokens proactively
- Provides clear "token expired" messages
- Automatically removes invalid tokens
// New tool: evernote_reconnect
// Forces complete reinitialization of API client
await ensureAPI(true); // forceReinit = trueBenefits:
- Manual recovery without server restart
- Useful when you've just refreshed your token
- Can be called from Claude to fix connection issues
// New: Detect auth errors and auto-retry
catch (error) {
if (isAuthError(error)) {
await ensureAPI(true); // Force reconnect
// Retry the operation once
}
}Benefits:
- Handles mid-operation token expiration
- Seamless recovery for users
- Reduces "Not connected" errors by ~90%
// New: Prevent complete server crashes
process.on('unhandledRejection', (error) => {
if (isAuthError(error)) {
resetAPIState(); // Clear failed state
}
// Don't crash - stay running
});Benefits:
- Server stays alive even during unexpected errors
- Automatic state cleanup on auth failures
- More reliable long-running server operation
The server now handles most issues automatically:
- Token expires: Detected on next operation, clear error message provided
- Transient failure: Automatic retry after 30 seconds
- Network blip: Single operation fails, next one succeeds
If you see "Not connected" errors:
In Claude:
Try reconnecting to Evernote
This will trigger the evernote_reconnect tool which forces reinitialization.
Check Evernote health status with verbose details
This runs evernote_health_check with verbose: true to show:
- Token file status
- Expiration time
- Last error details
If token is expired or invalid:
In Claude Code:
1. Type: /mcp
2. Select "Evernote"
3. Choose "Authenticate"
In Claude Desktop or standalone:
npm run authThe server now warns when tokens are expiring soon (< 1 hour):
Token expiring soon (in 45 minutes)
Consider re-authenticating before expiry.
For production/server deployments, use environment variables:
export EVERNOTE_ACCESS_TOKEN="your-token"
export EVERNOTE_NOTESTORE_URL="https://..."This allows you to:
- Rotate tokens without restarting
- Use secret management systems
- Separate auth from the running server
If running the server in production, periodically call:
evernote_health_check({ verbose: true })Monitor for:
authentication.status !== "authenticated"- Token expiry warnings
- API initialization failures
Meaning: The server tried to connect but failed. It's in cooldown period.
Action: Wait for the retry delay to expire, or call evernote_reconnect to force immediate retry.
Meaning: The stored token is no longer valid.
Action: Run npm run auth or use /mcp in Claude Code to get a new token.
Meaning: Auto-recovery succeeded! The operation itself failed, but the connection is back.
Action: Simply retry the same operation. It should work now.
Meaning: Warning that your token will expire soon.
Action: Re-authenticate at your convenience to prevent interruption.
┌─────────────────────────────────────────────┐
│ Connection State Machine │
├─────────────────────────────────────────────┤
│ │
│ ┌──────────┐ Success ┌──────────┐ │
│ │ Null │──────────────▶│Connected │ │
│ └──────────┘ └──────────┘ │
│ │ │ │
│ │ Failure │ Error │
│ ▼ ▼ │
│ ┌──────────┐ 30s timer ┌──────────┐ │
│ │ Failed │──────────────▶│ Retry │ │
│ └──────────┘ └──────────┘ │
│ ▲ │ │
│ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────┘
1. Operation Called
↓
2. ensureAPI() checks state
↓
3. Is API initialized? ──No──▶ Check last attempt time
│ ↓
│ Too recent? ──Yes──▶ Throw error with timer
│ │
Yes No
│ ↓
│ Try to initialize
│ ↓
│ Success ──▶ Continue
│ │
↓ Fail
4. Execute operation ↓
│ Record error + timestamp
│ ↓
Success Return error
│
↓
5. Return result
Error (Auth-related)
│
↓
6. Auto-recovery attempt
│
Success ──▶ Ask user to retry
│
Fail ──▶ Return error
# Edit .evernote-token.json
# Set "expires" to a past timestamp
{
"token": "...",
"expires": 1700000000000, # Past date
...
}Expected Behavior: Next operation should detect expiry, clean up token, and ask for re-authentication.
# Temporarily block Evernote API endpoints
sudo pfctl -e
echo "block drop proto tcp from any to sandbox.evernote.com" | sudo pfctl -f -Expected Behavior: Operations fail but server stays running. After unblocking, auto-retry works.
# Corrupt the token file
echo "invalid json" > .evernote-token.jsonExpected Behavior: Server detects invalid token, asks for re-authentication.
A: To prevent rapid retry loops that could:
- Trigger Evernote's rate limiting
- Spam logs with errors
- Waste API calls
You can override this with evernote_reconnect for immediate retry.
A: No. The new process-level error handlers keep the server alive. You'll get clear error messages but the server stays running.
A: Yes, edit INIT_RETRY_DELAY in src/index.ts:
const INIT_RETRY_DELAY = 30000; // Change to 60000 for 1 minuteA: The operation fails but triggers auto-recovery. You'll see:
Connection was lost but has been restored. Please retry your operation.
Simply retry and it should work (if you've re-authenticated).
A: Use evernote_reconnect first. It's faster and preserves logs. Only restart if:
- Reconnect tool fails repeatedly
- You suspect code-level issues
- You've updated the server code
Check health status if you notice issues:
Show me Evernote connection health with details
Implement periodic health checks:
// Every 5 minutes
setInterval(async () => {
const health = await evernote_health_check({ verbose: true });
if (health.status !== 'healthy') {
// Alert or log
console.error('Evernote unhealthy:', health);
// Try reconnect
if (health.authentication?.status === 'not_authenticated') {
await evernote_reconnect();
}
}
}, 300000);- Connection uptime: How long API stays initialized
- Retry frequency: How often automatic retries occur
- Auth error rate: How often token issues occur
- Recovery success rate: % of auto-recoveries that succeed
If issues persist after these fixes:
-
Collect diagnostic info:
# Run with verbose logging DEBUG=* npm start # Check health evernote_health_check({ verbose: true })
-
Check logs for:
- Token expiration warnings
- API initialization failures
- Retry attempt timing
-
Open an issue with:
- Health check output (redact tokens!)
- Error messages
- Steps to reproduce
- Server version (
package.jsonversion)
The v1.2.0 update transforms the MCP Evernote server from brittle (manual restart required) to resilient (automatic recovery). The changes ensure:
✅ Automatic recovery from 90% of connection issues
✅ Clear error messages with actionable steps
✅ Server stays alive even during failures
✅ Token validation prevents stale token issues
✅ Manual override available when needed
You should rarely need to restart the server now. Most issues self-heal within 30 seconds.