MCPInstall

notion

Notion API + ntn CLI: pages, databases, markdown, Workers.

Installs
387
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/nousresearch/hermes-agent --skill notion
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads notion automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Notion

Talk to Notion two ways. Same integration token works for both — pick by what's available.

◆ ntn CLI — Notion's official CLI. Shorter syntax, one-line file uploads, required for Workers. macOS + Linux only as of May 2026 (Windows support "coming soon"). Default when installed. ◆ HTTP + curl — works everywhere including Windows. Default fallback when ntn isn't installed.

Setup

1. Get an integration token (required for both paths)

  1. Create an integration at https://notion.so/my-integrations
  2. Copy the API key (starts with ntn_ or secret_)
  3. Store in ${HERMES_HOME:-~/.hermes}/.env:
    NOTION_API_KEY=ntn_your_key_here
    
  4. Share target pages/databases with the integration in Notion: page menu ... → Connect to → your integration name. Without this, the API returns 404 for that page even though it exists.

2. Install ntn (preferred path on macOS / Linux)

# Recommended
curl -fsSL https://ntn.dev | bash

# Or via npm (needs Node 22+, npm 10+)
npm install --global ntn

ntn --version    # verify

Skip ntn login — use the integration token instead. This works headlessly, no browser needed:

export NOTION_API_TOKEN=$NOTION_API_KEY      # ntn reads NOTION_API_TOKEN
export NOTION_KEYRING=0                       # don't try to use the OS keychain

Add those exports to your shell profile (or to ${HERMES_HOME:-~/.hermes}/.env) so every session inherits them.

3. Choose path at runtime

if command -v ntn >/dev/null 2>&1; then
  # use ntn
else
  # fall back to curl
fi

Windows users: skip step 2 entirely until native ntn ships — Path B works fine. If you want CLI ergonomics now, install ntn inside WSL2.

API Basics

Notion-Version: 2025-09-03 is required on all HTTP requests. ntn handles this for you. In this version, what users call "databases" are called data sources in the API.

Path A — ntn CLI (preferred, macOS / Linux)

Raw API calls (shorthand for curl)

ntn api v1/users                                  # GET
# POST with inline body
ntn api v1/pages parent[page_id]=abc123 \
  properties[title][0][text][content]="Notes"
ntn api v1/pages/abc123 -X PATCH archived:=true   # PATCH; := is non-string (bool/num/null)

Syntax notes:

  • key=value — string fields
  • key[nested]=value — nested object fields
  • key:=value — typed assignment (booleans, numbers, null, arrays)

Search

ntn api v1/search query="page title"

Read page metadata

ntn api v1/pages/{page_id}

Read page as Markdown (agent-friendly)

ntn api v1/pages/{page_id}/markdown

Read page content as blocks

ntn api v1/blocks/{page_id}/children

Create page from Markdown

ntn api v1/pages \
  parent[page_id]=xxx \
  properties[title][0][text][content]="Notes from meeting" \
  markdown="# Agenda

- Q3 roadmap
- Hiring"

Patch a page with Markdown

ntn api v1/pages/{page_id}/markdown -X PATCH \
  markdown="## Update

Shipped the prototype."

Query a database (data source)

ntn api v1/data_sources/{data_source_id}/query -X POST \
  filter[property]=Status filter[select][equals]=Active

For complex queries with sorts, multiple filter clauses, or compound logic, pipe JSON in:

echo '{"filter": {"property": "Status", "select": {"equals": "Active"}}, "sorts": [{"property": "Date", "direction": "descending"}]}' | \
  ntn api v1/data_sources/{data_source_id}/query -X POST --json -

File uploads (one-liner — biggest CLI win)

ntn files create < photo.png
ntn files create --external-url https://example.com/photo.png
ntn files list

Compare to the 3-step HTTP flow (create upload → PUT bytes → reference).

Useful env vars

VarEffect
NOTION_API_TOKENAuth token (overrides keychain) — set this to your integration token
NOTION_KEYRING=0File-based creds at ~/.config/notion/auth.json instead of OS keychain
NOTION_WORKSPACE_IDSkip the workspace picker prompt

