# notion-api-mcp-skill > Best practices for Notion API MCP tools. Use when:(1) Working with page properties or metadata, (2) Querying databases or searching pages, (3) Creating or updating content blocks, (4) Handling parent parameter validation errors, or (5) Avoiding move-page parent serialization issues - Author: Wang YiMing - Repository: yuyangzi/notion-api-mcp-skill - Version: 20260127202739 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/yuyangzi/notion-api-mcp-skill - Web: https://mule.run/skillshub/@@yuyangzi/notion-api-mcp-skill~notion-api-mcp-skill:20260127202739 --- --- name: notion-api-mcp-skill description: Best practices for Notion API MCP tools. Use when:(1) Working with page properties or metadata, (2) Querying databases or searching pages, (3) Creating or updating content blocks, (4) Handling parent parameter validation errors, or (5) Avoiding move-page parent serialization issues --- # Notion API MCP Practices ## Overview Proven patterns and critical warnings for using Notion API MCP tools reliably. Focus on property updates over page moves, correct parent object structures, and proper error handling. ## When to Use This Skill **Core Operations:** - Updating page properties (title, icon, cover) → Use `patch-page` - Querying databases for page lists → Use `query-data-source` with `data_source_id` - Searching pages or databases by title → Use `post-search` - Retrieving page content → Use `get-block-children` - Adding content blocks → Use `patch-block-children` **Avoid:** - **Move pages** with `move-page` → High risk of serialization errors. Use property updates instead. ## Parent Type Selection | Parent Type | Required Fields | When to Use | |-------------|----------------|-------------| | `database_id` | `database_id` (UUID) | Legacy databases (pre-2025-09-03) | | `data_source_id` | `data_source_id` (UUID) + `database_id` (UUID) | Modern databases (2025-09-03+) | | `page_id` | `page_id` (UUID) | Creating sub-pages under existing pages | | `workspace` | `workspace: true` | Creating root-level pages | | `block_id` | `block_id` (UUID) | Creating pages under specific blocks | **Critical Rule:** Always pass parent as object, NOT JSON string. See [references/parent-types.md](references/parent-types.md) for detailed examples. ## data_source_id vs database_id - `query-data-source` tool → Use `data_source_id` - Other operations → Check specific tool requirements - `data_source_id` type ALWAYS requires both `data_source_id` AND `database_id` fields ## Error Handling Priorities **Immediate Actions:** - **400 validation error** → Check parameter format, especially parent object structure - **401 unauthorized** → Regenerate NOTION_TOKEN - **403 forbidden** → Share integration with page/database in Notion UI - **429 rate limited** → Wait for `Retry-After` header, implement backoff See [references/error-codes.md](references/error-codes.md) for complete error reference and handling strategies. ## Operational Limits - **Rate limit**: 3 requests/second average - **Pagination**: Use cursor-based iteration, never assume single page returns all - **Block limits**: 100 blocks per request, 2 nesting levels max - **Payload size**: 500KB maximum ## Core Workflows ### Update Page Properties 1. Search for page with `post-search` 2. Update with `patch-page(page_id, properties)` 3. Verify changes ### Query Database 1. Use `query-data-source(data_source_id, start_cursor, page_size)` 2. Process results in batches 3. Continue until `has_more` is false ### Add Content 1. Retrieve block structure with `get-block-children` 2. Append blocks with `patch-block-children(block_id, children)` 3. Use `after` parameter for position control See [references/workflows.md](references/workflows.md) for complete code examples. ## Red Flags - STOP and Reconsider **Critical Warnings:** - Attempting to use `move-page` with complex parent objects - Seeing "body.parent should be an object" errors - Assuming `database_id` works everywhere (check tool specs) - Using `data_source_id` without `database_id` field - Missing required fields in parent objects - Forgetting Notion-Version header in custom implementations **Solution:** Use property updates and database organization instead of parent manipulation. ## Reference Materials | Topic | File | |--------|-------| | **Complete error codes** | [references/error-codes.md](references/error-codes.md) | | **All 12 property types** | [references/property-types.md](references/property-types.md) | | **Block operations** | [references/block-operations.md](references/block-operations.md) | | **Parent type details** | [references/parent-types.md](references/parent-types.md) | | **Complete workflows** | [references/workflows.md](references/workflows.md) | | **Testing patterns** | [references/testing.md](references/testing.md) |