An agent-first Notion CLI and MCP server, purpose-built for the Notion API 2025-09-03+ data-source model.
- 12 tools — query, search, get/create/update pages, get/create data sources, full block CRUD (retrieve, list children, append, update, delete)
- Page body support —
page create --childrenfor one-shot page + body creation - CLI + MCP — same tool surface accessible via shell commands or as an MCP stdio server
- Agent-friendly output — responses wrapped in an untrusted-source envelope with trust metadata;
--rawfor clean piping - Rate limiting — built-in 3 req/s token bucket with 429
Retry-Afterretry (configurable) - Response size cap — 10 MiB streaming limit prevents OOM on large payloads
- Schema introspection —
notion-cli schema <type>emits JSON Schema for 22 property value types, 12 block types, and more - Read-only MCP default — write tools require explicit
--allow-write; write operations logged to JSONL audit trail - Actionable error hints — common Notion validation errors get one-line remediation suggestions
- Structured exit codes — stable numeric codes (0/2/3/4/10/64/65/74) for scripting and CI
- Newtype ID validation — accepts 32-hex, dashed UUID, or full Notion URLs; rejects homoglyphs and control characters
--check-request— validate and preview request payloads locally without contacting Notion
# Install
cargo install --git https://github.com/0xarkstar/notion-cli
# Set your integration token
export NOTION_TOKEN='ntn_...'
# Search across your workspace
notion-cli search 'meeting notes'
# Query a data source with filters
notion-cli ds query <data-source-id> \
--filter '{"property":"Done","checkbox":{"equals":false}}'cargo install notion-cli-mcp(The crate is published as notion-cli-mcp; the installed binary is notion-cli.)
curl -LsSf https://github.com/0xarkstar/notion-cli/releases/latest/download/notion-cli-installer.sh | shbrew install 0xarkstar/tap/notion-cliPublished as notion-cli-mcp on ClawHub:
clawhub install 0xarkstar/notion-cli-mcpThe skill describes the full tool surface and example payloads for agent consumption.
cargo install --git https://github.com/0xarkstar/notion-cliRequires Rust 1.85+. Run notion-cli --version to verify.
# Retrieve a page (accepts IDs or full Notion URLs)
notion-cli page get https://notion.so/My-Page-abcdef0123456789abcdef0123456789
# Create a page under a data source
notion-cli page create \
--parent-data-source <data-source-id> \
--properties '{
"Name": {"type":"title","title":[{"type":"text","text":{"content":"New page"}}]},
"Status": {"type":"status","status":{"name":"In Progress"}}
}'
# Update properties
notion-cli page update <page-id> \
--properties '{"Status":{"type":"status","status":{"name":"Done"}}}'
# Archive
notion-cli page archive <page-id># Retrieve schema and metadata
notion-cli ds get <data-source-id>
# Query with filter, sort, and pagination
notion-cli ds query <data-source-id> \
--filter '{"property":"Priority","select":{"equals":"High"}}' \
--sorts '[{"property":"Due","direction":"ascending"}]' \
--page-size 25
# Create a new data source in a database container
notion-cli ds create \
--parent <database-id> \
--title 'Tasks' \
--properties '{"Name":{"title":{}},"Done":{"checkbox":{}}}'# Full-text search (filter by object type)
notion-cli search 'onboarding' \
--filter '{"property":"object","value":"page"}'
# Retrieve a database container (lists its data sources)
notion-cli db get <database-id>
# Print JSON Schema for property values (all 22 types)
notion-cli schema property-value --prettyPreview what would be sent without making an API call:
notion-cli --check-request --pretty page create \
--parent-data-source <id> \
--properties '{"Name":{"type":"title","title":[{"type":"text","text":{"content":"test"}}]}}'No token required for --check-request.
Start as an MCP stdio server for agent integration:
# Read-only (4 tools: get_page, get_data_source, query_data_source, search)
notion-cli mcp
# Full access (7 tools: above + create_page, update_page, create_data_source)
notion-cli mcp --allow-write
# With audit logging
notion-cli mcp --allow-write --audit-log ./notion-audit.jsonlmcp_servers:
notion:
command: notion-cli
args: [mcp, --allow-write, --audit-log, /var/log/notion-audit.jsonl]
env:
NOTION_TOKEN: ntn_xxx
enabled: trueResponses are wrapped in a trust-demarcation envelope by default:
{
"source": "notion",
"trust": "untrusted",
"api_version": "2026-03-11",
"content": { ... }
}This signals to consuming agents that content originates from an external source and should be treated as data, not instructions. Use --raw to strip the envelope, and --pretty for indented output.
| Setting | Source | Description |
|---|---|---|
NOTION_TOKEN |
env / --token |
Integration token (ntn_...) |
NOTION_CLI_AUDIT_LOG |
env / --audit-log |
Path for write-operation JSONL audit log |
Create an integration at notion.so/my-integrations, then share target pages/databases with it via the Connections menu.
| Code | Meaning |
|---|---|
| 0 | Success |
| 2 | Validation error |
| 3 | API error |
| 4 | Rate-limited |
| 10 | Auth / config error |
| 64 | Usage error |
| 65 | JSON parse error |
| 74 | I/O error |
cargo test # 130 tests
cargo clippy --all-targets -- -D warnings
cargo llvm-cov --all-targets --summary-only # 80%+ line coverage
cargo audit # 0 advisories
# Live smoke test against a real workspace
export NOTION_TOKEN='ntn_...'
cargo run --example smoke -- <database-url>- Block CRUD (page body / children)
- NDJSON streaming for paginated queries
--fieldsresponse field masks- YAML configuration file
- Multi-platform binaries via cargo-dist / Homebrew