notion-plus-mcp-server
Ships a GitHub Actions workflow that runs the server's Notion automation rules hourly (at minute 17) from the committed rules file, with a manual Run workflow button that accepts dry_run (on by default) and specific-rule inputs.
Provides tools for precise editing of Notion pages and databases: patching individual blocks by id, inserting markdown or structured blocks, find/replace that preserves formatting, deleting blocks, and trashing pages. For data it reads pages and schemas, queries rows with simple filters or raw Notion filters, creates pages, updates properties with schema validation and forgiving name matching, and performs filtered bulk updates with dry-run previews and rate limiting. It also manages schema (adding properties, adding select/multi-select options, renaming properties), records an undo journal so any prior write can be reverted, supports an optional expected-last-edited-time guard against stale overwrites, and can run scheduled rules that query a database and set/append/comment/trash matching rows.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@notion-plus-mcp-serverBulk update all rows in Tasks where Status is Blocked to In Progress, preview first"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
notion-plus-mcp-server
A local MCP server for Notion built for precise edits. It changes exactly the block or field you point at, checks every value against the database schema before writing, previews risky changes, and can undo anything it did.
Why this instead of the built-in Notion connector
Built-in connector | notion-plus | |
Editing page content | Rewrites content | Patches one block by id, inserts at an exact position, find/replace that keeps formatting and mentions |
Setting properties | Values passed through as-is | Validated against the schema; forgiving name and option matching; all errors reported at once |
Bulk changes | One call per row | Filtered bulk update with dry-run preview and rate limiting |
Mistakes | Manual cleanup | Every write returns an |
Stale overwrites | Not detected | Optional |
Schema changes | Limited | Add properties, add select options, rename properties |
Related MCP server: Notion Weaver
Setup
1. Create a Notion integration. Go to https://www.notion.so/profile/integrations, create an internal integration, enable read content, update content, insert content, and (if you want automations to comment) insert comments, then copy the secret. To set people properties by name or email, also enable "Read user information including email addresses". Personal access tokens can't look up users at all; with one, pass user ids.
2. Share pages with it. In Notion, open each top-level page or database you want Claude to reach, click ••• → Connections, and add the integration. Everything under a shared page is included.
3. Install. Requires Node 20 or later.
git clone https://github.com/katekruger/notion-mcp.git
cd notion-mcp
npm ci
npm run buildTo update later: git pull && npm ci && npm run build, then restart Claude (or start a new Claude Code session).
4. Connect it to Claude. Use the full path to your clone.
Claude Code:
claude mcp add notion-plus --env NOTION_TOKEN=ntn_your_secret_here -- node /ABSOLUTE/PATH/TO/notion-mcp/dist/index.js
claude mcp list # notion-plus should show as connectedClaude Desktop: open Settings → Developer → Edit Config, and add this to claude_desktop_config.json, then restart Claude Desktop:
{
"mcpServers": {
"notion-plus": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/notion-mcp/dist/index.js"],
"env": { "NOTION_TOKEN": "ntn_your_secret_here" }
}
}
}Turn off the built-in Notion connector while using this one so Claude doesn't pick between two sets of Notion tools. Keep the token out of the repo: it belongs only in your Claude config (or a local .env, which is gitignored).
5. Check it works. Ask Claude "search Notion for ". You should see notion_search results with ids. To call tools by hand instead, run NOTION_TOKEN=ntn_... npm run inspect to open the MCP Inspector.
6. Optional: scheduled automations. See Automations and GitHub Actions below.
Tools
Read
notion_search: find pages and databases by title.notion_get_page: properties plus a content outline with every block id.notion_get_blocks: read one section of a large page.notion_find_blocks: locate blocks by text or regex.notion_get_schema: property types, options, status groups, relations.notion_query: rows via simplewherepairs or raw Notion filters.
Write content
notion_patch_block: edit one block's text, checkbox, code language, or color.notion_insert_blocks: add markdown or structured blocks at the start, end, or after a specific block.notion_replace_text: find and replace across a page, keeping formatting (dry run by default).notion_delete_blocks: trash specific blocks.
Write data
notion_update_properties: set row fields with validation.notion_create_page: new row or sub-page with content.notion_bulk_update: change every matching row (dry run by default).notion_trash_page: trash a page.
Schema
notion_add_property: add a column.notion_update_options: add select or multi-select options. (Renaming options isn't possible through the API; see limits.)notion_rename_property: rename a column.
Safety
notion_history: recent changes and their undo ids.notion_undo: revert a change.
Automations (see below)
notion_automation_list: show the rules.notion_automation_add: check a rule against the live schema, save it, and preview what it would do.notion_automation_dry_run: show what each rule would change right now. Never writes.
The undo journal is stored in ~/.notion-plus/journal.json (last 500 changes; set NOTION_PLUS_HOME to move it). Undo restores the snapshot taken at write time, so it will also overwrite later edits to the same fields. Undoing notion_update_options deletes the added options, which also clears them from any rows that used them since.
Known Notion API limits
A block's type can't be changed in place; insert a new block and delete the old one.
Blocks can't be moved; insert a copy where you want it and delete the original.
Status options and Notion's built-in database automations can't be created or edited through the API.
Synced blocks, AI blocks, and some embeds are read-only.
Last-edited times are rounded to the minute, so the freshness check catches edits made in an earlier minute.
Select option names and colors can't be changed through the API. Renames are accepted and silently ignored; color changes are rejected. Rename options in Notion, or add a new option, move rows with
notion_bulk_update, and delete the old option in Notion.Leaving an option out of a schema update deletes it and clears it from every row.
One write can carry at most 100 relations or people, and at most 100 rich text segments per block or property (each segment up to 2000 characters). This server splits long text into segments and returns a clear error past those limits instead of truncating.
blocks.children.appendaccepts 2 levels of nesting per request; deeper content is added in follow-up requests automatically.Page reads include at most 25 items of a title, rich text, relation, or people value. Undo snapshots and before/after previews re-read the full value, so nothing is lost;
notion_get_pageand bulk dry-run previews may still show only the first 25.New databases take a few seconds to appear in
notion_search.Notion merges adjacent text segments with identical formatting when you read them back, and normalizes link URLs (for example adding a trailing
/).Undoing a large insert trashes blocks one request at a time (about 3 per second).
Automations
Rules in automations/rules.json run on a schedule. Each rule is a database query; every row it matches gets the rule's actions. There are no webhooks: a GitHub Actions workflow checks hourly.
{
"version": 1,
"timezone": "America/New_York",
"rules": [
{
"id": "stamp-completed",
"database": "https://www.notion.so/…",
"when": { "where": { "Status": "Done", "Completed Date": null } },
"actions": [{ "set": { "Completed Date": "{{today}}" } }]
},
{
"id": "archive-stale",
"database": "https://www.notion.so/…",
"when": { "where": { "Status": "Done" }, "relative": [{ "property": "$last_edited", "older_than_days": 30 }] },
"actions": [{ "trash": true }],
"limit": 20
},
{
"id": "welcome-high-priority",
"database": "https://www.notion.so/…",
"when": { "where": { "Priority": "High" } },
"actions": [{ "comment": "Flagged high priority: {{page.Name}}" }, { "append": "- [ ] Triage by {{today}}" }],
"marker": "Automated"
}
]
}Conditions (when): where and filter work exactly like notion_query. relative takes {property, older_than_days} or {property, newer_than_days} for a date, created time, or last edited time property, or "$created" / "$last_edited".
Actions: {"set": {...}} (validated like notion_update_properties), {"append": "markdown"} or blocks, {"comment": "text"}, {"trash": true}. Strings can use {{today}} (in the file's timezone), {{now}}, {{page.<Property>}}, {{page.url}}, and {{page.id}}.
Each rule acts once per row. Because rules are re-checked every hour, a rule must stop matching a row after acting on it, or it would act again on every run. The runner refuses a rule unless it changes a property its condition checks to a different value, trashes the row, or names a marker: a checkbox property the runner requires to be unchecked and then checks.
Other options: enabled (default true), limit (rows per run, default 50; the rest wait for the next run), allow_new_options, data_source_name.
Running
npm run automations -- --dry-run # preview every enabled rule
npm run automations -- --rule stamp-completed
npm run automations # applyOne run acts on at most 200 rows across all rules (--max-writes or AUTOMATIONS_MAX_WRITES). A failing rule is reported and the others still run. Each rule's run is one journal entry, so notion_undo <undo_id> reverts it. Comments can't be deleted through the API; undo leaves them.
From Claude, add rules with notion_automation_add (it saves to the local rules file); commit automations/rules.json so the scheduled workflow picks them up.
GitHub Actions
.github/workflows/automations.yml runs the rules hourly (at minute 17) from the committed automations/rules.json, and has a manual Run workflow button with dry_run (on by default for manual runs) and rule inputs.
One-time setup
Make a token for the job. Create a separate internal integration (step 1 of Setup) and share only the databases your rules touch with it. Enable insert comments if rules comment. This limits what the scheduled job can reach.
Add it as a repository secret. Open the repo on GitHub, click the repo's Settings tab (the one after Insights, not the Settings in your profile menu), then Secrets and variables → Actions → New repository secret. Name it
NOTION_TOKENand paste the token. Direct link:https://github.com/<owner>/notion-mcp/settings/secrets/actions.Test the workflow. Go to Actions → Notion automations → Run workflow, leave "dry run" checked, and run it. A green run with "No enabled rules." in the summary means the token and workflow are working.
Adding a rule
In Claude, ask for it in plain words, for example: "Add an automation to the Projects database that stamps Completed Date with today when Status is Done and Completed Date is empty." Claude uses
notion_automation_add, which checks the rule against the live database, shows the rows it would act on, and saves it to your localautomations/rules.json.Commit and push
automations/rules.json.Run the workflow once by hand with "dry run" checked and read the summary. After that, the hourly runs apply it.
To pause a rule, set "enabled": false and push. To stop everything, disable the workflow under Actions → Notion automations → ••• → Disable workflow.
Undoing a scheduled run
Each run writes its summary (with an undo id per rule) to the run page and uploads the undo journal as an artifact named notion-plus-journal-<run id>, kept 90 days. To revert:
Download the artifact from the run page and unzip it into a folder.
Run
NOTION_TOKEN=ntn_... NOTION_PLUS_HOME=/path/to/that/folder npm run inspect, or point your Claude config'sNOTION_PLUS_HOMEat it.Call
notion_undowith the undo id from the run summary.
GitHub may start scheduled runs a few minutes late, and turns off schedules in repos with no activity for 60 days.
Development
npm test # offline unit tests (no network)
npm run typecheck # src, scripts, and tests
npm run smoke # live test against a real workspacenpm run smoke needs NOTION_TOKEN and NOTION_TEST_PAGE (a page shared with the integration), from the environment or a local .env file (gitignored). It creates two throwaway databases under that page, runs every tool including dry runs and notion_undo for each write type, then moves them to the trash. It never writes outside the test page, and its undo journal goes to a temp folder. Set SMOKE_KEEP=1 to keep the databases for inspection.
Roadmap
Page templates, comments, and move/copy helpers.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
- LiveCRMOAuthai.livecrm
Typed, deterministic tools on a live Salesforce or HubSpot copy, every write audited and reversible.
Safe write access for AI agents. Every change is kept, attributed, and can be undone.
- SnipgetOAuthai.snipget
300+ deterministic data utilities for AI agents: validate, normalize, parse, match, redact.
Related MCP Servers
- FlicenseAqualityDmaintenanceEnables interaction with Notion databases through the Notion API, supporting full CRUD operations on pages and databases. Supports advanced querying, filtering, sorting, and all property types with Docker deployment for easy integration with Cursor and Claude.8-
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI workflows to integrate with Notion workspaces, supporting page and database creation, queries with filters and sorting, content updates, and workspace-wide search operations.-
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to read and write to Notion databases with schema adaptation and stable API integration.7Apache 2.0
- AlicenseNot gradedqualityAmaintenanceNotion-like workspace of pages and customizable databases with a remote MCP server (OAuth 2.1 + PKCE, scoped read/write tokens, full audit log). 14 tools to search, read, and write pages, database rows, and database schemas.73AGPL 3.0