@gongrzhe/server-notion-mcp
Version:
Official MCP server for Notion API with stateless architecture
481 lines (365 loc) • 13.8 kB
Markdown
# Notion MCP Server
> [!NOTE]
>
> This is a **stateless** MCP server for the Notion API with the following improvements:
> - **Stateless Architecture**: Complete request isolation with no session management
> - **Bearer Token Authentication**: Standard Authorization header support
> - **Fresh Instance Per Request**: Each request gets a new server instance
> - **Horizontal Scaling**: Stateless design enables easy load balancing
>
> Learn more about the official Notion MCP [here](https://developers.notion.com/docs/mcp)

This project implements an [MCP server](https://spec.modelcontextprotocol.io/) for the [Notion API](https://developers.notion.com/reference/intro).

### Installation
#### 1. Setting up Integration in Notion:
Go to [https://www.notion.so/profile/integrations](https://www.notion.so/profile/integrations) and create a new **internal** integration or select an existing one.

While we limit the scope of Notion API's exposed (for example, you will not be able to delete databases via MCP), there is a non-zero risk to workspace data by exposing it to LLMs. Security-conscious users may want to further configure the Integration's _Capabilities_.
For example, you can create a read-only integration token by giving only "Read content" access from the "Configuration" tab:

#### 2. Connecting content to integration:
Ensure relevant pages and databases are connected to your integration.
To do this, visit the **Access** tab in your internal integration settings. Edit access and select the pages you'd like to use.


Alternatively, you can grant page access individually. You'll need to visit the target page, and click on the 3 dots, and select "Connect to integration".

#### 3. Adding MCP config to your client:
##### Using npx (Recommended):
**Quick Start:**
Run directly without installation:
```bash
# STDIO mode (default)
npx /server-notion-mcp
# Stateless HTTP mode (recommended)
npx /server-notion-mcp --stateless
# Stateless HTTP mode with custom port
npx /server-notion-mcp --stateless --port 8080
```
**Cursor & Claude:**
Add the following to your `.cursor/mcp.json` or `claude_desktop_config.json` (MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`)
**Option 1: Using NOTION_TOKEN (recommended)**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "npx",
"args": ["-y", "@gongrzhe/server-notion-mcp"],
"env": {
"NOTION_TOKEN": "ntn_****"
}
}
}
}
```
**Option 2: Using OPENAPI_MCP_HEADERS (for advanced use cases)**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "npx",
"args": ["-y", "@gongrzhe/server-notion-mcp"],
"env": {
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer ntn_****\", \"Notion-Version\": \"2022-06-28\" }"
}
}
}
}
```
**Zed**
Add the following to your `settings.json`
```json
{
"context_servers": {
"some-context-server": {
"command": {
"path": "npx",
"args": ["-y", "@gongrzhe/server-notion-mcp"],
"env": {
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer ntn_****\", \"Notion-Version\": \"2022-06-28\" }"
}
},
"settings": {}
}
}
}
```
### Stateless Mode (Recommended)
The server now supports stateless architecture for better scalability, security, and operational simplicity.
#### Starting the Server in Stateless Mode
```bash
# Stateless mode (recommended)
npm run start:stateless
# Or manually with custom options
npx /server-notion-mcp --stateless --port 8080
# Development mode
npm run dev -- --stateless
```
#### Server Features in Stateless Mode
- **Complete Request Isolation**: Each request gets a fresh server instance
- **No Session Management**: No state stored between requests
- **Bearer Token Authentication**: Standard Authorization header support
- **Fresh Token Validation**: Each request validates tokens independently
- **Memory Efficient**: Automatic cleanup after each request
- **Horizontally Scalable**: Easy to load balance across multiple instances
#### API Reference
**Base URL**
```
http://localhost:30000/mcp
```
**Authentication**
All requests require a Bearer token in the Authorization header:
```
Authorization: Bearer <your_notion_token>
```
**Endpoints**
- **POST /mcp**: Main MCP endpoint for all operations
- Headers: `Content-Type: application/json`, `Authorization: Bearer <token>`
- Body: Standard MCP JSON-RPC request
- **GET /health**: Server health check (no authentication required)
- Returns server status, timestamp, and mode information
**Example Usage**
```bash
# Test tools listing
curl -X POST http://localhost:30000/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_notion_token" \
-d '{
"jsonrpc": "2.0",
"id": "test",
"method": "tools/list",
"params": {}
}'
# Test tool call
curl -X POST http://localhost:30000/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_notion_token" \
-d '{
"jsonrpc": "2.0",
"id": "test",
"method": "tools/call",
"params": {
"name": "search-database-simple",
"arguments": {"query": "test"}
}
}'
```
### Migration from Session-Aware Version
#### Breaking Changes
1. **Authentication**: Replace custom headers with `Authorization: Bearer <token>`
2. **Port**: Default port changed from 3000 to 30000 for stateless mode
3. **Session Management**: No longer supported (stateless mode only)
4. **Endpoints**: Only POST /mcp is supported for MCP operations
#### Migration Steps
1. Update client code to use Bearer tokens instead of custom session headers
2. Change default port in configurations from 3000 to 30000
3. Remove any session management code from clients
4. Update error handling for stateless responses (no session state persists)
### Legacy Multi-User Session-Aware Mode
The server still supports the legacy session-aware mode for backward compatibility:
```bash
# Legacy HTTP transport with multi-user support
npx /server-notion-mcp --transport http --multi-user --port 3000
```
However, **stateless mode is strongly recommended** for new deployments due to better scalability, security, and operational simplicity.
#### Client Connection
When connecting to the legacy multi-user server, clients must:
1. Provide the Notion token in the Authorization header: `Bearer ntn_****`
2. Use the `mcp-session-id` header to maintain session continuity
3. Connect to the `/mcp` endpoint using HTTP POST/GET methods
Example connection headers:
```
Authorization: Bearer ntn_your_notion_token_here
Content-Type: application/json
mcp-session-id: your-session-id (for subsequent requests)
```
#### Benefits
- **Scalability**: Support multiple users without token conflicts
- **Security**: Tokens are isolated per session, not shared globally
- **Flexibility**: Each user can have different Notion workspace access
- **Monitoring**: Real-time visibility into active sessions and usage
### Alternative Installation Methods
#### Global Installation
```bash
npm install -g /server-notion-mcp
# Then run with:
notion-mcp --transport http --multi-user
```
##### Using Docker:
There are two options for running the MCP server with Docker:
###### Option 1: Using the official Docker Hub image:
Add the following to your `.cursor/mcp.json` or `claude_desktop_config.json`:
**Using NOTION_TOKEN (recommended):**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e", "NOTION_TOKEN",
"mcp/notion"
],
"env": {
"NOTION_TOKEN": "ntn_****"
}
}
}
}
```
**Using OPENAPI_MCP_HEADERS (for advanced use cases):**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e", "OPENAPI_MCP_HEADERS",
"mcp/notion"
],
"env": {
"OPENAPI_MCP_HEADERS": "{\"Authorization\":\"Bearer ntn_****\",\"Notion-Version\":\"2022-06-28\"}"
}
}
}
}
```
This approach:
- Uses the official Docker Hub image
- Properly handles JSON escaping via environment variables
- Provides a more reliable configuration method
###### Option 2: Building the Docker image locally:
You can also build and run the Docker image locally. First, build the Docker image:
```bash
docker compose build
```
Then, add the following to your `.cursor/mcp.json` or `claude_desktop_config.json`:
**Using NOTION_TOKEN (recommended):**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"NOTION_TOKEN=ntn_****",
"notion-mcp-server"
]
}
}
}
```
**Using OPENAPI_MCP_HEADERS (for advanced use cases):**
```javascript
{
"mcpServers": {
"notionApi": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e",
"OPENAPI_MCP_HEADERS={\"Authorization\": \"Bearer ntn_****\", \"Notion-Version\": \"2022-06-28\"}",
"notion-mcp-server"
]
}
}
}
```
Don't forget to replace `ntn_****` with your integration secret. Find it from your integration configuration tab:

