# Directory Structure
```
├── .gitignore
├── mcp_instructions.md
├── notion_mcp_server.py
├── README.md
└── requirements.txt
```
# Files
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
.env
*.env
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# Notion Knowledge Base MCP Server
An MCP server that provides access to a Notion knowledge base through the Cline VSCode extension.
## Features
- Query your Notion knowledge base directly from Cline
- Get detailed answers with references to Notion pages
- Built with FastMCP for reliable performance
- Comprehensive error handling and logging
## Prerequisites
- Python 3.10 or higher
- [uv](https://github.com/astral-sh/uv) package manager
- [Cline VSCode extension](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev)
- A Dify API key for accessing the Notion knowledge base
## Installation
1. Clone this repository:
```bash
git clone https://github.com/yourusername/notion-mcp-server.git
cd notion-mcp-server
```
2. Create a `.env` file with your Dify API key:
```bash
echo "DIFY_API_BACKEND_KEY=your-api-key-here" > .env
```
3. Install the server in Cline:
```bash
fastmcp install notion_mcp_server.py
```
This will automatically:
- Install all required dependencies using uv
- Configure the server in Cline's settings
- Make the server available to use with Cline
## Usage
Once installed, you can use the server in Cline by asking questions about your Notion knowledge base. For example:
```
Tell me about internal tooling
```
The server will respond with relevant information from your Notion knowledge base, including:
- Detailed answers
- Links to relevant Notion pages
- Page IDs for reference
## Configuration
The server is configured automatically during installation, but you can manually update the settings in Cline's configuration file if needed:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
Example configuration:
```json
{
"mcpServers": {
"notion-kb": {
"command": "uv",
"args": [
"run",
"--with", "fastmcp",
"--with", "python-dotenv",
"--with", "requests",
"fastmcp",
"run",
"/absolute/path/to/notion_mcp_server.py"
],
"env": {
"DIFY_API_BACKEND_KEY": "your-api-key"
}
}
}
}
```
## Development
For development and testing:
1. Install dependencies:
```bash
pip install -r requirements.txt
```
2. Run the development server:
```bash
fastmcp dev notion_mcp_server.py
```
This will start the MCP Inspector interface for testing the server.
## Troubleshooting
1. **Server not connecting**
- Verify your API key in the `.env` file
- Ensure the server path in Cline's config is absolute
- Check that uv is installed and in your PATH
2. **Dependencies issues**
- Try reinstalling with `fastmcp install notion_mcp_server.py --force`
- Verify uv is installed correctly
3. **Server hangs**
- Ensure you're using the uv run command as specified in the config
- Check the server logs for errors
## Contributing
See [mcp_instructions.md](mcp_instructions.md) for detailed information about the server's implementation and architecture.
## License
MIT
```
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
```
fastmcp==0.4.1
python-dotenv
requests
```
--------------------------------------------------------------------------------
/notion_mcp_server.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
import os
import json
import requests
from dotenv import load_dotenv
from fastmcp import FastMCP, Context
from typing import Dict, Any
from pydantic import BaseModel, Field
# Initialize FastMCP server
mcp = FastMCP(
name="Notion Knowledge Base",
description="MCP server for querying a Notion knowledge base",
version="0.1.0",
dependencies=["python-dotenv", "requests"]
)
# Load environment variables
load_dotenv()
# Get API key from environment
API_KEY = os.getenv('DIFY_API_BACKEND_KEY')
if not API_KEY:
raise ValueError("DIFY_API_BACKEND_KEY environment variable not set")
class NotionResponse(BaseModel):
"""Structure for Notion API responses."""
answer: str = Field(default="")
notion_page_url: str = Field(default="")
notion_page_id: str = Field(default="")
@classmethod
def from_api_response(cls, data: Dict[str, Any]) -> "NotionResponse":
"""Create a NotionResponse from API response data."""
outputs = data.get('data', {}).get('outputs', {})
return cls(
answer=outputs.get('answer', ''),
notion_page_url=outputs.get('notion_page_url', ''),
notion_page_id=outputs.get('notion_page_id', '')
)
@mcp.tool()
def ask_notion_question(question: str, ctx: Context) -> Dict[str, Any]:
"""Ask a question about the Notion knowledge base.
Args:
question: The question to ask about the Notion knowledge base
ctx: MCP context for logging and progress tracking
Returns:
Dictionary containing the answer and related Notion page information
Raises:
ValueError: If the API key is not set or if the request fails
"""
ctx.info(f"Processing question: {question}")
try:
url = "https://dify.rickydata.com/v1/workflows/run"
headers = {
'Authorization': f"Bearer {API_KEY}",
'Content-Type': 'application/json'
}
payload = {
'inputs': {'question': question},
'response_mode': 'blocking',
'user': 'curation_agent_python'
}
ctx.debug("Sending request to Notion API")
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
if not data.get('data', {}).get('outputs', {}):
raise ValueError("Invalid response format from API")
result = NotionResponse.from_api_response(data)
ctx.debug("Successfully received response from Notion API")
return result.model_dump()
except requests.RequestException as e:
error_msg = f"API request failed: {str(e)}"
ctx.error(error_msg)
raise ValueError(error_msg)
except json.JSONDecodeError as e:
error_msg = f"Invalid JSON response: {str(e)}"
ctx.error(error_msg)
raise ValueError(error_msg)
except Exception as e:
error_msg = f"Unexpected error: {str(e)}"
ctx.error(error_msg)
raise ValueError(error_msg)
if __name__ == "__main__":
mcp.run()
```
--------------------------------------------------------------------------------
/mcp_instructions.md:
--------------------------------------------------------------------------------
```markdown
# Building a Notion Knowledge Base MCP Server
This guide walks through the process of creating an MCP server that interfaces with a Notion knowledge base via the Dify API.
## Starting Point
We began with a Python example that demonstrated how to query the Dify API:
```python
def pull_dify_api_result_with_input(input_example="input_example"):
load_dotenv()
url = "https://dify.rickydata.com/v1/workflows/run"
headers = {
'Authorization': f"Bearer {os.getenv('DIFY_API_BACKEND_KEY')}",
'Content-Type': 'application/json'
}
payload = {
'inputs': {
'input_example': input_example
},
'response_mode': 'blocking',
'user': 'curation_agent_python'
}
response = requests.post(url, headers=headers, json=payload)
response_data = response.json()
if response_data.get('data', {}).get('outputs', {}):
return response_data['data']['outputs']
return response_data
```
## Implementation Steps
### 1. Project Setup
1. Create a new directory for the MCP server:
```bash
mkdir notion_mcp_server
cd notion_mcp_server
```
2. Create initial files:
- `.env` for API key
- `requirements.txt` for dependencies
- `notion_mcp_server.py` for server implementation
### 2. Dependencies
Set up required dependencies in `requirements.txt`:
```
fastmcp==0.4.1
python-dotenv
requests
```
### 3. Server Implementation
1. Create a FastMCP server with proper configuration:
```python
mcp = FastMCP(
name="Notion Knowledge Base",
description="MCP server for querying a Notion knowledge base",
version="0.1.0",
dependencies=["python-dotenv", "requests"]
)
```
2. Define data models using Pydantic:
```python
class NotionResponse(BaseModel):
answer: str = Field(default="")
notion_page_url: str = Field(default="")
notion_page_id: str = Field(default="")
```
3. Implement the question-asking tool:
```python
@mcp.tool()
def ask_notion_question(question: str, ctx: Context) -> Dict[str, Any]:
"""Ask a question about the Notion knowledge base."""
# Implementation details...
```
### 4. Error Handling and Logging
Add comprehensive error handling and logging:
```python
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
except requests.RequestException as e:
error_msg = f"API request failed: {str(e)}"
ctx.error(error_msg)
raise ValueError(error_msg)
```
### 5. Testing
1. Test the basic Python implementation:
```bash
python3 notion_api.py
```
2. Test the MCP server:
```bash
fastmcp dev notion_mcp_server.py
```
### 6. Integration with Cline
1. Install the server in Cline:
```bash
fastmcp install notion_mcp_server.py
```
2. Configure the server in Cline's settings:
```json
{
"mcpServers": {
"notion-kb": {
"command": "uv",
"args": [
"run",
"--with", "fastmcp",
"--with", "python-dotenv",
"--with", "requests",
"fastmcp",
"run",
"/path/to/notion_mcp_server.py"
],
"env": {
"DIFY_API_BACKEND_KEY": "your-api-key"
}
}
}
}
```
## Key Learnings
1. **Synchronous vs Async**: Keep the implementation synchronous for simplicity and reliability.
2. **Proper Dependencies**: Use `uv run` with explicit dependencies for better isolation.
3. **Error Handling**: Implement comprehensive error handling and logging.
4. **Configuration**: Use environment variables for sensitive data.
5. **Testing**: Test thoroughly at each step of implementation.
## Troubleshooting
1. If the server hangs, ensure you're using `uv run` instead of `python3` directly.
2. If connection fails, verify the API key is properly set in environment variables.
3. For "Not connected" errors, ensure the server is properly configured in Cline settings.
```