Composite MCP Server for Notion - Human-Like Workflows for AI Agents
Mission: Enable AI agents to work with Notion using human-like workflows while maintaining near-complete API coverage with minimal tools and token usage.
This MCP server transforms Notion's 28+ atomic REST API endpoints into 7 mega action-based tools that mirror how humans actually work with Notion:
- Action-Based Design: Each tool supports multiple related actions (e.g., pages tool: create, get, update, archive)
- Markdown-First: Natural language content format optimized for AI understanding
- Auto-Pagination: Transparent handling of large datasets
- Bulk Operations: Process multiple items efficiently in one request
- Safe-by-Default: Only safe operations exposed (no risky schema updates)
- 7 Mega Tools: 75% Official API coverage (21/28 endpoints) with safe operations only
- 30 Actions: Multiple actions per tool for comprehensive functionality
- Markdown Support: Write and read Notion content in markdown format
- Auto-Pagination: Automatically fetch all results without cursor management
- Bulk Operations: Create/update/delete multiple items in single requests
- Simple Deployment: npx one-liner or Docker container
- Safe-by-Default: Risky operations (database schema updates) intentionally excluded
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["@n24q02m/better-notion-mcp"],
"env": {
"NOTION_TOKEN": "your-notion-token-here"
}
}
}
}{
"mcpServers": {
"notion": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-e", "NOTION_TOKEN=your-notion-token-here",
"n24q02m/better-notion-mcp:latest"
]
}
}
}- Visit https://www.notion.so/my-integrations
- Click "New integration"
- Name it and select your workspace
- Copy the Internal Integration Token
- Share pages/databases with your integration
Each tool supports multiple actions, mapping to 21+ Official Notion API endpoints.
Actions: create, get, update, archive, restore, duplicate
-
create: Create page with title + markdown content + properties in one call
- Maps to:
POST /v1/pages+PATCH /v1/blocks/{id}/children - Example:
{action: "create", title: "My Page", parent_id: "xxx", content: "# Hello\nMarkdown here"}
- Maps to:
-
get: Retrieve full page as markdown with all properties
- Maps to:
GET /v1/pages/{id}+GET /v1/blocks/{id}/children - Example:
{action: "get", page_id: "xxx"}
- Maps to:
-
update: Update title, properties, and/or content (replace/append/prepend)
- Maps to:
PATCH /v1/pages/{id}+PATCH /v1/blocks/{id}/children - Example:
{action: "update", page_id: "xxx", title: "New Title", append_content: "\n## New section"}
- Maps to:
-
archive/restore: Bulk archive or restore multiple pages
- Maps to: Multiple
PATCH /v1/pages/{id}calls - Example:
{action: "archive", page_ids: ["xxx", "yyy"]}
- Maps to: Multiple
-
duplicate: Duplicate a page with all content
- Example:
{action: "duplicate", page_id: "xxx"}
- Example:
Actions: create, get, query, create_page, update_page, delete_page, create_data_source, update_data_source, update_database
ARCHITECTURE NOTE: Notion databases now support multiple data sources. A database is a container that holds one or more data sources. Each data source has its own schema (properties) and rows (pages).
-
create: Create database with initial data source
- Maps to:
POST /v1/databases(API 2025-09-03) - Example:
{action: "create", parent_id: "xxx", title: "Tasks", properties: {Status: {select: {...}}}}
- Maps to:
-
get: Retrieve database schema and structure
- Maps to:
GET /v1/databases/{id}+ auto-fetch data_source_id - Example:
{action: "get", database_id: "xxx"}
- Maps to:
-
query: Query database with filters/sorts + smart search
- Maps to:
POST /v1/databases/{id}/query - Example:
{action: "query", database_id: "xxx", search: "project", limit: 10}
- Maps to:
-
create_page: Create new database items (bulk)
- Maps to:
POST /v1/pages - Example:
{action: "create_page", database_id: "xxx", pages: [{properties: {Name: "Task 1", Status: "Todo"}}]}
- Maps to:
-
update_page: Update database items (bulk)
- Maps to:
PATCH /v1/pages - Example:
{action: "update_page", page_id: "yyy", page_properties: {Status: "Done"}}
- Maps to:
-
delete_page: Delete database items (bulk)
- Maps to:
DELETE /v1/pages(via batch) - Example:
{action: "delete_page", page_ids: ["yyy", "zzz"]}
- Maps to:
-
create_data_source: Add second data source to database
- Maps to:
POST /v1/data_sources - Example:
{action: "create_data_source", database_id: "xxx", title: "Archive", properties: {...}}
- Maps to:
-
update_data_source: Update data source schema
- Maps to:
PATCH /v1/data_sources/{id} - Example:
{action: "update_data_source", data_source_id: "yyy", properties: {NewField: {checkbox: {}}}}
- Maps to:
-
update_database: Update database container (title, icon, cover, move)
- Maps to:
PATCH /v1/databases/{id} - Example:
{action: "update_database", database_id: "xxx", title: "New Title", icon: "π"}
- Maps to:
Actions: get, children, append, update, delete
- Maps to:
GET/PATCH/DELETE /v1/blocks/{id}+GET/PATCH /v1/blocks/{id}/children - Example:
{action: "append", block_id: "xxx", content: "## New section\nContent here"}
Actions: list, get, me, from_workspace
-
list: List all users in workspace (requires permission)
- Maps to:
GET /v1/users - Example:
{action: "list"}
- Maps to:
-
get: Get specific user by ID
- Maps to:
GET /v1/users/{id} - Example:
{action: "get", user_id: "xxx"}
- Maps to:
-
me: Get current bot/integration info
- Maps to:
GET /v1/users/me - Example:
{action: "me"}
- Maps to:
-
from_workspace: Extract users from accessible pages (permission bypass)
- Alternative method when users.list() permission is denied
- Example:
{action: "from_workspace"}
Actions: info, search
-
info: Get bot and workspace information
- Maps to:
GET /v1/users/me - Example:
{action: "info"}
- Maps to:
-
search: Smart workspace-wide search with filters
- Maps to:
POST /v1/search - Example:
{action: "search", query: "project", filter: {object: "page"}, limit: 10}
- Maps to:
Actions: list, create
- Maps to:
GET /v1/comments,POST /v1/comments - Example:
{action: "list", page_id: "xxx"}or{action: "create", page_id: "xxx", content: "Great!"}
Utility tool for converting between formats (not a direct API call)
-
markdown-to-blocks: Parse markdown into Notion block structure
- Example:
{direction: "markdown-to-blocks", content: "# Hello\n\nWorld"}
- Example:
-
blocks-to-markdown: Convert Notion blocks to markdown
- Example:
{direction: "blocks-to-markdown", content: [{"type": "paragraph", "paragraph": {...}}]}
- Example:
- Node.js 22+ (uses native fetch)
- npm 7+
- Notion Integration with appropriate permissions
git clone https://github.com/n24q02m/better-notion-mcp
cd better-notion-mcp
npm install
npm run build# Run with your Notion token
NOTION_TOKEN=secret_xxx npm run dev
# Or use environment variable
export NOTION_TOKEN=secret_xxx
npm run dev# Run all tests
npm test
# Watch mode
npm run test:watch
# With coverage
npm run test:coverage# Build image
npm run docker:build
# Run container
npm run docker:runWe welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Make your changes following our commit conventions
- Run tests:
npm test - Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
See CHANGELOG.md for release history.
MIT License - See LICENSE