#
tokens: 3581/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── mcp_instructions.md
├── notion_mcp_server.py
├── README.md
└── requirements.txt
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | .env
2 | *.env
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Notion Knowledge Base MCP Server
  2 | 
  3 | An MCP server that provides access to a Notion knowledge base through the Cline VSCode extension.
  4 | 
  5 | ## Features
  6 | 
  7 | - Query your Notion knowledge base directly from Cline
  8 | - Get detailed answers with references to Notion pages
  9 | - Built with FastMCP for reliable performance
 10 | - Comprehensive error handling and logging
 11 | 
 12 | ## Prerequisites
 13 | 
 14 | - Python 3.10 or higher
 15 | - [uv](https://github.com/astral-sh/uv) package manager
 16 | - [Cline VSCode extension](https://marketplace.visualstudio.com/items?itemName=saoudrizwan.claude-dev)
 17 | - A Dify API key for accessing the Notion knowledge base
 18 | 
 19 | ## Installation
 20 | 
 21 | 1. Clone this repository:
 22 |    ```bash
 23 |    git clone https://github.com/yourusername/notion-mcp-server.git
 24 |    cd notion-mcp-server
 25 |    ```
 26 | 
 27 | 2. Create a `.env` file with your Dify API key:
 28 |    ```bash
 29 |    echo "DIFY_API_BACKEND_KEY=your-api-key-here" > .env
 30 |    ```
 31 | 
 32 | 3. Install the server in Cline:
 33 |    ```bash
 34 |    fastmcp install notion_mcp_server.py
 35 |    ```
 36 | 
 37 |    This will automatically:
 38 |    - Install all required dependencies using uv
 39 |    - Configure the server in Cline's settings
 40 |    - Make the server available to use with Cline
 41 | 
 42 | ## Usage
 43 | 
 44 | Once installed, you can use the server in Cline by asking questions about your Notion knowledge base. For example:
 45 | 
 46 | ```
 47 | Tell me about internal tooling
 48 | ```
 49 | 
 50 | The server will respond with relevant information from your Notion knowledge base, including:
 51 | - Detailed answers
 52 | - Links to relevant Notion pages
 53 | - Page IDs for reference
 54 | 
 55 | ## Configuration
 56 | 
 57 | The server is configured automatically during installation, but you can manually update the settings in Cline's configuration file if needed:
 58 | 
 59 | - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
 60 | - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
 61 | 
 62 | Example configuration:
 63 | ```json
 64 | {
 65 |   "mcpServers": {
 66 |     "notion-kb": {
 67 |       "command": "uv",
 68 |       "args": [
 69 |         "run",
 70 |         "--with", "fastmcp",
 71 |         "--with", "python-dotenv",
 72 |         "--with", "requests",
 73 |         "fastmcp",
 74 |         "run",
 75 |         "/absolute/path/to/notion_mcp_server.py"
 76 |       ],
 77 |       "env": {
 78 |         "DIFY_API_BACKEND_KEY": "your-api-key"
 79 |       }
 80 |     }
 81 |   }
 82 | }
 83 | ```
 84 | 
 85 | ## Development
 86 | 
 87 | For development and testing:
 88 | 
 89 | 1. Install dependencies:
 90 |    ```bash
 91 |    pip install -r requirements.txt
 92 |    ```
 93 | 
 94 | 2. Run the development server:
 95 |    ```bash
 96 |    fastmcp dev notion_mcp_server.py
 97 |    ```
 98 | 
 99 | This will start the MCP Inspector interface for testing the server.
100 | 
101 | ## Troubleshooting
102 | 
103 | 1. **Server not connecting**
104 |    - Verify your API key in the `.env` file
105 |    - Ensure the server path in Cline's config is absolute
106 |    - Check that uv is installed and in your PATH
107 | 
108 | 2. **Dependencies issues**
109 |    - Try reinstalling with `fastmcp install notion_mcp_server.py --force`
110 |    - Verify uv is installed correctly
111 | 
112 | 3. **Server hangs**
113 |    - Ensure you're using the uv run command as specified in the config
114 |    - Check the server logs for errors
115 | 
116 | ## Contributing
117 | 
118 | See [mcp_instructions.md](mcp_instructions.md) for detailed information about the server's implementation and architecture.
119 | 
120 | ## License
121 | 
122 | MIT
123 | 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | fastmcp==0.4.1
2 | python-dotenv
3 | requests
4 | 
```

--------------------------------------------------------------------------------
/notion_mcp_server.py:
--------------------------------------------------------------------------------

```python
 1 | #!/usr/bin/env python3
 2 | import os
 3 | import json
 4 | import requests
 5 | from dotenv import load_dotenv
 6 | from fastmcp import FastMCP, Context
 7 | from typing import Dict, Any
 8 | from pydantic import BaseModel, Field
 9 | 
10 | # Initialize FastMCP server
11 | mcp = FastMCP(
12 |     name="Notion Knowledge Base",
13 |     description="MCP server for querying a Notion knowledge base",
14 |     version="0.1.0",
15 |     dependencies=["python-dotenv", "requests"]
16 | )
17 | 
18 | # Load environment variables
19 | load_dotenv()
20 | 
21 | # Get API key from environment
22 | API_KEY = os.getenv('DIFY_API_BACKEND_KEY')
23 | if not API_KEY:
24 |     raise ValueError("DIFY_API_BACKEND_KEY environment variable not set")
25 | 
26 | class NotionResponse(BaseModel):
27 |     """Structure for Notion API responses."""
28 |     answer: str = Field(default="")
29 |     notion_page_url: str = Field(default="")
30 |     notion_page_id: str = Field(default="")
31 | 
32 |     @classmethod
33 |     def from_api_response(cls, data: Dict[str, Any]) -> "NotionResponse":
34 |         """Create a NotionResponse from API response data."""
35 |         outputs = data.get('data', {}).get('outputs', {})
36 |         return cls(
37 |             answer=outputs.get('answer', ''),
38 |             notion_page_url=outputs.get('notion_page_url', ''),
39 |             notion_page_id=outputs.get('notion_page_id', '')
40 |         )
41 | 
42 | @mcp.tool()
43 | def ask_notion_question(question: str, ctx: Context) -> Dict[str, Any]:
44 |     """Ask a question about the Notion knowledge base.
45 |     
46 |     Args:
47 |         question: The question to ask about the Notion knowledge base
48 |         ctx: MCP context for logging and progress tracking
49 |         
50 |     Returns:
51 |         Dictionary containing the answer and related Notion page information
52 |         
53 |     Raises:
54 |         ValueError: If the API key is not set or if the request fails
55 |     """
56 |     ctx.info(f"Processing question: {question}")
57 |     
58 |     try:
59 |         url = "https://dify.rickydata.com/v1/workflows/run"
60 |         headers = {
61 |             'Authorization': f"Bearer {API_KEY}",
62 |             'Content-Type': 'application/json'
63 |         }
64 |         payload = {
65 |             'inputs': {'question': question},
66 |             'response_mode': 'blocking',
67 |             'user': 'curation_agent_python'
68 |         }
69 |         
70 |         ctx.debug("Sending request to Notion API")
71 |         response = requests.post(url, headers=headers, json=payload)
72 |         response.raise_for_status()
73 |         
74 |         data = response.json()
75 |         if not data.get('data', {}).get('outputs', {}):
76 |             raise ValueError("Invalid response format from API")
77 |         
78 |         result = NotionResponse.from_api_response(data)
79 |         ctx.debug("Successfully received response from Notion API")
80 |         
81 |         return result.model_dump()
82 |         
83 |     except requests.RequestException as e:
84 |         error_msg = f"API request failed: {str(e)}"
85 |         ctx.error(error_msg)
86 |         raise ValueError(error_msg)
87 |     except json.JSONDecodeError as e:
88 |         error_msg = f"Invalid JSON response: {str(e)}"
89 |         ctx.error(error_msg)
90 |         raise ValueError(error_msg)
91 |     except Exception as e:
92 |         error_msg = f"Unexpected error: {str(e)}"
93 |         ctx.error(error_msg)
94 |         raise ValueError(error_msg)
95 | 
96 | if __name__ == "__main__":
97 |     mcp.run()
98 | 
```

--------------------------------------------------------------------------------
/mcp_instructions.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Building a Notion Knowledge Base MCP Server
  2 | 
  3 | This guide walks through the process of creating an MCP server that interfaces with a Notion knowledge base via the Dify API.
  4 | 
  5 | ## Starting Point
  6 | 
  7 | We began with a Python example that demonstrated how to query the Dify API:
  8 | 
  9 | ```python
 10 | def pull_dify_api_result_with_input(input_example="input_example"):
 11 |     load_dotenv()
 12 |     url = "https://dify.rickydata.com/v1/workflows/run"
 13 |     headers = {
 14 |         'Authorization': f"Bearer {os.getenv('DIFY_API_BACKEND_KEY')}",
 15 |         'Content-Type': 'application/json'
 16 |     }
 17 |     payload = {
 18 |         'inputs': {
 19 |             'input_example': input_example
 20 |         },
 21 |         'response_mode': 'blocking',
 22 |         'user': 'curation_agent_python'
 23 |     }
 24 |     
 25 |     response = requests.post(url, headers=headers, json=payload)
 26 |     response_data = response.json()
 27 |     
 28 |     if response_data.get('data', {}).get('outputs', {}):
 29 |         return response_data['data']['outputs']
 30 |     return response_data
 31 | ```
 32 | 
 33 | ## Implementation Steps
 34 | 
 35 | ### 1. Project Setup
 36 | 1. Create a new directory for the MCP server:
 37 |    ```bash
 38 |    mkdir notion_mcp_server
 39 |    cd notion_mcp_server
 40 |    ```
 41 | 
 42 | 2. Create initial files:
 43 |    - `.env` for API key
 44 |    - `requirements.txt` for dependencies
 45 |    - `notion_mcp_server.py` for server implementation
 46 | 
 47 | ### 2. Dependencies
 48 | Set up required dependencies in `requirements.txt`:
 49 | ```
 50 | fastmcp==0.4.1
 51 | python-dotenv
 52 | requests
 53 | ```
 54 | 
 55 | ### 3. Server Implementation
 56 | 1. Create a FastMCP server with proper configuration:
 57 |    ```python
 58 |    mcp = FastMCP(
 59 |        name="Notion Knowledge Base",
 60 |        description="MCP server for querying a Notion knowledge base",
 61 |        version="0.1.0",
 62 |        dependencies=["python-dotenv", "requests"]
 63 |    )
 64 |    ```
 65 | 
 66 | 2. Define data models using Pydantic:
 67 |    ```python
 68 |    class NotionResponse(BaseModel):
 69 |        answer: str = Field(default="")
 70 |        notion_page_url: str = Field(default="")
 71 |        notion_page_id: str = Field(default="")
 72 |    ```
 73 | 
 74 | 3. Implement the question-asking tool:
 75 |    ```python
 76 |    @mcp.tool()
 77 |    def ask_notion_question(question: str, ctx: Context) -> Dict[str, Any]:
 78 |        """Ask a question about the Notion knowledge base."""
 79 |        # Implementation details...
 80 |    ```
 81 | 
 82 | ### 4. Error Handling and Logging
 83 | Add comprehensive error handling and logging:
 84 | ```python
 85 | try:
 86 |     response = requests.post(url, headers=headers, json=payload)
 87 |     response.raise_for_status()
 88 | except requests.RequestException as e:
 89 |     error_msg = f"API request failed: {str(e)}"
 90 |     ctx.error(error_msg)
 91 |     raise ValueError(error_msg)
 92 | ```
 93 | 
 94 | ### 5. Testing
 95 | 1. Test the basic Python implementation:
 96 |    ```bash
 97 |    python3 notion_api.py
 98 |    ```
 99 | 
100 | 2. Test the MCP server:
101 |    ```bash
102 |    fastmcp dev notion_mcp_server.py
103 |    ```
104 | 
105 | ### 6. Integration with Cline
106 | 1. Install the server in Cline:
107 |    ```bash
108 |    fastmcp install notion_mcp_server.py
109 |    ```
110 | 
111 | 2. Configure the server in Cline's settings:
112 |    ```json
113 |    {
114 |      "mcpServers": {
115 |        "notion-kb": {
116 |          "command": "uv",
117 |          "args": [
118 |            "run",
119 |            "--with", "fastmcp",
120 |            "--with", "python-dotenv",
121 |            "--with", "requests",
122 |            "fastmcp",
123 |            "run",
124 |            "/path/to/notion_mcp_server.py"
125 |          ],
126 |          "env": {
127 |            "DIFY_API_BACKEND_KEY": "your-api-key"
128 |          }
129 |        }
130 |      }
131 |    }
132 |    ```
133 | 
134 | ## Key Learnings
135 | 
136 | 1. **Synchronous vs Async**: Keep the implementation synchronous for simplicity and reliability.
137 | 2. **Proper Dependencies**: Use `uv run` with explicit dependencies for better isolation.
138 | 3. **Error Handling**: Implement comprehensive error handling and logging.
139 | 4. **Configuration**: Use environment variables for sensitive data.
140 | 5. **Testing**: Test thoroughly at each step of implementation.
141 | 
142 | ## Troubleshooting
143 | 
144 | 1. If the server hangs, ensure you're using `uv run` instead of `python3` directly.
145 | 2. If connection fails, verify the API key is properly set in environment variables.
146 | 3. For "Not connected" errors, ensure the server is properly configured in Cline settings.
147 | 
```