A toolkit for exporting Obsidian Markdown notes to Notion. It handles Obsidian-specific syntax — YAML frontmatter, [[wikilinks]], and callout blocks — and supports two export modes: an offline Python script that produces a Notion-importable Markdown file, and an online mode that pushes pages directly to Notion via an MCP server connected through OpenCode and LiteLLM.
- YAML frontmatter → Notion page properties: Frontmatter is preserved as a clean
---YAML block. When imported into a Notion database, fields map to typed properties:title→ page titledate→ Date property (normalised toYYYY-MM-DD)tags→ Multi-select propertycategories→ Multi-select propertypublished→ Checkbox propertyslug→ Rich text property
[[wikilinks]]preserved: Wikilinks are kept in their original Obsidian syntax so they are easy to find in Notion and manually converted to@mentions.- Obsidian callouts → emoji blockquotes: Callout blocks (
> [!type]) are converted to emoji-prefixed blockquotes that are visually distinct after import. - HTML comments stripped:
<!-- ... -->blocks are removed from the output. - Everything else passed through: Tables, headings, lists, bold, italic, inline code, and external links are left unchanged for Notion to parse on import.
- Named output files: Each exported file is named
<original-filename>-notion-export.md.
- Native Notion blocks: Pages are created with proper native block types — real callout blocks, typed page properties, and resolved wikilinks — rather than Markdown approximations.
- Wikilink resolution: OpenCode searches Notion for matching page titles and links them directly.
- Prompt-driven: A reusable prompt template (
prompt-export-notion.md) instructs OpenCode exactly how to handle each element, invoked via the Agent Client Plugin inside Obsidian.
- Single entry point:
export.shhandles both modes interactively. - Mode selection: Choose offline (Python script) or online (MCP server) at runtime.
- Source and destination prompts: Specify any Obsidian vault folder as source and any local folder as destination, with example paths provided.
- Auto-creates destination: Offers to create the destination folder if it does not exist.
- Confirmation step: Shows a summary before processing any files.
- Recursive file discovery: Finds all
.mdfiles in the source folder, excluding previously exported*-notion-export.mdfiles.
| Obsidian type | Emoji |
|---|---|
note / info |
📝 / ℹ️ |
summary / abstract / tldr |
📋 |
tip / hint |
💡 |
important |
❗ |
warning / caution |
|
danger |
🚨 |
bug |
🐛 |
example |
📌 |
quote |
💬 |
todo |
✅ |
question |
❓ |
failure |
❌ |
ONLINE MODE (native Notion blocks)
Obsidian
└── Agent Client Plugin
└── OpenCode
└── LiteLLM gateway
└── Notion MCP server
└── Notion API
OFFLINE MODE (Notion-importable Markdown)
Obsidian note (.md)
└── export.sh → convert.py
└── <filename>-notion-export.md
└── Notion: Settings → Import → Markdown & CSV
- Offline mode: Python managed via pyenv + uv
- Online mode: Obsidian with the Agent Client Plugin, OpenCode running locally, LiteLLM configured as the gateway, Notion MCP server connected via LiteLLM, and a Notion integration token (see below)
-
Clone the repository:
git clone https://github.com/axelquack/obsidian2notion.git cd obsidian2notion -
Install Python dependencies (offline mode only):
uv add python-frontmatter
-
Make the shell script executable:
chmod +x export.sh
The Notion MCP server authenticates against the Notion API, so a token is required regardless of the MCP/LiteLLM abstraction on top. Check notion.so/my-integrations first — you may already have one.
To create a new token:
- Go to notion.so/my-integrations
- Click New integration
- Give it a name (e.g.
OpenCode Export) and select your workspace - Copy the Internal Integration Token (
secret_...) - Add the token to your MCP server config — LiteLLM/OpenCode holds it, not this script
To grant the integration access to your pages:
- Open the target page or database in Notion
- Click
···(top right) → Connections - Find and add your integration by name
Run the interactive shell script from the project folder:
cd ~/Documents/Projects/obsidian2notion
./export.shOr from anywhere using the full path:
~/Documents/Projects/obsidian2notion/export.shThe script will prompt for:
- Mode: offline (Python script) or online (MCP server)
- Source folder: your Obsidian vault or a subfolder, e.g.:
~/Documents/Obsidian/MyVault~/Documents/Obsidian/MyVault/Projects
- Destination folder (offline only): where exported files are written, e.g.:
~/Documents/notion-exports~/Desktop/notion-ready
Import into Notion via Settings → Import → Markdown & CSV and upload the exported file(s).
- Frontmatter maps to page properties only when importing into a Notion database. Importing to a plain page will ignore the YAML block.
[[wikilinks]]are kept as-is. In Notion, find them and type@PageNameto convert to internal page mentions.
The online mode relies on the following stack running locally:
- Obsidian with the Agent Client Plugin — sends note content to OpenCode
- OpenCode — the AI coding agent that executes the prompt
- LiteLLM — acts as the gateway between OpenCode and connected MCP servers
- Notion MCP server — exposes Notion API tools (
search,create_page,append_block_children) to OpenCode
Setup:
- Configure the Notion MCP server in LiteLLM with your Notion integration token
- In the Agent Client Plugin settings, set Default agent to
OpenCode (opencode) - Enable Auto-mention active note — this automatically includes the current note's content in every message sent to OpenCode, no manual copy-paste needed
Usage:
- Open the note you want to export in Obsidian
Cmd+P→ Agent Client: New chat- Paste the contents of
prompt-export-notion.mdinto the chat and press Enter - OpenCode receives the prompt and the note content automatically, then uses the Notion MCP tools to create the page
- OpenCode returns the URL of the newly created Notion page
| Feature | Online (MCP) | Offline (script) |
|---|---|---|
| Frontmatter → page properties | ✅ Native typed properties | ✅ YAML block (maps on database import) |
[[wikilinks]] |
✅ Resolved to Notion page URLs | |
| Obsidian callouts | ✅ Native Notion callout blocks | |
| Tables | ✅ Native Notion table blocks | ✅ Passed through |
| Headings, lists, code, bold | ✅ Native blocks | ✅ Passed through |
| Requires internet / token | Yes | No |
obsidian2notion/
├── export.sh # Interactive entry point — run this
├── convert.py # Offline conversion script (called by export.sh)
├── prompt-export-notion.md # OpenCode prompt template for online export
├── pyproject.toml # uv dependency config
├── uv.lock # uv lockfile
└── README.md # This file
Feel free to fork this repository, adapt it, and submit pull requests. Suggestions for additional Obsidian syntax conversions, new callout types, or improvements to the prompt template are welcome.
This project is licensed under the Apache License 2.0.
- You are free to: Use, copy, modify, and distribute this work for any purpose, including commercial use.
- Conditions: You must include a copy of the license and any NOTICE file, state any changes made, and retain all copyright and attribution notices.
- No warranty: This software is provided as-is, without warranties or conditions of any kind.