关于 Notion
Notion MCP 服务供 AI 助手搜索、读取和修改已共享的 Notion 工作区,并结合 Markdown 页面编辑、类型化数据库查询、视图、评论与文件操作。
主要功能
- 01跨工作区搜索页面和数据库
- 02以 Markdown 读取和编辑页面
- 03查询、计数并检查数据库行
- 04创建和修改页面、数据库及列
- 05管理评论并传输文件
适用场景
- 01查找并总结工作区页面
- 02按状态统计任务数量
- 03添加或更新数据库条目
- 04下载页面或数据库行的附件
MCP 相关
向 MCP 客户端提供 Notion 工作区搜索、页面、数据库、评论和文件操作工具。访问范围取决于配置的工作区令牌及共享给集成的页面。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @foreverworks/mcp-notionNOTION_TOKENS_DIR密钥A folder holding one file per workspace, notion-<label>, each with that workspace's integration token or personal access token.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
27收录的工具列表 · 更新于 3 天前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| column | object | 是 | |
| column.name | string | 是 | 列名;该名称必须尚未被表使用(忽略大小写)。 |
| column.type | enum | 是 | 列类型。汇总、唯一 ID 和按钮需在 Notion 应用中创建。rich_text | number | select | multi_select | status | date | people | files | checkbox | url | email | phone_number | formula | relation | created_time | created_by | last_edited_time | last_edited_by |
| column.format | string | 否 | 数字:Notion 的格式名称,例如 number、number_with_commas、percent、euro、dollar。 |
| column.options | array | 否 | 选择、 多选或状态:按顺序列出选项。 |
| column.expression | string | 否 | 公式:表达式,例如 prop("Hours") * prop("Rate")。 |
| column.description | string | 否 | 列的用途说明,最多 280 个字符。 |
| column.relation_to | string | 否 | 关联:指向的数据库(ID 或 URL),必须位于同一工作区。单向关联。 |
| source | string | 否 | 源表,仅当数据库包含多个表时使用(describe_database 会列出这些表):指定表名或 ID。 |
| account | string | 否 | 工作区:标签列表 `accounts` 名称(“*”:全部)。很少需要:ID 或 URL 可自行查找。 |
| database | string | 是 | 数据库:其 ID、Notion URL,或为其搜索返回的 dataSourceId。 |
详细介绍
Notion MCP 服务
通过你的 AI 助手搜索、读取和写入 Notion 工作区;多个工作区可共用一个服务:以 Markdown 格式处理页面,按列查询和统计数据库,查看已保存的视图、人员、评论和文件。它可以创建页面、行、列和数据库,编辑属性和正文,添加评论、上传文件,并将页面移至 Notion 垃圾桶(保留 30 天;restore_page 可将其恢复)。没有工具是 money。
你需要: 每个工作区对应一个 Notion 集成,将其令牌单独存放在一个文件中,并将顶层页面共享给该集成:集成只能看到你共享的内容。上传文件大小上限为 20 MiB(Notion 免费计划为 5 MiB)。
可以询问什么
- “在我的工作区中找到 Q3 路线图页面并总结。”
- “Tasks 数据库中每种 Status 有多少行?”
- “显示我的 Due this week 视图。”
- “将《Thinking in Systems》添加到 Reading List,状态设为 To read,标签设为 Books。”
- “在 Onboarding 页面中,将所有 ‘Slack’ 替换为 ‘Mattermost’。”
- “下载 Contracts 数据库中 Client SRL 行所附的 PDF。”
安装
使用 Claude Code:
claude mcp add notion -e NOTION_TOKENS_DIR="<path to Notion tokens folder>" -- npx -y @foreverworks/mcp-notion
Claude Desktop(Settings、Developer、Edit Config)和大多数其他客户端都通过 JSON 读取相同的命令:
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-y", "@foreverworks/mcp-notion"],
"env": {
"NOTION_TOKENS_DIR": "<path to Notion tokens folder>"
}
}
}
}
每种方式都会在 Node 22.19 或更高版本上运行已发布的软件包。VS Code 和 Claude Desktop 安装包会在添加服务时询问 NOTION_TOKENS_DIR。Cursor 则从环境变量中读取该值(${env:NOTION_TOKENS_DIR}),因此请在启动 Cursor 前设置它。配置介绍了该目录的内容。
从克隆版本安装
git clone https://github.com/foreverworks/mcps.git && cd mcps
npm ci && npm run build
claude mcp add notion -e NOTION_TOKENS_DIR="<path to Notion tokens folder>" -- node "$PWD/servers/notion/dist/index.js"
在 JSON 配置中,命令为 node,其唯一参数是 servers/notion/dist/index.js 的完整路径。若要通过 HTTP 在多个客户端之间共享同一个运行中的副本,请参阅 docs/deploying.md。
通过 HTTP 部署时,如果需要限制主机,请设置
MCP_EGRESS_ALLOW=api.notion.com,prod-files-secure.s3.us-west-2.amazonaws.com,s3.us-west-2.amazonaws.com:
Notion API 以及托管其文件的主机。
配置
| 变量 | 必填 | 含义 |
|---|---|---|
NOTION_TOKENS_DIR | 是,或设置 CREDENTIALS_DIRECTORY | 存放各工作区文件的文件夹,每个文件对应一个工作区,文件名为 notion-<label>,且文件中只包含该工作区的令牌。 |
CREDENTIALS_DIRECTORY | 未设置 NOTION_TOKENS_DIR 时读取:在 systemd 下,LoadCredential=notion-<label>:<path> 会将相同的文件放在这里,且只有该单元可以读取。 | |
NOTION_OUTBOX_DIR | 使用 download_files 时必填 | 保存下载文件的文件夹,服务会写入该文件夹,你可以读取其中的文件。若未设置,download_files 会返回一条指出此变量的 config 错误;其他工具均可正常使用。 |
每个文件对应一个工作区:notion-personal 和 notion-work 分别标记为
personal 和 work,服务启动时会列出找到的标签。标签只能包含小写字母、
数字和连字符;空文件会被跳过。
没有默认文件夹,因此测试或手动运行的副本不会意外访问工作区。文件最多每分钟
重新读取一次;令牌被拒绝后会立即重新读取,因此新令牌无需重启。所有服务共用的
变量(传输方式、限制、用于上传的 MCP_FILE_ROOTS)见
docs/configuration.md。
获取令牌
对于每个工作区:
- 登录对应工作区,打开 https://www.notion.so/profile/integrations,并创建新的内部集成。
- 启用助手所需的功能:读取、更新和插入页面与数据库内容,以及评论相关功能。 只有在助手可以读取包含电子邮件地址的用户信息时,才会显示人员的电子邮件地址。
- 将其 Internal Integration Secret 直接复制到令牌文件夹中的
notion-<label>, 并确保只有你自己可以读取该文件(权限模式为 0600)。不要将其粘贴到聊天中。 - 将页面分享给该集成,因为它起初看不到任何内容。在 Notion 中,打开助手应 访问的每个顶层页面,然后依次选择 ••• 菜单、Connections,并添加该集成。 该页面下的页面会继承访问权限;新的顶层页面必须以相同方式分享。
也可以在同一个文件中使用个人访问令牌(登录工作区后,在 https://www.notion.so/developers/tokens 创建,并启用 Notion API 功能)。 该令牌以你的身份运行:它可以查看你能查看的所有页面,无需分享页面;还可以创建 私有顶层页面,而集成无法做到这一点。令牌会在一年内过期。
首次运行
请助手运行 Notion 的 health 检查。它会针对每个工作区说明令牌是否有效、工作区
和集成的名称,以及集成是否已能看到页面;如果还看不到,请执行上面的第 4 步。
在 shell 中,运行 node dist/index.js --health 会为每个工作区输出一行
NOTION:,并在一切正常时以状态码 0 退出;需要人工处理时(令牌被拒绝、缺少功能)
以状态码 1 退出;出现警告时(集成尚看不到任何内容,或 Notion 状态异常)以状态码 2
退出,适用于定时任务。
工具
read 不会进行任何更改;write 会更改工作区中的内容。接受 ID 的工具也接受 Notion URL,并会自行查找工作区。
工作区与搜索
| 工具 | 访问权限 | 功能 |
|---|---|---|
list_accounts | 读取 | 列出有令牌文件的工作区及其标签。不向 Notion 发送请求。 |
health | 读取 | 针对每个工作区,检查令牌是否有效、工作区和集成的名称,以及是否已能看到页面。 |
list_users | 读取 | 列出所有工作区中的人员(和机器人):ID、名称,以及令牌获准读取时的电子邮件地址;可按关键词筛选。 |
search | 读取 | 一次搜索所有工作区中标题匹配的页面和数据库,并在每条结果上标注其所属工作区。 |
页面
| 工具 | 访问权限 | 功能 |
|---|---|---|
read_page | 读取 | 以纯值形式返回页面属性,并以 Notion 的 Markdown 格式返回正文。 |
read_blocks | 读取 | 返回页面或区块内的直接子区块:id、类型、纯文本。会议记录区块会标出保存其摘要、笔记和转录内容的区块。 |
create_page | 写入 | 创建数据库中的一行(根据其列进行校验,或基于其中一个模板创建),或创建子页面;两者都可以包含 Markdown 正文。 |
update_page | 写入 | 更新页面属性和图标。 |
append_content | 写入 | 在末尾、开头或某段内容之后追加 Markdown。 |
edit_content | 写入 | 在页面的 Markdown 中查找并替换内容。 |
replace_content | 写入 | 替换页面的整个正文;仅当使用 clear 时才能替换为空正文。返回页面标题以及替换前后的区块数。 |
move_page | 写入 | 在同一工作区内,将页面移至其他页面下或移入数据库。 |
trash_page / restore_page | 写入 | 将页面移入 Notion 回收站(保留 30 天)或恢复页面。数据库模板仅在使用 allow_template 时可操作。 |
数据库
| 工具 | 访问权限 | 功能 |
|---|---|---|
describe_database | 读取 | 返回数据库的表和列:类型、选项、状态组、关联目标和公式。 |
query_database | 读取 | 返回行;可按 where(根据架构指定类型)或 Notion 自带的筛选条件进行筛选、排序;单次调用最多返回 1,000 行。 |
count_rows | 读取 | 返回符合条件的行数,以及某列各值对应的行数(例如“各状态的任务数”),而不发送行数据。 |
list_views | 读取 | 返回数据库已保存的视图:id、名称、类型,以及每个视图中已保存的筛选条件和排序方式、列名。 |
query_view | 读取 | 按照 Notion 应用筛选条件的方式,按视图顺序返回已保存视图显示的行,并包含视图的总数。 |
list_database_templates | 读取 | 返回数据库的页面模板:页面 id、名称,以及哪个模板为默认模板。 |
add_column | 写入 | 向数据库添加列:可自定义名称、类型及其设置(选项、数字格式、公式、关联);先根据表进行校验。 |
add_options | 写入 | 向单选、多选或状态列添加选项;现有选项按 id 保留,之后会重新读取该列。 |
create_database | 写入 | 在页面下创建数据库,包含标题列和其他列;添加每列前都会先与其他列进行校验。 |
评论和文件
| 工具 | 访问权限 | 功能 |
|---|---|---|
get_comments | 读取 | 获取页面中未解决的评论。 |
add_comment | 写入 | 在页面上添加评论,或在讨论中回复。 |
upload_file | 写入 | 按路径上传文件,将其上传到某行的文件列,或上传到页面正文末尾的区块中;返回文件大小和 SHA-256。 |
download_files | 读取 | 将页面托管在 Notion 上的文件(文件列和正文中的文件区块)保存到 outbox,并返回每个文件的 SHA-256。 |
test/tools.snapshot.json 固定了客户端列出的内容;其中的差异属于不兼容变更。
故障排查
health 显示“集成尚未看到页面”,或调用返回
not_shared。 对于不存在的 ID 和未与集成共享的页面,Notion 会返回相同的 404。请检查 ID,然后共享页面(获取令牌的第 4 步);共享顶层页面会一并共享其下的所有内容。
auth。 令牌被拒绝:可能已撤销,或个人访问令牌已过期。请在 notion-<label> 文件中放入新令牌;下次调用时会读取该令牌。
forbidden。 集成缺少执行此调用所需的权限。请在 https://www.notion.so/profile/integrations 中启用相应权限(获取令牌的第 2 步)。
config。 NOTION_TOKENS_DIR 指向的位置没有令牌文件、令牌文件不可读,或其中包含多个令牌。对于 download_files,请设置 NOTION_OUTBOX_DIR。
create_page 未提供父页面时返回 input。 Notion 不允许集成创建顶层页面;请指定父页面,或使用个人访问令牌。其他 input 会指出需要修复的内容,且不会做出任何更改。
outcome_unknown。 追加内容、查找并替换、新建页面或评论的调用未能收到响应;系统绝不会在未确认的情况下重新发送。再次写入前,请先读取页面(新建页面则使用 search):更改可能已经生效。
conflict:有人同时编辑了同一对象;请重新读取,然后重试。rate_limited:重试后 Notion 仍在限流(Free 计划每分钟 180 次请求);请等待一分钟。api:Notion 无法访问或发生故障;请稍后重试。若 reason: "drift",表示其响应结构发生变化:请报告此问题。
工作原理
ID 定位其所属工作区
一个 ID 只属于一个工作区,因此 src/app/locate.ts 会逐个询问,直到其中一个工作区响应;若全部返回 404,则为 not_shared。进程运行期间会记住找到的 ID,以及搜索或查询返回的 ID,因此每次未找到都只需查找一次。URL 可以来自 notion.so、notion.site 或 app.notion.com;?p= 表示数据库中打开的页面。
数据库由其自身 ID 或其数据源的 ID 标识(搜索会返回两者)。从 API 2025-09-03 开始,数据库包含数据源,通常只有一个;若有多个,source 用于指定表;若省略,则会拒绝请求并列出数据源名称。
Agent 可见的值
| Notion 类型 | 输出 | 输入 |
|---|---|---|
| title, rich_text | 字符串 | 字符串,拆分为每段 2000 个字符(Notion 的限制),且不会从字符中间截断 |
| number | Notion 发送的 JSON 数字 | 有限数值 |
| select, status | 选项名称 | 已存在的选项(忽略大小写进行匹配);只有在使用 allow_new_options 时才能创建新的 select 选项;status 选项不可新建(API 无法创建) |
| multi_select | 名称 | 名称,规则相同 |
| date | {start, end?, timeZone?} | YYYY-MM-DD、ISO 日期时间,或 {start, end, time_zone} |
| checkbox | 布尔值 | 布尔值 |
| url, email, phone_number | 字符串 | 字符串;留空会清除该值 |
| relation | 页面 ID,包含全部 | 页面 ID 或 URL,最多 100 个 |
| files | [{name, url, expiresAt?}] | 外部 URL;自己的文件需通过 upload_file 上传 |
| people, created_by, last_edited_by | {id, name};若页面只提供 ID,则名称取自工作区用户 | 拒绝 |
formula, rollup, created/edited time, unique_id (PREFIX-12) | 计算出的值 | 拒绝:由 Notion 计算 |
| button | 省略:它没有值 | 拒绝 |
空值会从页面或行中省略(describe_database 会列出每一列)。页面对象最多列出关联中的 25 个页面;read_page 会通过属性端点读取其余页面(最多 1,000 个),查询行则会在 truncated 下列出此类列。服务不会对数字进行算术运算。
where
Notion 的筛选条件按列类型确定,而 Agent 常会弄错。
where 指定列名、操作符和值,并从架构中获取类型:
{"where": [{"property": "Status", "op": "equals", "value": ["In progress", "Blocked"]},
{"property": "Due", "op": "next_week"}],
"match": "all"}
如果类型不支持某个操作符,或某个选项不存在,工具会在发送任何请求前拒绝操作,并告知现有内容。人员列接受姓名、电子邮件、用户 ID 或 "me"。姓名会与工作区用户匹配:先精确匹配,再匹配某个人姓名中的部分内容;如果有多人同名或无人匹配,工具会拒绝操作,并告知符合条件的人员。对于 where 无法表达的条件,notion_filter 接受 Notion 自己的筛选对象,并与 where 的条件进行 AND 运算。
模板
搜索会将模板作为普通页面返回,而模板会影响此后创建的每一行,因此 list_database_templates 会列出模板,trash_page 则会拒绝处理未设置 allow_template 的模板。create_page 使用 template 时,会检查模板是否属于该数据库。Notion 会在创建行后立即填充内容,因此稍后调用 read_page 即可查看结果。模板旁边提供的属性会保留;Markdown 正文则会被拒绝,以免与模板发生竞争。
更改数据库列
add_column、add_options 和 create_database 会在发送前根据表格当前状态检查请求:名称已被占用、选项已存在、类型不支持某项设置、公式缺少表达式、关联缺少目标,或选项超过 Notion 的 100 项上限。Notion 将架构更新中的选项列表定义为要设置的全部选项,因此 add_options 会先发送所有现有选项的 ID,再发送新增选项,并在之后读取该列;如果有选项消失,此次调用就会失败。
文件
upload_file 可从 MCP_FILE_ROOTS 内的路径上传文件,也可由脚本以 base64 和其 SHA-256 上传,绝不会将模型输入的文本当作文件。如果数据库行中有文件列,文件会添加到该列已有文件中;否则会根据文件类型将其作为内容末尾的区块插入(图片、PDF、视频或音频)。Notion 的 API 会整体替换文件列,且无法重新写入由 Notion 托管的文件,因此,包含 Notion 托管文件的列需要设置 replace: true,这会移除这些文件;外部链接则始终保留。
download_files 会将页面中由 Notion 托管的文件保存到 NOTION_OUTBOX_DIR:包括文件列,以及正文中的文件、图片、PDF、视频和音频区块,也包括嵌套区块(最多读取前 1,000 个区块)。Notion 的链接是有效期为一小时的签名 URL,通过 https 获取时不会使用工作区令牌,也不会跟随重定向。外部链接只会列出,不会获取,因为它们可能指向任意位置。
已保存的视图
query_view 会像 Notion 一样运行视图,包括快速筛选条件和 me。Notion 只会返回页面 ID,且结果会保留约 15 分钟,因此 query_view 会自行读取每一行(默认 25 行,每次最多 100 行),并通过 nextCursor 在同一结果中继续读取。结果过期后,工具会提示重新开始;期间被移至废纸篓或取消共享的行会列在 unreadable 下。
人员和会议记录
对于 AI 会议记录页面,使用 include_transcript 调用 read_page 会以一段 Markdown 文本返回摘要、笔记和文字记录。read_blocks 会列出这些内容对应的区块;对于 transcriptBlockId,它会逐行读取文字记录,每行都带有区块 ID,供 AI 摘要中的引用链接使用。
替换整个正文
replace_content 无法通过 API 撤销,而且模型可能会在它的两个参数上出错:使用错误行的页面 ID,或得到空的 markdown。因此,若正文为空,必须设置 clear: true;返回结果会提供页面标题以及 blocksBefore 和 blocksAfter,这样一来,页面选错或正文几乎被清空都会立即显现。
网络
- 版本:每个请求都使用
2026-03-11,这是包含 Markdown 端点和in_trash的版本。 - 请求节奏:Free 计划下,集成每分钟可发送 180 个请求。每个工作区使用一个令牌桶(一次最多 30 个,之后每秒 2.5 个),由进程服务的所有会话共享,确保每分钟请求数不超过 180;工作区级别的限制则交由 429 退避和
Retry-After处理。 - 重发规则:429 或 409
conflict_error能证明请求没有产生任何影响,因此每个请求都会重试。5xx 或连接中断则无法证明请求是否产生影响:读取请求会重试,同一操作重复执行结果相同的请求(属性更新、移动、整页内容替换)也会重试;其余请求会以outcome_unknown失败(notionApi.ts标明了哪些请求属于哪一类)。401 会重试一次,重试前会重新读取令牌文件。 - 缓存:数据源的列缓存 1 分钟,工作区的用户缓存 5 分钟。
为什么使用 REST,而不使用托管 MCP
Notion 会将每个令牌限定在一个工作区内,托管 MCP 也不例外,因此单次登录无法访问多个工作区。托管 MCP 的数据源查询取决于计划,它会转发本仓库未建模的工具,而且其刷新令牌可能失效,需要人工处理。个人访问令牌也可以通过 REST 以用户身份操作,每年续期一次。
scripts/smoke.ts 以只读方式运行已构建的服务;添加 --write 则会写入并移至垃圾桶一个页面。
限制
- 列只能添加,不能重命名或删除;汇总、唯一 ID 和按钮需在 Notion 应用中创建。无法写入人员列。
- **会议转录文本不会标明发言者或发言时间。**API 会将其作为纯文本
paragraph块提供(API 2026-03-11,@notionhq/client5.27.0,其类型定义中没有发言者字段),但 Notion 应用会显示发言轮次和时间戳。 - 页面只能在自己的工作区内移动;Notion 不支持在工作区之间移动页面。
query_database每次最多返回 1,000 行(之后使用nextCursor),count_rows每次查询最多读取 Notion 的 10,000 行限制。- 上传采用单部分传输,每个文件最多 20 MiB;下载上限为 50 MiB。
- 无法将托管在 Notion 上的文件写回文件列,因此向此类列添加内容需要设置
replace: true,否则文件会进入正文。
其他 Notion 服务
检索日期:2026-10-15;重新查阅 Notion 的 MCP 页面日期:2026-10-18。
- Notion 的托管服务(
mcp.notion.com,Streamable HTTP)需要在浏览器中通过 OAuth 登录,且每个连接只能访问一个工作区;只有 Enterprise 工作区可以通过其身份提供商免浏览器登录。其工具集最全面(视图、文件上传、数据源上的 SQL、Custom Agent 会话)。AI 搜索和数据源上的无限 SQL 需要配备 Notion AI 的 Business 或 Enterprise 计划;所有计划均可查询已保存的视图。 @notionhq/notion-mcp-server是 Notion 的开源服务(stdio 或 HTTP,通过环境变量传入一个令牌),目前已不再积极维护。- npm 上的
notion-mcp-server是功能最强的社区服务:通过一个令牌使用 stdio 或 HTTP,提供 3 个工具,涵盖 47 种操作;支持类型化筛选器,写入操作会根据数据库架构进行检查,还支持模板、视图、文件上传和批量写入。 @suekou/mcp-notion-server(stdio,一个令牌)也可以根据架构查询和创建行。notion-multi-workspace是唯一找到的多工作区服务,目前已归档。
此服务适用于在一个无头服务后接入多个工作区,每个工作区各自使用一个令牌文件:搜索可以一次覆盖所有工作区,输入任意页面或数据库 ID 或 URL 都能找到对应的工作区。它还可以按列值统计匹配的行数,而无需发送这些行;执行整页内容替换时,除非收到明确要求,否则不会接受空正文,并会返回替换前后的块数量。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。