apimlett/notion-mcp-server
If you are the rightful owner of notion-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The Notion MCP Server is a Model Context Protocol server that facilitates comprehensive read and write access to Notion workspaces via the Notion API.
notion_search_pages
Search for pages across your workspace.
notion_get_page
Retrieve a specific page with all its content.
notion_create_page
Create a new page with content.
notion_update_page
Update an existing page's properties and content.
notion_append_blocks
Append blocks to an existing page.
notion_query_database
Query a database with filters and sorting.
notion_create_database_page
Create a new page in a database.
notion_update_database_page
Update properties of a database page.
notion_get_blocks
Get child blocks of a page or block.
notion_update_block
Update a specific block's content.
notion_delete_block
Delete a specific block.
notion_get_users
List all users in the workspace.
notion_get_databases
List accessible databases.
Notion MCP Server
A Model Context Protocol (MCP) server that provides comprehensive read and write access to Notion workspaces through the Notion API.
Features
- š Search and retrieve pages, databases, and blocks
- š Create and update pages with rich content
- šļø Database operations - query, create, and update database entries
- šļø Block manipulation - append, update, and delete blocks
- š Secure authentication using Notion integration tokens
- š”ļø Error handling with proper MCP error responses
- š Comprehensive logging for debugging and monitoring
Quick Start
1. Installation
git clone https://github.com/your-username/notion-mcp-server.git
cd notion-mcp-server
npm install
2. Notion Integration Setup
- Go to Notion Developers
- Click "New integration"
- Fill in basic information:
- Name: "MCP Server Integration"
- Associated workspace: Select your workspace
- Capabilities: Read content, Update content, Insert content
- Click "Submit"
- Copy the "Internal Integration Token"
3. Configuration
Create a .env
file in the project root:
NOTION_TOKEN=your_notion_integration_token_here
Note: The server automatically finds and loads the .env
file from the project directory, regardless of where the MCP client runs it from.
4. Grant Page Access
For each Notion page/database you want to access:
- Open the page in Notion
- Click the "..." menu ā "Add connections"
- Select your integration
5. Running the Server
# Development
npm run dev
# Production
npm start
Client Integration
Claude Code (CLI)
Add the server to your Claude Code MCP configuration:
{
"mcpServers": {
"notion": {
"command": "node",
"args": ["/path/to/notion-mcp-server/dist/index.js"]
}
}
}
Or using npm:
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-p", "/path/to/notion-mcp-server", "node", "dist/index.js"]
}
}
}
The server will automatically read the NOTION_TOKEN
from your .env
file.
Claude Desktop
Add to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%/Claude/claude_desktop_config.json
{
"mcpServers": {
"notion": {
"command": "node",
"args": ["/path/to/notion-mcp-server/dist/index.js"]
}
}
}
The server will automatically read the NOTION_TOKEN
from your .env
file in the project directory.
ChatGPT (via OpenAI)
For ChatGPT integration, you'll need to run the server with a JSON-RPC transport. Create a wrapper script:
notion-mcp-wrapper.js:
#!/usr/bin/env node
const { spawn } = require('child_process');
const server = spawn('node', ['/path/to/notion-mcp-server/dist/index.js'], {
env: process.env, // Inherits environment variables including NOTION_TOKEN from .env
stdio: ['pipe', 'pipe', 'pipe'],
cwd: '/path/to/notion-mcp-server' // Ensures .env file is found
});
process.stdin.pipe(server.stdin);
server.stdout.pipe(process.stdout);
server.stderr.pipe(process.stderr);
server.on('exit', (code) => {
process.exit(code);
});
Then configure ChatGPT to use:
{
"tools": [
{
"type": "mcp_server",
"mcp_server": {
"command": "node",
"args": ["/path/to/notion-mcp-wrapper.js"]
}
}
]
}
Alternative: Global Installation
For easier configuration, you can install the server globally:
# Make the server globally available
npm link
# Or install globally if published
npm install -g notion-mcp-server
Then use in configurations:
{
"mcpServers": {
"notion": {
"command": "notion-mcp-server"
}
}
}
Note: When using global installation, ensure your .env
file is in the working directory where the client runs, or set the NOTION_TOKEN
as a system environment variable.
Security Best Practices
ā
DO: Keep your Notion token in the .env
file
NOTION_TOKEN=secret_your_notion_integration_token_here
ā DON'T: Put tokens directly in MCP client configurations
// AVOID THIS - tokens exposed in config files
{
"mcpServers": {
"notion": {
"env": {
"NOTION_TOKEN": "secret_token_here"
}
}
}
}
System Environment Variables (Optional)
If you prefer system-wide environment variables instead of .env
files:
# Add to your shell profile (.bashrc, .zshrc, etc.)
export NOTION_TOKEN="your_notion_integration_token_here"
This approach works well with global installations and containerized deployments.
MCP Tools Available
Page Operations
notion_search_pages
Search for pages across your workspace.
{
"query": "meeting notes",
"filter": "page",
"sort": "last_edited_time"
}
notion_get_page
Retrieve a specific page with all its content.
{
"page_id": "page-uuid-here"
}
notion_create_page
Create a new page with content.
{
"parent": {
"type": "page_id",
"page_id": "parent-page-uuid"
},
"title": "New Page Title",
"content": "# Heading\n\nThis is some content."
}
notion_update_page
Update an existing page's properties and content.
{
"page_id": "page-uuid-here",
"title": "Updated Title",
"content": "Updated content here"
}
notion_append_blocks
Append blocks to an existing page.
{
"block_id": "page-or-block-uuid",
"content": "Additional content to append"
}
Database Operations
notion_query_database
Query a database with filters and sorting.
{
"database_id": "database-uuid-here",
"filter": {
"property": "Status",
"select": {
"equals": "In Progress"
}
},
"sorts": [
{
"property": "Created",
"direction": "descending"
}
]
}
notion_create_database_page
Create a new page in a database.
{
"database_id": "database-uuid-here",
"properties": {
"Name": {
"title": [
{
"text": {
"content": "New Task"
}
}
]
},
"Status": {
"select": {
"name": "To Do"
}
}
},
"content": "Task description here"
}
notion_update_database_page
Update properties of a database page.
{
"page_id": "page-uuid-here",
"properties": {
"Status": {
"select": {
"name": "Completed"
}
}
}
}
Block Operations
notion_get_blocks
Get child blocks of a page or block.
{
"block_id": "block-uuid-here"
}
notion_update_block
Update a specific block's content.
{
"block_id": "block-uuid-here",
"content": "Updated block content"
}
notion_delete_block
Delete a specific block.
{
"block_id": "block-uuid-here"
}
Utility Operations
notion_get_users
List all users in the workspace.
notion_get_databases
List accessible databases.
Configuration
Environment Variables
Variable | Description | Required |
---|---|---|
NOTION_TOKEN | Notion integration token | Yes |
LOG_LEVEL | Logging level (debug, info, warn, error) | No (default: info) |
PORT | Server port for health checks | No (default: 3000) |
Integration Capabilities
When creating your Notion integration, ensure you enable:
- ā Read content - Required for all read operations
- ā Update content - Required for updating pages/blocks
- ā Insert content - Required for creating pages/blocks
- ā Read user information - Required for user operations
Error Handling
The server implements comprehensive error handling:
- Authentication errors - Invalid or missing Notion token
- Permission errors - Access denied to specific pages/databases
- Rate limiting - Automatic retry with exponential backoff
- Validation errors - Invalid parameters or malformed requests
- Network errors - Connection timeouts and retries
Development
Project Structure
notion-mcp-server/
āāā src/
ā āāā index.ts # Main server entry point
ā āāā types.ts # TypeScript type definitions
ā āāā tools/ # MCP tool implementations
ā ā āāā pages.ts # Page-related tools
ā ā āāā databases.ts # Database-related tools
ā ā āāā blocks.ts # Block-related tools
ā ā āāā utils.ts # Utility tools
ā āāā notion/ # Notion API wrappers
ā ā āāā client.ts # Notion client setup
ā ā āāā converters.ts # Content converters
ā ā āāā validators.ts # Input validation
ā āāā utils/
ā āāā logger.ts # Logging utilities
ā āāā errors.ts # Error handling
āāā tests/ # Test files
āāā docs/ # Additional documentation
āāā package.json
āāā tsconfig.json
āāā .env.example
āāā README.md
Building
npm run build
Testing
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run integration tests (requires valid Notion token)
npm run test:integration
Linting
npm run lint
npm run lint:fix
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Commit your changes:
git commit -m 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Open a Pull Request
Development Guidelines
- Follow TypeScript best practices
- Add tests for new features
- Update documentation for API changes
- Use conventional commit messages
- Ensure all tests pass before submitting PR
Security
- Never commit
.env
files or tokens to the repository - Use environment variables for sensitive configuration
- Regularly rotate your Notion integration tokens
- Follow the principle of least privilege when granting access
Troubleshooting
Common Issues
"Cannot use import statement outside a module" Error
This project uses ES modules. Make sure your package.json
includes:
{
"type": "module"
}
"Expected ',' or ']' after array element in JSON" Error
This error occurs when logs are sent to stdout instead of stderr, interfering with MCP JSON communication. The server has been fixed to send all logs to stderr, but if you encounter this:
- Ensure you're using the latest version
- Check that no
console.log
statements are in the code - Restart Claude Desktop after updating the server
"Missing required environment variable: NOTION_TOKEN" Error
The server automatically loads the .env
file from the project directory. If you see this error:
- Ensure the
.env
file exists in the project root with your token:NOTION_TOKEN=your_notion_integration_token_here
- Verify the token is valid and not expired
- Check that there are no extra spaces or quotes around the token
"Cannot find module" Error
- Verify the path in your MCP client configuration points to the correct location
- Ensure you've built the project:
npm run build
- Check that the
dist/
folder exists and containsindex.js
"Unauthorized" Error
- Verify your
NOTION_TOKEN
is correct in the.env
file - Ensure the integration has been added to the pages/databases you're accessing
- Check that your integration has the required capabilities
"Object not found" Error
- Verify the page/database ID is correct
- Ensure the integration has access to the specific object
- Check if the object has been deleted or moved
Rate Limiting
- The server automatically handles rate limits with exponential backoff
- If you encounter persistent rate limiting, consider reducing request frequency
Debug Mode
Enable debug logging:
LOG_LEVEL=debug npm start
This will output detailed information about API calls and responses.
Testing the Server
To verify the server works correctly:
# Build the project
npm run build
# Test TypeScript compilation
npm run typecheck
# Run the server (will start and wait for MCP connections)
npm start
Changelog
See for a detailed list of changes.
License
This project is licensed under the MIT License - see the file for details.
Acknowledgments
- Notion API for providing the excellent API
- Model Context Protocol for the MCP specification
- The open-source community for inspiration and contributions
Support
- š
- š Issue Tracker
- š¬ Discussions
- š§
Made with ā¤ļø by the open-source community