@verygoodplugins/mcp-evernote
v2.0.0
Published
MCP server for Evernote integration with note management and synchronization
Readme
MCP Evernote Server
A Model Context Protocol (MCP) server that provides seamless integration with Evernote for note management, organization, and knowledge capture. Works with both Claude Code and Claude Desktop.
⚠️ No API Key? Use Browser Cookie Auth
Evernote stopped issuing new developer API keys. If you are a new user and cannot obtain a Consumer Key/Secret, skip the standard OAuth setup and use the cookie-based authentication method instead — no API key required.
Installation Requirements
Node.js
Supported Node.js: >=20.16.0 <21 or >=22.3.0. In practice that means
Node 20.16+, 22.3+, 24, or newer — the two gaps are Node 21.x and Node
22.0–22.2. This is not an arbitrary floor: it mirrors the engines range that
the PDF attachment extraction path (pdf-parse, and its pdfjs-dist
transitive dependency) actually declares, and the range is genuinely disjoint.
Check with node --version. On Node 18 or 21, or on 22.0–22.2, upgrade before
installing — Node 21 reached end-of-life in June 2024, and 22.3+ supersedes the
early 22 patches.
Upgrading from 1.x? 2.0.0 raises the Node requirement from 18.18.0 and changes
evernote_get_resourceto return extracted text by default instead of binary data. The tool surface was also consolidated from 27 tools to 15 — the retired names still work as deprecated aliases, so existing calls keep running. See MIGRATION.md.
For Claude Desktop Users:
- OAuth Authentication Required: Yes, run the auth command once (prompts for API keys)
- Repository Download: No, you can use npx directly from npm
- API Credentials: The auth script will prompt you for your Evernote API keys
- Simple Setup: Just one command to authenticate and configure
For Claude Code Users:
- OAuth Authentication: Handled automatically via
/mcpcommand - Repository Download: Not required
- Setup: Single command installation
Current Status
✅ Working Features
- 🔐 OAuth Authentication - Interactive setup for Claude Desktop, automatic for Claude Code
- 📝 Note Operations
- Create notes with plain text or markdown content
- Read and retrieve note contents
- Update existing notes
- Delete notes
- Automatic Markdown ↔ ENML conversion (GFM + local attachments)
- 📚 Notebook Management
- List all notebooks
- Create new notebooks
- Organize with stacks
- 🏷️ Tag System
- List all tags
- Create new tags
- Hierarchical tag support
- 🔍 Advanced Search - Full Evernote search syntax support
- 👤 User Info - Get account details and quota usage
- 🤖 Smart Setup - Interactive credential prompts and environment detection
Quick Start
Installation Methods
Option 1: Using NPX (No Installation Required)
The simplest way - no need to install anything globally:
# For Claude Desktop - Run authentication
npx -y -p @verygoodplugins/mcp-evernote mcp-evernote-auth
# For Claude Code - Just add the server
claude mcp add evernote "npx -y -p @verygoodplugins/mcp-evernote mcp-evernote"Change Notifications
Polling for Changes
The server can poll Evernote for changes and send webhook notifications when notes are created, updated, or deleted.
Configuration
# Enable auto-start polling (default: false)
EVERNOTE_POLLING_ENABLED=true
# Poll interval in milliseconds (default: 3600000 = 1 hour, min: 900000 = 15 min)
EVERNOTE_POLL_INTERVAL=3600000
# Webhook URL to receive change notifications
EVERNOTE_WEBHOOK_URL=https://your-endpoint.com/webhooks/evernoteWebhook Payload
When changes are detected, a POST request is sent to your webhook URL:
{
"source": "mcp-evernote",
"timestamp": "2025-12-15T10:30:00.000Z",
"changes": [
{
"type": "note_created",
"guid": "abc123...",
"title": "My New Note",
"notebookGuid": "def456...",
"timestamp": "2025-12-15T10:29:55.000Z"
}
]
}Manual Control
Use the evernote_polling tool to control polling:
polling({action:"start"})- Start polling manuallypolling({action:"stop"})- Stop pollingpolling({action:"poll"})- Check for changes immediatelypolling({action:"status"})- Get polling configuration and status
Evernote Webhooks (Real-time)
For real-time notifications, Evernote supports webhooks but requires manual registration:
Email
[email protected]with:- Your Consumer Key
- Webhook URL endpoint
- Any filters (optional)
They'll configure your webhook to receive HTTP GET requests on note create/update events.
Option 2: Global Installation
Install once, use anywhere:
# Install globally
npm install -g @verygoodplugins/mcp-evernote
# For Claude Desktop - Run authentication
mcp-evernote-auth
# For Claude Code - Add the server
claude mcp add evernote "mcp-evernote"Option 3: Local Development
For contributing or customization:
# Clone and install
git clone https://github.com/verygoodplugins/mcp-evernote.git
cd mcp-evernote
npm install
# Run setup wizard
npm run setupConfiguration
1. Get Evernote API Credentials
Note: Evernote has stopped issuing new developer API keys to new applicants. If you are a new user, skip this section and use the cookie-based authentication method instead.
- Visit Evernote Developers
- Create a new application
- Copy your Consumer Key and Consumer Secret
2. Authentication Options
Interactive Setup (Recommended)
The auth script will prompt you for credentials if not found:
# Run authentication - prompts for API keys if needed
npx -p @verygoodplugins/mcp-evernote mcp-evernote-authEnvironment Variables (Optional)
For automation, you can set credentials via environment variables:
# Create .env file (optional)
EVERNOTE_CONSUMER_KEY=your-consumer-key
EVERNOTE_CONSUMER_SECRET=your-consumer-secret
EVERNOTE_ENVIRONMENT=production # or 'sandbox'
OAUTH_CALLBACK_PORT=3000 # Default: 3000
# Polling configuration (optional)
EVERNOTE_POLLING_ENABLED=true # Auto-start polling
EVERNOTE_POLL_INTERVAL=3600000 # 1 hour (min: 900000 = 15 min)
EVERNOTE_WEBHOOK_URL=https://your-endpoint.com/webhooks/evernote # Webhook for change notifications
# Rate-limit transport (optional)
EVERNOTE_MAX_CONCURRENCY=3 # Max simultaneous NoteStore RPCs (default: 3)
EVERNOTE_RATE_LIMIT_AUTO_RETRY_SECONDS=15 # Auto-retry a rate-limited call once if the wait is <= this many seconds; 0 = off
EVERNOTE_MAX_RESPONSE_CHARS=60000 # Total note-body chars per multi-note response; bodies past this are dropped with truncated:true
# Note body cache (optional)
EVERNOTE_NOTE_CACHE_SIZE=200 # Max notes held in the USN-keyed body cache; 0 disables
EVERNOTE_NOTE_CACHE_SYNC_TTL_MS=30000 # How long a getSyncState result is trusted before re-checking for external editsOn the hourly rate limit, tool errors return JSON with error: "rate_limited"
and retryAfterSeconds (Evernote's exact backoff window). Bounding concurrency
smooths bursts but cannot restore quota — the quota is a per-token hourly call
count, so the durable fixes are fewer calls and honoring the backoff.
Re-reading the same notes is served from an in-memory, USN-keyed body cache
instead of re-spending getNote calls — the direct fix for the hourly limit
tripping on repeat corpus reads. Notes you edit through this server are evicted
immediately; edits made elsewhere are picked up within
EVERNOTE_NOTE_CACHE_SYNC_TTL_MS via a sync-state probe. Extracted OCR /
attachment text is always re-read live, never cached.
3. Configure Your Client
Quick Setup (Using NPX)
claude mcp add evernote "npx -y -p @verygoodplugins/mcp-evernote -c mcp-evernote" \
--env EVERNOTE_CONSUMER_KEY=your-key \
--env EVERNOTE_CONSUMER_SECRET=your-secretOAuth Authentication
- In Claude Code, type
/mcp - Select "Evernote"
- Choose "Authenticate"
- Follow the browser OAuth flow
- Tokens are stored and refreshed automatically by Claude Code
Note: Claude Code handles OAuth automatically - no manual token management needed!
Step 1: Authenticate
Using NPX (no installation required):
npx -y -p @verygoodplugins/mcp-evernote mcp-evernote-authThe auth script will:
- Prompt for your API credentials (if not in environment)
- Open your browser for OAuth authentication
- Save a compatible token file to
.evernote-token.json - Display the access token so you can use
EVERNOTE_ACCESS_TOKENinstead
Or if installed globally:
mcp-evernote-authStep 2: Add to Configuration
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"evernote": {
"command": "npx",
"args": ["-y", "-p", "@verygoodplugins/mcp-evernote", "-c", "mcp-evernote"],
"env": {
"EVERNOTE_CONSUMER_KEY": "your-consumer-key",
"EVERNOTE_CONSUMER_SECRET": "your-consumer-secret",
"EVERNOTE_ACCESS_TOKEN": "your-access-token",
"EVERNOTE_ENVIRONMENT": "production"
}
}
}
}Or if installed globally:
{
"mcpServers": {
"evernote": {
"command": "mcp-evernote",
"env": {
"EVERNOTE_CONSUMER_KEY": "your-consumer-key",
"EVERNOTE_CONSUMER_SECRET": "your-consumer-secret"
}
}
}
}Cookie-Based Authentication (No API Key Needed)
Since Evernote stopped issuing developer API keys to new applicants, new users can authenticate using the clipper-sso browser cookie from the Evernote web UI. This cookie carries the same format as a developer-issued access token and works directly as EVERNOTE_ACCESS_TOKEN — no Consumer Key or Consumer Secret required.
Security warning: Treat this value like a password. Anyone with it can access your Evernote account. Never commit it to git, paste it into chat logs, or share it publicly.
Credit: Discovered by community member @tdrayson. (Issue #49)
Step 1: Extract the Cookie
- Log in to www.evernote.com in your browser
- Open DevTools: F12 (Windows/Linux) or Cmd+Option+I (Mac)
- Navigate to the Application tab → Cookies →
www.evernote.com - Find the cookie named
clipper-sso - Copy its Value — it looks like:
S=s101:U=XXX:XXXXX:C=XXXX:P=XXX:A=en-chrome-clipper-xauth-new:V=2:H=XXXXX
Step 2: Configure Your Client
Claude Code:
claude mcp add evernote "npx -y -p @verygoodplugins/mcp-evernote -c mcp-evernote" \
--env EVERNOTE_ACCESS_TOKEN="S=s101:U=XXX:..."Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json on macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"evernote": {
"command": "npx",
"args": ["-y", "-p", "@verygoodplugins/mcp-evernote", "-c", "mcp-evernote"],
"env": {
"EVERNOTE_ACCESS_TOKEN": "S=s101:U=XXX:..."
}
}
}
}Note:
EVERNOTE_NOTESTORE_URLis not required when using the cookie token — the server fetches it automatically at startup.
Caveats
- Token expiry: The
clipper-ssotoken typically expires after roughly one year, or when you explicitly log out of Evernote in your browser. When it expires, log back in to www.evernote.com, re-extract the cookie, and updateEVERNOTE_ACCESS_TOKEN. - Browser session: The cookie is tied to your browser login session. Logging out of the Evernote web app will invalidate the token.
- Production only: This uses your live Evernote account. There is no sandbox equivalent for this method.
Authentication Methods
Recommended for new users: Cookie-Based Authentication (No API Key Needed).
1. Claude Code (Automatic)
Claude Code handles OAuth automatically via the /mcp command. Tokens are managed by Claude Code.
2. Claude Desktop (Manual)
Run npx -y -p @verygoodplugins/mcp-evernote mcp-evernote-auth to authenticate via browser. The script saves .evernote-token.json for compatibility and also prints a token you can set as EVERNOTE_ACCESS_TOKEN.
3. Environment Variables (CI/CD)
EVERNOTE_ACCESS_TOKEN=your-token
EVERNOTE_NOTESTORE_URL=your-notestore-url
EVERNOTE_ALLOWED_FILE_ROOTS=/Users/you/Documents:/Users/you/Projects4. Direct Token (Advanced)
{
"env": {
"EVERNOTE_ACCESS_TOKEN": "your-access-token",
"EVERNOTE_NOTESTORE_URL": "your-notestore-url"
}
}Available Tools
The server exposes 15 tools (consolidated from 27). Retired tool names still
work as deprecated aliases and can be re-listed with EVERNOTE_LEGACY_TOOLS=true
— see MIGRATION.md for the full old→new mapping. Highlights:
get_resource({guid, as}) projects an attachment (text/binary/recognition/metadata);
list_notebooks/list_tags return one entity when passed a name/guid;
update_note takes replacements[] for patch-style edits; and the polling
and connection tools dispatch on an action.
Markdown Support
This server automatically converts between Markdown and Evernote's ENML format:
- Create/update: Markdown input is rendered to ENML-safe HTML inside
<en-note>.- GFM task lists
- [ ]map to Evernote checkboxes<en-todo/>. - Checked tasks
- [x]map to<en-todo checked="true"/>.
- GFM task lists
- Local Markdown images/files (
orfile://...) are uploaded as Evernote resources automatically.
- Local Markdown images/files (
- Existing attachments are preserved by referencing
evernote-resource:<hash>in Markdown.
- Existing attachments are preserved by referencing
- Remote
http(s)images remain links (download locally if you want them embedded).
- Remote
- Common Markdown elements (headings, lists, code blocks, tables, emphasis, links) are preserved.
- Retrieve: ENML content is converted back to Markdown (GFM), including task lists and attachments.
- Embedded images become
and other files become[file](evernote-resource:<hash>)so you can round-trip them safely.
- Embedded images become
Limitations:
- Remote URLs are not fetched automatically; save them locally and reference the file to embed.
- Keep the
evernote-resource:<hash>references in Markdown if you want existing attachments to survive edits. - Some exotic HTML not supported by ENML will be sanitized/removed.
Note Operations
evernote_create_note
Create a new note in Evernote.
Parameters:
title(required): Note titlecontent(required): Note content (plain text or markdown)notebookName(optional): Target notebook nametags(optional): Array of tag names
Example:
Create a note titled "Meeting Notes" with content "Discussed Q4 planning" in notebook "Work" with tags ["meetings", "planning"]evernote_search_notes
Search for notes using Evernote's search syntax. Returns note metadata plus totalNotes; page with offset/nextOffset.
Parameters:
query(required): Search query (use"*"to match all notes)notebookName(optional): Limit to specific notebookmaxResults(optional): Results per page (default: 20, max: 100; capped at 25 whenincludeContentis true)offset(optional): Result offset for paging (default: 0)includeContent(optional): Include each note's full body incontent, one API call per note (default: false)format(optional): Body projection whenincludeContentis true —markdown(default),text, orenmlincludePreview(optional): Include a ~300-char plain-text preview per note (ignored whenincludeContentis true)
Export a whole notebook as text without a dedicated tool: query: "*", set notebookName + includeContent, and page with offset until hasMore is false.
Example:
Search for notes containing "project roadmap" in the "Work" notebookevernote_get_note
Retrieve one note (full detail) or a batch of up to 25 (body-focused).
Parameters: provide exactly one of guid or guids.
guid: single note GUID — full detail, including PDF/image-OCR attachment textguids: array of up to 25 GUIDs — metadata +contentonly (no attachment text; use a singleguidfor that). Returns{ notes, failed?, aborted? }; on a mid-batch rate limit it stops with partial results plus the guids left to resume.format(optional): body projection —markdown(default),text, orenmlincludeContent(optional): include note content (default: true)includeAttachmentText(optional, single-note only): extract PDF/OCR attachment text (default: true)
Returned Markdown represents embedded resources with
evernote-resource:<hash>URLs. Leave those references intact so attachments stay linked when you edit the note.
evernote_update_note
Update an existing note. Two mutually exclusive modes:
Full-update mode parameters:
guid(required): Note GUIDtitle(optional): New titlecontent(optional): New content (Markdown supported)notebookName(optional): Move the note to this notebooktags(optional): New tags (replaces existing)
Patch mode parameter (replaces the old evernote_patch_note):
replacements(optional): Array of{find, replace, replaceAll?}find-and-replace edits applied to the note body, preserving title, tags, notebook, and attachments. Cannot be combined with the full-update fields above.
evernote_delete_note
Delete a note.
Parameters:
guid(required): Note GUID
Notebook Operations
evernote_list_notebooks
List all notebooks in your account, or get one notebook's full detail by passing
its name or guid (absorbs the old evernote_get_notebook).
evernote_create_notebook
Create a new notebook.
Parameters:
name(required): Notebook namestack(optional): Stack name for organization
evernote_update_notebook
Rename a notebook or move it between stacks.
Parameters:
guid(required): Notebook GUIDname(optional): New notebook namestack(optional): Stack name — pass an empty string to remove it from its stack
Tag Operations
evernote_list_tags
List all tags in your account, or get one tag's full detail by passing its
name or guid (absorbs the old evernote_get_tag).
evernote_create_tag
Create a new tag.
Parameters:
name(required): Tag nameparentTagName(optional): Parent tag for hierarchy
evernote_update_tag
Rename a tag or re-parent it.
Parameters:
guid(required): Tag GUIDname(optional): New tag nameparentTagName(optional): Parent tag name — pass an empty string to remove the parent
Attachments & Resources
evernote_get_resource
Read one attachment, projected through one of four views.
⚠️ Breaking change in 2.0.0. This tool used to return base64 binary data by default. It now returns extracted text by default. Pass
as: "binary"to get the old behavior.
Parameters:
guid(required): Resource GUID (from a note'sresources[], viaevernote_get_note)as(optional, default"text"): How to project the attachment"text"— extracted text. PDFs go through the text layer, falling back to Evernote's OCR data for scanned documents; images use OCR."binary"— base64-encoded file body."recognition"— raw Evernote OCR recognition data."metadata"— filename, MIME type, size, hash, andhasRecognition.
includeData(optional, deprecated):truemaps toas:"binary",falsetoas:"metadata".
There is no separate tool to list a note's attachments — evernote_get_note
returns them in resources[].
Example:
Get the text of the PDF attached to that invoice noteevernote_add_resource_to_note
Attach a local file to an existing note.
Parameters:
noteGuid(required): Target note GUIDfilePath(required): Path to the local file. Must sit under an allowed root — seeEVERNOTE_ALLOWED_FILE_ROOTS(defaults to your home directory and the current working directory).filename(optional): Override the attachment's display name
Connection & Account
evernote_connection
Manage the Evernote connection and account. Dispatches on action
(replaces the old health_check, get_user_info, reconnect, revoke_auth):
action:"status"— health/diagnostic check (server + auth state). Passverbose:truefor detailed diagnostics.action:"user"— current user information and quota usage.action:"reconnect"— force reconnection (useful on "Not connected" errors).action:"revoke"— revoke the stored authentication token.
Example:
Check Evernote connection health with verbose detailsPolling Operations
evernote_polling
Manage background polling for changes (detected changes are sent to the
configured webhook). Dispatches on action (replaces the old start_polling,
stop_polling, poll_now, polling_status):
action:"start"— begin polling on the configured interval.action:"stop"— halt polling.action:"poll"— check for changes immediately; returns detected changes.action:"status"— current polling configuration and state (running, interval, webhook URL, last poll time, error count).
Example:
Start polling for Evernote changesSearch Syntax
Evernote supports advanced search operators:
intitle:keyword- Search in titlesnotebook:name- Search in specific notebooktag:tagname- Search by tagcreated:20240101- Search by creation dateupdated:day-1- Recently updated notesresource:image/*- Notes with imagestodo:true- Notes with checkboxes-tag:archive- Exclude archived notes
Integration with Claude Automation Hub
This MCP server works seamlessly with the Claude Automation Hub for workflow automation:
// Example workflow tool
export default {
name: 'capture-idea',
description: 'Capture an idea to Evernote',
handler: async ({ idea, category }) => {
// The MCP server handles the Evernote integration
return {
tool: 'evernote_create_note',
args: {
title: `Idea: ${new Date().toISOString().split('T')[0]}`,
content: idea,
notebookName: 'Ideas',
tags: [category, 'automated']
}
};
}
};Memory Service Integration
To enable synchronization with MCP memory service:
- Set the memory service URL in your environment:
MCP_MEMORY_SERVICE_URL=http://localhost:8765- Use the sync tools to persist important notes to memory:
Sync my "Important Concepts" notebook to memory for long-term retentionConnection Resilience
The server includes automatic recovery from connection issues:
Automatic Features
- Auto-retry: Failed connections automatically retry after 30 seconds
- Token validation: Expired tokens are detected proactively
- Graceful degradation: Server stays alive during failures
- Clear error messages: Actionable feedback on connection issues
"Not Connected" Errors
If you see "Not connected" errors, the server will usually recover automatically. You can also:
Try the reconnect tool (fastest):
Reconnect to EvernoteCheck server health:
Check Evernote connection health with verbose detailsRe-authenticate if needed:
- Claude Code:
/mcp→ Evernote → Authenticate - Claude Desktop:
npx -p @verygoodplugins/mcp-evernote mcp-evernote-auth
- Claude Code:
For detailed information about connection issues and recovery, see CONNECTION_TROUBLESHOOTING.md.
Troubleshooting
Authentication Issues
"Authentication required" error in Claude Desktop
This means you haven't authenticated yet. Run the authentication script:
npx -p @verygoodplugins/mcp-evernote mcp-evernote-authOr if installed globally:
mcp-evernote-authOAuth callback fails
If the OAuth callback doesn't work:
- Make sure port 3000 is available (or set
OAUTH_CALLBACK_PORTin.env) - Check your firewall settings
- Try using a different browser
Token expired
If your token expires, the server will now detect this automatically and prompt you to re-authenticate:
- In Claude Code: Use
/mcpcommand to re-authenticate - In Claude Desktop: Run
npx -p @verygoodplugins/mcp-evernote mcp-evernote-auth
Or use the reconnect tool to force immediate retry:
Reconnect to EvernoteConnection Errors
The server now handles most connection errors automatically:
- Transient failures: Auto-retry after 30 seconds
- Token expiry: Clear error message with re-auth instructions
- Network issues: Server stays alive and retries
If issues persist:
- Check your API credentials are correct
- Verify you're using the right environment (sandbox vs production)
- See CONNECTION_TROUBLESHOOTING.md for detailed guidance
Rate Limiting
Evernote API has rate limits. If you encounter limits:
- Reduce the frequency of requests
- Use batch operations where possible
- Implement caching for frequently accessed data
Development
Building from Source
npm install
npm run buildRunning in Development Mode
npm run devTesting
npm testLinting
npm run lint
npm run formatSecurity
- Token lookup prefers
EVERNOTE_ACCESS_TOKEN, then Claude Code OAuth env, then.evernote-token.json - Never commit token files to version control
- Use environment variables for sensitive configuration
- Local file attachments are restricted to
EVERNOTE_ALLOWED_FILE_ROOTS; by default this is your home directory and the current working directory - Tokens expire after one year by default
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request against
main
License
GPL-3.0 - See LICENSE file for details.
Support
- Issues: GitHub Issues
Acknowledgments
- Built with Model Context Protocol SDK
- Powered by Evernote API
- Part of the Very Good Plugins ecosystem
Roadmap
Near Term
- [ ] Tag Management - Add/remove tags from existing notes
- [x] ENML ↔ Markdown Converter - Bidirectional conversion between Evernote's ENML format and Markdown
- [ ] Real-time Sync Hooks - Detect changes made via Evernote desktop/mobile apps
- [ ] Database Monitoring - Watch Evernote DB service for live updates
Future Enhancements
- [ ] Web clipper functionality
- [ ] Rich text editing support
- [ ] File attachment handling
- [ ] Shared notebook support
- [ ] Business account features
- [ ] Template system
- [ ] Bulk operations
- [ ] Export/Import tools
- [ ] Advanced filtering options
- [ ] Reminder management
