notion-full-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| NOTION_API_TOKEN | Yes | Your Notion API token |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| extensions | {
"io.modelcontextprotocol/ui": {}
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| search_pagesA | Search Notion pages by title. Returns page IDs, titles, and URLs. |
| searchA | Search Notion pages and/or databases. Args: query: Text to search for. filter_type: Restrict results to "page", "database", or "" for both. max_results: Maximum number of results to return. |
| get_page_infoB | Get metadata for a Notion page (title, parent, dates, URL). |
| read_page_deepA | Read a Notion page with all nested children recursively. Args: page_id: The Notion page ID. max_depth: Maximum nesting depth to fetch (default 5). format: Output format - 'markdown' for readable text, 'json' for full block tree. Returns full document content including nested blocks like sub-lists, toggle contents, and table rows. |
| list_block_childrenA | List direct children of a block or page (shallow, no recursion). Returns block IDs, types, and optionally their text content. Useful for finding specific block IDs before surgical edits. |
| update_block_textA | Replace all text in a specific block with new plain text. Preserves the block type but replaces all rich text content. Use find_replace_in_block for targeted text changes that preserve formatting. |
| find_replace_in_blockA | Find and replace text within a block, preserving all formatting. Replaces occurrences of old_text with new_text in each rich text segment while keeping bold, italic, links, and other annotations intact. Returns an error (not a silent no-op) if old_text does not appear in the block. The error message includes the block's current plain text so the caller can diagnose Unicode / whitespace / formatting mismatches (e.g., en-dash U+2013 vs hyphen-minus U+002D, curly vs straight quotes, non-breaking space U+00A0 vs regular space). Use update_block_text or update_table_cell for full-text replacement when find/replace doesn't match because of character mismatches. The success response includes a |
| update_block_rich_textB | Update a block's rich text with fully specified formatting. rich_text_json should be a JSON array of rich text objects, e.g.: [{"type":"text","text":{"content":"Bold text"},"annotations":{"bold":true}}] |
| insert_blocks_afterA | Insert new blocks after a specific block. blocks_json should be a JSON array of block objects. Use make_block format: [{"type":"paragraph","paragraph":{"rich_text":[{"type":"text","text":{"content":"Hello"}}]}}] For simple cases, use insert_text_after instead. |
| insert_text_afterC | Insert a simple text block after a specific block. Args: block_id: The block to insert after. text: The text content. block_type: Block type (paragraph, heading_1, heading_2, heading_3, bulleted_list_item, numbered_list_item, quote, etc.) |
| append_blocks_to_pageB | Append blocks to the end of a page. blocks_json should be a JSON array of block objects. |
| upload_fileA | Upload a file to Notion's own storage. Returns a Args: file_path: Local path to the file (PNG, JPEG, GIF, SVG, PDF, etc.) Files up to 20 MiB use single-part mode. |
| upload_image_as_blockA | Upload an image file to Notion and insert it as a new image block. This is the standard replacement for imgur-hosted images. The image is stored in Notion's own workspace storage. Args: file_path: Local path to the image (PNG, JPEG, GIF, SVG, WEBP, etc.) after_block_id: If provided, insert immediately after this block (siblings). parent_id: If after_block_id is empty, append to this page/block instead. caption: Optional caption text for the image. Exactly one of after_block_id or parent_id must be provided. |
| replace_image_blockA | Replace an existing image block's content with a newly uploaded image. Preserves the block's position in the parent by deleting the old block and inserting the new one after the previous sibling. If the image block is the very first child of its parent, the new block is appended to the end (Notion does not support prepend-at-position). Args: block_id: The existing image block to replace. file_path: Local path to the new image. caption: Optional caption for the new image (omit to drop the old one). |
| download_image_blockA | Download the image file from an image block to a local path. Works for all three image source types: external URL, Notion-hosted file, and file_upload references. Notion-hosted URLs are signed and short-lived, so this tool re-fetches them at call time. Args: block_id: The image block to download from. output_path: Local path to write the image to. |
| upload_file_as_blockA | Upload a file (PDF, doc, any attachment) to Notion and insert as a file block. Analogous to upload_image_as_block but for non-image files. Use this for PDFs, spreadsheets, archives, etc. Args: file_path: Local path to the file. after_block_id: If provided, insert after this block (siblings). parent_id: If after_block_id is empty, append to this page/block. caption: Optional caption. name: Optional display name override (defaults to the filename). |
| insert_table_rowA | Insert a new row into an existing table. The number of cells must match the table's existing width. Args: table_id: The table block ID. cells_json: JSON array. Each element is either: - a plain string (single text segment) - a list of strings (multi-segment plain text in one cell) Example for a 4-column table: '["SMB", "$15K", "$0.015", "$80k - $300k"]' after_row_id: Optional row ID to insert after. If empty, append to end. |
| update_table_cellA | Replace the text of a single cell in a table row. Args: row_id: The table_row block ID. cell_index: Zero-based index of the cell within the row. new_text: New plain-text content for the cell. Overwrites all existing rich text segments in that cell. |
| delete_blockC | Delete a specific block by ID. |
| snapshot_pageA | Create a complete snapshot of a page with all nested children. Saves to a JSON file if output_path is provided. The snapshot includes the full block tree with recursive children, suitable for restore. Default path: ~/notion-snapshots/<page_id>_.json |
| restore_page_from_snapshotA | Restore a page from a previously saved snapshot. WARNING: This deletes all current content and replaces it with the snapshot. Always take a snapshot of the current state before restoring. Args: page_id: The page to restore into. snapshot_path: Path to the snapshot JSON file. |
| create_pageA | Create a new Notion page under a parent page or database. Args: parent_id: ID of the parent page or database. title: Title for the new page. parent_type: "page_id" (default) or "database_id". icon_emoji: Optional emoji character to use as the page icon. children_json: Optional JSON array of block objects for initial content. properties_json: Optional JSON object of additional database properties to set. Example for setting Status: {"Status": {"status": {"name": "Done"}}} Example for setting Date: {"Due date": {"date": {"start": "2026-04-15"}}} |
| update_pageA | Update a page's title, icon, or archive status. Only fields with non-default values are sent in the PATCH body. To archive a page pass archived=True; to unarchive pass archived=False (but note the server only sends archived when a caller explicitly toggles it — see the implementation which guards on the sentinel value). Args: page_id: The page to update. title: New title text. Omit or pass "" to leave unchanged. icon_emoji: New icon emoji. Omit or pass "" to leave unchanged. archived: Pass True to archive the page. Defaults to False (no change sent). properties_json: Optional JSON object of database properties to set. Example: {"Status": {"status": {"name": "Done"}}} Example: {"Due date": {"date": {"start": "2026-04-15"}}} Can be combined with title — both will be applied. |
| move_pageA | NOT SUPPORTED: Notion's public API does not support moving a page. The PATCH /pages/{id} endpoint silently ignores parent field changes -- the call returns HTTP 200 but the page is not actually moved. This tool is preserved only to return a clear error message and point callers to the working alternatives. To move a page, use one of these instead: * copy_page_to_parent -- destructive recreate-and-archive (block IDs will change, file_upload media degrades to short-lived URLs) * Manually drag the page in the Notion sidebar (recommended for pages with nested subpages or heavy media content) |
| restore_pageA | Restore a page (and its children) from trash. This is the explicit counterpart to delete_block on a page. When called on a page that was archived via a cascade (for example, a section container that was deleted along with its subpages), restoring the parent container automatically restores the cascaded descendants. Args: page_id: The page to restore from trash. |
| copy_page_to_parentA | Recreate a page under a new parent (destructive workaround for move). Since Notion's public API does not support changing a page's parent, this tool works around the limitation by creating a new page at the target location with the same title, icon, and content, then archiving the original. LIMITATIONS (read carefully): * Block IDs of the new page are different from the original. Any external references to original block IDs (graphics-spec.md, cross-page links, Change Log entries) will point at the archived original and need to be updated. * file_upload image blocks are copied as external URL references using the Notion-signed URL returned at copy time. Those URLs expire within an hour. For permanent preservation, re-upload the source files via upload_image_as_block after the copy. * child_page descendants (nested subpages) are NOT recursively copied -- the tool refuses to run if any are present. Copy them individually. * Comments, page history, permissions, and synced blocks are not copied. Args: page_id: The source page to copy. new_parent_id: The target parent page or database ID. parent_type: "page_id" (default) or "database_id". archive_original: If True (default), archive the source page after the copy completes. Set False to keep both copies side-by-side. |
| create_commentB | Add a comment to a Notion page. |
| list_commentsC | List all comments on a page or block. |
| get_databaseB | Get metadata and schema for a Notion database. |
| query_databaseA | Query a Notion database with optional filters and sorts. Args: database_id: The database to query. filter_json: JSON string for a Notion filter object. Leave empty for no filter. sorts_json: JSON string for a Notion sorts array. Leave empty for no sorting. page_size: Maximum rows per page fetch (max 100). All pages are returned. |
| get_selfA | Get the current authenticated Notion user or bot info. |
| list_usersA | List all users in the workspace. |
| get_blockA | Get a single block by ID, including its type, content, and metadata. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/cphoskins/notion-full-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server