#### Installing via Smithery
[](https://smithery.ai/server/@makenotion/notion-mcp-server)
To install Notion API Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@makenotion/notion-mcp-server):
```bash
npx -y /cli install @makenotion/notion-mcp-server --client claude
```
### Transport Options
The Notion MCP Server supports two transport modes:
#### STDIO Transport (Default)
The default transport mode uses standard input/output for communication. This is the standard MCP transport used by most clients like Claude Desktop.
```bash
# Run with default stdio transport
npx /notion-mcp-server
# Or explicitly specify stdio
npx /notion-mcp-server --transport stdio
```
#### Streamable HTTP Transport
For web-based applications or clients that prefer HTTP communication, you can use the Streamable HTTP transport:
```bash
# Run with Streamable HTTP transport on port 3000 (default)
npx /notion-mcp-server --transport http
# Run on a custom port
npx /notion-mcp-server --transport http --port 8080
# Run with a custom authentication token
npx /notion-mcp-server --transport http --auth-token "your-secret-token"
```
When using Streamable HTTP transport, the server will be available at `http://0.0.0.0:<port>/mcp`.
##### Authentication
The Streamable HTTP transport requires bearer token authentication for security. You have three options:
**Option 1: Auto-generated token (recommended for development)**
```bash
npx /notion-mcp-server --transport http
```
The server will generate a secure random token and display it in the console:
```
Generated auth token: a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789ab
Use this token in the Authorization header: Bearer a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789ab
```
**Option 2: Custom token via command line (recommended for production)**
```bash
npx /notion-mcp-server --transport http --auth-token "your-secret-token"
```
**Option 3: Custom token via environment variable (recommended for production)**
```bash
AUTH_TOKEN="your-secret-token" npx /notion-mcp-server --transport http
```
The command line argument `--auth-token` takes precedence over the `AUTH_TOKEN` environment variable if both are provided.
##### Making HTTP Requests
All requests to the Streamable HTTP transport must include the bearer token in the Authorization header:
```bash
# Example request
curl -H "Authorization: Bearer your-token-here" \
-H "Content-Type: application/json" \
-H "mcp-session-id: your-session-id" \
-d '{"jsonrpc": "2.0", "method": "initialize", "params": {}, "id": 1}' \
http://localhost:3000/mcp
```
**Note:** Make sure to set either the `NOTION_TOKEN` environment variable (recommended) or the `OPENAPI_MCP_HEADERS` environment variable with your Notion integration token when using either transport mode.
### Examples
1. Using the following instruction
```
Comment "Hello MCP" on page "Getting started"
```
AI will correctly plan two API calls, `v1/search` and `v1/comments`, to achieve the task
2. Similarly, the following instruction will result in a new page named "Notion MCP" added to parent page "Development"
```
Add a page titled "Notion MCP" to page "Development"
```
3. You may also reference content ID directly
```
Get the content of page 1a6b35e6e67f802fa7e1d27686f017f2
```
### Development
Build
```
npm run build
```
Execute
```
npx -y --prefix /path/to/local/notion-mcp-server /notion-mcp-server
```
Publish
```
npm publish --access public
```