Evernote MCP服务器

一个通过MCP stdio协议暴露Evernote笔记本和笔记操作的Python服务器,适用于Gemini CLI集成和开发扩展。

  • by CopyPasteFail
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 CopyPasteFail/evernote-mcp-server

使用说明

Evernote MCP服务器

evernote-mcp-server 是一个Python MCP服务器,通过MCP公开Evernote笔记本和笔记操作 stdio.

它主要是为那些想在已发布的Docker镜像中从Gemini CLI使用它的人记录的。贡献者和维护者的工作流程将在本README的后面出现,因此第一个运行路径保持简单。

概述

此服务器将Evernote操作作为MCP工具公开。当前刀具表面包括:

  • 笔记本工具: list_notebooks
  • 阅读工具: search_notes, get_note, get_note_metadata
  • 写入工具: append_to_note_plaintext, insert_into_note_plaintext, set_note_title, add_tags_by_name, move_note, create_note, delete_note

insert_into_note_plaintext 通过获取当前ENML,在可见文本锚点之前或之后插入转义的明文块,并以乐观的并发性将完整的ENML文档保存回Evernote,支持富笔记的无损中间插入。它不接受原始ENML或HTML。

开始前的重要默认设置

  • READ_ONLY=true 默认情况下,除非您明确选择加入,否则写入工具将被阻止。
  • 在正常运行时启动之前,需要一次OAuth引导才能与Evernote通信。
  • OAuth访问令牌不存储在 .env;它们保存在Evernote MCP配置目录中。
  • 仅 stdio 传输是在v0.1中实现的。 --transport sse 故意不可用。

选择安装路径

大多数人应该使用已发布的Docker路径。这是到工作的Gemini MCP服务器的最短路径,不需要克隆此存储库。

配置和身份验证模型

这些设置适用于所有运行时路径。将本节作为配置行为的规范参考。

共享先决条件

每个运行时路径都需要相同的Evernote端先决条件:

  • Evernote消费者凭证: EVERNOTE_CONSUMER_KEY 和 EVERNOTE_CONSUMER_SECRET
  • 一个支持浏览器的环境,用于在本地主机上进行一次性OAuth授权

环境变量

变量 必填 默认 用途
EVERNOTE_CONSUMER_KEY 需要 auth 无 Evernote OAuth消费者密钥
EVERNOTE_CONSUMER_SECRET 需要 auth 无 Evernote OAuth消费者秘密
EVERNOTE_SANDBOX 没有 false 使用Evernote沙箱OAuth和API端点
READ_ONLY 没有 true 除非设置为,否则阻止写入工具 false
LOG_LEVEL 没有 INFO 流程日志冗长

接受的布尔值 EVERNOTE_SANDBOX 和 READ_ONLY:

  • true / false
  • 1 / 0
  • yes / no
  • on / off

按路径配置文件位置

  • 发布的Docker路径在以下位置使用主机环境文件 ~/.config/evernote-mcp-server/evernote-mcp.env
  • 参与者本地路径使用本地存储库 .env,通常由 .env.example

保存的令牌位置和持久性

OAuth引导程序将Evernote访问令牌保存在Evernote MCP配置目录中,而不是 .env.

  • 在一台普通的本地机器上,被拯救的代币存活在 $XDG_CONFIG_HOME/evernote-mcp-server/token.json 当 XDG_CONFIG_HOME 已设置
  • 否则,它就住在 ~/.config/evernote-mcp-server/token.json
  • 在发布的Docker路径中,推荐的持久性模型是一个名为Docker的卷,挂载在 /home/appuser/.config/evernote-mcp-server

这种分离很重要,因为启动程序会从磁盘读取保存的令牌。如果令牌丢失,正常的服务器启动将失败,直到您再次运行OAuth引导程序。

快速入门:发布Docker+Gemini

这是大多数用户的推荐路径。它配置Gemini CLI以运行已发布的GHCR映像,在需要时创建持久的env文件,并为保存的OAuth状态创建Docker卷。

特定路径的先决条件

在运行安装程序之前,请确保这些本地工具可用:

  • bash
  • curl
  • docker
  • python3
  • Gemini CLI

安装Gemini MCP入口

运行发布安装程序,使用最新发布的版本配置Gemini v* 图像标签。

curl -fsSL https://raw.githubusercontent.com/CopyPasteFail/evernote-mcp-server/main/scripts/install_gemini_mcp_release.sh | bash

安装程序对此路径执行三个重要操作:

  • 配置Gemini MCP设置以使用已发布的GHCR映像
  • 创造 ~/.config/evernote-mcp-server/evernote-mcp.env 如果它不存在
  • 创建Docker卷 evernote-mcp-auth 如果它不存在

