Skip to main content

Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support

Project description

Notionary logo

Notionary

PyPI version Python Version License: MIT Downloads Documentation Notion API

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. Also ships with a built-in MCP server for tool-use with any MCP-compatible AI agent.


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 editing Read a page as Markdown, transform it, write it back
Full coverage Pages, databases, data sources, file uploads, users, workspace search

Installation

pip install notionary          # core library
pip install notionary[mcp]     # + MCP server

Set your Notion integration token:

export NOTION_API_KEY=your_integration_key

Quick Start

All access goes through the Notionary client, which exposes namespace objects — each mapping to a Notion API area.

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())

Core API

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()       # read as Markdown
    await page.append("## New Section") # append blocks
    await page.replace("# Replaced")   # overwrite all content
    await page.clear()                  # remove all blocks

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")
    await page.properties.set_property("Due Date", "2025-12-31")

Comments & Lifecycle

    await page.comment("Review completed")
    await page.lock()
    await page.trash()

Notion API Reference: Pages · Markdown


Databases

async with Notionary() as notion:
    # Lookup
    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

Data sources represent queryable Notion databases with schema awareness — useful for building structured content pipelines.

async with Notionary() as notion:
    ds = await notion.data_sources.find("Engineering Backlog")

    # Schema introspection
    schema = await ds.get_schema()

    # Create a page inside the data source
    page = await ds.create_page(title="New Feature")

    # Query with filters
    results = await ds.query(filter={"property": "Status", "select": {"equals": "In Progress"}})

    # 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 (e.g. generated images, in-memory content)
    result = await notion.file_uploads.upload_from_bytes(
        content=image_bytes,
        filename="chart.png",
    )

    # List previous 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

  • Find pages and databases by human-readable name
  • Fuzzy matching handles typos and partial titles
  • No more hunting for opaque IDs or copying page URLs

Markdown Content API

  • Read any Notion page as clean Markdown
  • Append or replace blocks using Markdown syntax
  • Powered by the official Notion Markdown API

Round-Trip Editing

# Read → transform → write back
md = await page.get_markdown()
updated = md.replace("Draft", "Final")
await page.replace(updated)

Modern Python

  • Full async / await support throughout
  • Type hints on all public APIs
  • Pydantic models for all API responses
  • Context-manager client for clean resource handling

AI-Ready Architecture

  • Namespace-based API maps naturally to agent tool sets
  • Predictable response models enable prompt chaining
  • Works with LangChain, LlamaIndex, OpenAI Agents SDK, Claude, and any MCP-compatible host

MCP Server

Notionary ships a built-in Model Context Protocol server so any MCP-compatible AI agent can manage your Notion workspace out of the box.

pip install notionary[mcp]

Claude Desktop / Claude Code

{
  "mcpServers": {
    "notionary": {
      "command": "notionary-mcp",
      "env": {
        "NOTION_API_KEY": "your_integration_key"
      }
    }
  }
}

OpenAI Agents SDK

import asyncio, 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())

Available MCP 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

Contributing

Contributions are welcome — whether you're fixing bugs, adding features, improving docs, or sharing examples. Check the Contributing Guide to get started.


Documentation

mathisarends.github.io/notionary — Complete API reference auto-generated from source.


Built with ❤️ for Python developers and AI agents

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

notionary-0.6.3.tar.gz (17.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

notionary-0.6.3-py3-none-any.whl (81.1 kB view details)

Uploaded Python 3

File details

Details for the file notionary-0.6.3.tar.gz.

File metadata

  • Download URL: notionary-0.6.3.tar.gz
  • Upload date:
  • Size: 17.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for notionary-0.6.3.tar.gz
Algorithm Hash digest
SHA256 0ee03e9465676a3c1782c63c1e3faee67efac9b4f903c5f7920eb02d2567827e
MD5 e7cc17e0faec3f05aa656800d9b9a4d6
BLAKE2b-256 32033e8a806cc7fb02f423765b822c951cd42c27176c698ea69c7e3a3bc25c16

See more details on using hashes here.

File details

Details for the file notionary-0.6.3-py3-none-any.whl.

File metadata

  • Download URL: notionary-0.6.3-py3-none-any.whl
  • Upload date:
  • Size: 81.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for notionary-0.6.3-py3-none-any.whl
Algorithm Hash digest
SHA256 e49bb38b4a0afd1edc2e0bd5213c1ebb09a590fc4e6454b941320466bd11a827
MD5 5052708ec7344e208584362646a59cef
BLAKE2b-256 cbee4ae857d145dd1e71d72c571c0da73b51fe87457fdec328470452c34b2d3d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page