The round trip is what makes it usable: read a page as markdown, change a heading's section or one toggle, and write only that back, with update_block preserving the block identity that deep links and comment threads hang off. Two things to respect — the destructive tools announce themselves, since update_section and update_toggle delete before they write and a failed write is not rolled back, and the integration only sees pages that have been shared with it, which is the usual reason a page appears to be missing.
A markdown-first Notion server. Content goes in as GFM markdown and is converted server-side into native Notion blocks, and comes back as markdown, so a page can be read, edited and written back without reconstructing the block tree.
- create_page and create_page_from_file build a page from markdown or a local markdown file; append_content adds to one, replace_content rewrites it atomically in a single Notion call
- Surgical edits rather than whole-page rewrites: update_section by heading, update_block in place by id — preserving deep-link anchors and inline comment threads — find_replace for text, and update_toggle keeping the toggle's own block id
- read_page, read_section, read_block and read_toggle return markdown at whatever grain you need, with nested blocks fetched recursively
- search_in_page searches a page's block text, optionally scoped to one toggle or toggleable heading
- Toggles archived and restored by title and archived block id, and pages archived, restored, moved, duplicated and shared as a URL
- Databases created and inspected: get_database returns property names, types and select options, list_databases enumerates what the integration can reach, and query_database filters, sorts or keyword-searches
- Entries added one at a time or in bulk with simple key-value properties such as {"Status": "Done"}, then updated or deleted
- Database views listed, read, created, updated, queried and deleted, with deletion requiring confirm set to exactly true
- Comments listed and added, workspace users listed, get_me for the bot identity
- Tools that destroy content say so in their own description — update_section and update_toggle delete blocks before writing, with no rollback
- A prompt-injection defence built in: a content notice prefix and URL sanitisation on what comes back from Notion
- A CLI with named profiles in ~/.config/easy-notion-mcp/profiles.json, so read-only and read-write Notion integrations can be kept separate without registering another MCP server
A Notion integration token in NOTION_TOKEN, with the pages shared to that integration — a page the integration cannot see does not exist as far as the tools are concerned. NOTION_ROOT_PAGE_ID sets the default parent for create_page. It runs as npx -y easy-notion-mcp over stdio. OAuth is the alternative for shared deployments, needing NOTION_OAUTH_CLIENT_ID and NOTION_OAUTH_CLIENT_SECRET; the HTTP server binds 127.0.0.1 and requires NOTION_MCP_BEARER in static-token mode, with NOTION_MCP_BIND_HOST to change the bind.
One command plus a key — npx easy-notion-mcp, then supply credentials
