Notion MCP Server
Provides comprehensive Notion database operations including CRUD, search, query, schema management, and content formatting via the Notion API.
Click on "Install 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 MCP Serverfind all pages created in the last week in my projects database"
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 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
Related MCP server: Notion MCP Server
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 configurationDesign 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-fastmcpInstall dependencies
uv syncConfigure environment
cp .env.example .env
# Edit .env and add your NOTION_TOKENConfigure databases
cp databases.yaml.example databases.yaml
# Edit databases.yaml and add your database configurationsGetting Your Notion Credentials
Create Integration
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-03Usage
Running the Server
Development:
python main.pyWith FastMCP CLI:
fastmcp run main.pyClaude 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.pyFull connection test:
python connection_testing/test_connection.pyThis will:
Validate your configuration
Test API connectivity
Check database access
Fetch schemas
Validation Testing
Test the property validator directly:
python test_validation.pyDevelopment
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.tooldecoratorImport 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 resultProject 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.exampleAdd your token from https://www.notion.so/my-integrations
"Database not found (404)"
Check database_id in
databases.yamlEnsure integration is added to the database
Verify integration has access
"No databases configured"
Create
databases.yamlfromdatabases.yaml.exampleAdd 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.logAPI 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
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/kascoded/kas-fastmcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server