Path B — HTTP + curl (cross-platform, default on Windows)

All requests share this pattern:

curl -s -X GET "https://api.notion.com/v1/..." \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json"

On Windows the curl shipped with Windows 10+ works as-is. PowerShell users can also use Invoke-RestMethod.

Search

curl -s -X POST "https://api.notion.com/v1/search" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{"query": "page title"}'

Read page metadata

curl -s "https://api.notion.com/v1/pages/{page_id}" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03"

Read page as Markdown (agent-friendly)

Easier to feed to a model than block JSON.

curl -s "https://api.notion.com/v1/pages/{page_id}/markdown" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03"

Read page content as blocks (when you need structure)

curl -s "https://api.notion.com/v1/blocks/{page_id}/children" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03"

Create page from Markdown

POST /v1/pages accepts a markdown body param.

curl -s -X POST "https://api.notion.com/v1/pages" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"page_id": "xxx"},
    "properties": {"title": [{"text": {"content": "Notes from meeting"}}]},
    "markdown": "# Agenda\n\n- Q3 roadmap\n- Hiring\n\n## Decisions\n- Ship MVP Friday"
  }'

Patch a page with Markdown

curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}/markdown" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{"markdown": "## Update\n\nShipped the prototype."}'

Create page in a database (typed properties)

curl -s -X POST "https://api.notion.com/v1/pages" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"database_id": "xxx"},
    "properties": {
      "Name": {"title": [{"text": {"content": "New Item"}}]},
      "Status": {"select": {"name": "Todo"}}
    }
  }'

Query a database (data source)

curl -s -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {"property": "Status", "select": {"equals": "Active"}},
    "sorts": [{"property": "Date", "direction": "descending"}]
  }'

Create a database

curl -s -X POST "https://api.notion.com/v1/data_sources" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{
    "parent": {"page_id": "xxx"},
    "title": [{"text": {"content": "My Database"}}],
    "properties": {
      "Name": {"title": {}},
      "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
      "Date": {"date": {}}
    }
  }'

Update page properties

curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{"properties": {"Status": {"select": {"name": "Done"}}}}'

Append blocks to a page

curl -s -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{
    "children": [
      {"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello from Hermes!"}}]}}
    ]
  }'

File uploads (3-step flow)

# 1. Create upload
curl -s -X POST "https://api.notion.com/v1/file_uploads" \
  -H "Authorization: Bearer $NOTION_API_KEY" \
  -H "Notion-Version: 2025-09-03" \
  -H "Content-Type: application/json" \
  -d '{"filename": "photo.png", "content_type": "image/png"}'

# 2. PUT bytes to the upload_url returned above
curl -s -X PUT "{upload_url}" --data-binary @photo.png

# 3. Reference {file_upload_id} in a page/block payload

Property Types

Common property formats for database items:

  • Title: {"title": [{"text": {"content": "..."}}]}
  • Rich text: {"rich_text": [{"text": {"content": "..."}}]}
  • Select: {"select": {"name": "Option"}}
  • Multi-select: {"multi_select": [{"name": "A"}, {"name": "B"}]}
  • Date: {"date": {"start": "2026-01-15", "end": "2026-01-16"}}
  • Checkbox: {"checkbox": true}
  • Number: {"number": 42}
  • URL: {"url": "https://..."}
  • Email: {"email": "user@example.com"}
  • Relation: {"relation": [{"id": "page_id"}]}

API Version 2025-09-03 — Databases vs Data Sources

  • Databases became data sources. Use /data_sources/ endpoints for queries and retrieval.
  • Two IDs per database: database_id and data_source_id.
    • database_id when creating pages: parent: {"database_id": "..."}
    • data_source_id when querying: POST /v1/data_sources/{id}/query
  • Search returns databases as "object": "data_source" with the data_source_id field.

Notion Workers (advanced, requires ntn)

Workers are TypeScript programs Notion hosts for you. One worker can expose any combination of:

  • Syncs — pull data from external APIs into a Notion database on a schedule (default 30 min).
  • Tools — appear as callable tools inside Notion's Custom Agents.
  • Webhooks — receive HTTP events from external services (GitHub, Stripe, etc.) and act in Notion.

