Notion MCP Server
A production-grade Notion MCP server with full CRUD, search, and schema validation capabilities for AI-assisted productivity workflows.
README
Notion MCP Server
A production-grade Model Context Protocol (MCP) server for Notion, providing comprehensive database operations with schema validation and intelligent property handling.
Features
- 🔧 Full CRUD Operations - Create, read, update pages across Notion databases
- 🔍 Smart Search & Query - Powerful filtering and search capabilities
- 📊 Schema Management - Automatic schema fetching and validation
- 🎨 Content Formatting - Markdown ↔ Notion blocks conversion
- ⚡ Async Architecture - High-performance async operations
- 🛡️ Type Safety - Comprehensive property validation
- 🔄 API 2025-09-03 - Uses latest Notion API with data sources
Architecture
kas-fastmcp/
├── main.py # Entry point
├── config.py # NotionConfig, loads databases.yaml
├── notion_server/
│ ├── server.py # FastMCP("KasNotionMCP") instance
│ ├── deps.py # Shared NotionClient + SchemaManager singletons
│ ├── core/
│ │ ├── client.py # NotionClient (httpx wrapper, 429 retry, connection pool)
│ │ ├── schema.py # SchemaManager (10-min TTL, disk cache)
│ │ └── formatters.py # PropertyFormatter, BlockFormatter (markdown <-> blocks)
│ ├── tools/
│ │ ├── query.py # notion_query, notion_find_page_by_name, notion_search, notion_list_data_sources, notion_discover_databases
│ │ ├── pages.py # notion_get_page, notion_get_data_source, notion_create_item, notion_update_item
│ │ ├── content.py # notion_get_page_content, notion_append_content, notion_replace_content
│ │ └── schema_sync.py # notion_sync_schemas, notion_validate_config
│ └── utils/
│ └── validators.py # PropertyValidator
└── databases.yaml # Database configuration
Design Principles
- Separation of Concerns - Core logic separated from MCP layer
- No Circular Dependencies - Clean, linear dependency flow
- Immutable Configuration - Config is never mutated at runtime
- Schema-First - Validate against actual Notion schemas
- Testable - Each layer can be tested independently
Installation
Prerequisites
- Python 3.10+
- Notion Integration with API access
- Notion databases with integration added
Setup
- Clone the repository
git clone <your-repo-url>
cd kas-fastmcp
- Install dependencies
uv sync
- Configure environment
cp .env.example .env
# Edit .env and add your NOTION_TOKEN
- Configure databases
cp databases.yaml.example databases.yaml
# Edit databases.yaml and add your database configurations
Getting Your Notion Credentials
-
Create Integration
- Go to https://www.notion.so/my-integrations
- Click "New integration"
- Give it a name and select your workspace
- Copy the "Internal Integration Token"
-
Get Data Source IDs
- Open your database in Notion
- Click "..." menu → Settings
- Manage data sources → Copy data source ID
- Add to
databases.yaml
-
Add Integration to Databases
- Open each database in Notion
- Click "..." menu → Connections
- Add your integration
Configuration
databases.yaml
Define all your Notion databases:
zettelkasten:
data_source_id: "your-data-source-id-here"
database_id: "your-database-id-here"
title_property: "title"
description: "Personal knowledge management"
habits:
data_source_id: "your-data-source-id-here"
database_id: "your-database-id-here"
title_property: "title"
description: "Habit tracking"
.env
NOTION_TOKEN=ntn_your_token_here
NOTION_API_VERSION=2025-09-03
Usage
Running the Server
Development:
python main.py
With FastMCP CLI:
fastmcp run main.py
Claude Desktop Integration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"kas-notion": {
"command": "python",
"args": ["/path/to/kas-fastmcp/main.py"]
}
}
}
Available Tools (15 total)
Query Tools (query.py)
notion_query- Query pages from a databasenotion_find_page_by_name- Find page by exact titlenotion_search- Workspace-wide searchnotion_list_data_sources- List data sources for a databasenotion_discover_databases- Discover all accessible databases
Page Tools (pages.py)
notion_get_page- Get page with properties (fully paginated wheninclude_content=True)notion_get_data_source- Get database schemanotion_create_item- Create new pagenotion_update_item- Update page properties
Content Tools (content.py)
notion_get_page_content- Get page content as markdownnotion_append_content- Append blocks to pagenotion_replace_content- Clear all blocks on a page and write new markdown content
Schema Tools (schema_sync.py)
notion_sync_schemas- Sync schemas from Notion and optionally update confignotion_validate_config- Validate current database configuration
Available Resources
notion://databases- Lists all configured databases as JSONnotion://databases/{source_name}/schema- Returns the cached schema for a specific database
Testing
Connection Testing
Quick token verification:
python connection_testing/token_verification.py
Full connection test:
python connection_testing/test_connection.py
This will:
- Validate your configuration
- Test API connectivity
- Check database access
- Fetch schemas
Validation Testing
Test the property validator directly:
python test_validation.py
Development
Adding a New Database
- Add to
databases.yaml:
my_database:
data_source_id: "your-id"
database_id: "your-id"
title_property: "Name"
description: "My new database"
- No code changes needed! The server automatically loads all databases from the YAML file.
Adding a New Tool
- Choose the appropriate module (
query.py,pages.py, orcontent.py) - Use the
@mcp.tooldecorator - Import and use core modules
- Document with clear docstrings
Example:
from notion_server.server import mcp
from notion_server.deps import _client # shared singleton — do not instantiate a new one
@mcp.tool
async def my_new_tool(param: str) -> dict:
"""
Tool description.
Args:
param: Parameter description
Returns:
Result description
"""
result = await _client.get(f"endpoint/{param}")
return result
Project Structure Explained
core/ - Pure business logic, no MCP dependencies
- Testable independently
- Reusable in other projects
- No side effects
tools/ - MCP tool definitions
- Thin wrappers around core modules
- Handle MCP-specific concerns
- Minimal business logic
utils/ - Shared utilities
- Validators
- Helpers
- Common functions
Validation System
How It Works
Properties are validated against Notion's schema before API calls:
# Automatic validation
notion_create_item(
source_name="zettelkasten",
properties={
"title": {"title": [{"text": {"content": "My Note"}, "type": "text"}]},
"nonexistent": {"rich_text": [...]} # ❌ Validation error!
}
)
What Gets Validated
✅ Property exists in schema
✅ Property type matches
✅ Select options are valid
✅ Read-only properties rejected
✅ Required properties present (strict mode)
Direct Validation
Use the validator directly in your code:
from notion_server.core import SchemaManager, NotionClient
from notion_server.utils import PropertyValidator
client = NotionClient()
schema_manager = SchemaManager(client)
schema = await schema_manager.get_schema("zettelkasten")
validator = PropertyValidator(schema)
is_valid, errors = validator.validate_properties(properties)
Troubleshooting
Common Issues
"NOTION_TOKEN not found"
- Create
.envfile from.env.example - Add your token from https://www.notion.so/my-integrations
"Database not found (404)"
- Check database_id in
databases.yaml - Ensure integration is added to the database
- Verify integration has access
"No databases configured"
- Create
databases.yamlfromdatabases.yaml.example - Add at least one database configuration
"Property validation failed"
- Check property names match your schema
- Ensure values are in correct Notion format
- Verify select options are valid
Debug Mode
Enable detailed logging by checking server output:
python main.py 2>&1 | tee server.log
API Reference
NotionClient
client = NotionClient(token=None, api_version=None)
await client.get(endpoint)
await client.post(endpoint, payload)
await client.patch(endpoint, payload)
SchemaManager
schema_manager = SchemaManager(client)
schema = await schema_manager.get_schema(source_name)
data_source_id = await schema_manager.get_data_source_id(source_name)
config = schema_manager.get_source_config(source_name)
PropertyFormatter
formatter = PropertyFormatter()
title = formatter.extract_title(properties)
formatted = formatter.format_for_display(properties)
BlockFormatter
formatter = BlockFormatter()
markdown = formatter.to_markdown(blocks)
blocks = formatter.from_markdown(markdown)
Contributing
Code Style
- Use type hints
- Write docstrings
- Keep functions focused
- Follow separation of concerns
Testing
- Test core modules independently
- Test tools through MCP protocol
- Validate against real Notion databases
License
MIT
Acknowledgments
- Built with FastMCP
- Uses Notion API 2025-09-03
- Developed for AI-powered productivity workflows
See CHANGELOG.md for version history.
Support
For issues, questions, or contributions, please open an issue on GitHub.
Built with ❤️ for AI-powered productivity
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。