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.2.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.2-py3-none-any.whl (80.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: notionary-0.6.2.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.2.tar.gz
Algorithm Hash digest
SHA256 d0b5c2879f6ebe9d5454527dadb48b9f374c59cea59a0721a4a102fa6dc8dc47
MD5 fbd151b880e13b89e9453b8a6488ca8c
BLAKE2b-256 5cae65201bf1c989584eed8b6053706d84b193783305c1956a6c376c4e9c8f80

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for notionary-0.6.2-py3-none-any.whl
Algorithm Hash digest
SHA256 2b478706ec2b0451d8a178cfd2dd8ab4a212694f5f56c290f3d913b640a37dcb
MD5 303ae080187f380e075180e92540deec
BLAKE2b-256 213e9c9327dbd81c76e77e9949cf1e12526d982363cc68a11f479ae3a72d586a

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