Plan / platform gating:

  • CLI works on all plans. Deploying Workers requires Business or Enterprise.
  • ntn is macOS/Linux only as of May 2026. Windows users need WSL2 or to wait for native support.
  • Free through August 11, 2026; metered on Notion credits after.

Minimal Worker

ntn workers new my-worker      # scaffold
cd my-worker
# Edit src/index.ts
ntn workers deploy --name my-worker

src/index.ts:

import { Worker } from "@notionhq/workers";

const worker = new Worker();
export default worker;

worker.tool("greet", {
  title: "Greet a User",
  description: "Returns a friendly greeting",
  inputSchema: { type: "object", properties: { name: { type: "string" } }, required: ["name"] },
  execute: async ({ name }) => `Hello, ${name}!`,
});

Webhook capability

worker.webhook("onGithubPush", {
  title: "GitHub Push Handler",
  execute: async (events, { notion }) => {
    for (const event of events) {
      // event.body, event.rawBody (for signature verification), event.headers
      console.log("got delivery", event.deliveryId);
    }
  },
});

After deploy: ntn workers webhooks list shows the URL Notion generates. Treat that URL as a secret — anyone with it can POST events unless you add signature verification.

Worker lifecycle commands

ntn workers deploy
ntn workers list
ntn workers exec <capability-key> -d '{"name": "world"}'
ntn workers sync trigger <key>            # run a sync now
ntn workers sync pause <key>
ntn workers env set GITHUB_WEBHOOK_SECRET=...
ntn workers runs list                     # recent invocations
ntn workers runs logs <run-id>
ntn workers webhooks list

When asked to build a Worker, scaffold with ntn workers new, write the code in src/index.ts, set any secrets with ntn workers env set, and deploy. Notion's docs at https://developers.notion.com/workers cover the full API surface.

Notion-Flavored Markdown (used by /markdown endpoints)

Standard CommonMark plus XML-like tags for Notion-specific blocks. Use tabs for indentation.

Blocks beyond CommonMark:

<callout icon="🎯" color="blue_bg">
	Ship the MVP by **Friday**.
</callout>

<details color="gray">
<summary>Toggle title</summary>
	Children indented one tab
</details>

<columns>
	<column>Left side</column>
	<column>Right side</column>
</columns>

<table_of_contents color="gray"/>

