@atikk-co-jp/notion-mcp-server
v0.14.0
Published
MCP server for Notion API - Create, read, update pages and databases
Maintainers
Readme
notion-mcp-server
English | 日本語
MCP (Model Context Protocol) server for Notion API. Enables AI assistants to interact with Notion pages, databases, and blocks.
API Version: 2025-09-03 (latest)
Why this repository?
Why I Built This
I wanted to use AI agents to process tasks from my Notion database with specific conditions:
"Get tasks where Status = 'Not Started' AND Assignee = 'Alice', sorted by Priority"
Here's what I found with existing options:
| MCP Option | Property Filtering | Token Efficiency | Plan Required |
|------------|-------------------|------------------|---------------|
| Official Notion MCP | Metadata only (created_at, created_by) / Full (Enterprise+AI) | Good | Notion AI |
| @notionhq/notion-mcp-server | ✅ Full support | Large responses | None |
| This repository | ✅ Full support | Optimized | None |
The gap I wanted to fill:
- Full database property filtering (AND/OR, select, checkbox, date, etc.)
- Optimized response sizes for LLM token efficiency
- No plan restrictions
This repository provides property filtering with fields parameter for 90% token reduction.
Quick Start
1. Get a Notion Token
- Go to Notion Integrations
- Click "New integration"
- Give it a name and select the workspace
- Copy the "Internal Integration Token" (starts with
ntn_) - Share the pages/databases you want to access with your integration
2. Configure Your AI Client
Claude Desktop
Add to your configuration (~/.config/claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-y", "@atikk-co-jp/notion-mcp-server"],
"env": {
"NOTION_TOKEN": "ntn_xxxxxxxxxxxx"
}
}
}
}Claude Code
Add to your .mcp.json:
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-y", "@atikk-co-jp/notion-mcp-server"],
"env": {
"NOTION_TOKEN": "ntn_xxxxxxxxxxxx"
}
}
}
}That's it! Restart your AI client and start using Notion.
Features
- Page Operations: Create, retrieve, update, and move Notion pages
- Database Operations: Create, retrieve, update, and query databases with filters and sorts
- Block Operations: Retrieve, update, delete, and append blocks
- Search: Search across pages and databases
- Comments: Create and list comments
- Users: List users and retrieve user info
- Token-Efficient Output: Markdown/simple format reduces token usage by ~96%
- Markdown Input: Create and append content using Markdown (80% fewer input tokens)
API Coverage
⭐ = Markdown input supported (reduces input tokens by ~80%)
📤 = Minimal response (id/url only) - reduces output tokens by ~90%
| Category | Notion API | MCP Tool | Input | Output (default) |
|----------|-----------|----------|-------|------------------|
| Pages | | | | |
| | Create page | create-page 📤 | JSON | {id, url} |
| | | create-page-simple ⭐📤 | Markdown | {id, url} |
| | Retrieve page | retrieve-page | JSON | simple/json |
| | Update page | update-page 📤 | JSON | {id, url} |
| | Retrieve page property | retrieve-page-property | JSON | json |
| | Move page | move-page 📤 | JSON | {id, url} |
| | Archive page | archive-page 📤 | JSON | {id} |
| Databases | | | | |
| | Create database | create-database 📤 | JSON | {id, url} |
| | Retrieve database | retrieve-database | JSON | simple/json |
| | Update database | update-database 📤 | JSON | {id, url} |
| | Archive database | archive-database 📤 | JSON | {id} |
| Data Sources | | | | |
| | Retrieve data source | retrieve-data-source | JSON | simple/json |
| | Query data source | query-data-source | JSON | simple/json |
| | Update data source | update-data-source 📤 | JSON | {id} |
| Blocks | | | | |
| | Retrieve block | retrieve-block | JSON | markdown/json |
| | Update block | update-block 📤 | JSON | {id} |
| | | update-block-simple ⭐📤 | Markdown | {id} |
| | Delete block | delete-block 📤 | JSON | {id} |
| | | delete-blocks-batch 📤 | JSON | {deleted_count, failed_count} |
| | | clear-page-content 📤 | JSON | {deleted_count, failed_count} |
| | Retrieve block children | get-block-children | JSON | markdown/simple/json |
| | Append block children | append-block-children 📤 | JSON | {block_ids} |
| | | append-blocks-simple ⭐📤 | Markdown | {block_ids} |
| | | replace-page-content ⭐📤 | Markdown | {deleted_count, created_count} |
| | | find-and-replace-in-page ⭐📤 | Markdown | {updated_count, updated_block_ids} |
| Comments | | | | |
| | Create comment | create-comment 📤 | JSON | {id} |
| | | create-comment-simple ⭐📤 | Markdown | {id} |
| | List comments | list-comments | JSON | json |
| Users | | | | |
| | List users | list-users | JSON | json |
| | Retrieve user | retrieve-user | JSON | json |
| | Retrieve bot user | retrieve-bot-user | JSON | json |
| Search | | | | |
| | Search | search | JSON | simple/json |
Available Tools
retrieve-page
Retrieve a Notion page by its ID.
Parameters:
page_id(required): The ID of the page to retrieveformat(optional): Output format -"simple"(default) or"json"simple: Returns simplified property values with reduced token usagejson: Returns raw Notion API response
include_content(optional): Include page content as markdown (default: true)
{
"page_id": "page-uuid-here",
"format": "simple",
"include_content": true
}create-page
Create a new page. Supports two parent types:
- Child page: Use
parent.page_idto create a page under an existing page - Database entry: Use
parent.data_source_idto create a page in a database
Create a child page:
{
"parent": { "page_id": "parent-page-uuid-here" },
"properties": {
"title": {
"title": [{ "text": { "content": "Child Page Title" } }]
}
}
}Create a database entry:
{
"parent": { "data_source_id": "data-source-uuid-here" },
"properties": {
"Name": {
"title": [{ "text": { "content": "New Page Title" } }]
},
"Status": {
"status": { "name": "In Progress" }
}
}
}create-page-simple ⭐
Create a new page using Markdown. ~80% fewer input tokens compared to create-page.
Supports two parent types:
- Child page: Use
parent.page_idto create a page under an existing page - Database entry: Use
parent.data_source_idto create a page in a database
Parameters:
parent(required): Either{ page_id }or{ data_source_id }title(required): Page title as a simple stringcontent(optional): Page content in Markdownproperties(optional): Additional Notion propertiesicon(optional): Emoji icon (e.g., "🐛")
Supported Markdown:
- Headings:
# ## ###(#### and beyond → heading_3) - Lists:
-or*(bulleted),1.(numbered) - Checkboxes:
- [ ]/- [x] - Code blocks:
```with language - Quotes:
> - Dividers:
--- - Images:
 - Tables:
| col1 | col2 |with header separator|---|---| - Inline:
**bold**,*italic*,~~strike~~,`code`,[link](url)
Extended Markdown (bidirectional):
- Toggle:
<details><summary>title</summary>content</details> - Callout:
> [!NOTE],> [!WARNING],> [!TIP],> [!IMPORTANT],> [!CAUTION] - Equation:
$$E = mc^2$$(inline/block) - Underline:
<u>text</u>or++text++ - Color:
{color:red}text{/color},{bg:yellow}text{/bg} - Bookmark:
[bookmark](url)or[bookmark:caption](url) - Columns:
:::columns/:::column/::: - Media:
@[embed](url),@[video](url),@[audio](url),@[file](url),@[pdf](url) - Table of contents:
[TOC]
Create a child page:
{
"parent": { "page_id": "parent-page-uuid-here" },
"title": "Meeting Notes",
"content": "## Agenda\n\n1. Review progress\n2. Next steps"
}Create a database entry:
{
"parent": { "data_source_id": "data-source-uuid-here" },
"title": "Bug Report",
"content": "## Steps to Reproduce\n\n1. Login\n2. Open settings\n\n## Expected Behavior\n\nShould display correctly",
"properties": {
"Status": { "status": { "name": "Open" } }
},
"icon": "🐛"
}Token Comparison: | Method | Tokens | Reduction | |--------|--------|-----------| | create-page (blocks) | ~152 | - | | create-page-simple (markdown) | ~26 | 83% |
update-page
Update a page's properties, icon, cover, archive status, or lock status.
Parameters:
page_id(required): The ID of the page to updateproperties(optional): Properties to updateicon(optional): Icon (set to null to remove)cover(optional): Cover image (set to null to remove)archived(optional): Set to true to archiveis_locked(optional): Lock the page to prevent edits in the UI
{
"page_id": "page-uuid-here",
"properties": {
"Status": {
"status": { "name": "Done" }
}
},
"is_locked": true
}query-data-source
Query a data source with optional filters and sorts.
Parameters:
data_source_id(required): The ID of the data source to queryfilter(optional): Filter conditions as a JSON objectsorts(optional): Sort conditions as an arraystart_cursor(optional): Cursor for paginationpage_size(optional): Number of results to return (1-100)format(optional): Output format -"simple"(default) or"json"simple: Returns simplified property values with reduced token usagejson: Returns raw Notion API response
{
"data_source_id": "data-source-uuid-here",
"filter": {
"property": "Status",
"status": { "equals": "In Progress" }
},
"sorts": [
{ "property": "Created", "direction": "descending" }
],
"format": "simple"
}create-database
Create a new database as a subpage of an existing page.
Parameters:
parent_page_id(required): The ID of the parent pageproperties(required): Database schema with at least one title propertytitle(optional): Database title as rich text arrayicon(optional): Icon for the databasecover(optional): Cover image for the databaseis_inline(optional): If true, creates an inline database
{
"parent_page_id": "parent-page-uuid",
"properties": {
"Name": { "title": {} },
"Status": { "select": { "options": [{ "name": "Todo" }, { "name": "Done" }] } },
"Priority": { "number": {} }
},
"title": [{ "type": "text", "text": { "content": "Task Database" } }]
}update-database
Update an existing database container (title, description, icon, cover).
Note: For schema (properties/columns) updates, use update-data-source instead.
Parameters:
database_id(required): The ID of the database to updatetitle(optional): New title as rich text arraydescription(optional): New description as rich text arrayicon(optional): Icon (set to null to remove)cover(optional): Cover image (set to null to remove)is_inline(optional): If true, creates an inline databasearchived(optional): Set to true to archiveis_locked(optional): Lock the database to prevent edits in the UI
{
"database_id": "database-uuid-here",
"title": [{ "type": "text", "text": { "content": "New Title" } }],
"is_locked": true
}retrieve-data-source
Retrieve a data source schema by its ID.
Parameters:
data_source_id(required): The ID of the data sourceformat(optional): Output format -"simple"(default) or"json"
{
"data_source_id": "data-source-uuid-here",
"format": "simple"
}update-data-source
Update a data source schema (properties/columns).
Parameters:
data_source_id(required): The ID of the data source to updateproperties(optional): Properties to add, update, or delete (set to null)
{
"data_source_id": "data-source-uuid-here",
"properties": {
"NewColumn": { "rich_text": {} },
"OldColumn": null
}
}search
Search across all pages and data sources.
{
"query": "search term",
"filter": { "value": "page", "property": "object" }
}Filter values: "page" or "data_source"
get-block-children
Get the child blocks of a page or block.
Parameters:
block_id(required): The ID of the block or page to get children fromstart_cursor(optional): Cursor for paginationpage_size(optional): Number of results to return (1-100)format(optional): Output format -"markdown"(default),"simple", or"json"markdown: Returns human-readable markdown with significantly reduced token usage (~96% reduction)simple: Returns ID + type + markdown content (lightweight, for deletion target selection)json: Returns raw Notion API response
fetch_nested(optional): Whenformat="markdown", fetch nested children blocks recursively (default: false)
{
"block_id": "page-or-block-uuid-here",
"format": "markdown",
"fetch_nested": true
}Get block IDs for deletion:
{
"block_id": "page-or-block-uuid-here",
"format": "simple"
}Returns:
{
"blocks": [
{ "id": "abc123", "type": "heading_1", "content": "# Title" },
{ "id": "def456", "type": "paragraph", "content": "Some text" }
],
"has_more": false
}append-block-children
Append new blocks to a page or block.
{
"block_id": "page-or-block-uuid-here",
"children": [
{
"type": "paragraph",
"paragraph": {
"rich_text": [{ "text": { "content": "New paragraph" } }]
}
}
]
}append-blocks-simple ⭐
Append blocks using Markdown. ~80% fewer output tokens compared to append-block-children.
Parameters:
block_id(required): The page or block ID to append tocontent(required): Content in Markdownafter(optional): Insert after this block ID
Same Markdown support as create-page-simple.
{
"block_id": "page-or-block-uuid-here",
"content": "# New Section\n\nThis is **important** content with a [link](https://example.com).\n\n- Item 1\n- Item 2\n\n```javascript\nconst x = 1;\n```"
}Token Comparison: | Method | Tokens | Reduction | |--------|--------|-----------| | append-block-children (blocks) | ~201 | - | | append-blocks-simple (markdown) | ~42 | 79% |
replace-page-content ⭐
Replace all content of a page with new Markdown content. Automatically preserves child_database and child_page blocks.
Parameters:
page_id(required): The page ID to updatecontent(required): New content in Markdowndry_run(optional): Preview which blocks will be deleted without making changes (default: false)
⚠️ Warning: Blocks not representable in Extended Markdown (table_of_contents, synced_block, etc.) will be DELETED. Use dry_run: true to preview before executing.
Use when: You want to completely rewrite page content without finding individual block IDs.
Same Markdown support as create-page-simple.
{
"page_id": "page-uuid-here",
"content": "# New Page Title\n\nThis is the new content.\n\n## Section 1\n\n- Item 1\n- Item 2"
}Preview deletions (dry run):
{
"page_id": "page-uuid-here",
"content": "# New content",
"dry_run": true
}find-and-replace-in-page ⭐
Find text in a page and replace it with new content. Supports regex patterns for advanced matching.
Parameters:
page_id(required): The page ID to search infind(required): Text to find (string or regex pattern)replace(required): Replacement text (supports Markdown:**bold**,*italic*, etc.)use_regex(optional): If true, treatfindas a regex pattern (default: false)
Use when: You want to update specific text without rewriting the entire page.
{
"page_id": "page-uuid-here",
"find": "old text",
"replace": "**new text**"
}With regex:
{
"page_id": "page-uuid-here",
"find": "item\\d+",
"replace": "updated item",
"use_regex": true
}delete-blocks-batch
Delete multiple blocks by their IDs. Blocks are deleted sequentially to respect API rate limits (3 req/s).
Parameters:
block_ids(required): Array of block IDs to delete (max 100)
Use when: You want to delete specific blocks. Use get-block-children with format="simple" to get block IDs first.
{
"block_ids": ["block-uuid-1", "block-uuid-2", "block-uuid-3"]
}Returns:
{
"deleted_count": 3,
"failed_count": 0,
"deleted": ["block-uuid-1", "block-uuid-2", "block-uuid-3"]
}clear-page-content
Delete all content from a page. By default, preserves child_database and child_page blocks.
Parameters:
page_id(required): The page ID to clearpreserve_types(optional): Block types to preserve (default:["child_database", "child_page"]). Set to[]to delete all.
Use when: You want to delete all content from a page without selecting individual blocks.
{
"page_id": "page-uuid-here"
}Delete everything (including child databases/pages):
{
"page_id": "page-uuid-here",
"preserve_types": []
}Returns:
{
"deleted_count": 15,
"failed_count": 0
}create-comment
Add a comment to a page.
{
"page_id": "page-uuid-here",
"rich_text": [{ "type": "text", "text": { "content": "This is a comment" } }]
}create-comment-simple ⭐
Add a comment using Markdown. Simpler than create-comment.
Parameters:
page_id(required): The ID of the pagecontent(required): Comment in Markdowndiscussion_id(optional): Reply to existing thread
{
"page_id": "page-uuid-here",
"content": "This is **important** with a [link](https://example.com)"
}Development
# Install dependencies
pnpm install
# Run in development mode
pnpm dev
# Build for production
pnpm build
# Type check
pnpm typecheck
# Lint
pnpm lint
# Format code
pnpm format
# Run tests
pnpm test
# Run tests in watch mode
pnpm test:watchLicense
MIT
