Notionary
Notion API made simple. Write Markdown, get Notion pages. Built for Python developers and AI automation. Async, typed, battle-tested.
Install / Use
/learn @mathisarends/NotionaryQuality Score
Category
Development & EngineeringSupported Platforms
README
Transform complex Notion API interactions into simple, Pythonic code. Perfect for developers building AI agents, automation workflows, and dynamic content systems.
</div>Why Notionary?
- AI-friendly – Composable APIs that drop cleanly into agent workflows
- Smart discovery – Find pages/databases by title with fuzzy matching (no ID spelunking)
- Markdown content – Read & write page content as Markdown via the Notion Markdown API
- Async-first – Modern Python with full
async/await - Round-trip content – Read a page as Markdown, transform, write back
- Full coverage – Pages, databases, data sources, file uploads, users, workspace search
Installation
pip install notionary
Set up your Notion integration and configure your token:
export NOTION_API_KEY=your_integration_key
Quick Start
All access goes through the Notionary client:
import asyncio
from notionary import Notionary
async def main():
async with Notionary() as notion:
# Find a page by title (fuzzy matching)
page = await notion.pages.find("Meeting Notes")
print(page.title, page.url)
# Read content as Markdown
md = await page.get_markdown()
print(md)
# Append content
await page.append("## Action Items\n- [ ] Review proposal")
# Replace all content
await page.replace("# Fresh Start\nThis page was rewritten.")
asyncio.run(main())
Architecture Overview
flowchart TD
N[Notionary] --> PG[pages]
N --> DB[databases]
N --> DS[data_sources]
N --> FU[file_uploads]
N --> USR[users]
N --> WS[workspace]
PG --> P[Page]
DB --> D[Database]
DS --> S[DataSource]
S --> P
The Notionary client exposes namespace objects – each mapping to a Notion API area.
Content operations use the Notion Markdown API directly.
Core Concepts
Pages
async with Notionary() as notion:
# Lookup
page = await notion.pages.find("Sprint Board")
page = await notion.pages.from_id(page_uuid)
# List & search
pages = await notion.pages.list(query="roadmap")
# Content (Markdown API)
md = await page.get_markdown()
await page.append("## New Section")
await page.replace("# Replaced content")
await page.clear()
# Metadata
await page.rename("New Title")
await page.set_icon("🚀")
await page.set_cover("https://example.com/cover.png")
await page.random_cover()
# Properties
await page.properties.set_property("Status", "Done")
# Comments
await page.comment("Review completed")
# Lifecycle
await page.lock()
await page.trash()
Databases
async with Notionary() as notion:
db = await notion.databases.find("Tasks")
db = await notion.databases.from_id(db_uuid)
# Create
db = await notion.databases.create(
parent_page_id=page_uuid,
title="New Database",
icon_emoji="📊",
)
# Metadata
await db.set_title("Project Tracker")
await db.set_description("All current projects")
await db.set_icon("📊")
await db.lock()
Notion API Reference: Databases
Data Sources
async with Notionary() as notion:
ds = await notion.data_sources.find("Engineering Backlog")
# Create a page inside the data source
page = await ds.create_page(title="New Feature")
# Metadata
await ds.set_title("Sprint Board")
await ds.set_icon("🧭")
Notion API Reference: Data Sources
File Uploads
from pathlib import Path
async with Notionary() as notion:
# Upload from disk
result = await notion.file_uploads.upload(Path("./report.pdf"))
# Upload from bytes
result = await notion.file_uploads.upload_from_bytes(
content=image_bytes,
filename="chart.png",
)
# List uploads
uploads = await notion.file_uploads.list()
Users
async with Notionary() as notion:
all_users = await notion.users.list()
people = await notion.users.list(filter="person")
bots = await notion.users.list(filter="bot")
me = await notion.users.me()
matches = await notion.users.search("alex")
Workspace Search
async with Notionary() as notion:
results = await notion.workspace.search(query="roadmap")
for r in results:
print(type(r).__name__, r.title)
Key Features
<table> <tr> <td width="50%">Smart Discovery
- Find pages/databases by name
- Fuzzy matching for approximate searches
- No more hunting for IDs or URLs
Markdown Content API
- Read page content as Markdown
- Append, replace, or clear content
- Powered by the official Notion Markdown API
Modern Python
- Full async/await support
- Type hints throughout
- Pydantic models for API responses
Round-Trip Editing
- Read existing content as Markdown
- Edit and modify
- Write back to Notion seamlessly
AI-Ready Architecture
- Predictable models enable prompt chaining
- Ideal for autonomous content generation
- Clean namespace-based API
Complete Coverage
- Pages, databases, data sources
- File uploads with automatic handling
- Users and workspace search
MCP Server
Notionary ships a built-in Model Context Protocol server so AI agents can manage your Notion workspace out of the box.
pip install notionary[mcp]
Use with the OpenAI Agents SDK
import asyncio
import sys
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
async def main():
async with MCPServerStdio(
name="Notionary",
params={
"command": sys.executable,
"args": ["-m", "notionary.mcp.server"],
},
) as server:
agent = Agent(
name="Notion Assistant",
instructions="You help users manage their Notion workspace.",
mcp_servers=[server],
)
result = await Runner.run(agent, "Search my workspace and list what you find.")
print(result.final_output)
asyncio.run(main())
Use with Claude Desktop / Claude Code
Add to your MCP config:
{
"mcpServers": {
"notionary": {
"command": "notionary-mcp",
"env": {
"NOTION_API_KEY": "your_integration_key"
}
}
}
}
Available Tools
| Area | Tools |
|------|-------|
| Workspace | search_workspace |
| Pages | list_pages, find_page, get_page_content, get_page_comments, update_page, append_to_page, replace_page_content, clear_page, comment_on_page, rename_page, set_page_property, trash_page, restore_page, lock_page, unlock_page |
| Data Sources | list_data_sources, find_data_source, get_data_source_schema, create_page_in_data_source, update_data_source, list_data_source_templates, trash_data_source, restore_data_source |
| Databases | list_databases, find_database, create_database, update_database, trash_database, restore_database |
| Users | list_users, search_users, get_me |
Full Documentation
mathisarends.github.io/notionary – Complete API reference with auto-generated docs from source code
Contributing
We welcome contributions from the community! Whether you're:
- Fixing bugs - Help improve stability and reliability
- Adding features - Extend functionality for new use cases
- Improving docs - Make the library more accessible
- Sharing examples - Show creative applications and patterns
Check our Contributing Guide to get started.
<div align="center">
Ready to revolutionize your Notion workflows?
📖 Read the Docs · 💻 Browse Examples
Built with ❤️ for Python developers and AI agents
</div>Related Skills
apple-reminders
350.1kManage Apple Reminders via remindctl CLI (list, add, edit, complete, delete). Supports lists, date filters, and JSON/plain output.
node-connect
350.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
109.9kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
109.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