Inline:

  • Mentions: <mention-user url="..."/>, <mention-page url="...">Title</mention-page>, <mention-date start="2026-05-15"/>
  • Underline: <span underline="true">text</span>
  • Color: <span color="blue">text</span> or block-level {color="blue"} on the first line
  • Math: inline $x^2$, block $$ ... $$
  • Citations: [^https://example.com]

Colors: gray brown orange yellow green blue purple pink red, plus *_bg variants for backgrounds.

Headings 5/6 collapse to H4. Multiple > lines render as separate quote blocks — use <br> inside a single > for multi-line quotes.

Choosing the Right Path

Taskmac / LinuxWindows
Read/write pages, search, query databasesntn api ...curl
Read a page for an agent to summarizentn api v1/pages/{id}/markdowncurl /markdown endpoint
Upload a filentn files create < file3-step HTTP flow
One-off API explorationntn api ...curl
Build a sync / webhook / agent tool hosted by Notionntn workers ...WSL2 + ntn workers ...

Notes

  • Page/database IDs are UUIDs (with or without dashes — both accepted).
  • Rate limit: ~3 requests/second average. The CLI doesn't bypass this.
  • The API cannot set database view filters — that's UI-only.
  • Use "is_inline": true when creating data sources to embed them in a page.
  • Always pass -s to curl to suppress progress bars (cleaner agent output).
  • Pipe JSON through jq when reading: ... | jq '.results[0].properties'.
  • Notion also ships an MCP server now (Notion MCP, ~91% more token-efficient on DB ops than the previous version) — wire it via Hermes' MCP support if you want streaming Notion access from inside a session, but the paths above are enough for most one-shot tasks.

FAQ

What does the notion skill do?

Notion API + ntn CLI: pages, databases, markdown, Workers.

How do I install notion?

Run npx skills add https://github.com/nousresearch/hermes-agent --skill notion in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/notion/ (personal) or .claude/skills/notion/ (project).

Which AI agents can use notion?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is notion safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains notion?

It is published by nousresearch in nousresearch/hermes-agent. It has 387 recorded installs.

More from nousresearch/hermes-agent

View all →

dogfood

nousresearch/hermes-agent

Exploratory QA of web apps: find bugs, evidence, reports.

Testing & QA6.4K installs

humanizer

nousresearch/hermes-agent

Humanize text: strip AI-isms and add real voice.

Media & Creative1.3K installs

hermes-agent

nousresearch/hermes-agent

Use, configure, theme, extend, and orchestrate Hermes Agent.

Frontend & Design1.1K installs

popular-web-designs

nousresearch/hermes-agent

54 real design systems (Stripe, Linear, Vercel) as HTML/CSS.

Frontend & Design921 installs

powerpoint

nousresearch/hermes-agent

Create, read, edit .pptx decks with python-pptx.

Docs & Writing754 installs

arxiv

nousresearch/hermes-agent

Search arXiv papers by keyword, author, category, or ID.

Popular productivity & automation skills

View category →

agent-browser

vercel-labs/agent-browser

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

OfficialProductivity & Automation1.3M installs

lark-doc

open.feishu.cn

飞书云文档(Docx / Wiki)内容操作:读取、创建、编辑文档,插入或下载图片附件,以及操作思维笔记。用户提供文档 URL/token(包括 doubao.com 的 /docx/、/wiki/)时使用;按 URL 路径/token 而非域名路由;/page/ 是妙搭应用,非飞书云文档。文档内嵌资源按读取参考中的统一规则分流。独立评论操作走 lark-drive;随正文读取评论使用 docs +fetch。表格或 Base 内部数据操作不在本 skill。

lark-base

open.feishu.cn

飞书多维表格(Base)操作:建表、字段、记录、视图、统计、公式/lookup、表单、仪表盘、应用模式(BaseApp/AppMode 页面与组件)、Workspace 目录、workflow、角色权限、模板中心(多维表格模板分类/列表/搜索);遇到 Base/多维表格/bitable、BaseApp/AppMode、/base/ 或 /app/ 链接时使用。BaseApp 不走 lark-apps;文件导入/导出转 lark-drive,认证/授权转 lark-shared。

lark-drive

open.feishu.cn

飞书云空间(云盘/云存储):管理 Drive 文件和文件夹,包含上传/下载、创建文件夹、复制/移动/删除、查看元数据、查询权限设置、评论/权限/订阅、标题、版本、飞书文档密级标签(secure labels)和本地文件导入。用户需要整理云盘目录、处理云空间资源 URL/token、判断链接类型/真实 token/标题,或导入 Word/Markdown/Excel/CSV/PPTX/.base 为 docx/sheet/bitable/slides 时使用;doubao.com 云空间 URL/token 也按资源路径和 token 路由,不回退 WebFetch。不负责:文档内容编辑(走 lark-doc)、表格/Base 表内数据操作(走 lark-sheets/lark-base)、知识空间节点/成员管理(走 lark-wiki)、原生 Markdown 文件读写/patch/diff(走 lark-markdown)。

lark-shared

open.feishu.cn

Use for lark-cli setup/auth tasks: auth login/status/logout, user vs bot identity, business-domain permissions (--domain, including all/docs/drive), missing scopes, revoking authorization, or handling notice JSON.

lark-im

open.feishu.cn

飞书即时通讯:收发消息和管理群聊。发送和回复消息、搜索聊天记录、管理群聊成员、上传下载图片和文件、管理表情回复、发送应用内/短信/电话加急、发送和处理交互卡片(Interactive Card)、监听卡片按钮回调(card.action.trigger)。当用户需要发消息、查看或搜索聊天记录、下载聊天中的文件、查看群成员、搜索群、创建群聊或话题群、管理标记数据、管理 Feed 置顶(添加/移除/查询置顶会话)、管理标签数据、处理卡片回调时使用。