填写环境文件

在尝试OAuth引导之前,请编辑生成的env文件。至少,填写Evernote消费者凭证。离开 READ_ONLY=true 除非您有意启用写入工具。

  • 环境文件: ~/.config/evernote-mcp-server/evernote-mcp.env

运行一次性OAuth Bootstrap

填充env文件后,初始化Docker卷所有权一次,然后运行一次性OAuth引导命令。安装程序会打印带有配置的映像标签和卷的两个命令。

Docker命名的卷最初可能由root拥有,而此映像以非root身份运行 appuser。初始化卷所有权一次可以避免令牌保存失败:

docker run --rm --user root \
  -v evernote-mcp-auth:/home/appuser/.config/evernote-mcp-server \
  ghcr.io/CopyPasteFail/evernote-mcp-server:latest \
  python -c "import os; p='/home/appuser/.config/evernote-mcp-server'; os.makedirs(p, exist_ok=True); os.chown(p, 1000, 1000); os.chmod(p, 0o700)"

然后运行容器身份验证:

docker run --rm -it \
  --env-file ~/.config/evernote-mcp-server/evernote-mcp.env \
  -v evernote-mcp-auth:/home/appuser/.config/evernote-mcp-server \
  -p 8765:8765 \
  ghcr.io/CopyPasteFail/evernote-mcp-server:latest \
  python -m evernote_mcp auth \
    --listen-host 0.0.0.0 \
    --listen-port 8765 \
    --callback-url http://127.0.0.1:8765/callback

OAuth引导程序打开浏览器进行Evernote授权,然后将令牌保存到已挂载的配置卷中,以便Gemini可以在以后的运行中重用它。

为什么有效:监听器在容器内绑定(0.0.0.0:8765)而Evernote重定向到主机可见的回调URL(127.0.0.1:8765)通过已发布的Docker端口。

WSL注释:浏览器自动打开在某些环境中仍可能失败;CLI会打印授权URL,以便您可以手动打开它。

参与者设置

如果您正在迭代代码、运行测试或在本地调试服务器,请使用此路径。

共享贡献者先决条件

稍后选择您想要的本地运行时,但存储库引导是共享的:

  • Git
  • Python 3.13
  • 如果您希望Gemini启动本地运行时,请使用Gemini CLI
  • 仅当您选择本地Docker运行时

克隆回购并创建本地配置

在选择运行时路径之前,克隆存储库并创建本地env文件。

git clone https://github.com/CopyPasteFail/evernote-mcp-server.git
cd evernote-mcp-server
cp .env.example .env

在共享设置之后,选择一个本地运行时。

选项A:本地Python运行时

当您想要最快的编辑-运行-测试循环并直接访问Python进程时,请使用此路径。

在本机Windows上,请按照专用 本机Windows本地Python安装程序 而不是下面的POSIX shell命令。

python3.13 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
PYTHONPATH=src python -m evernote_mcp auth
python3 scripts/install_gemini_mcp.py --mode python

此路径安装开发依赖项,对本地环境运行OAuth引导程序,并可选择更新Gemini设置,以便Gemini可以启动本地Python运行时。不要使用手动启动的 --transport stdio 作为端到端测试的过程;stdio MCP期望客户端提供JSON-RPC。

本地安装程序写入Gemini CLI设置。在运行它之前,请确认Gemini CLI已安装 gemini --version 或 Get-Command gemini,然后运行 gemini 只需一次,即可使用拥有Gemini订阅的Google帐户登录。使用 --print-config 当您只希望JSON手动检查或复制到另一个MCP客户端时。

选项B:本地Docker运行时

当您希望将本地代码更改打包在容器中,同时保持与基于Docker的使用相同的通用运行时模型时,请使用此路径。

docker build -t evernote-mcp-server:local .
docker volume create evernote-mcp-auth

初始化卷所有权一次:

docker run --rm --user root \
  -v evernote-mcp-auth:/home/appuser/.config/evernote-mcp-server \
  evernote-mcp-server:local \
  python -c "import os; p='/home/appuser/.config/evernote-mcp-server'; os.makedirs(p, exist_ok=True); os.chown(p, 1000, 1000); os.chmod(p, 0o700)"

然后运行容器身份验证:

docker run --rm -it \
  --env-file .env \
  -v evernote-mcp-auth:/home/appuser/.config/evernote-mcp-server \
  -p 8765:8765 \
  evernote-mcp-server:local \
  python -m evernote_mcp auth \
    --listen-host 0.0.0.0 \
    --listen-port 8765 \
    --callback-url http://127.0.0.1:8765/callback

然后将Gemini配置为本地Docker模式:

