notion-plus-mcp-server
A local MCP server for Notion that provides precise, validated, undoable read/write operations, database and view management, charts/reports, and automations/workflows.
Search and read pages, blocks, databases, schemas, comments, and templates.
Query, aggregate, and bulk create/update rows with dry-run previews and schema validation.
Edit content surgically: patch/insert/delete/copy/move blocks, find/replace, update page properties/icons/covers/moves, duplicate pages.
Create and edit databases: full schemas, relations, rollups, formulas, unique IDs, property/option changes.
Manage views (table, board, calendar, timeline, gallery, form, chart, map, dashboard) and generate chart images/reports/Mermaid diagrams.
Automate recurring rules and multi-step workflows via schedules, webhooks, approval steps, and external HTTP/Slack actions.
Undo changes with snapshots, change history, recovery from interrupted writes, and safety checks against concurrent edits.
Run diagnostics and capability checks, and manage local state/templates for repeatable pages.
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 records undo for the writes it supports (best effort; see Undo coverage).
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 | Writes return an |
Stale overwrites | Not detected | Optional |
Schema changes | Limited | Create databases with relations, rollups, formulas, unique IDs, and status groups; add, rename, retype, or delete properties; manage options and number formats. Deleted properties keep their values for undo |
Views | Not available | Create, edit, and delete table, board, list, calendar, timeline, gallery, form, chart, map, and dashboard views |
Related MCP server: cs-ai-notion-mcp
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. Two ways:
One-click bundle (Claude Desktop and Cowork). Download the
.mcpbfile for your computer (darwin-arm64for Apple silicon Macs,darwin-x64for Intel Macs,win32-x64,linux-x64) from the Releases page, double-click it (or drag it onto Claude Desktop's Settings → Extensions), and paste your integration secret when asked. You can also pick a folder uploads may come from and your time zone. Cowork runs inside Claude Desktop and uses the extensions installed there. Skip to step 5.From source (for Claude Code, or to run automations). Requires Node 22 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).
To build a bundle yourself: npm run bundle writes bundles/notion-plus-<version>-<platform>-<arch>.mcpb. Bundles are per platform because chart images use a native renderer; pushing a v* tag builds all four in GitHub Actions and attaches them to a release.
4. Connect it to Claude (from source). 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 to "run notion_doctor". It checks the settings, the token, the integration's capabilities, whether any pages are shared with it, the local state folder, upload folders, and the chart renderer, and says how to fix anything that fails. Then ask "search Notion for "; you should see notion_search results with ids. If a setting is invalid (a misspelled time zone, say), the server still starts and every tool answers with the exact setting to fix. 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
Every tool answers with the same JSON shape:
{
"status": "ok | partial | error",
"summary": "one line",
"data": { "...the tool's own result..." },
"warnings": ["things to know, such as what couldn't be copied"],
"undo": { "id": "a1b2c3d4", "coverage": "full | partial | none" },
"pagination": { "next_cursor": "…" },
"next_actions": ["what to do next, when there's something to do"]
}Only status, summary, and data are always there. Results that would be too large shrink their longest lists and say how many items were left out (truncated); they're always valid JSON. Results that carry page, block, comment, or row text include a warning that the text is untrusted data, and the server's instructions tell the model the same: content in Notion pages isn't a source of instructions.
Read
notion_search: find pages and databases by title.notion_get_page: properties plus a content outline with every block id, or (format: "markdown") the whole page as Notion-flavored markdown that can be written back.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 viawhere(equality, operators,in,or/and, relative dates) or raw Notion filters.notion_aggregate: counts, sums, averages, and more, grouped by any property or date bucket, without pulling rows into context.
Write content
notion_patch_block: edit one block's text, checkbox, code language or caption, color, toggle heading, callout icon, or a table row's cells.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's text, table cells, captions, and title, keeping formatting (dry run by default).notion_delete_blocks: trash specific blocks.notion_copy_blocks: copy blocks with everything inside them to another spot, or move them (move: true, dry run by default).notion_comments: list, add, and reply to comments.
Pages
notion_update_page: title, icon, cover, lock, or move a page under another page or into a database.notion_duplicate_page: copy a page with its content, icon, cover, properties, sub-pages, and databases (schema and rows, or schema only withdatabases: "schema"). Sub-pages and databases keep their place in the page.notion_list_templates: a database's templates, fornotion_create_page'stemplate.
Write data
notion_update_properties: set row fields with validation.notion_create_page: new row or sub-page with content, an icon and cover, or from a database template.notion_bulk_update: set values on every matching row, or different values per row (dry run by default, up to 500 rows).notion_bulk_create: add up to 1000 rows from JSON or CSV (dry run by default; every row validated first).notion_trash_page: trash a page.
Databases
notion_create_database: a database with its full schema in one call: options (status options with groups), number formats, formulas, one- or two-way relations (including to itself), rollups, unique IDs, files, places.notion_schema: add, rename, or delete a property (delete previews first and undo restores the values), add select/multi-select/status options, change number formats and descriptions.
Views and visuals
notion_views: list, read, create, update, and delete views: table, board, list, calendar, timeline, gallery, form, map, dashboard, and Notion's native chart views (column, bar, line, donut, number, with stacking). A view can be a database tab, a linked view placed anywhere on a page, or a dashboard widget.notion_create_chart: render a chart image (bar, column, stacked, grouped, line, area, pie, donut, scatter) from inline data or a database query, and refresh it in place later.notion_build_report: a report page for a database: summary, KPI numbers, live and image charts, a table of key rows (such as overdue items), and a Mermaid Gantt chart.notion_workflow: multi-step workflows with schedule, manual, or webhook triggers (see Workflows).notion_template: build pages from reusable templates (see Templates): list, get, validate, preview (outline, counts, and a diff against an existing page), render, save, delete, export, import.
Safety
notion_history: changes and their undo ids, newest first, paged withcursor. Each says whether it's undoable, partly undoable, undone, or was interrupted part-way (with the tool's input, to check by hand).notion_doctor: check the setup and say how to fix what isn't working. Changes nothing.notion_capabilities: what the server can do with this integration (probed with read-only calls), the API version, and the limits that matter for planning.notion_undo: revert a change. Refuses if anything it would restore was edited afterward, and lists what; passforce: trueto overwrite.
Automations (see below)
notion_automation: list, add, update, validate, dry-run, enable, disable, delete, and run rules, and see recent runs.
API version
The server pins Notion API version 2026-03-11 (set NOTION_VERSION to override). That version renamed archived to in_trash, transcription blocks to meeting_notes, and replaced the flat after parameter of block appends with position; this server already used the new forms, and the full live suite passes on it.
Content formats
notion_insert_blocks and notion_create_page take markdown or structured blocks, and both can express every block type the API can create:
Content | Markdown | Structured block |
Headings 1–4, toggle headings |
|
|
Lists, to-dos, nesting |
|
|
Callouts |
|
|
Toggles |
|
|
Tables | pipe tables, or |
|
Columns |
|
|
Tabs |
|
|
Code, Mermaid diagrams |
|
|
Equations |
|
|
Images, files, PDF, video, audio |
|
|
Bookmarks, embeds |
|
|
Synced blocks |
|
|
Links to pages, TOC, breadcrumb |
|
|
Dividers |
|
|
Inline: **bold**, *italic*, `code`, ~~strike~~, <u>underline</u>, [link](url), $x^2$, <span color="red">…</span> (any color, or blue_bg for backgrounds), and mentions: <mention-page url="…"/>, <mention-user email="…"/>, <mention-date start="2026-10-01"/>. A block's color goes at the end of its line: Text {color="blue"}.
These are the same tags Notion's markdown export uses, so notion_get_page with format: "markdown" returns markdown you can edit and insert back; the live test suite checks that a full page survives the round trip line for line. Local files can be uploaded from the working directory and the temp folder; set NOTION_PLUS_UPLOAD_DIRS (separated by :, or ; on Windows) to allow other folders.
The undo journal is stored in ~/.notion-plus/workspaces/<integration id>/journal.json (last 500 changes; see Local state). Each write is journaled before it reaches Notion: if the server stops mid-write, notion_history shows the entry as interrupted with the tool's input, so you can check those objects by hand. Undo restores the snapshot taken at write time. Before writing, it checks every page, block, or database it would restore; if any was edited after the original change (by a person, or by a later change through this server, which it names), it writes nothing and lists them. The check is per object, so an edit to a different field of the same page also counts, and edits in the same minute as the original change can't be seen. Undoing added options deletes them, which also clears them from any rows that used them since. Schema changes are the exception to the edit check: a database's edit time moves with every schema change, so it can't tell whose change it was; schema undo only touches the property it names.
Visuals: which to use
Native Notion content for structure and diagrams: callouts, columns, tables, equations, and Mermaid diagrams (
```mermaidcode blocks: flowcharts, sequence, Gantt, pie, timeline). Mermaid is checked before writing so a typo doesn't leave an error box.Chart views (
notion_viewswithtype: "chart") when the data lives in a Notion database: they stay live, filter with the database, and people can click through. They can sit on any page as a linked view.Chart images (
notion_create_chart) for chart types Notion lacks, data from outside Notion, or a fixed snapshot. Types: bar, column, stacked and grouped columns, line, area, stacked area, pie, donut, scatter, and:histogram(one row per observation;bins),boxplot(x = group, y = observation),heatmap(x = column, series = row, y = value)waterfall(rows in order, y = change; a row with series"total"shows the running total),funnel(stages in order),bullet(actualandtargetrows per category)small_multiples(one panel per series),dual_axis(two series: columns on the left axis, a line on the right),treemap(x = item, y = size, series = group),sankey(x = from, series = to, y = amount; flows must only go forward),network(x and series are the two ends of a link, y its weight; nodes sit on a circle sized by how connected they are)
annotationsadd labeled reference lines ({at: "Q2", label: "Launch"}or{value: 100, label: "Target"}). Images use a colorblind-checked palette by default, thin marks, direct value labels, and a legend whenever there's more than one series; past eight series the smallest fold into "Other".paletteswitches tocool,warm,mono, or your own hex colors. Notion shows an image the same way in light and dark mode, so pick the surface withtheme:light(default),dark, ortransparent.format: "svg"uploads a vector image instead of a PNG.data_table: trueadds a "Chart data" toggle under the chart with a one-line description and the numbers, so the chart has a text alternative (the description is also returned asalt_text). For anything else, pass a whole Vega-Lite spec asvega_lite: data must be inline, and specs that load URLs, link out, or use image marks are refused;vega_lite_themepicks its surface the same way. The recipe of a regular chart is stored incharts.jsonin the local state folder, andrefresh_block_idredraws it from current data in the same block.Embeds (
embedblocks) for interactive charts hosted elsewhere, when neither of the above fits.
notion_build_report combines these: it uses a live chart view where Notion supports the chart type and renders an image otherwise.
Queries and aggregation
where in notion_query, notion_aggregate, notion_bulk_update, and automation rules accepts:
{
"Status": {"in": ["Done", "At Risk"]},
"Due": {"before": "today"},
"Estimate": {">": 500, "<=": 1000},
"Tags": "Q4",
"Owner": null,
"or": [{"Priority": "High"}, {"Task": {"contains": "urgent"}}],
"$last_edited": {"after": "-7d"}
}Operators: =, !=, >, >=, <, <=, contains, not_contains, starts_with, ends_with, in, not_in, is_empty, before, after, on_or_before, on_or_after, and date ranges such as past_week or next_month. Dates accept today, tomorrow, yesterday, and offsets like +7d, -2w, +1m (in NOTION_PLUS_TIMEZONE, default the system zone). Property names and option values are matched forgivingly and checked against the schema.
notion_aggregate takes group_by (a property, or {"property": "Due", "by": "month"}) and metrics such as ["count", "sum:Estimate", "avg:Estimate"]. Rows with several values (multi-select, people, relations) count once in each of their groups, and relation groups show the related rows' titles. It scans up to 10,000 rows by default (max_rows, up to 50,000).
Relation values in writes can be page ids, links, or the related row's exact title.
Undo coverage
Undo is best effort: it covers the writes below, from a snapshot taken at write time, and refuses when something it would restore was edited afterward.
Write | Undo |
Property values, page title/icon/cover/lock, moves | Restores the previous values |
Inserted, copied, or report blocks; created pages, rows, databases | Trashes them |
Patched or replaced blocks, find and replace | Restores the previous content |
Deleted blocks, trashed pages | Restores them from the trash |
Schema changes, including deleted properties | Restores the property and up to 2000 rows' values |
Comments added by this server | Deletes them |
Views created, changed, or deleted | Deletes, restores, or re-creates them |
Chart refreshes | Puts back the previous image (when it could be downloaded) |
Automation runs | Everything above that the run did, as one entry |
Results say coverage: "partial" when part of a write can't be reverted (the entry names what), and none when nothing can. Undo can't see edits in the same minute as the original change (Notion reports edit times to the minute), entries roll off after 500 changes, and comments by other integrations, re-created unique IDs, and Notion-hosted files that expired can't be restored. A write interrupted by a crash is journaled as interrupted before it starts, so it's visible but may have nothing to undo.
Templates
notion_template builds a page from a declarative template, so a recurring page (a weekly update, a brief, a launch plan) is one call with values rather than dozens of block calls. Five ship with the server: weekly-executive-report, content-brief, launch-plan, research-dossier, and database-report (the page notion_build_report makes, as a template you can copy and change); get shows any of them as a starting point for your own, and save keeps yours in templates.json in the home folder (a saved template with a built-in's name replaces it).
A template declares its variables (type, required, default), then lists blocks:
{
"version": 1,
"name": "weekly-update",
"variables": { "week_of": { "type": "date", "required": true }, "wins": { "type": "list", "default": [] } },
"title": "Week of {{week_of}}",
"blocks": [
{ "kpis": [{ "label": "Open tasks", "metric": { "database": "https://www.notion.so/…", "value": "count", "where": { "Status": { "not": "Done" } } } }] },
{ "if": "wins", "then": [{ "heading": "Wins" }, { "each": "wins", "as": "w", "blocks": [{ "markdown": "- {{w}}" }] }] },
{ "chart": { "spec": { "type": "line", "title": "Signups" }, "source": { "database": "https://www.notion.so/…", "x": { "property": "Created", "by": "week" }, "y": "count" } } },
{ "slot": "notes" }
]
}Blocks can be markdown, headings, callouts, toggles, columns, dividers, KPI numbers (fixed, or computed from a database), charts (any notion_create_chart type, from data or a database query), live database views (top level), tables (fixed rows or a database query), a database summary callout (summary: rows, completion, overdue), Mermaid Gantt charts (fixed tasks, or query for a database's dated rows), and raw block specs. Where a field takes an object or list (a where, a table's properties), it can also be a whole "{{variable}}" that holds one. each repeats blocks for every item of a list ({{item.field}}, {{item_index}}), if picks blocks by a condition ("var" for set and non-empty, or {var, equals | not | in | gt | lt | empty}), parts are named block lists a template reuses with {part, with}, and slots are filled at render time with markdown or blocks. Every variable is checked before anything is written, and a reference to a value that doesn't exist is an error rather than a blank in the page. preview shows the outline, the charts and views it would make, an estimate of the Notion requests, and, with compare_to, a line diff against an existing page; render creates the page under parent or appends to append_to, and notion_undo removes what it wrote.
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, so
notion_copy_blockswithmove: truecopies and then trashes the original: moved blocks get new ids and lose their comments. It refuses moves that would lose content the API can't recreate (databases, read-only blocks) or break synced-block references. Pages are moved natively.There's no API for duplicating a page or a database;
notion_duplicate_pagerebuilds both. Databases directly on the page are recreated in place with their schema and up to 500 rows per data source (values and content); relations inside the copied database point at the copied rows, while a two-way relation to a database outside the copy becomes one-way so nothing outside the copy changes. Views aren't copied (the copy gets a default table view), and linked database views can't be read through the API, so both are reported. Notion only creates pages and databases directly on a page, so sub-pages inside toggles or columns go to the end of the copy and databases there are skipped.Button blocks can't be created or read through the API. Breadcrumbs, bookmarks, and links to pages don't appear in Notion's markdown export; this server fills them in. Code captions aren't in the markdown export either.
A heading 4 can't be updated without resending its text;
notion_patch_blockhandles that.Notion's built-in database automations can't be created or edited through the API. Button blocks, AI blocks, and some embeds are read-only (the API returns them as
unsupported).Map views need a place property (
map_by). Dashboards can be created and given widgets, but the widget layout beyond "new row" or "existing row" is set in Notion.A chart image can be replaced in place, but Notion won't take an old file link back, so a refresh keeps a copy of the previous image in
~/.notion-plus/charts/for undo.Status options can be added, each in a group (To-do, In progress, Complete). Options sent without a group all land in To-do, so this server guesses the group from the option name ("Done" → Complete) and says so.
Last-edited times are rounded to the minute, so the freshness check catches edits made in an earlier minute.
Select and status 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, so this server always sends the full list.
Verification properties can only be created in wikis; in a regular database Notion skips them without an error (
notion_create_databasereports it).There's no aggregation endpoint;
notion_aggregatereads the matching rows and summarizes them on your machine (about 100 rows per request). Rows with more than 25 relations or people are counted by their first 25.Deleting a property deletes its values.
notion_schemasaves up to 2000 rows' values first so undo can put them back; a re-created unique ID renumbers rows, and a re-created two-way relation re-creates its other side.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).
A comment can only be deleted by the integration that created it, so undo can remove comments this server added, but nothing else.
Requests time out after 30 seconds (
NOTION_TIMEOUT_MS). Reads are retried after timeouts and dropped connections; writes are not, since the first attempt may have landed. Notion's 429 and 5xx responses are retried by the client, honoringRetry-After.Results are capped at 25,000 characters. Long lists are shortened (with a count of what was left out) so the result stays valid JSON; narrow the request to see the rest.
Automations
Rules run on a schedule in GitHub Actions (or locally with npm run automations). Rules you manage from Claude are saved in rules.json in the local state folder, so they survive reinstalling or upgrading the server; the GitHub workflow runs the committed automations/rules.json (it sets NOTION_PLUS_RULES to it). Upgrading from 0.9 or earlier, rules already in automations/rules.json of your checkout are copied to the new location the first time. A rule picks rows with a condition, runs at set times, or both, and acts on what it finds. Manage rules from Claude with notion_automation ("add an automation that…"), which checks each rule against the live database and previews it before saving.
{
"version": 1,
"timezone": "America/New_York",
"rules": [
{
"id": "at-risk",
"schedule": "weekdays 09:00",
"database": "https://www.notion.so/…",
"when": { "where": { "Due": { "before": "today" }, "Status": { "not_in": ["Done", "At Risk"] } } },
"actions": [{ "set": { "Status": "At Risk" } }, { "comment": "Past due: {{page.Task}} was due {{page.Due}}" }]
},
{
"id": "stamp-completed",
"database": "https://www.notion.so/…",
"when": { "where": { "Status": "Done", "Completed Date": null } },
"actions": [{ "set": { "Completed Date": "{{today}}" } }],
"then": [{ "refresh_chart": "<chart image block id>" }]
},
{
"id": "weekly-report",
"schedule": "weekly mon 08:00",
"then": [{ "build_report": { "database": "https://www.notion.so/…", "parent": "https://www.notion.so/…", "title": "Week of {{today}}" } }]
}
]
}When a rule runs. With only when, every run (hourly in GitHub Actions) checks for matching rows. With a schedule ("hourly", "daily 09:00", "weekdays 09:00", "weekly mon 09:00", "monthly 1 09:00", or 5-field cron, in the file's timezone), the rule fires once per scheduled time, on the first run at or after it; with both, the condition is checked only at those times. Because the workflow runs at minute 17, "weekdays 09:00" fires at about 9:17.
Conditions (when): where and filter work exactly like notion_query, including operators and relative dates. relative takes {property, older_than_days | newer_than_days} for a date, created time, or last edited time property, or "$created" / "$last_edited".
Row actions (actions), applied to each matching row: {"set": {...}} (validated like notion_update_properties), {"append": "markdown"} or blocks, {"comment": "text"}, {"trash": true}.
Follow-up actions (then), run once per firing after the row actions (and, when the rule has a condition, only if it acted on at least one row):
{"refresh_chart": "<block id>"}: redraw a chart made bynotion_create_chartor a report. When you save the rule throughnotion_automation, the chart's recipe is copied into the rule so the GitHub runner can redraw it.{"build_report": {...}}: the same arguments asnotion_build_report.replace_previous(on by default) trashes the report this rule built last time.{"create_page": {"parent", "title", "template"?, "properties"?, "markdown"?}}.
Strings can use {{today}} (in the file's timezone), {{now}}, and in row actions {{page.<Property>}}, {{page.url}}, {{page.id}}.
Each rule acts once per row. 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 writes a value its condition no longer matches (for example Status: {"not_in": ["Done", "At Risk"]} then setting "At Risk"), trashes the row, or names a marker: a checkbox property the runner requires to be unchecked and then checks. Scheduled rules also remember which scheduled time they last fired for, so a time fires once even if runs overlap or repeat.
Order, retries, and partial failure. Each row's actions run as steps, and progress is saved after every step: first set values that keep the row matching, then append and comment, then the writes that take the row out of the condition (the marker, or set values for properties the condition checks), then trash. A row is only marked handled once everything before it landed. If a step fails, the row keeps matching, and the next run picks it up again from the step that failed, skipping the ones that succeeded. A scheduled occurrence only counts as fired when every row and every then action of it succeeded; otherwise the next run retries it (completed then actions aren't repeated), until it succeeds, a newer occurrence arrives, or you waive it. An edited rule starts unfinished rows over. Each rule's run reports succeeded, partial (some steps failed or were left for the next run), failed, or skipped (not due).
Other options: enabled (default true), limit (rows per run, default 50; the rest wait for the next run), allow_new_options, data_source_name, name.
Managing rules from Claude
notion_automation handles every step: list, get, add, update (merge fields), validate (check a rule and preview what it would do), dry_run (never writes; force: true ignores schedules), enable, disable, delete, run (writes; one undo id per rule; returned as an error unless every rule succeeded, with the details and undo ids kept), history (local runs, newest first, paged with limit and cursor), waive (give up on a rule's unfinished firing: the occurrence counts as fired and unfinished rows start over), export and import (the whole rules file as JSON; import_mode merge or replace), and deploy (the rules file with chart recipes embedded, plus the steps to run it in GitHub Actions). list and get return the file's revision; passing it back as expected_revision refuses the edit if the file changed in the meantime.
Running locally
npm run automations -- --dry-run # preview every enabled rule that's due
npm run automations -- --dry-run --force # preview as if every schedule were due
npm run automations -- --rule at-risk --force
npm run automations # applyOne run stops starting new rows once it reaches any of its limits: 200 rows (--max-rows, AUTOMATIONS_MAX_ROWS; the old --max-writes still works), 3000 Notion requests (--max-requests), 5000 appended blocks (--max-blocks), or 20 minutes (--max-minutes). Rows left over run next time, and the run reports partial. A failing rule is reported and the others still run. The command exits non-zero unless every rule succeeded, and logs one JSON line per event on stderr, each with the run's run_id (NOTION_PLUS_LOG=text for plain lines, off to silence). Each rule's run is one journal entry, so notion_undo <undo_id> reverts it, including deleting the comments it added and trashing pages it created. Runs are logged to automation-runs.jsonl, and schedule state is kept in automation-state.json, both in the local state folder.
GitHub Actions
.github/workflows/automations.yml runs every hour (at minute 17) from the committed automations/rules.json. It never lets two runs overlap. Schedule state (which occurrences fired, and unfinished rows and occurrences to resume) is committed after every run to the notion-automations-state branch, which only holds automation-state.json (no page content). Once that branch exists, a run whose state can't be restored stops instead of re-firing old occurrences. The undo journal and run log carry over in the Actions cache (best effort: an evicted cache only shortens undo history) and are uploaded as an artifact (notion-plus-journal-<run id>, kept 90 days). When a run fails or is partial, it opens an issue labeled notion-automations (creating the label if needed) or comments on the open one; if that isn't possible, the job summary says so. The manual Run workflow button takes dry_run (on by default), rule, and force.
One-time setup
Make a token for the job. Create a separate internal integration (step 1 of Setup) and share only the pages and databases your rules touch with it (including report parents). 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, then Secrets and variables → Actions → New repository secret. Name it
NOTION_TOKENand paste the token.Test the workflow. Go to Actions → Notion automations → Run workflow, leave "dry run" checked, and run it. A green run whose summary lists your rules (or "No enabled rules.") means the token and workflow work.
Adding a rule
In Claude, ask for it in plain words, for example: "Every weekday at 9am, mark rows past their due date as At Risk and add a comment." Claude uses
notion_automation, which checks the rule against the live database, shows the rows it would act on, and saves it on your machine.Ask Claude to deploy the rules (
notion_automationdeploy), save the returned file asautomations/rules.jsonin your repository, and commit and push it. (If you work in a checkout withNOTION_PLUS_RULESpointing atautomations/rules.json, edits land there directly.)Run the workflow once by hand with "dry run" checked (and "force" to see a scheduled rule now), and read the summary. After that, the hourly runs apply it.
To pause a rule, disable it (or set "enabled": false) and push. To give up on an occurrence that keeps failing, waive it (locally, on a state file restored from the notion-automations-state branch) or fix the cause; it's retried every run until then. To stop everything, disable the workflow under Actions → Notion automations → ••• → Disable workflow.
Undoing a scheduled run
Download the run's notion-plus-journal-<run id> artifact, unzip it into a folder (it keeps the workspaces/<integration id>/ layout), point NOTION_PLUS_HOME at that folder (in your Claude config, or NOTION_TOKEN=… NOTION_PLUS_HOME=… npm run inspect), and call notion_undo with 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.
What Notion itself can't do through the API
Notion's built-in database automations (the ⚡ button in a database) can't be created, read, or changed through the API. Rules here are the programmable alternative; they poll rather than react instantly.
Webhooks can push changes the moment they happen, but Notion needs a public HTTPS URL to deliver them, and a local server doesn't have one. A future option: a small hosted endpoint (or a tunnel such as Cloudflare Tunnel) that receives the webhook and triggers the workflow with
workflow_dispatch, so rules run within seconds instead of within the hour.
Modes
Mode | What runs it | Rules | State |
Interactive | Claude Desktop, Cowork, or Claude Code, through this server | Edited with | Local state folder |
Local scheduled |
| Same file as interactive | Same folder |
GitHub runner |
| The committed |
|
Webhook |
| Workflows in your home folder (or | The server's |
Workflows
Workflows are version 2 of automations: a trigger and a list of steps that run in order, with outputs that later steps use. Manage them with notion_workflow (save, run, runs, run_status, resume, cancel, convert, …); they're kept in workflows.json in the home folder (NOTION_PLUS_WORKFLOWS moves it; the GitHub workflow uses the repo's automations/workflows.json). Rules keep working, and convert turns a rule into an equivalent workflow (saved disabled, so you can check it first).
{
"version": 2,
"id": "launch-review",
"trigger": { "webhook": { "events": ["page.properties_updated"], "database": "https://www.notion.so/…" } },
"steps": [
{ "id": "ready", "query": { "database": "https://www.notion.so/…", "where": { "Status": "Ready for review" } } },
{ "id": "each", "foreach": { "items": "${steps.ready.rows}", "as": "row", "steps": [
{ "id": "ask", "approval": { "page": "${row}", "property": "Approved", "message": "Approve ${row.title} for launch?" } },
{ "id": "ship", "set": { "page": "${row}", "values": { "Status": "Launched", "Launched on": "${today}" } } },
{ "id": "tell", "slack": { "webhook": "${secret:launch_slack}", "text": "Launched: ${row.title} ${row.url}" }, "retry": { "attempts": 3 } }
] } }
],
"on_failure": [{ "comment": "https://www.notion.so/…ops-page" }]
}Triggers: manual (always available through run), schedule (same forms as rules, in the server's time zone), and webhook (Notion events, optionally only for one database).
Steps: each has an id, and may have if (a ${…} reference that must be set and not empty), retry (attempts, backoff_seconds), timeout_seconds, and continue_on_error. Actions:
Notion:
query(rows withid,url,title, and every property),set,append,comment,create_page,move_page,duplicate_page,trash,replace_text,export_markdown,render_template.Outside:
http(to hosts listed inNOTION_PLUS_HTTP_ALLOW, comma-separated,*.example.comallowed) andslack(an incoming-webhook URL, best kept as a secret).Control:
foreach(over a list,${item}or theasname),switch(cases by value),approval(pauses until a checkbox is checked or a comment containing a keyword is posted; optional request comment and expiry),delay(pauses for minutes), andrun_workflow(another workflow, with inputs).
References: ${steps.<id>.<path>}, ${trigger.*} (for webhooks: event, page_id, entity, data), ${inputs.*}, ${today}, ${now}, and ${secret:NAME}, read from the environment variable NOTION_PLUS_SECRET_NAME. Secret values are replaced with *** everywhere a run is stored or shown.
Durable runs. Every step's state is saved as it changes. A run that fails, pauses, or is interrupted continues after the last finished step (resume, or the next scheduler pass). A step that started but didn't finish is retried as a resume: creating steps first look for what the interrupted attempt already made (a page with the same title, a comment with the same text, appended blocks created since it started) and adopt or remove it, so retries don't duplicate content; HTTP steps send an Idempotency-Key header for the same reason. (Rules get the same protection for retried appends.) Each run records undo for what it wrote, and on_failure reports failed runs to Slack, an HTTP endpoint, or a page comment. Set NOTION_PLUS_NOTIFY (for example slack:ops_slack,comment:<page>) to be told about failed or partial rule runs too.
Scheduling. Each npm run automations (hourly in GitHub Actions) also starts scheduled workflows that are due and continues waiting runs whose approval or delay has come. Run state is saved on the notion-automations-state branch with the rules' state.
Webhook mode
npm run webhook (or the Dockerfile) runs a small server that reacts to Notion events within seconds instead of within the hour:
Run it somewhere Notion can reach over HTTPS (behind a reverse proxy, a tunnel such as Cloudflare Tunnel, or a platform that terminates TLS), with
NOTION_TOKEN, a persistentNOTION_PLUS_HOME(the container uses/data), and optionallyNOTION_PLUS_WEBHOOK_PORT(default 8787).In the integration's settings, add a webhook subscription to
https://<your host>/notion/webhook. Notion sends a verification token; the server logs it. Paste it into Notion to verify, and setNOTION_PLUS_WEBHOOK_TOKENto it (restart).Give workflows a
webhooktrigger.
Every delivery must carry a valid X-Notion-Signature (HMAC-SHA256 of the body with that token). Events are accepted once (by id, remembered for a week), only if they're less than 10 minutes old, and acknowledged right away; a worker then starts the matching workflows, retrying with backoff, and moves an event that fails five times to dead letters. notion_workflow events lists the queue, replay retries an event, and discard drops one. GET /healthz reports queued and dead events. The same worker continues waiting runs and starts scheduled workflows every minute, so hourly polling becomes a fallback.
Local state
Everything the server remembers lives under ~/.notion-plus (NOTION_PLUS_HOME moves it), in a folder per integration: workspaces/<integration id>/, with journal.json (undo history), charts.json (chart recipes), automation-state.json (which scheduled occurrences fired), and automation-runs.jsonl (run log). Two integrations sharing a machine never mix their history. NOTION_PLUS_WORKSPACE sets the folder name instead of looking up the integration; NOTION_PLUS_STATE moves just the automation state file. The first time a folder is created, state from older versions (kept directly in ~/.notion-plus) is copied into it.
These files are safe to share between several servers at once (Claude Desktop, Cowork, Claude Code, the scheduled runner): each change is made under a lock, written to a temporary file, flushed, and swapped in, with the previous version kept as <file>.bak. If a file can't be read (cut off by a crash or a full disk, edited by hand into invalid JSON, or not readable), the server stops with an error naming it instead of treating it as empty, since that would lose undo history or repeat scheduled automations. Fix the file, restore the .bak, or move it away to start fresh. A leftover <file>.lock from a process that died is cleared automatically.
Development
npm test # offline unit and property tests with vitest (no network)
npm run test:coverage # the same, failing if coverage drops below the thresholds in vitest.config.ts
npm run lint # ESLint (typescript-eslint strict)
npm run typecheck # src, scripts, and tests
npm run check # lint, typecheck, tests with coverage, build; CI runs this on Node 22 and 24
npm run check:version # package.json, manifest.json, package-lock.json, and CHANGELOG.md agree
npm run test:live # live integration suite against a real workspace
npm run bundle && node scripts/bundle-smoke.mjs # build this platform's bundle and install-test itCI also fails on known high-severity advisories in runtime dependencies, reviews new dependencies in pull requests (on public repos, or private ones with GitHub Code Security once the repository variable DEPENDENCY_REVIEW is true), and Dependabot proposes updates weekly. Every GitHub Action is pinned to a commit. A release builds a bundle on each platform, install-tests it (unpack, start, list every tool, render a chart), and publishes it with sha256sums.txt, an SBOM, and build provenance.
Live tests in CI. .github/workflows/live.yml runs the smoke and acceptance suites nightly and on release tags once two repository secrets exist: NOTION_TOKEN (an integration used only for testing, in a throwaway workspace) and NOTION_TEST_PAGE (a page shared with it). Until then it passes with a notice. It never runs for pull requests, so forks can't reach the secrets.
Evaluations and acceptance tests
evals/notion-plus.xmlholds 10 realistic, read-only questions (in the MCP evaluation format) that each need several tools to answer: aggregation, relations, schema, views, page content, and comments.npm run eval:seedbuilds the fixed dataset they're written against under your test page;npm run eval:verifyanswers every question through the tools and checks the expected answers. To measure how well a model picks tools, run the questions with the MCP evaluation harness against this server.npm run acceptanceruns the seven acceptance scenarios (project tracker, views, report page, find/replace with preview and undo, the At Risk and Completed Date automations, and a 300-row bulk update with undo) and leaves the results under an "Acceptance " page.
npm run test:live (also npm 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.
Versions follow semver; see CHANGELOG.md and, for supported versions and deprecations, SUPPORT.md.
Roadmap
Built in phases, each ending with the build, unit tests, and the live suite passing:
Foundations: tests, lint, CI, timeouts, partial-failure reporting, safer undo. (done, 0.2.0)
Content: every creatable block type, rich text colors and mentions, markdown round trip, move/copy/duplicate, icons, covers, templates, comments. (done, 0.3.0)
Databases: create with full schemas, schema editing (including status options), every property type, aggregation, bulk create. (done, 0.4.0)
Views and visuals: views including native chart views, generated chart images, Mermaid, report pages. (done, 0.5.0)
Automations: schedules, run state, more actions, full management from Claude. (done, 0.6.0)
Distribution: MCP Bundle, tool evaluations, acceptance tests, API version 2026-03-11. (done, 0.7.0)
Next: hosted team mode (multi-user, OAuth, a shared database); see docs/hosted-design.md.
Available Tools
33 toolsnotion_aggregateAggregate RowsARead-onlyIdempotent
Answer "how many / how much by X" without reading every row into context. Filters with where/filter (same as notion_query), groups by any property (multi-select, people, and relations count a row in each of its groups; dates can be bucketed by day/week/month/quarter/year), and computes metrics: count, count_values, count_empty, distinct, sum, avg, min, max, median, checked, percent_checked (e.g. ["count", "sum:Points"]). Returns totals and the top groups.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| sort | No | ||
| where | No | ||
| filter | No | ||
| metrics | No | e.g. ["count", "sum:Points", "avg:Estimate"] | |
| database | Yes | ||
| group_by | No | ||
| max_rows | No | ||
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry readOnly/idempotent/non-destructive, but the description adds real behavioral detail: multi-select/people/relation rows count once per group, and dates can be bucketed by day/week/month/quarter/year. It also discloses the shape of the return ('totals and the top groups'), which annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the agent's intent ('how many / how much by X'), then dense but purposeful clauses about filtering, grouping, and metrics. The parenthetical syntax examples earn their space; nothing reads as filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with 11% schema coverage and no output schema, the description covers grouping and metrics well but omits the pagination/ordering controls (top, sort, max_rows) and data_source_name. An agent could still call it, but would be guessing on those knobs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 11%, so the description must compensate and it partially does: it explains where/filter semantics (same as notion_query), group_by including date bucketing, and gives a concrete metric syntax example ("sum:Points"). However top, sort, max_rows, and data_source_name are left entirely unexplained, so the compensation is incomplete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb+resource (aggregate row metrics over a Notion database) and frames it by the question it answers ('how many / how much by X'). This clearly separates it from notion_query, which pulls full rows into context.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the use case (aggregate counts/sums instead of reading every row) and notes filters behave like notion_query, implying when to pick each. It stops short of a direct 'use notion_query when you need the actual rows' exclusion, so not quite a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_automationAutomationsADestructive
Manage and run automation rules (rules.json in the local state folder, or NOTION_PLUS_RULES). A rule has a when condition (same where/filter as notion_query, plus relative dates), a schedule ("weekdays 09:00", "daily 18:00", "hourly", cron), or both. Row actions apply to each matching row: {set: {...}}, {append: markdown}, {comment: text}, {trash: true}. then actions run once per firing: {refresh_chart: block_id}, {build_report: {...notion_build_report args}}, {create_page: {parent, title, …}}. Strings accept {{today}}, {{now}}, {{page.}}. A rule must stop matching a row after acting on it (write a value outside its condition, trash, or use marker). Actions: list, get, add, update (merge fields), validate (checks against the live schema and previews), dry_run (never writes), enable, disable, delete, run (writes; one undo_id per rule), history (recent runs, paged), waive (mark a rule's unfinished firing as handled), export / import (the rules file as JSON), deploy (the rules file plus steps to run it on a schedule in GitHub Actions). Each row's actions run in order with progress saved after each step: values that keep the row matching, then content and comments, then the marker or values that take it out of the condition, then trash. A failed row is retried next run from the step that failed, and a scheduled occurrence only counts as fired when all of it succeeded. run reports status succeeded, partial, or failed, and is an error unless every rule succeeded. list and get return the file's revision; pass it as expected_revision on edits so a change made elsewhere in the meantime isn't overwritten.
| Name | Required | Description | Default |
|---|---|---|---|
| rule | No | add: the whole rule; update: only the fields to change; validate: a rule to check without saving | |
| force | No | dry_run/run: ignore schedules and run now | |
| limit | No | history: runs per page. | |
| action | Yes | ||
| cursor | No | history: next_cursor from the previous page. | |
| rule_id | No | ||
| max_rows | No | run: rows acted on across all rules (default 200); the rest wait for the next run. | |
| timezone | No | Set the rules file's time zone (IANA, e.g. America/New_York). | |
| max_blocks | No | run: blocks appended (default 5000). | |
| rules_file | No | import: a whole rules file ({version: 1, timezone, rules: [...]}), e.g. from export. | |
| import_mode | No | import: merge adds or replaces rules by id; replace swaps the whole file. | merge |
| max_minutes | No | run: wall time (default 20). | |
| max_requests | No | run: Notion requests (default 3000). | |
| expected_revision | No | Edits: the revision from list/get. The edit is refused if the rules file changed since. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only flag destructive/openWorld/non-idempotent; the description adds far more: dry_run never writes, run writes with one undo_id per rule, run errors unless every rule succeeded and reports succeeded/partial/failed, failed rows retry from the failed step, scheduled occurrences only count as fired when fully successful, and expected_revision guards against concurrent overwrites. This is exactly the behavioral depth annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is long, but for a 15-action tool with a nested rule grammar the density is largely earned, and it is front-loaded with the core purpose before descending into rule structure and action semantics. A few clauses (e.g., the step-ordering narrative) could be tightened, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, 14 parameters, nested objects, and destructive actions, the description carries a heavy load and does so: it covers rule grammar, all actions, run status semantics, retry behavior, and revision safety. An agent has enough to select an action and invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 86%, so the baseline is 3, but the description meaningfully supplements the near-empty `rule` object by specifying its shape (when/schedule/actions/then, marker requirement, action ordering) and explains confirmed-vs-merge update semantics and the revision/edit contract. It adds real meaning beyond the schema's `additionalProperties: {}` without fully specifying every field's syntax.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Manage and run automation rules') and grounds it in concrete state (rules.json or NOTION_PLUS_RULES), which no sibling covers. It even positions itself relative to siblings by noting the `when` condition reuses notion_query's where/filter and `then` reuses notion_build_report args, making its scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description enumerates every action (list, get, add, update, validate, dry_run, enable, disable, delete, run, history, waive, export/import, deploy) with a short gloss of what each does, which is strong per-action usage context. It stops short of explicit when-to-use-this-vs-a-sibling routing (e.g., vs notion_bulk_update or notion_undo), so it is clear rather than exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_build_reportBuild Report PageA
Build a report page for a database in one call: a summary callout (row count, completion, overdue), KPI numbers side by side, charts (live Notion chart views where Notion supports the type, rendered images otherwise), a table of key rows (e.g. overdue items), and a Mermaid Gantt chart of dated work. Every section is optional; where scopes the whole report. Image charts can be refreshed later with notion_create_chart. notion_undo trashes the page.
| Name | Required | Description | Default |
|---|---|---|---|
| kpis | No | Default: total rows plus a count per status group. | |
| gantt | No | ||
| table | No | ||
| title | No | ||
| where | No | Limits every section to these rows. | |
| charts | No | ||
| parent | Yes | Page to create the report under. | |
| summary | No | ||
| database | Yes | ||
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare a non-read-only, non-idempotent, non-destructive write, and the description adds value beyond them: it discloses that charts may be live views or rendered images, that image charts are refreshable via notion_create_chart, and that notion_undo trashes the created page (i.e. it is reversible). It still omits permission requirements and what exactly is returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the verb and outcome, then the optionality/scope rule, then related-tool notes. Three dense sentences that each carry information, though the section enumeration is somewhat packed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter nested tool with no output schema, the description adequately conveys what is produced and the optionality/scope behavior. The main gap is that it does not describe the return value (e.g. the created page id/url), which has no schema to fall back on.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 30%, so the description must compensate more than it does. It clarifies the role of `where` (scopes the whole report) and maps sections (summary, kpis, charts, table, gantt) to params, but leaves database, parent, title, and data_source_name unexplained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (build) plus resource (a report page for a database) and explicitly notes it happens 'in one call'. It enumerates exactly what the page contains (summary callout, KPIs, charts, table, Gantt), distinguishing it from lower-level page/block tools in the sibling list.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context: every section is optional, `where` scopes the whole report, and it routes the agent to notion_create_chart for refreshing images and notion_undo for trashing. It does not explicitly say when to prefer this over manually composing pages with notion_create_page/notion_insert_blocks, so no full exclusion set.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_bulk_createBulk Create RowsA
Create up to 1000 database rows from JSON objects (rows) or CSV (csv text or csv_path). Column/key names match properties forgivingly; values follow notion_update_properties rules (relations accept related rows' titles). Empty CSV cells are left unset. Every row is validated before anything is written, and all problems are reported by row. Defaults to dry_run=true. Rows that fail while writing are reported; the rest stay. One notion_undo trashes every created row.
| Name | Required | Description | Default |
|---|---|---|---|
| csv | No | ||
| rows | No | ||
| dry_run | No | ||
| csv_path | No | Local CSV file (from the working directory or temp folder). | |
| database | Yes | ||
| data_source_name | No | ||
| allow_new_options | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing pre-write validation ('Every row is validated before anything is written'), partial-failure semantics ('Rows that fail while writing are reported; the rest stay'), and the fact that one notion_undo trashes all created rows — none of which is in readOnly/destructive/idempotent hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five dense sentences, each carrying distinct information, front-loaded with the core action and input modes and closing with failure/undo behavior. No repetition of the title or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and 7 parameters, the description covers the essential risk surface (validation, dry_run default, partial failure, undo) and value semantics via notion_update_properties. It is slightly short on the two undocumented secondary parameters but otherwise complete enough to call safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 14%, so the description must compensate, and it does partly: it maps rows/csv/csv_path, notes the dry_run default, and clarifies forgiving key matching and empty-cell handling. However, data_source_name and allow_new_options get no explanation at all, leaving gaps the schema cannot fill.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Create up to 1000 database rows') with concrete input modes (JSON objects, CSV text, CSV path), which cleanly distinguishes it from notion_create_page and notion_bulk_update.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the input paths and the dry_run default, and points to notion_update_properties for value semantics plus notion_undo for reversal. It does not explicitly state when to prefer this over notion_create_page or notion_bulk_update, so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_bulk_updateBulk Update RowsADestructiveIdempotent
Update many rows at once, in one of two ways: set the same values on every row matching where/filter (same syntax as notion_query, including operators like {"Due": {"before": "today"}}), or give rows: [{page, set}] to set different values per row. Up to 500 rows. Defaults to dry_run=true, which returns the rows and their current values so you can confirm first. Values are validated before anything is written; every changed row is snapshotted, failures are reported per row, and the whole batch reverts with one notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| set | No | Values for every matching row (with where/filter). | |
| rows | No | Per-row values, instead of where/filter + set. | |
| limit | No | Safety cap on rows touched (where/filter mode). | |
| where | No | ||
| filter | No | ||
| dry_run | No | ||
| database | No | Needed with where/filter. | |
| data_source_name | No | ||
| allow_new_options | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive=true and idempotent=true, but the description adds major behavioral context: dry-run defaults on and returns current values, validation happens before writes, changed rows are snapshotted, failures are reported per row, and the entire batch can be reverted with one notion_undo.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loaded: it states the core operation and its two modes immediately, then layers safety behavior and limits. Every sentence carries information useful for correct invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 9-parameter mutation tool with no output schema, the description covers the important operational contract: modes, row cap, dry-run default, validation, snapshots, per-row failures, and undo. It is only slightly incomplete because a few supporting parameters are left to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema coverage at 44%, the description compensates well for the core parameters: it explains set with where/filter, rows as [{page, set}], the 500-row cap, and dry_run behavior. It adds filter operator examples via notion_query syntax, though less common parameters such as database, data_source_name, and allow_new_options remain unexplained in the prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: update many rows at once, with two distinct modes. It distinguishes bulk update from single-row siblings like notion_update_properties by naming the where/filter and rows approaches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly explains the two supported usage modes and recommends dry_run=true as the default confirmation step. It references notion_query for filter syntax and notion_undo for reverting, but does not explicitly state when not to use this tool versus single-row update alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_capabilitiesCapabilitiesARead-onlyIdempotent
What this server can do with the current integration: the areas it covers, the Notion API version, limits that matter for planning (rows copied, blocks per copy, run limits), and which integration capabilities are available (probed with read-only calls; write capabilities show as unknown until a write).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as read-only, idempotent, open-world, and non-destructive, so the bar is lower. The description still adds meaningful behavior: capabilities are probed with read-only calls and write capabilities show as unknown until an actual write occurs, which tells the agent how reliable each capability answer is.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence that begins with the core purpose before parenthetically listing the details. It is dense but every listed element (areas, API version, limits, capability availability) is relevant and earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must convey what the tool returns, and it does so by enumerating areas, API version, limits, and capability status. For a zero-parameter introspection tool with clear safety annotations, this is complete enough, with only the exact response structure left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there are no parameter semantics to document and the baseline is 4. The description correctly avoids inventing parameters and focuses on the returned information instead.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reports what the server can do with the current integration and enumerates the specific deliverables: covered areas, Notion API version, planning-relevant limits, and available capabilities. It is a distinct discovery/introspection purpose, though it does not explicitly differentiate itself from any sibling tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through 'limits that matter for planning' and the note that write capabilities only become known after a write, suggesting this tool is for pre-flight discovery. However, there is no explicit when-to-use instruction, no when-not-to-use guidance, and no named alternative among the many sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_commentsCommentsA
Read, add, or reply to comments. action=list returns a page's or block's open comments with discussion ids (Notion's API doesn't return resolved threads). action=add starts a discussion on a page or block; action=reply answers a discussion by discussion_id. text is markdown (bold, links, mentions such as ). Added comments can be removed with notion_undo; an integration can only delete its own comments.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | add, reply: markdown body. | |
| limit | No | ||
| action | Yes | ||
| target | No | Page or block URL/id (list, add). | |
| discussion_id | No | reply: from action=list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare openWorldHint and non-idempotent but leave the mixed read/write nature and deletion semantics opaque. The description supplies the important gaps: the API does not return resolved threads, added comments are removed via notion_undo, and an integration can only delete its own comments.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One tight paragraph, front-loaded with the action breakdown before the format and lifecycle notes. Every clause carries information; nothing is repeated from the schema or name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-output-schema mutation/read tool with 5 params, the description covers the return shape for list (open comments plus discussion ids) and the write lifecycle. Pagination via `limit` and the exact add/reply response shape are unstated, but the essentials for correct invocation are present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema coverage at 60%, the description compensates by explaining that `text` is markdown with bold/links/mention syntax (a concrete example format the schema lacks) and by tying `discussion_id` to action=list. It adds real meaning beyond the field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening verb triad ('Read, add, or reply to comments') names both the resource and each operation, and then disambiguates the three actions line by line. An agent can distinguish this from notion_insert_blocks or notion_patch_block without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It specifies the condition selecting each action (list for a page/block's open comments, add to start a discussion, reply to answer by discussion_id) and routes removal to notion_undo. It stops short of stating when to prefer this over other comment-adjacent siblings, but the action-level guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_copy_blocksCopy or Move BlocksADestructive
Copy blocks (with everything nested inside them) to another spot: a page or block, at the start, end, or after a block. With move=true the originals are trashed afterward (the API has no move, so moved blocks get new ids and lose their comments). Sub-pages among the given blocks are moved with Notion's page move, or duplicated when copying; they land at the end of the destination page. A move is refused if it would lose something the API can't recreate (databases, read-only blocks, original synced blocks whose references would break). Copying an original synced block creates a reference to it. Moves default to dry_run=true. One notion_undo reverts everything.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | Destination page or block. | |
| move | No | ||
| dry_run | No | Default: true for moves, false for copies. | |
| position | No | end | |
| block_ids | Yes | Blocks to copy, in the order they should appear. | |
| after_block_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the destructiveHint annotation: moved blocks get new ids and lose comments, sub-pages use page-move semantics and land at the destination end, moves are refused for non-recreatable content, and one notion_undo reverts everything. This is exactly the operational context an agent needs before mutating state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Dense but front-loaded: the core operation comes first, then caveats and safety. Every sentence carries information, though the paragraph is long enough that it could be split for faster scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter destructive mutation with no output schema, the description covers the safety model, edge-case refusals, id-loss behavior, and undo path thoroughly. Return-value details are unspecified, but the absence of adverse outcomes for the caller is largely addressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 50% schema coverage, the description compensates by explaining the semantics of move, dry_run (default true for moves), and position (start/end/after a block). It adds real meaning beyond the terse schema, though after_block_id's linkage to position=after_block edges is only implied.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb (copy/move) and resource (blocks, with nested children) and the destination options. It clearly distinguishes itself from siblings like notion_insert_blocks and notion_patch_block by covering relocation rather than creation or editing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the copy-vs-move decision (move=true trashes originals) and the dry_run default that makes moves safe to preview, giving clear context for when to use each mode. It stops short of naming an explicit alternative tool for the plain-insert case, but the mode guidance is strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_create_chartCreate or Refresh Chart ImageA
Render a chart image (PNG, or SVG) and put it on a page, or refresh an existing chart image in place. Types: bar, column, stacked_bar, stacked_column, grouped_column, line, area, stacked_area, pie, donut, scatter, and histogram (one row per observation; y is the value (x is ignored). bins sets the number of bins.); heatmap (x = column, series = row, y = the cell's value.); boxplot (one row per observation; x = group, y = value.); waterfall (rows in order; y = change. A row with series "total" shows the running total instead.); funnel (rows in stage order; y = how many reached the stage.); bullet (per x: a row with series "actual" (or none) and a row with series "target".); small_multiples (x and y as for a line chart; one small panel per series.); dual_axis (exactly two series: the first as columns (left axis), the second as a line (right axis).); treemap (x = item, y = size; optional series groups items (one color per group).); sankey (one row per flow: x = from, series = to, y = amount. Flows must only go forward (no loops).); network (one row per link: x = one end, series = the other, y = weight (line thickness).). Data is inline data ([{x, y, series?}]) or a source query that groups a database (x, y like "count" or "sum:Estimate", optional series). annotations add labeled reference lines; palette picks colors (default is a validated colorblind-safe order). data_table adds a toggle under the chart with a description and the numbers, for readers who can't see the image. For anything the types don't cover, pass a full Vega-Lite spec as vega_lite (data inline only; nothing is fetched). The recipe is remembered, so refresh_block_id re-renders it from current data. Prefer notion_views chart views when a live Notion chart is enough. Reversible with notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| chart | No | Required for a new chart; optional on refresh (keeps the stored one). | |
| format | No | png (default) or svg (sharp at any zoom). | png |
| parent | No | New chart: page or block to insert into. | |
| source | No | ||
| caption | No | ||
| position | No | end | |
| vega_lite | No | Advanced: a complete Vega-Lite spec (data in data.values) instead of chart + data. Not refreshable. | |
| data_table | No | Add a toggle under the chart with a description and the data, as a text alternative. | |
| after_block_id | No | ||
| vega_lite_theme | No | vega_lite only: light (default), dark, or transparent, applied where the spec sets no colors of its own. | |
| refresh_block_id | No | An image block made by this tool: re-render it in place. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations disclose mutation (readOnlyHint=false, destructiveHint=false, openWorldHint=true), but the description adds genuinely behavioral facts beyond them: the recipe is remembered so refresh re-renders from current data, vega_lite does no fetching ('nothing is fetched'), and operations are reversible via notion_undo. It also discloses that vega_lite is 'Not refreshable', a real limitation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, create/refresh, and the notion_views alternative in the first sentence, but the long run-on enumeration of 22 chart types and data-shape rules makes the body dense. The content mostly earns its place, though a bulleted chart-type reference would read better.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 12-parameter, nested-object tool with no output schema, the description covers data sourcing (inline vs `source` query), chart-type semantics, placement, refresh behavior, the escape hatch (vega_lite), and reversibility. Nothing an agent needs to call it correctly appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 58% schema coverage, the description supplies the missing semantics: per-chart-type meaning of x, y and series (heatmap x=column/series=row, waterfall ordering, dual_axis two-series rule, sankey forward-only flows), plus `bins`, `annotations`, `palette`, and `data_table` behavior. This is meaning well beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Render a chart image... and put it on a page, or refresh an existing chart image in place'), covering both create and refresh modes. It explicitly distinguishes itself from the sibling notion_views ('Prefer notion_views chart views when a live Notion chart is enough'), so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the primary alternative (notion_views chart views) with the condition that selects it, and explains the refresh path via `refresh_block_id` plus the fallback to `vega_lite` 'for anything the types don't cover'. Both when-to-use and when-to-prefer-something-else are present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_create_databaseCreate DatabaseA
Create a database under a page with its full schema in one call: select/multi-select/status options (status options can name their group: To-do, In progress, Complete), number formats, formulas, relations (one- or two-way, to another database or "self"), rollups over those relations, unique IDs with a prefix, people, dates, files, places, and more. If no title property is given, one called "Name" is added. Add rows with notion_bulk_create or notion_create_page. notion_undo trashes the database.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Emoji, image URL, or local image path. | |
| cover | No | ||
| title | Yes | ||
| inline | No | Show the database inline on the parent page instead of as a sub-page. | |
| parent | Yes | Page URL or id to create the database in. | |
| properties | Yes | ||
| description | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false, openWorld=true, idempotent=false, and destructive=false. The description adds useful behavior: full schema creation in one call, automatic 'Name' title property, and that notion_undo trashes the database. It does not cover permission requirements or rate limits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and remains dense with useful schema details. It is long, but the complexity of the property schema justifies most of the length; phrases like 'and more' are slightly imprecise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema and only 43% schema description coverage, the description gives solid creation semantics, default title behavior, and next-step routing. It stops short of covering permissions, return value expectations, or all parameter details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 43%, so the description must compensate. It does so substantially for the complex 'properties' parameter by enumerating property types, status groups, number formats, formulas, relations, rollups, unique ID prefixes, and the default title property behavior, though it leaves icon, cover, inline, parent, and description parameters mostly to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Create a database under a page with its full schema in one call.' It also names sibling tools for adding rows and undoing the operation, so an agent can distinguish this from notion_create_page, notion_bulk_create, and notion_undo without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly routes post-creation row insertion to notion_bulk_create or notion_create_page and notes that notion_undo trashes the database. However, it does not explicitly state when not to use this tool or compare it to other database-related tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_create_pageCreate PageA
Create a page. If parent is a database, properties are validated against its schema (same rules as notion_update_properties) and title fills the title property; template applies one of the database's templates (see notion_list_templates). If parent is a page, a sub-page is created. Content can be markdown or structured blocks (same formats as notion_insert_blocks). icon is an emoji, image URL, or local image path; cover is an image URL or local path.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Emoji, image URL, or local image path. | |
| cover | No | Image URL or local image path. | |
| title | No | ||
| blocks | No | ||
| parent | Yes | Parent database or page URL/id. | |
| markdown | No | ||
| template | No | Database parents: "default", or a template name or id from notion_list_templates. | |
| icon_emoji | No | Older name for icon. | |
| properties | No | ||
| data_source_name | No | ||
| allow_new_options | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations flag it as a non-idempotent, non-destructive, open-world write, and the description adds real behavior beyond that: properties are schema-validated, template applies a database template, and content can arrive as markdown or blocks. It doesn't mention auth/permission needs or what is created on failure, but the added context is substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then orders clauses by parameter importance. Dense but every clause carries information; no filler sentences, though it is on the longer side.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 11 parameters, nested block objects, no output schema, and 45% schema coverage, the description covers the branching logic and content formats an agent needs. Gaps remain around the return value and the unmentioned params (allow_new_options, data_source_name).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 45%, so the description must carry weight and largely does: it explains parent (database vs page), properties validation, title filling, template, markdown/blocks, icon, and cover. It silently omits icon_emoji, data_source_name, and allow_new_options, so not fully compensating for the low coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Create a page') and elaborates on the two creation modes (database parent vs page parent), which distinguishes it meaningfully from sibling reads like notion_get_page. It does not explicitly contrast itself with notion_duplicate_page or notion_bulk_create, so it lands at 4 rather than 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description branches on parent type to explain what each mode does, and routes the agent to notion_update_properties, notion_list_templates, and notion_insert_blocks for adjacent semantics. It never states when to prefer this over siblings like notion_duplicate_page or notion_bulk_create, so no exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_delete_blocksDelete BlocksADestructive
Move specific blocks (by id) to the trash. Nothing else on the page is touched. Reversible with notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| block_ids | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and readOnlyHint=false, so the mutation profile is known. The description adds real value beyond that: a precise blast radius ('Nothing else on the page is touched') and recoverability ('Reversible with notion_undo'), which the annotations do not convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, zero filler, with the core action front-loaded and the safety/recovery note trailing. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter destructive tool with no output schema, the description covers action, scope, and reversibility. It could be improved by noting the 100-item cap or failure behavior on invalid IDs, but nothing essential is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the burden. 'By id' clarifies that block_ids are identifiers and the plural phrasing hints at multi-block input, but it omits the 1–100 cardinality constraint and any ID format detail, leaving the schema array underspecified in prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Move specific blocks ... to the trash') and immediately scopes the blast radius ('Nothing else on the page is touched'), which distinguishes it from sibling mutators like notion_patch_block, notion_insert_blocks, and notion_trash_page.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied but never stated: the description doesn't say when to prefer block-level deletion over notion_trash_page, nor any prerequisites (permissions, block type restrictions). Referencing notion_undo as a recovery path is useful context, but there is no explicit when-to-use/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_doctorCheck SetupARead-onlyIdempotent
Check that the server is set up and working, and say how to fix what isn't: settings, the token, the integration's capabilities, whether any pages are shared with it, the local state folder (undo journal, chart recipes, automation state), upload folders, the chart renderer, automation rules, and unfinished automation runs. Changes nothing. Run it first when something doesn't work.
| Name | Required | Description | Default |
|---|---|---|---|
| offline | No | Skip checks that call Notion. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered; the description reinforces it with 'Changes nothing.' It earns credit beyond the annotations by disclosing that it both detects problems and prescribes fixes ('say how to fix what isn't') and by scoping the inspected state precisely.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then a scannable inventory of checks, then two short directive sentences. The middle list is long but every item is a distinct diagnostic surface, so it earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only diagnostic with no output schema, the description is nearly self-sufficient: it names what is checked, promises remediation guidance, and states side-effect behavior. It does not describe the shape of the report it returns, which is the main remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single optional parameter at 100% schema coverage, so the schema fully documents 'offline' ('Skip checks that call Notion.'). The description adds nothing about the parameter, which is acceptable given the schema does the work — the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('check that the server is set up and working') and enumerates the exact surfaces it inspects, from settings and token to the chart renderer and automation runs. It does not differentiate itself from a sibling like notion_capabilities, which also concerns the integration's capabilities, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Run it first when something doesn't work' gives a clear triggering condition, and 'Changes nothing' signals it is safe to run speculatively. It does not name a when-not case or an alternative sibling, so it stops short of explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_duplicate_pageDuplicate PageA
Copy a page with its icon, cover, content (every block type the API can create, with formatting), and, when it stays in the same database, all writable properties. Sub-pages and databases on the page are copied in place; databases get their schema and (by default) their rows with content, with relations inside the copy pointing at the copied rows. Views, linked database views, and read-only blocks are listed as skipped, and the result's status is "partial" when anything was. Database rows keep their own content, sub-pages, and databases. Uploaded files and images are re-uploaded so the copy doesn't depend on expiring links. dry_run shows what would be copied. notion_undo trashes the copy.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Destination page or database. Defaults to the original's parent. | |
| page | Yes | Page to copy. | |
| title | No | Defaults to "<original title> (copy)". | |
| dry_run | No | ||
| max_rows | No | Rows copied per data source (default and cap 500). | |
| databases | No | Databases on the page: copy schema and rows (up to 500 per data source), schema only, or skip them. | rows |
| copy_row_content | No | Copy each row's own content (blocks, sub-pages, databases). Turn off for large databases where only values matter. | |
| data_source_name | No | ||
| include_subpages | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations mark it as non-read-only and non-destructive, but the description adds rich behavioral detail: what gets skipped, status 'partial', re-uploading of files, relation handling, and the role of dry_run and notion_undo. This goes well beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense paragraph that front-loads the core behavior. It is efficient but could be slightly more structured for readability; every sentence does contribute useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (9 parameters, no output schema), the description covers most operational aspects: copy scope, database handling, file re-upload, and undo/dry-run. However, it doesn't address error conditions, rate limits, or the exact format of the 'partial' status result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, so the description must compensate. It explains the 'databases' parameter behavior, the effect of dry_run, and what max_rows controls. However, it doesn't clarify all parameters (e.g., data_source_name, include_subpages) fully, leaving some ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description specifies exactly what is copied (icon, cover, content blocks, writable properties) and what is not (views, linked views, read-only blocks). It clearly distinguishes the tool from siblings like notion_create_page and notion_copy_blocks by focusing on full page duplication.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
While the description implies use cases (e.g., dry_run for preview, notion_undo for reversal), it doesn't explicitly state when to use this tool versus alternatives such as notion_copy_blocks or notion_create_page. The guidance is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_find_blocksFind BlocksARead-onlyIdempotent
Find blocks on a page whose text matches a string or regex. Returns block id, type, text, and last_edited_time. Use this to locate exactly which block to edit instead of rewriting the page.
| Name | Required | Description | Default |
|---|---|---|---|
| page | Yes | Page URL or id. | |
| query | Yes | ||
| regex | No | ||
| max_depth | No | ||
| max_results | No | ||
| case_sensitive | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), so the bar is lower. The description adds value by disclosing the return fields (block id, type, text, last_edited_time), which the annotations do not. It omits limits on depth/results and pagination behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences: what it does, what it returns, and when to use it. Front-loaded with the core action and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter tool with low schema coverage and no output schema, the description covers the core search semantics and return shape but leaves four behavioral parameters (depth, result cap, case sensitivity, regex flag behavior) undocumented anywhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 17%, so the description must carry the load. It clarifies that query matches as a string or regex, tying the query and regex parameters together, but says nothing about max_depth, max_results, case_sensitive, or the page parameter format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (find) and resource (blocks on a page) with the matching criterion (string or regex). It is clearly distinguishable from notion_get_blocks (retrieval by structure) and notion_replace_text/notion_update_page, which it implicitly contrasts.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete when-to-use: locate the exact block to edit rather than rewriting the page. It does not name a specific sibling alternative or state exclusions (e.g., when to use notion_get_blocks instead), so it falls short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_get_blocksGet Block TreeARead-onlyIdempotent
Read the children of a page or block as an outline with block ids. Use for large pages to read one section at a time.
| Name | Required | Description | Default |
|---|---|---|---|
| block | Yes | Page or block URL/id. | |
| max_depth | No | ||
| max_blocks | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the safety profile is covered. The description adds value they don't: the return format (outline with block ids) and the incremental-read strategy for large pages, which is behaviorally meaningful for an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action and scope, with no wasted words. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description's brief mention of the outline/block-id return shape is helpful. However, given three parameters with only 33% schema coverage, the limits on depth and block count remain unexplained, leaving the definition incomplete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 33% — 'block' is documented but max_depth and max_blocks have no descriptions. The description does not explain depth limiting or block-count limits, leaving two of three parameters semantically undocumented despite the low schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('read the children of a page or block') and clarifies the return shape ('as an outline with block ids'). It does not name or differentiate against close siblings like notion_find_blocks or notion_get_page, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use for large pages to read one section at a time' gives a genuine usage context, but no alternatives are named and no when-not-to-use condition is stated (e.g., how it differs from notion_find_blocks or notion_get_page). Usage is implied rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_get_pageGet PageARead-onlyIdempotent
Read a page: its properties as simple values, the database it belongs to (if any), and its content. format "outline" (default) lists every block with its id in ⟨…⟩, for surgical edits with notion_patch_block, notion_insert_blocks, notion_delete_blocks, notion_copy_blocks. format "markdown" returns the whole page as Notion-flavored markdown (colors, callouts, columns, tables, toggles, mentions), which notion_insert_blocks / notion_create_page accept back. last_edited_time can be passed to write tools as expected_last_edited_time to avoid overwriting someone else's edit.
| Name | Required | Description | Default |
|---|---|---|---|
| page | Yes | Page URL or id. | |
| format | No | outline | |
| max_depth | No | How deep to read nested blocks. | |
| max_blocks | No | ||
| include_content | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/openWorld/non-destructive, so safety is covered. The description adds genuine extra context: the outline format includes block ids for later surgical edits, and last_edited_time can be echoed back as expected_last_edited_time to avoid clobbering concurrent edits — a concurrency-control hint annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose in the first clause, then the format semantics, then the concurrency tip. Dense but every sentence carries information; slightly long for the payload but no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description rightly describes returns (properties, database, content, block ids, markdown flavors). It does not mention truncation/pagination behavior for max_blocks, which is the main remaining gap for an agent deciding how much will come back.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 40%, and the description only elaborates on 'format' (its enum values and downstream consumers). max_depth, max_blocks, and include_content are left to their names and defaults, so the description does not fully compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Read a page') and enumerates exactly what is returned: properties as simple values, parent database, and content. This distinguishes it from block-level siblings like notion_get_blocks and notion_find_blocks without needing to inspect schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the two format modes and routes the agent to the right consumers: 'outline' for surgical edits via notion_patch_block/insert/delete/copy_blocks, 'markdown' for round-tripping into notion_insert_blocks/notion_create_page. It does not explicitly contrast against notion_get_blocks or notion_find_blocks, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_get_schemaGet Database SchemaARead-onlyIdempotent
Read a database's properties: names, types, select/status options (with status groups), relation targets, and which are read-only. Read this before writing properties so values match exactly.
| Name | Required | Description | Default |
|---|---|---|---|
| database | Yes | Database URL/id or data source id. | |
| data_source_name | No | Only needed if the database has several data sources. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar is lower. The description adds real value beyond them by disclosing the shape of the result, including status groups and which properties are read-only, plus the dependency on write operations. No pagination or error behavior is mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler. The content it returns is listed first and the operational reason to call it is front-loaded as the closing admonition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates the fields returned and the write-prerequisite workflow. It is close to complete for a two-parameter read tool, though it omits any mention of multi-data-source ambiguity resolution beyond what the schema's data_source_name already implies.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters (database, data_source_name) are fully documented in the schema itself. The description adds no syntax, format, or selection guidance for them, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Read') and resource ('a database's properties') and enumerates exactly what the read returns: names, types, select/status options, status groups, relation targets, and read-only flags. It is not differentiated from the similarly-named sibling notion_schema, which is the only gap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit just-in-time guidance: 'Read this before writing properties so values match exactly.' That tells the agent both when to call it and why. No exclusion or alternative tool is named, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_historyChange HistoryARead-onlyIdempotent
List changes made through this server, newest first, with their undo ids and how much of each undo can revert. Entries marked interrupted or failed stopped part-way; their input is included so the objects can be checked.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| cursor | No | next_cursor from the previous page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description earns credit for going further: it discloses result ordering, that entries carry undo ids with revert scope, and that interrupted/failed entries stopped part-way with input retained. This partial-failure semantics is genuinely useful and not derivable from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences, front-loaded with the tool's purpose and no filler. The second sentence about interrupted/failed entries is slightly cryptic but earns its place by clarifying an edge case in the results.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully characterizes the return payload (undo ids, revert extent, partial-failure entries), which is exactly what an agent needs. The remaining gap is pagination — the cursor param exists but nothing explains paging behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description says nothing about limit or cursor, and schema coverage is only 50% (limit is undocumented in the schema). With half the parameters lacking any definition, the description needed to compensate for limit's default and max, but it adds no meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb (list) and resource (changes made through this server), plus ordering (newest first), so the agent immediately knows this is a change-log reader. It distinguishes itself from notion_undo only implicitly by surfacing undo ids rather than naming the sibling, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: surfacing undo ids and revert scope suggests reviewing history before calling notion_undo, but the description never says when to use this versus notion_undo, nor names any exclusion. Adequate context, no explicit guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_insert_blocksInsert BlocksA
Insert new content at an exact spot: at the start or end of a page/block, or directly after a specific block id. Existing content is never rewritten. markdown accepts headings (# to ####), lists and to-dos nested by indentation to any depth, quotes, code (mermaid for diagrams), $$ equations $$, pipe tables, > [!NOTE]/[!TIP]/[!WARNING] callouts, and Notion's markdown tags as returned by notion_get_page format=markdown (, , , , , , mentions, {color="…"}). Or give structured blocks (tables via rows, columns, tabs, images/files from a URL or local path, bookmarks, embeds, equations, synced blocks, link_to_page, table_of_contents, breadcrumb). Everything is validated and uploaded before the first write. Returns the new block ids.
| Name | Required | Description | Default |
|---|---|---|---|
| blocks | No | ||
| parent | Yes | Page or block URL/id to insert into. | |
| markdown | No | ||
| position | No | end | |
| after_block_id | No | Required when position is after_block; must be a direct child of parent. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnlyHint=false, destructiveHint=false, non-idempotent, open-world). The description adds meaningful beyond-schema behavior: 'Everything is validated and uploaded before the first write' (validation/atomicity) and 'Existing content is never rewritten.' It also states the return value ('Returns the new block ids'), which is useful since no output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and positioning are front-loaded, followed by a dense but content-rich enumeration of markdown/block features. It is a single long paragraph rather than structurally broken up, but nearly every sentence carries specific, actionable detail, so it earns its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (many block types and markdown features), no output schema, and existing annotations, the description is quite complete. It covers positioning, content formats, validation behavior, and return value; only permission prerequisites and parent constraints are left to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 40% schema description coverage, the description compensates well by detailing the markdown parameter's supported syntax (headings, nested lists, callouts, mermaid, equations, tables) and the structured blocks types. It also clarifies the position semantics (start/end/after a specific block id), adding meaning beyond the enum and schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise verb and resource ('Insert new content at an exact spot') and enumerates the insertion positions, clearly distinguishing this tool from modification tools. An agent immediately understands this is for adding new blocks, not rewriting existing content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context — insert at start, end, or after a specific block — but never names or compares to sibling tools like notion_patch_block or notion_replace_text. The statement that 'Existing content is never rewritten' is a behavioral constraint rather than a routing guideline, so usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_list_templatesList Database TemplatesARead-onlyIdempotent
List a database's page templates (name, id, which is the default). Use a name or id as notion_create_page's template.
| Name | Required | Description | Default |
|---|---|---|---|
| database | Yes | ||
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety profile is covered. The description adds value beyond that by naming the returned fields (name, id, default), which matters since there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with the purpose front-loaded and the downstream usage appended; no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with no output schema, the description usefully sketches the return shape and the consumer of that output. However, it leaves the second parameter undocumented, which is a real gap given 0% schema coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for two parameters. The description implies the `database` parameter via 'a database's page templates' but says nothing about `data_source_name` or the expected id/name format, so it fails to compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (a database's page templates) and even enumerates the returned fields (name, id, default). No sibling tool covers templates, so it is unambiguous which tool to pick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells the agent the follow-on action: feed a returned name or id into notion_create_page's `template` parameter, which implies when this tool is used. It does not state any when-not condition, but the workflow context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_patch_blockPatch One BlockAIdempotent
Edit a single block in place by id without touching anything else on the page: replace its text (inline markdown, colors, mentions allowed), check/uncheck a to-do, set a code block's language or caption, change color, make a heading a toggle, change a callout's icon, or replace a table row's cells. Block type can't change (Notion API limit); to change type, insert a new block and delete the old one. Snapshots the old content for notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | callouts: emoji, image URL, or local image path | |
| text | No | New full text for the block. Omit to leave the text as-is. | |
| cells | No | table_row blocks: new text for every cell, in order | |
| color | No | e.g. default, gray, red, blue_background (or blue_bg) | |
| caption | No | code blocks | |
| checked | No | ||
| block_id | Yes | ||
| language | No | ||
| toggleable | No | headings only | |
| expected_last_edited_time | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (non-destructive, idempotent), but the description adds meaningful behavior: it snapshots the old content for notion_undo and clarifies that it edits only a single block by id. It does not explain concurrency or error behavior, but it goes beyond what the annotations alone provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose and scope, then packs the per-block-type capabilities into one efficient sentence. The third sentence covers the API limitation and undo snapshot. It is dense but well-structured with no obvious filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter mutation tool with no output schema, the description is nearly complete: it explains the edit scope, supported operations, the block-type limitation, and the undo-snapshot behavior. It omits details on expected_last_edited_time and error handling, which are relatively minor against the full picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 60%, so the schema already documents some parameters. The description compensates by explaining what many parameters do in context: text supports inline markdown/colors/mentions, checked toggles a to-do, language/caption apply to code blocks, toggleable applies to headings, icon applies to callouts, and cells replace table-row content. It leaves expected_last_edited_time unexplained, which keeps it from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Edit a single block in place by id') and immediately scopes it ('without touching anything else on the page'). The list of supported edits makes it easy to distinguish from siblings like notion_insert_blocks or notion_bulk_update.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear when-not condition for block type changes and names the alternative workflow (insert a new block and delete the old one). It does not explicitly route the agent between this tool and siblings like notion_replace_text or notion_bulk_update, but the context is otherwise clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_queryQuery DatabaseARead-onlyIdempotent
Query database rows. where takes equality ({"Status": "Done"}), operators ({"Due": {"before": "today"}}, {"Estimate": {">": 500}}, {"Task": {"contains": "x"}}, {"Owner": null}), lists ({"Status": {"in": ["Done", "Blocked"]}}), {"or": [...]}, relative dates ("today", "+7d", "-2w"), and "$created"/"$last_edited"; names and options are matched forgivingly and validated. filter takes raw Notion filter JSON; both are combined with AND. Returns rows with simple values and page ids. For counts or totals use notion_aggregate instead of reading every row.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| sorts | No | ||
| where | No | ||
| cursor | No | next_cursor from a previous call. | |
| filter | No | ||
| database | Yes | Database URL/id or data source id. | |
| properties | No | Only return these properties (saves context). | |
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a read-only, idempotent, open-world, non-destructive operation, so the bar is lower. The description still adds real behavior: `where` and `filter` are combined with AND, and names/options are 'matched forgivingly and validated', which tells the agent it can be loose with casing/labels. Return shape ('rows with simple values and page ids') is also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, then the `where` reference. The operator enumeration is dense but every clause carries usable syntax information, and the alternate-tool pointer is placed at the end where it matters. Slightly long, but nothing is truly redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a query tool with no output schema and 8 params, the description covers the query semantics and the return shape adequately. Gaps remain around pagination/sorthing behavior (cursor is only explained in the schema), but nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 38% with 8 parameters, so the description must compensate. It does so thoroughly for the two hardest params (`where` and `filter`), enumerating equality, operators, lists, or-groups, relative dates, and $created/$last_edited, plus the AND combination. It leaves limit, sorts, and data_source_name unaddressed, keeping it below 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Query database rows') and immediately clarifies scope: rows, not aggregates. The closing sentence names the sibling it is not and why ('For counts or totals use notion_aggregate'), so an agent can distinguish it from notion_aggregate and notion_search without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes count/total needs to notion_aggregate instead of reading every row, which is a genuine when-not rule. It does not cover other plausible alternatives (e.g. notion_search for cross-database lookups) or prerequisites, so it falls short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_replace_textFind and Replace TextA
Find and replace text across a page while keeping bold/italic/links/colors and mentions intact: every text block, table cell, and code caption, plus the page title (include_title). Supports regex with $1-style groups. Defaults to dry_run=true, which shows every change (before/after) so you can confirm. Matches that cross a mention or equation are skipped and reported. Sub-pages are separate documents and aren't searched. All changes revert together with notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| find | Yes | ||
| page | Yes | ||
| regex | No | ||
| dry_run | No | ||
| replace | Yes | ||
| block_ids | No | Limit to these blocks. | |
| include_title | No | Also replace in the page title. | |
| case_sensitive | No | ||
| max_replacements | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations (which only say non-read-only, non-destructive, non-idempotent, open-world). It discloses formatting preservation, regex support with $1 groups, dry_run default with before/after preview, cross-mention matches being skipped/reported, sub-page exclusion, and that changes revert together with notion_undo – all critical behavioral traits for safe invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single dense paragraph, front-loaded with core purpose and scope, then safety default and edge cases. Every sentence adds unique information with zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a multi-param mutation tool with no output schema and sparse schema descriptions, the description covers scope, safety, regex, formatting preservation, limitation handling, and undo integration. It provides everything an agent needs to call correctly and safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 22%, so the description must compensate. It explains include_title, regex, dry_run, and block_ids behavior meaningfully. However, it doesn't clarify case_sensitive or max_replacements defaults, leaving two parameters (case_sensitive, max_replacements) undocumented semantically.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (find and replace text across a page) and details the exact scope: every text block, table cell, code caption, and the page title. This clearly distinguishes it from siblings like notion_update_page or notion_patch_block, which don't perform cross-page text substitution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly mentions the default dry_run=true safety behavior and that sub-pages aren't searched, which helps an agent decide when to use this tool. It does not name alternative sibling tools for narrower edits, but the scoping ('across a page') implies when this bulk-replace approach is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_schemaEdit Database SchemaADestructive
Change a database's properties. action=add adds a property (same definition as notion_create_database). action=rename renames one. action=delete removes one: it defaults to a dry run showing how many rows have values, and snapshots up to 2000 rows' values so notion_undo can re-create the property and restore them. action=add_options adds select/multi-select/status options (status options take a group). action=set_number_format and action=set_description change those settings. Notion's API can't rename or recolor options (it ignores or rejects it); rename them in Notion, or add a new option, move rows with notion_bulk_update, and delete the old one in Notion.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | action=rename: new name. | |
| action | Yes | ||
| dry_run | No | Default true for delete, false otherwise. | |
| options | No | action=add_options | |
| database | Yes | ||
| property | No | Existing property (every action except add). | |
| definition | No | action=add: the new property. | |
| description | No | ||
| number_format | No | ||
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and non-idempotent, and the description goes well beyond them: delete defaults to a dry run showing affected row counts and snapshots up to 2000 rows' values for notion_undo recovery. It also discloses a hard API limitation (options cannot be renamed or recolored; the API ignores or rejects it), which is genuinely new behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and one sentence per action variant, so every clause carries information. It is a dense single paragraph, though, and some clauses (the full option-recolor workaround) run long relative to their marginal selection value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-action, 10-parameter mutation tool with no output schema, the description covers dry-run defaults, undo/snapshot behavior, per-action parameter intent, and an API constraint. An agent has enough to choose the right action and predict side effects without further research.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% across 10 parameters, and the description adds real meaning by mapping each action to the parameters it consumes (to=rename, property=existing property, definition=add, options=add_options). It does not mention data_source_name or clarify number_format/description handling for the settings actions, leaving minor gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Change a database's properties') and then enumerates every action the tool supports (add, rename, delete, add_options, set_number_format, set_description). It clearly distinguishes itself from siblings like notion_create_database and notion_update_properties via explicit cross-references.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives per-action guidance and names concrete alternatives: notion_create_database for the add definition syntax, notion_bulk_update to move rows when changing options, and notion_undo to re-create/restore a deleted property. It even explains when NOT to expect a capability (rename/recolor of options) and prescribes the workaround.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_searchSearch NotionARead-onlyIdempotent
Search pages and databases shared with the integration by title. Returns id, type, title, url, and last edited time. Use this to find ids before reading or editing. Only content shared with the integration is searchable.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Restrict to pages or databases (data sources). | |
| limit | No | ||
| query | Yes | Text to match in titles. Empty string lists recent items. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description earns credit by adding the integration-visibility constraint ('Only content shared with the integration is searchable') and enumerating returned fields, both of which are not in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, all front-loaded: purpose, return shape, then usage. No filler and each sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly compensates by listing the returned fields. Usage and scoping constraints are present; the only gap is that the limit/pagination behavior of the search is never addressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 67%: 'query' and 'type' are documented in the schema, but 'limit' (default 20, max 100) is undocumented anywhere. The description adds no parameter detail, leaving the limit parameter's semantics entirely implicit.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search pages and databases ... by title') plus a scope qualifier ('shared with the integration'). This implicitly distinguishes it from notion_query (database-scoped retrieval) and notion_find_blocks (block content search), though no sibling is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear intent: 'Use this to find ids before reading or editing,' which tells the agent where this fits in a workflow. It stops short of naming alternatives or stating when NOT to use it versus notion_query or notion_find_blocks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_templatePage TemplatesA
Build pages from reusable templates instead of many block calls. Built-in templates: weekly-executive-report, content-brief, launch-plan, research-dossier; save your own. Actions: list, get (a template's full spec, a good starting point), validate (check a template, and with variables that it compiles), preview (the page outline, block count, charts, views, estimated requests, and, with compare_to, what differs from an existing page; writes nothing), render (create the page under parent, or append to append_to; charts are rendered and uploaded, live views placed; notion_undo removes it), save, delete, export (your saved templates), import. A template is {version: 1, name, description?, variables: {name: {type: string|number|boolean|date|list|object, required?, default?, description?}}, parts?: {name: [nodes]}, title, icon?, blocks: [nodes]}. Strings use {{variable}} (also {{item.field}} in loops, {{item_index}}, {{today}}, {{now}}); a string that is exactly one {{variable}} passes lists and objects through. Nodes: {markdown}, {heading, level?}, {callout, icon?, color?}, {toggle, children}, {columns: [[nodes], …]}, {divider: true}, {kpis: [{label, value} | {label, metric: {database, value: "count"|"sum:Prop", where?}}]}, {chart: {spec (as notion_create_chart), data | source, data_table?, format?}}, {view: {database, view (as notion_views)}} (top level only), {table: {header?, rows} | {query: {database, properties?, where?, limit?}}}, {gantt: {title?, tasks}}, {each: "list", as: "item", blocks}, {if: "var" | {var, equals|not|in|gt|lt|empty}, then, else?}, {part: name, with?}, {slot: name, default?} (filled by slots), {blocks: [raw block specs]}.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Template name (get, preview, render, delete). | |
| slots | No | Fill named slots with markdown, or with template nodes. | |
| action | Yes | ||
| parent | No | render: page to create the new page under. | |
| template | No | A template spec (validate, save, or preview/render without saving). | |
| append_to | No | render: existing page to append to instead. | |
| templates | No | import: template specs. | |
| variables | No | ||
| compare_to | No | preview: an existing page to compare the result with. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false, openWorldHint=true and destructiveHint=false; the description usefully augments this by stating preview 'writes nothing' and that render can be reversed via notion_undo. It also implicitly flags mutation (create/append) and that render uploads charts and places live views, which are real side effects. Return formats and error behavior are not disclosed, but the safety-relevant behavior is well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded, but the remainder is one enormous run-on paragraph with nested parentheticals that buries the per-action guidance mid-sentence. The length is arguably justified by the DSL complexity and every clause conveys something, yet the lack of structure (no separation of actions vs. template spec) hurts scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a nine-action, deeply nested tool with no output schema, the description is substantively complete: it covers every action, built-in templates, the template object shape, variable syntax, and all node types. Only the return values of list/export/import and error handling are left unspecified, which is a minor gap given the richness elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 78%, so the schema documents most params (name, parent, append_to, compare_to). The description goes well beyond it by defining the free-form `template` spec, the `variables` interpolation syntax, `slots`, and the full node DSL, which the schema cannot express. That is meaningful added semantics for the two most complex, free-form parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb+resource+benefit ('Build pages from reusable templates instead of many block calls'), distinguishing this tool from siblings like notion_insert_blocks and notion_create_page. It then enumerates all nine actions and the four built-in templates, so an agent can tell exactly what the tool does and when it replaces lower-level block calls.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Per-action conditions are given inline: validate checks a template and compiles variables, preview 'writes nothing', render targets `parent` or `append_to`, and delete/export/import are self-evident. The routing away from 'many block calls' is explicit, but it never names a specific sibling alternative (e.g. notion_list_templates or notion_create_page) to prefer for a given case, so it stops short of full when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_trash_pageMove Page to TrashADestructive
Move a page or database row to the Notion trash. Reversible with notion_undo or from Notion's trash.
| Name | Required | Description | Default |
|---|---|---|---|
| page | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, readOnlyHint=false, and openWorldHint=true, so the safety profile is covered. The description adds valuable context beyond annotations: that the action is reversible via notion_undo or Notion's trash. It doesn't cover permissions or rate limits, but the reversibility note is meaningful added value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with the core action and followed by the reversibility note. Every word earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter mutation tool with rich annotations, the description covers the essential action and reversibility. It doesn't explain permissions or potential side effects (e.g., what happens to child blocks), which would be helpful, but it's largely complete for the scope.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It mentions 'page' as the target but doesn't clarify that the parameter is a page ID string. Since there's only one parameter and its name is self-explanatory, baseline 3 is appropriate given the low schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Move') and resource ('page or database row') with a clear destination ('the Notion trash'). This distinguishes it from siblings like notion_delete_blocks and notion_update_page by identifying exactly what operation occurs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (when you want to trash a page), but doesn't explicitly compare to alternatives like notion_delete_blocks or notion_update_page. It mentions recovery via notion_undo, which is helpful, but doesn't state when to prefer trash over other deletion methods.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_undoUndoADestructive
Revert a change made through this server. With no id, reverts the most recent change that hasn't been undone. Use notion_history to find ids. Undo restores the snapshot taken at write time. Before writing, it checks whether anything it would restore was edited later (by a person or a later change here) and refuses, listing those objects, unless force is true. Edits made within the same minute as the original write can't be detected (Notion rounds edit times to the minute).
| Name | Required | Description | Default |
|---|---|---|---|
| force | No | Overwrite edits made after the original change. Only after confirming with the user. | |
| undo_id | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, so safety is covered; the description goes well beyond them by explaining the restore-from-snapshot mechanism, the conflict-detection-and-refusal behavior (including that it lists blocking objects), and a real limitation (minute-rounded edit times make same-minute edits undetectable). That is exactly the kind of behavioral disclosure that cannot be inferred from structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four sentences, front-loaded with the core action and default behavior, then escalating to the lookup tool, the refusal semantics, and the edge-case limitation. No filler, no restatement of the title or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, non-idempotent mutation with no output schema and only two params, the description supplies everything an agent needs: default behavior, id acquisition path, refusal conditions, override flag semantics, and a known blind spot. Nothing material is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 50% (undo_id has no description), and the description compensates: it defines undo_id as optional with 'no id reverts the most recent change that has not been undone' plus a lookup path, and it defines force by tying it to the conflict refusal rather than merely repeating the schema's terse 'Overwrite edits made after the original change.' Both parameters gain meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Revert a change made through this server') with scope qualifier ('through this server'), which cleanly separates it from siblings that write (notion_update_page, notion_patch_block) and from the read/inspection tools. The default no-id behavior is spelled out, so the agent knows the operation is optional-argument driven.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent to notion_history to obtain ids, defines the no-id fallback, and states the precise when-not condition: the tool refuses if anything it would restore was edited later, unless force is true. That is a complete use/avoid decision rule rather than an implied one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_update_pageUpdate PageAIdempotent
Change a page's title, icon, or cover, lock or unlock it, or move it under another page or into a database. Icons: an emoji, image URL, or local image path; covers: an image URL or local path; "none" removes either. For database row fields use notion_update_properties. Reversible with notion_undo (an icon or cover that was an uploaded file is uploaded again on undo).
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | ||
| page | Yes | Page URL or id. | |
| cover | No | ||
| title | No | ||
| locked | No | ||
| move_to | No | New parent: a page, or a database (the page becomes a row). | |
| data_source_name | No | ||
| expected_last_edited_time | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false, and the description adds real value beyond them: it discloses that changes are reversible via notion_undo and that an uploaded icon/cover file is re-uploaded on undo. It does not mention permission requirements or what happens to unspecified fields, so it falls short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences, front-loaded with the core capability, then value-format details, then sibling routing and undo behavior. No filler; every clause carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and 8 parameters at low coverage, the description would need to carry more. It handles the icon/cover/move semantics well but leaves data_source_name and expected_last_edited_time unexplained, so an agent cannot fully infer correct invocation for those fields.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 25% of 8 parameters, so the description has to compensate. It does clarify icon/cover value formats and the 'none' sentinel that removes either, but title, locked, data_source_name, and expected_last_edited_time (notably a concurrency guard) get no explanation in either place.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb plus resource and enumerates the exact operations available (title/icon/cover, lock/unlock, move under a page or into a database). It also explicitly distinguishes itself from notion_update_properties for database row fields, so an agent can separate the two siblings without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names the alternative for a specific case ('For database row fields use notion_update_properties') and points at notion_undo for reverting, which gives clear routing. It stops short of covering other near siblings (notion_create_page, notion_patch_block) or stating exclusions for arbitrary block content.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_update_propertiesUpdate Page PropertiesAIdempotent
Set properties on a database row using simple values: strings, numbers, booleans, arrays for multi-select/people/relations, ISO dates or {start,end}, null to clear. Property names and option values are matched forgivingly and validated against the schema before anything is written; all problems are reported together. Saves a snapshot so notion_undo can revert. Set dry_run to preview the before/after.
| Name | Required | Description | Default |
|---|---|---|---|
| page | Yes | Page URL or id (must be a database row). | |
| dry_run | No | ||
| properties | Yes | e.g. {"Status": "In progress", "Tags": ["Q4", "Launch"], "Due": "2026-10-15"} | |
| allow_new_options | No | Allow creating new select/multi-select options. | |
| expected_last_edited_time | No | From a prior read; refuses to write if the page changed since. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (non-read-only, idempotent, non-destructive, open-world); the description adds substantial behavior the annotations do not: forgiving name/option matching, full-schema validation before writing, aggregated error reporting, and a saved snapshot enabling notion_undo. These are exactly the mutation-time facts an agent needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with the core action and value formats, then validation guarantees, then side effects and preview. No filler and nothing repeated from the schema or annotations verbatim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter mutation tool with nested objects and no output schema, the description covers value encoding, validation timing, error aggregation, undo support, and preview mode. An agent can call this correctly without further context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema coverage at 80%, the baseline is 3, but the description adds real meaning: it defines how each value type maps to property kinds (arrays for multi-select/people/relations, ISO dates or {start,end}, null to clear) and explains what dry_run actually previews. The remaining params (allow_new_options, expected_last_edited_time) are already documented in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Set properties on a database row') and enumerates accepted value types, so the agent knows exactly what is being written. It does not explicitly differentiate itself from close siblings like notion_update_page or notion_bulk_update, so a routing agent still has to infer which one to pick.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent to use dry_run to preview, and that paths through validation happen before any write, which implies a cautious first-call workflow. However, it never states when to prefer this tool over notion_update_page, notion_bulk_update, or notion_patch_block, nor any prerequisite like fetching the schema first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_viewsDatabase ViewsADestructive
List, read, create, update, or delete database views. Types: table, board, list, calendar, timeline, gallery, form, map, and chart (Notion's native, live charts: column, bar, line, donut, number, with stacking). A view can be a tab on the database (default), a linked view placed on any page (on: {page, after_block}), or a widget on a dashboard view (on: {dashboard}). Views take where/filter like notion_query, sorts, group_by (e.g. board by Status, dates by week), visible properties, and a chart spec like {type: "column", x: "Owner", y: "count"} or y: "sum:Estimate". Every change is reversible with notion_undo.
| Name | Required | Description | Default |
|---|---|---|---|
| on | No | create: place a linked view on a page, or a widget on a dashboard view. Omit for a database tab. | |
| view | No | create: the full view; update: name, type, and only what should change | |
| limit | No | list: views per page. | |
| action | Yes | ||
| cursor | No | list: next_cursor from the previous page. | |
| view_id | No | get, update, delete (a view id or a view URL with ?v=) | |
| database | No | list, create | |
| data_source_name | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=false, and the description adds that 'Every change is reversible with notion_undo' — genuine value that softens the destructive profile. It does not detail permissions or what the response looks like, but the annotation coverage lowers the bar and the reversibility note is the most important behavioral fact.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action list and packed densely with concrete examples rather than filler. It is somewhat long but nearly every clause (types, placement, chart spec, reversibility) earns its place for a complex 8-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex tool with nested objects and no output schema, the description covers the action set, view types, placement modes, filter/sort/group references, chart specifics, and reversibility. It is largely self-sufficient, though it could note pagination or update semantics more explicitly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75%, so the schema already documents most parameters. The description adds concrete semantics beyond the schema, e.g. the chart spec example `{type: "column", x: "Owner", y: "count"}` or `y: "sum:Estimate"`, and group_by examples ('board by Status, dates by week'), which clarify usage beyond bare field names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (database views) with the full CRUD verb set (list, read, create, update, delete), which an agent can immediately distinguish from siblings like notion_query or notion_create_chart. It also enumerates the view types, making the scope of the tool concrete.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for the `on` parameter's two placements (linked view on a page, widget on a dashboard) versus the default tab. It references notion_query for filter syntax and notion_undo for reversibility, but does not explicitly state when to prefer this tool over siblings like notion_query or notion_create_chart.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notion_workflowWorkflowsADestructive
Multi-step workflows (version 2 of automations): a trigger (manual, schedule, or Notion webhook events) and typed steps run in order. Step actions: query, set, append, comment, create_page, move_page, duplicate_page, trash, replace_text, export_markdown, render_template, http, slack, foreach, switch, approval, delay, run_workflow. Each step has an id; may have if (a ${…} reference), retry {attempts, backoff_seconds}, timeout_seconds, and continue_on_error. Steps read earlier outputs with ${steps..} (query returns rows with id, url, title, and each property), the trigger with ${trigger.}, inputs with ${inputs.}, loop items with ${item} (or the foreach as name), and secrets with ${secret:NAME} (environment variable NOTION_PLUS_SECRET_NAME; never stored or shown). approval pauses until a checkbox is checked or a comment with a keyword is posted; delay pauses for minutes; both resume on the next scheduler pass. Runs are durable: a crash, failure, or pause resumes after the last finished step, and creating steps check what an interrupted attempt already made, so nothing is created twice. http and slack steps only reach hosts in NOTION_PLUS_HTTP_ALLOW (Slack's hook host is always allowed for slack). on_failure notifies Slack, an HTTP endpoint, or a page comment. Actions: list, get, save, delete, validate, run (now, with inputs), runs (history), run_status, resume (continue a waiting or failed run), cancel, convert (a v1 rule into a workflow, saved disabled), events / replay / discard (the webhook queue and its dead letters). Webhook events: page.created, page.content_updated, page.properties_updated, page.moved, page.deleted, page.undeleted, comment.created, data_source.content_updated, data_source.schema_updated.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Workflow id (get, delete, run, runs, convert: the rule id). | |
| limit | No | ||
| action | Yes | ||
| inputs | No | run: values for ${inputs.*}. | |
| run_id | No | ||
| status | No | runs / events: filter. | |
| event_id | No | ||
| workflow | No | save / validate: the whole workflow spec. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already declaring destructiveHint=true and openWorldHint=true, the description layers substantial extra behavior: secrets are referenced as ${secret:NAME} and 'never stored or shown', http/slack are restricted to NOTION_PLUS_HTTP_ALLOW hosts, runs are durable and resume after the last finished step with double-create protection, and approval/delay pause until the next scheduler pass. This is exactly the kind of operational context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is dense and mostly relevant, and the core purpose is front-loaded, but the body degenerates into a long semicolon-heavy run-on mixing step actions, reference syntax, durability, and action enums. It would benefit from paragraph or bullet structure; nearly every clause is useful but hard to parse as one block.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex tool with 8 params, no output schema, and nested objects, the description covers triggers, step actions, reference variables, durability/idempotency, host allow-lists, approval/delay pauses, and the full action set. What is missing is per-action return behavior, but that is a modest gap given how much ground is already covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 50% across 8 params. The description explains the `inputs` param ('run: values for ${inputs.*}') and extensively documents the `workflow` object's internal structure, but leaves run_id, event_id, limit, and status semantics to the schema. It adds meaningful value for the nested workflow spec but does not fully close the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a precise verb+resource: 'Multi-step workflows (version 2 of automations): a trigger (manual, schedule, or Notion webhook events) and typed steps run in order.' It names the sibling relationship to automations v1 via the 'convert (a v1 rule into a workflow)' action, so an agent can distinguish it from notion_automation without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied through the enumerated actions (list, get, save, run, runs, resume, cancel, convert) and the mention that convert migrates a v1 rule, but there is no explicit 'use this instead of X when Y' routing against the obvious alternative notion_automation. The agent can infer the lifecycle but gets no exclusions or conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v1.0.0- Changed
notion_build_report1 field changed- changed
Input schema / properties / charts / items / properties / type / enumPrevious value: -[ - "bar", - "column", - "stacked_bar", - "stacked_column", - "grouped_column", - "line", - "area", - "stacked_area", - "pie", - "donut", - "scatter" -]New value: +[ + "bar", + "column", + "stacked_bar", + "stacked_column", + "grouped_column", + "line", + "area", + "stacked_area", + "pie", + "donut", + "scatter", + "histogram", + "heatmap", + "boxplot", + "waterfall", + "funnel", + "bullet", + "small_multiples", + "dual_axis", + "treemap", + "sankey", + "network" +]
- Added
notion_capabilities - Changed
notion_create_chart8 fields changed- added
Input schema / properties / chart / properties / annotationsAdded value: +{ + "description": "Reference lines with labels: {at: \"Q2\", label: \"Launch\"} marks a category; {value: 100, label: \"Target\"} marks a level", + "items": { + "properties": { + "at": { + "type": [ + "string", + "number" + ] + }, + "label": { + "type": "string" + }, + "value": { + "type": "number" + } + }, + "required": [ + "label" + ], + "type": "object" + }, + "maxItems": 10, + "type": "array" +} - added
Input schema / properties / chart / properties / binsAdded value: +{ + "description": "histogram: number of bins (default 20)", + "maximum": 100, + "minimum": 2, + "type": "integer" +} - added
Input schema / properties / chart / properties / paletteAdded value: +{ + "anyOf": [ + { + "enum": [ + "default", + "cool", + "warm", + "mono" + ], + "type": "string" + }, + { + "items": { + "pattern": "^#[0-9a-fA-F]{6}$", + "type": "string" + }, + "maxItems": 12, + "minItems": 2, + "type": "array" + } + ], + "description": "Colors: default (validated colorblind-safe order), cool, warm, mono, or your brand's hex colors in slot order" +} - changed
Input schema / properties / chart / properties / type / enumPrevious value: -[ - "bar", - "column", - "stacked_bar", - "stacked_column", - "grouped_column", - "line", - "area", - "stacked_area", - "pie", - "donut", - "scatter" -]New value: +[ + "bar", + "column", + "stacked_bar", + "stacked_column", + "grouped_column", + "line", + "area", + "stacked_area", + "pie", + "donut", + "scatter", + "histogram", + "heatmap", + "boxplot", + "waterfall", + "funnel", + "bullet", + "small_multiples", + "dual_axis", + "treemap", + "sankey", + "network" +] - added
Input schema / properties / data_tableAdded value: +{ + "default": false, + "description": "Add a toggle under the chart with a description and the data, as a text alternative.", + "type": "boolean" +} - added
Input schema / properties / formatAdded value: +{ + "default": "png", + "description": "png (default) or svg (sharp at any zoom).", + "enum": [ + "png", + "svg" + ], + "type": "string" +} - added
Input schema / properties / vega_liteAdded value: +{ + "additionalProperties": {}, + "description": "Advanced: a complete Vega-Lite spec (data in data.values) instead of chart + data. Not refreshable.", + "propertyNames": { + "type": "string" + }, + "type": "object" +} - added
Input schema / properties / vega_lite_themeAdded value: +{ + "description": "vega_lite only: light (default), dark, or transparent, applied where the spec sets no colors of its own.", + "enum": [ + "light", + "dark", + "transparent" + ], + "type": "string" +}
- Added
notion_doctor - Changed
notion_history1 field changed- added
Input schema / properties / cursorAdded value: +{ + "description": "next_cursor from the previous page.", + "maximum": 9007199254740991, + "minimum": 0, + "type": "integer" +}
- Added
notion_template - Changed
notion_views2 fields changed- added
Input schema / properties / cursorAdded value: +{ + "description": "list: next_cursor from the previous page.", + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "default": 25, + "description": "list: views per page.", + "maximum": 100, + "minimum": 1, + "type": "integer" +}
- Added
notion_workflow
29 tool updates
v0.10.0- First observed
notion_aggregate - First observed
notion_automation - First observed
notion_build_report - First observed
notion_bulk_create - First observed
notion_bulk_update - First observed
notion_comments - First observed
notion_copy_blocks - First observed
notion_create_chart - First observed
notion_create_database - First observed
notion_create_page - First observed
notion_delete_blocks - First observed
notion_duplicate_page - First observed
notion_find_blocks - First observed
notion_get_blocks - First observed
notion_get_page - First observed
notion_get_schema - First observed
notion_history - First observed
notion_insert_blocks - First observed
notion_list_templates - First observed
notion_patch_block - First observed
notion_query - First observed
notion_replace_text - First observed
notion_schema - First observed
notion_search - First observed
notion_trash_page - First observed
notion_undo - First observed
notion_update_page - First observed
notion_update_properties - First observed
notion_views
TDQS
Scored across 33 tools
Most tools have distinct resource+action boundaries, and descriptions actively steer the agent (e.g. prefer notion_views for live charts, use notion_aggregate for counts). However, a few areas overlap: notion_automation vs notion_workflow, notion_template vs notion_list_templates, and notion_doctor vs notion_capabilities. These are clarified by descriptions but still require careful reading.
All tools use snake_case with a consistent notion_ prefix, which is predictable and readable. Most names are verb_noun (get_page, create_page, update_properties), but several are noun-only or action-packed (comments, views, schema, undo, history, doctor, capabilities, automation, workflow, template), and singular/plural use varies slightly.
33 tools is above the 25+ threshold considered too many for a well-scoped server. While Notion is broad and many tools earn their place, the surface is heavy and includes advanced features (automation, workflows, templates, charts, reports) that could be consolidated or exposed as sub-actions. This increases selection overhead and the risk of misselection.
The server covers an unusually full Notion lifecycle: search, page/block read and write, database schema and row CRUD, bulk operations, comments, views, charts, templates, automations, and undo/history. Minor gaps remain: no user-directory tool for people properties, no restore for pages trashed outside this server, and comment deletion is only available indirectly via notion_undo. These are workaroundable but notable.
Maintenance
Related MCP Connectors
Shared tables and Markdown docs for teams and AI-built apps, with scoped access and audited changes.
Read, write, and combine connected apps and databases with shared code and per-person permissions.
Create and edit Myrlo characters, stories, and worlds, with review before every change saves.
Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to read and write to Notion databases with schema adaptation and stable API integration.7Apache 2.0
- AlicenseCqualityCmaintenanceProvides full CRUD capabilities over Notion pages, databases, and content blocks, enabling natural language search, creation, and modification of Notion data.7MIT
- AlicenseNot gradedqualityAmaintenanceConnects AI agents to a Notion workspace with token-based authentication, letting them create and edit pages, query databases, append blocks, apply templates, comment, and upload or read files through plain-language requests. Its three-tool, context-efficient design and built-in batched, idempotent operations support headless automation in CI, cron jobs, and self-hosted agents.2,210 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents like Claude, Cursor, and VS Code to read and write Notion content through a token-authenticated connection, covering pages, databases, blocks, comments, and file uploads. It supports headless and CI use with context-efficient tooling, batched mutations, and idempotent retries.2,210 npmMIT