MCPilot / src /simulators /notion.py
girish-hari's picture
checking-in the project source code
2358888
"""
Notion API simulator.
Provides realistic mock responses for Notion API actions.
"""
from typing import Optional
from .base import BaseSimulator
from datetime import datetime
import uuid
class NotionSimulator(BaseSimulator):
"""Simulator for Notion API."""
def __init__(self):
super().__init__('notion')
def load_mock_responses(self):
"""Load Notion mock response templates."""
self.mock_responses = {
'create_page': self._create_page_template,
'read_database': self._read_database_template,
'update_page': self._update_page_template,
'get_page': self._get_page_template,
'query_database': self._query_database_template,
'create_database': self._create_database_template,
}
def get_required_permissions(self, action: str) -> set[str]:
"""Get required Notion permissions for an action."""
permissions_map = {
'create_page': {'pages:write'},
'read_database': {'databases:read'},
'update_page': {'pages:write'},
'get_page': {'pages:read'},
'query_database': {'databases:read'},
'create_database': {'databases:write'},
}
return permissions_map.get(action, set())
def validate_params(self, action: str, params: dict) -> tuple[bool, Optional[str]]:
"""Validate parameters for Notion actions."""
if action == 'create_page':
required = {'parent'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
if 'database_id' not in params['parent'] and 'page_id' not in params['parent']:
return False, "Parent must contain either database_id or page_id"
elif action == 'read_database':
required = {'database_id'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
elif action == 'update_page':
required = {'page_id'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
elif action == 'get_page':
required = {'page_id'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
elif action == 'query_database':
required = {'database_id'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
elif action == 'create_database':
required = {'parent', 'title', 'properties'}
missing = required - set(params.keys())
if missing:
return False, f"Missing required parameters: {missing}"
else:
return False, f"Unknown action: {action}"
return True, None
def generate_mock_response(self, action: str, params: dict) -> dict:
"""Generate realistic Notion API response."""
if action not in self.mock_responses:
raise ValueError(f"Unknown action: {action}")
template_func = self.mock_responses[action]
return template_func(params)
def _generate_id(self) -> str:
"""Generate a Notion-style UUID."""
return str(uuid.uuid4())
def _create_page_template(self, params: dict) -> dict:
"""Mock response for creating a page."""
page_id = self._generate_id()
now = datetime.utcnow().isoformat() + "Z"
return {
"object": "page",
"id": page_id,
"created_time": now,
"last_edited_time": now,
"created_by": {
"object": "user",
"id": self._generate_id()
},
"last_edited_by": {
"object": "user",
"id": self._generate_id()
},
"cover": params.get('cover'),
"icon": params.get('icon'),
"parent": params['parent'],
"archived": False,
"properties": params.get('properties', {
"title": {
"id": "title",
"type": "title",
"title": [
{
"type": "text",
"text": {
"content": "New Page",
"link": None
}
}
]
}
}),
"url": f"https://www.notion.so/{page_id.replace('-', '')}"
}
def _read_database_template(self, params: dict) -> dict:
"""Mock response for reading a database."""
database_id = params['database_id']
return {
"object": "database",
"id": database_id,
"created_time": "2025-11-01T00:00:00.000Z",
"last_edited_time": datetime.utcnow().isoformat() + "Z",
"title": [
{
"type": "text",
"text": {
"content": "Tasks Database"
}
}
],
"properties": {
"Name": {
"id": "title",
"name": "Name",
"type": "title",
"title": {}
},
"Status": {
"id": "status",
"name": "Status",
"type": "select",
"select": {
"options": [
{"name": "Not started", "color": "default"},
{"name": "In progress", "color": "blue"},
{"name": "Done", "color": "green"}
]
}
},
"Priority": {
"id": "priority",
"name": "Priority",
"type": "select",
"select": {
"options": [
{"name": "High", "color": "red"},
{"name": "Medium", "color": "yellow"},
{"name": "Low", "color": "gray"}
]
}
},
"Due Date": {
"id": "due",
"name": "Due Date",
"type": "date",
"date": {}
}
},
"url": f"https://www.notion.so/{database_id.replace('-', '')}"
}
def _update_page_template(self, params: dict) -> dict:
"""Mock response for updating a page."""
page_id = params['page_id']
return {
"object": "page",
"id": page_id,
"created_time": "2025-11-15T10:00:00.000Z",
"last_edited_time": datetime.utcnow().isoformat() + "Z",
"archived": params.get('archived', False),
"properties": params.get('properties', {}),
"url": f"https://www.notion.so/{page_id.replace('-', '')}"
}
def _get_page_template(self, params: dict) -> dict:
"""Mock response for getting a page."""
page_id = params['page_id']
return {
"object": "page",
"id": page_id,
"created_time": "2025-11-15T10:00:00.000Z",
"last_edited_time": "2025-11-25T14:30:00.000Z",
"created_by": {
"object": "user",
"id": self._generate_id()
},
"last_edited_by": {
"object": "user",
"id": self._generate_id()
},
"cover": None,
"icon": {
"type": "emoji",
"emoji": "📝"
},
"parent": {
"type": "database_id",
"database_id": self._generate_id()
},
"archived": False,
"properties": {
"Name": {
"id": "title",
"type": "title",
"title": [
{
"type": "text",
"text": {
"content": "Sample Task"
}
}
]
},
"Status": {
"id": "status",
"type": "select",
"select": {
"name": "In progress",
"color": "blue"
}
},
"Priority": {
"id": "priority",
"type": "select",
"select": {
"name": "High",
"color": "red"
}
}
},
"url": f"https://www.notion.so/{page_id.replace('-', '')}"
}
def _query_database_template(self, params: dict) -> dict:
"""Mock response for querying a database."""
# Return a few sample pages
pages = []
for i in range(3):
page_id = self._generate_id()
pages.append({
"object": "page",
"id": page_id,
"created_time": f"2025-11-{20+i}T10:00:00.000Z",
"last_edited_time": datetime.utcnow().isoformat() + "Z",
"properties": {
"Name": {
"id": "title",
"type": "title",
"title": [
{
"type": "text",
"text": {"content": f"Task {i+1}"}
}
]
},
"Status": {
"id": "status",
"type": "select",
"select": {
"name": ["In progress", "Done", "Not started"][i],
"color": ["blue", "green", "default"][i]
}
}
},
"url": f"https://www.notion.so/{page_id.replace('-', '')}"
})
return {
"object": "list",
"results": pages,
"next_cursor": None,
"has_more": False
}
def _create_database_template(self, params: dict) -> dict:
"""Mock response for creating a database."""
database_id = self._generate_id()
now = datetime.utcnow().isoformat() + "Z"
return {
"object": "database",
"id": database_id,
"created_time": now,
"last_edited_time": now,
"title": params['title'],
"properties": params['properties'],
"parent": params['parent'],
"url": f"https://www.notion.so/{database_id.replace('-', '')}"
}