Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support
Project description
The Modern Notion API for Python & AI Agents
Transform complex Notion API interactions into simple, Pythonic code. Perfect for developers building AI agents, automation workflows, and dynamic content systems.
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
Smart Discovery
Markdown Content API
Modern Python
|
Round-Trip Editing
AI-Ready Architecture
Complete Coverage
|
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.
Ready to revolutionize your Notion workflows?
📖 Read the Docs · 💻 Browse Examples
Built with ❤️ for Python developers and AI agents
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file notionary-0.6.1.tar.gz.
File metadata
- Download URL: notionary-0.6.1.tar.gz
- Upload date:
- Size: 17.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42d85a701648a6d5f727417f067a8d7e810a6167b9d1c275427154d0b133cd19
|
|
| MD5 |
453bbec9e7f514050ea2e5aa72c5bed9
|
|
| BLAKE2b-256 |
c86cbc2785cba1f4d905a4eab360acd445a454e73d6f880b193b4055e1936e5f
|
File details
Details for the file notionary-0.6.1-py3-none-any.whl.
File metadata
- Download URL: notionary-0.6.1-py3-none-any.whl
- Upload date:
- Size: 75.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf6afee8b33f307f871fcbf1638150b61d8d5c4ac32a33cd58ca2eee017db6bf
|
|
| MD5 |
0fb4bb3863888b471839bb51863327e4
|
|
| BLAKE2b-256 |
75001cf3843443c26c43b9dc308a45e489b6070c552e4141950ec1cbfdecb01c
|