Feat: Add Notion MCP Usecase (#494)

This commit is contained in:
Xiaotian Jin 2025-04-21 13:17:15 +03:00 committed by GitHub
commit 58102ac75b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 243 additions and 0 deletions

View File

@ -0,0 +1,95 @@
# Notion Integration with OWL
This project demonstrates the integration of Notion with OWL (Optimized Workforce Learning) using the official Notion MCP server. It provides automated interaction with Notion workspaces through AI agents.
## Prerequisites
- Python >=3.10,<3.13
- Node.js and npm
- CAMEL framework installed
- A Notion account and integration
## Installation
#### 1. Clone this repository:
```sh
git clone https://github.com/camel-ai/owl.git
cd owl
```
#### 2. Install dependencies:
```sh
pip install -r requirements.txt
```
#### 3. Set up environment variables:
- Create a `.env` file and add your API keys/configuration as needed.
## Setup
#### 1. Install the required Node.js package:
```bash
npm install -g @notionhq/notion-mcp-server@latest
```
#### 2. Set up your Notion integration:
- Go to https://www.notion.so/profile/integrations
- Create a new integration
- Copy the integration token
- Update `mcp_servers_config.json` with your token
#### 3. Connect your Notion pages:
- Open each Notion page you want to work with
- Click "..." (three dots) in the top right
- Select "Add connections"
- Choose your integration
#### 4. Visit official Notion MCP GitHub Repository
Visit the [Notion_MCP GitHub Repo](https://github.com/makenotion/notion-mcp-server) for detailed setup instructions.
## Usage
Navigate to the community use case directory before running the script:
```sh
cd community_usecase/Notion_MCP
```
#### Run the script using:
```bash
python notion_manager.py
```
This will run the default task which:
- Searches for a specific page
- Updates its properties
- Adds a comment
## Supported Operations
The integration supports these Notion API operations:
- Searching for pages
- Reading page content
- Updating page properties
- Adding comments
- Creating new pages
- Retrieving database content
## Troubleshooting
If you encounter errors:
1. Verify your Notion token is correct
2. Check that pages are connected to your integration
3. Ensure you have the required permissions
4. Check the Notion API version in config matches the current version
## Error Handling
The script includes:
- Graceful connection handling
- Task execution error catching
- Proper cleanup on exit
- Windows-specific asyncio handling
## Repository
For more details, visit the OWL repository: [OWL GitHub Repo](https://github.com/camel-ai/owl)

View File

@ -0,0 +1,11 @@
{
"mcpServers": {
"notionApi": {
"command": "npx",
"args": ["-y", "@notionhq/notion-mcp-server"],
"env": {
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer ntn_****\", \"Notion-Version\": \"2022-06-28\" }"
}
}
}
}

View File

@ -0,0 +1,137 @@
import os
import asyncio
import sys
from pathlib import Path
from typing import List
from dotenv import load_dotenv
from camel.models import ModelFactory
from camel.toolkits import FunctionTool, MCPToolkit
from camel.types import ModelPlatformType, ModelType
from camel.logger import get_logger, set_log_file
from owl.utils.enhanced_role_playing import OwlRolePlaying, arun_society
# Set logging level
set_log_file("notion_mcp.log")
logger = get_logger(__name__)
# Load environment variables
load_dotenv(os.path.join(os.path.dirname(__file__), '../../owl/.env'))
async def construct_society(
question: str,
tools: List[FunctionTool],
) -> OwlRolePlaying:
"""Build a multi-agent OwlRolePlaying instance for Notion management."""
models = {
"user": ModelFactory.create(
model_platform=ModelPlatformType.OPENAI,
model_type=ModelType.GPT_4O,
model_config_dict={
"temperature": 0.7,
},
),
"assistant": ModelFactory.create(
model_platform=ModelPlatformType.OPENAI,
model_type=ModelType.GPT_4O,
model_config_dict={
"temperature": 0.7,
},
),
}
user_agent_kwargs = {"model": models["user"]}
assistant_agent_kwargs = {
"model": models["assistant"],
"tools": tools,
}
task_kwargs = {
"task_prompt": question,
"with_task_specify": False,
}
return OwlRolePlaying(
**task_kwargs,
user_role_name="notion_manager",
user_agent_kwargs=user_agent_kwargs,
assistant_role_name="notion_assistant",
assistant_agent_kwargs=assistant_agent_kwargs,
)
async def execute_notion_task(society: OwlRolePlaying):
"""Execute the Notion task and handle the result."""
try:
result = await arun_society(society)
if isinstance(result, tuple) and len(result) == 3:
answer, chat_history, token_count = result
logger.info(f"\nTask Result: {answer}")
logger.info(f"Token count: {token_count}")
else:
logger.info(f"\nTask Result: {result}")
except Exception as e:
logger.info(f"\nError during task execution: {str(e)}")
raise
async def main():
config_path = Path(__file__).parent / "mcp_servers_config.json"
mcp_toolkit = MCPToolkit(config_path=str(config_path))
try:
logger.info("Connecting to Notion MCP server...")
await mcp_toolkit.connect()
logger.info("Successfully connected to Notion MCP server")
default_task = (
"Notion Task:\n"
"1. Find the page titled 'Travel Itinerary\n"
"2. Create a list of Top 10 travel destinations in Europe and add them to the page along with their description.\n"
"3. Also mention the best time to visit these destintions.\n"
)
task = sys.argv[1] if len(sys.argv) > 1 else default_task
logger.info(f"\nExecuting task:\n{task}")
tools = [*mcp_toolkit.get_tools()]
society = await construct_society(task, tools)
await execute_notion_task(society)
except Exception as e:
logger.info(f"\nError: {str(e)}")
raise
finally:
logger.info("\nPerforming cleanup...")
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
for task in tasks:
task.cancel()
try:
await task
except asyncio.CancelledError:
pass
try:
await mcp_toolkit.disconnect()
logger.info("Successfully disconnected from Notion MCP server")
except Exception as e:
logger.info(f"Cleanup error (can be ignored): {e}")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("\nReceived keyboard interrupt. Shutting down gracefully...")
finally:
if sys.platform == 'win32':
try:
import asyncio.windows_events
asyncio.windows_events._overlapped = None
except (ImportError, AttributeError):
pass