From better-notion-mcp
Transforms unstructured Notion pages into structured databases with correct property types, schema design, and migration via Notion API actions.
npx claudepluginhub n24q02m/better-notion-mcpThis skill uses the workspace's default tool permissions.
Transform unstructured Notion pages into a well-designed, queryable database.
Migrates data to/from Notion databases or between workspaces with property mapping, validation, rate limiting. For CSV/JSON imports, exports, syncing, ETL pipelines.
Automates Notion operations like creating/updating pages, querying/managing databases, blocks, comments, users via Rube MCP and Composio tools. Requires Rube MCP connection and Notion OAuth.
Interact with Notion workspaces via unofficial private API for full CRUD on pages, databases, blocks; plus search, users, comments using vibe-notion CLI.
Share bugs, ideas, or general feedback.
Transform unstructured Notion pages into a well-designed, queryable database.
Choose the right property type -- LLMs frequently pick the wrong one:
| Data pattern | Correct type | Wrong choice (common mistake) |
|---|---|---|
| Fixed categories (status, priority) | select | rich_text (loses filtering) |
| Multiple tags per item | multi_select | select (only allows one) |
| References to other DBs | relation | rich_text (breaks linking) |
| Computed from relations | rollup | formula (can't aggregate across DBs) |
| True/false flags | checkbox | select with Yes/No (over-engineered) |
| Long-form content | Page body (blocks) | rich_text property (2000 char limit) |
Every property value MUST use the correct nested format. The Notion API rejects flat values.
// WRONG -- flat values (API will error or silently fail)
{
"Tags": "engineering",
"Status": "In Progress",
"Description": "Some text"
}
// CORRECT -- properly typed nested objects
{
"Tags": { "multi_select": [{ "name": "engineering" }] },
"Status": { "select": { "name": "In Progress" } },
"Description": { "rich_text": [{ "text": { "content": "Some text" } }] },
"Name": { "title": [{ "text": { "content": "Page title" } }] },
"Done": { "checkbox": true },
"Due Date": { "date": { "start": "2026-03-23" } },
"URL": { "url": "https://example.com" },
"Count": { "number": 42 },
"Contact": { "email": "user@example.com" }
}
Key gotcha: rich_text is an ARRAY of text objects, never a plain string.
Audit existing content -- find the pages to organize:
pages(action="search", query="<topic>") to locate scattered pagesDesign schema -- create the database with identified properties:
databases(action="create", parent_id="<parent_page_id>", title="...", properties={
"Name": { "title": {} },
"Category": { "select": { "options": [{ "name": "..." }] } },
"Tags": { "multi_select": { "options": [{ "name": "..." }] } },
...
})
select for status/category -- it enables Notion's board view.Bulk-create pages from existing content:
pages(action="create", parent_id="<database_id>", properties={...}, content=[...])Archive old pages (only after user confirms migration looks correct):
blocks(action="delete", block_id="<old_page_block_id>") or move to archive pageVerify the new database:
databases(action="query", database_id="<id>") to list all entries