python3 scripts/install_gemini_mcp.py --mode docker

在OAuth引导和Gemini设置之后,运行时使用相同的Docker卷

您可以通过运行以下命令来检查卷现在是否具有令牌:

docker run --rm -it \
  -v evernote-mcp-auth:/home/appuser/.config/evernote-mcp-server \
  evernote-mcp-server:local \
  python -c "from pathlib import Path; p=Path('/home/appuser/.config/evernote-mcp-server/token.json'); print(p.exists(), p)"

它应该打印 True 和路径。

验证安装

完成任一设置路径后,在尝试任何更复杂的操作之前,请使用简单的只读调用验证服务器。

使用这样的Gemini提示:

Use MCP server "evernote-mcp-server" and call list_notebooks. Return the names of 2 notebooks.

如果这有效,MCP接线、Evernote身份验证和保存的令牌状态都在预期的位置。

第二个健全性检查是保持 READ_ONLY=true 起初。这证实了写入工具在您有意启用之前一直处于阻止状态。

故障排除

缺少消费者凭据

如果OAuth引导程序因缺少凭据而失败,请验证是否在所选路径的env文件中设置了这两个凭据:

  • EVERNOTE_CONSUMER_KEY
  • EVERNOTE_CONSUMER_SECRET

丢失已保存的令牌

如果启动失败是因为缺少Evernote令牌,请使用相同的env文件和所选路径的相同持久性位置再次运行OAuth引导程序。

沙盒不匹配警告

如果保存的令牌是使用与当前不同的沙盒设置创建的 EVERNOTE_SANDBOX 值,使用您实际想要使用的沙盒模式重新运行OAuth引导程序。

写入被阻止

如果写入工具失败,请检查 READ_ONLY。安全默认值为 true,因此在您设置之前,写入操作将一直被阻止 READ_ONLY=false 并重新启动读取该env文件的运行时。

sse 不起作用

sse v0.1中故意不实现传输。使用 --transport stdio.

贡献者工作流

这些步骤用于在本地设置工作后进行持续开发。

运行开发检查

在推动更改之前,运行完整的本地检查套件。

make lint
make security
make test
make check

需要验证时,单独运行容器漏洞扫描 Docker镜像在本地运行,而不将其作为默认贡献者循环的一部分。

make container-security

此目标构建 evernote-mcp-server:local 并运行Trivy图像扫描 失败在 HIGH 或 CRITICAL 调查结果。 此可选检查需要本地Docker和 trivy 待安装。 本地Trivy运行故意比GitHub Actions更严格,可能会在 CI忽略的未修复的基础映像漏洞。

可选预推钩

如果你想让Git运行 make check 自动推送之前 main,将Git指向存储库挂钩路径。

git config core.hooksPath .githooks
chmod +x .githooks/pre-push

维护人员工作流程

本节有意与首次设置和贡献者入职分开。

创建发布标签

使用发布脚本创建并推送下一个语义版本标签 main.

./scripts/release.sh patch

支持的凹凸类型有 patch, minor,以及 major.

如果标签推送被拒绝 GH013 和 creations being restricted,您的存储库标记规则集正在阻止为您的参与者创建标记。将旁路参与者(维护者用户/团队/应用程序)添加到 v* 标记规则集,然后再次运行release命令。

发布工作流行为

发布过程受到保护:

  • 仅从匹配的标签创建发布 v*
  • 脚本需要一个干净的工作树 main
  • 脚本获取 origin/main 如果是当地人,则拒绝继续 HEAD 不匹配
  • make check 在创建标记之前必须通过
  • GitHub发布工作流验证标记的提交是否可从以下位置访问 origin/main,重播 make check,然后发布GHCR镜像和GitHub版本

可选的存储库强化脚本

这些脚本是维护人员专用的存储库强化工具,通常每个存储库只需要运行一次:

建议一次性设置Dependabot默认值和漏洞警报:

./scripts/setup-dependabot.sh

建议一次性设置释放标签保护规则:

./scripts/setup-tag-protection.sh

重要提示:限制创建的标签保护规则必须包括一个显式的绕过角色,用于运行维护者身份 ./scripts/release.sh,否则所有标签推送都被阻止。

这两个脚本都使用经过身份验证的GitHub CLI会话来应用存储库设置。

建筑与进一步阅读

本自述文件有意专注于入职培训和常见工作流程。有关更深入的设计和实现细节,请阅读 docs/ARCHITECTURE.md.

该文件涵盖:

  • 交通抽象与当前 stdio /未来 sse 分裂
  • MCP工具如何注册并向客户端公开
  • 安全模型,包括令牌持久性和写策略执行
  • Evernote Thrift整合理论
  • 发布模型细节和未来改进领域