### Setup Project Dependencies and Configuration Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md This snippet outlines the steps to clone the repository, set up a Python virtual environment, install dependencies, and configure API keys by copying an example environment file. ```bash git clone https://github.com/umair-ds92/notion-mcp-agent.git cd notion-mcp-agent python -m venv .venv && source .venv/bin/activate pip install --upgrade pip && pip install -r requirements.txt cp .env.example .env # fill in OPENAI_API_KEY and NOTION_API_KEY ``` -------------------------------- ### OpenTelemetry Tracing Setup (Python) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Illustrates how to initialize OpenTelemetry distributed tracing for a FastAPI application. The `setup_tracing` function automatically instruments FastAPI routes and outbound HTTP calls. Tracing is optional and disabled by default, with configuration managed via environment variables. ```python from tracing import setup_tracing from fastapi import FastAPI app = FastAPI() # Enable tracing at startup (only if OTEL_ENABLED=true) setup_tracing(app) # Configure via environment variables: # OTEL_ENABLED=true # OTEL_SERVICE_NAME=notion-mcp-agent # OTEL_EXPORTER_ENDPOINT=http://jaeger:4317 ``` -------------------------------- ### Structured JSON Logging (Python) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Shows how to use the `get_logger` function to obtain a logger that outputs logs in a structured JSON format. This is beneficial for log aggregation systems. The examples demonstrate basic info logging, logging with request context, and error logging with exception details, all including timestamp, level, logger name, and custom fields. ```python from logger import get_logger log = get_logger(__name__) # Basic logging log.info("server_started", extra={"port": 7001, "version": "0.4.0"}) # Log with request context log.info("task_received", extra={ "request_id": "abc-123", "task_preview": "Create a page titled...", "client_ip": "192.168.1.1" }) # Error logging with exception details try: result = await risky_operation() except Exception as exc: log.error("operation_failed", extra={ "error": str(exc), "request_id": request_id, "task": task[:80] }) raise ``` -------------------------------- ### Interact with Notion MCP Agent API Endpoints Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Examples demonstrating how to use `curl` to interact with the agent's REST API. It shows how to send tasks for immediate results (`/run`) and for real-time streaming (`/run/stream`), including necessary headers and data payloads. ```bash curl -X POST http://localhost:7001/run \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{"task": "Create a page titled Sprint 42 Retro"}' # Streaming curl -X POST http://localhost:7001/run/stream \ -H "Content-Type: application/json" \ -H "Authorization: Bearer " \ -d '{"task": "List all pages"}' --no-buffer ``` -------------------------------- ### Build Docker Image for Notion MCP Agent Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt This Dockerfile is used to build a containerized image for the Notion MCP Agent. It specifies the base Python image, installs system and Python dependencies, copies application code, and defines the command to run the application. It requires a 'requirements.txt' file in the same directory. ```dockerfile FROM python:3.11-slim WORKDIR /app RUN apt-get update && apt-get install -y nodejs npm curl && rm -rf /var/lib/apt/lists/* COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 7001 CMD ["python", "app.py"] ``` -------------------------------- ### Configuration Access (Python) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Demonstrates how to access application configuration values loaded from environment variables using the `config` module. It shows how to validate required variables at startup and how to conditionally enable features like tracing or NGROK based on configuration settings. ```python import config # Validate required variables at startup config.validate() # Raises EnvironmentError if OPENAI_API_KEY or NOTION_API_KEY missing # Use configuration values model = config.OPENAI_MODEL # "o4-mini" max_turns = config.AGENT_MAX_TURNS # 5 port = config.PORT # 7001 log_level = config.LOG_LEVEL # "INFO" # Check optional features if config.OTEL_ENABLED: setup_tracing() if config.USE_NGROK: public_url = ngrok.connect(config.PORT) ``` -------------------------------- ### Add Custom MCP Tool Servers in Python Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Demonstrates how to extend the agent's capabilities by adding custom tool servers to the tool registry. Each server is defined using the `ToolServer` dataclass, specifying connection parameters and enabling/disabling status. The agent automatically loads these tools at startup, allowing for modular integration of new services like Notion and optionally Gmail. ```python # tools/registry.py from dataclasses import dataclass from autogen_ext.tools.mcp import StdioServerParams import config @dataclass class ToolServer: name: str params: StdioServerParams enabled: bool = True description: str = "" def _build_registry() -> list[ToolServer]: servers = [] # Notion is always enabled servers.append(ToolServer( name="notion", description="Notion workspace — create, search, and update pages", params=StdioServerParams( command="npx", args=["-y", "mcp-remote", config.NOTION_MCP_URL], env={"NOTION_API_KEY": config.NOTION_API_KEY}, read_timeout_seconds=config.MCP_READ_TIMEOUT, ), )) # Gmail (optional - enable with GMAIL_ENABLED=true) if config.GMAIL_ENABLED: servers.append(ToolServer( name="gmail", description="Gmail — read, search, and send emails", params=StdioServerParams( command="npx", args=["-y", "@modelcontextprotocol/server-gmail"], env={"GMAIL_CREDENTIALS": config.GMAIL_CREDENTIALS}, read_timeout_seconds=config.MCP_READ_TIMEOUT, ), )) # Add your custom MCP server here: # if config.SLACK_ENABLED: # servers.append(ToolServer( # name="slack", # description="Slack — send and read messages", # params=StdioServerParams( # command="npx", # args=["-y", "@modelcontextprotocol/server-slack"], # env={"SLACK_TOKEN": config.SLACK_TOKEN}, # ), # )) return [s for s in servers if s.enabled] TOOL_REGISTRY: list[ToolServer] = _build_registry() ``` -------------------------------- ### AgentPool Initialization Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Details on how to initialize the singleton agent pool, which loads MCP tools, creates the OpenAI model client, and builds the AutoGen team. This process is thread-safe and idempotent. ```APIDOC ## AgentPool Initialization ### Description Initializes the singleton agent pool at application startup. This method loads all MCP tools from registered servers, creates the OpenAI model client, and builds the AutoGen team. It's thread-safe and idempotent - subsequent calls have no effect if already initialized. ### Method `AgentPool.initialise()` (asynchronous) ### Usage This method should be called once at application startup, typically within the lifespan management of a FastAPI application. ### Code Example (Python) ```python from agent_pool import AgentPool from contextlib import asynccontextmanager # Example of calling initialise at startup async def startup_event(): await AgentPool.initialise() # Agent pool is now ready to process tasks # Using FastAPI's lifespan context manager @asynccontextmanager async def lifespan(app): await AgentPool.initialise() yield await AgentPool.shutdown() # Optional: Call shutdown on application exit ``` ### Notes - The `AgentPool.initialise()` method is designed to be called automatically by the application's startup sequence. - It ensures that all necessary resources and agents are set up before the API becomes available. - Subsequent calls to `initialise()` after the pool has been set up will not perform any actions. ``` -------------------------------- ### AgentPool Initialization (Python) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The AgentPool.initialise() method initializes the singleton agent pool at application startup. It loads MCP tools, creates the OpenAI model client, and builds the AutoGen team. This method is thread-safe and idempotent. ```python from agent_pool import AgentPool # Initialize at application startup async def startup(): await AgentPool.initialise() # Agent pool is now ready to process tasks # Tools from Notion (and optionally Gmail, Calendar) are loaded # The lifespan context manager handles this automatically in app.py from contextlib import asynccontextmanager @asynccontextmanager async def lifespan(app): await AgentPool.initialise() yield await AgentPool.shutdown() ``` -------------------------------- ### Docker Compose Configuration (YAML) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Provides a sample `docker-compose.yml` file for deploying the agent. It defines the service, build context, port mapping, environment file loading, and health check configuration, ensuring proper container management and readiness checks. ```yaml version: "3.8" services: agent: build: . ports: - "7001:7001" env_file: - .env healthcheck: test: ["CMD", "curl", "-f", "http://localhost:7001/health"] interval: 30s timeout: 10s retries: 3 ``` -------------------------------- ### Docker Compose Commands (Bash) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Lists essential Docker Compose commands for managing the agent container. This includes building the image, running the container in the foreground or background, viewing logs, and stopping the services. ```bash # Build and run docker compose up --build # Run in background docker compose up -d --build # View logs docker compose logs -f agent # Stop docker compose down ``` -------------------------------- ### Run the Notion MCP Agent Locally or via Docker Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Instructions for running the agent application either directly using Python or through Docker Compose. The server will be accessible at http://localhost:7001, with documentation available at /docs. ```bash # Local python app.py # Docker docker compose up --build ``` -------------------------------- ### Run Project Tests and Linting Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Commands to execute the project's test suite using `pytest`, perform code linting with `ruff`, and type checking with `mypy`. These commands ensure code quality and correctness. ```bash pytest tests/ -v ruff check . mypy app.py ``` -------------------------------- ### Run Task Stream API Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Submits a task to the agent and returns results in real-time as a Server-Sent Events (SSE) stream. ```APIDOC ## POST /run/stream ### Description Submits a task to the agent and returns results in real-time as a Server-Sent Events (SSE) stream. Requires authentication. ### Method POST ### Endpoint /run/stream ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **task** (string) - Required - The natural language task to be executed by the agent. ### Request Example ```json { "task": "List all pages" } ``` ### Response #### Success Response (200) - **event stream** - A stream of Server-Sent Events containing the task's progress and results. #### Response Example ``` data: {"output": "Searching for pages..."} data: {"output": "Found 5 pages."} data: {"output": "Page 1: 'Project Plan'"} ... ``` ``` -------------------------------- ### Run Task Endpoint Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /run endpoint accepts a natural language task and returns the complete result once the agent finishes processing. It requires Bearer token authentication when API_KEY is configured, validates task length (1-2000 characters), and includes a unique request ID in both the response body and headers for tracing. ```APIDOC ## POST /run ### Description Executes a natural language task against the Notion workspace and returns the complete result upon completion. Supports creating, searching, and updating Notion pages. ### Method POST ### Endpoint /run ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **task** (string) - Required - The natural language instruction for the agent (1-2000 characters). ### Request Example ```json { "task": "Create a page titled Sprint 42 Retro in my workspace" } ``` ### Response #### Success Response (200) - **status** (string) - Indicates the success or failure of the task execution. - **result** (string) - The outcome of the task performed by the agent. - **request_id** (string) - A unique identifier for the request, useful for tracing. #### Response Example ```json { "status": "success", "result": "I've created a new page titled 'Sprint 42 Retro' in your workspace...", "request_id": "550e8400-e29b-41d4-a716-446655440000" } ``` #### Error Response (500) - **status** (string) - Indicates an error occurred during task execution. - **code** (string) - An error code specifying the type of agent error. - **message** (string) - A detailed error message explaining the failure. - **request_id** (string) - A unique identifier for the request. #### Error Response Example ```json { "status": "error", "code": "agent_error", "message": "MCP subprocess crashed", "request_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ``` -------------------------------- ### Retry with Specific Exceptions (Python) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Demonstrates how to use the `with_retry` decorator to automatically retry function calls only when specific exceptions occur. It configures the maximum number of attempts, base delay between retries, and the set of exceptions that should trigger a retry. The decorator handles the retry logic, and logs retry attempts. ```python from tenacity import retry, stop_after_attempt, wait_fixed @retry( stop=stop_after_attempt(3), wait=wait_fixed(2.0), retry_error_callback=lambda retry_state: print(f"Failed after {retry_state.attempt_number} attempts"), reraise=True ) def fetch_with_timeout(): # Your code that might raise ConnectionError or TimeoutError pass # Inline usage without decorator # result = await with_retry(max_attempts=3)(some_async_fn)(arg1, arg2) ``` -------------------------------- ### Run Task Endpoint (Bash) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /run endpoint accepts a natural language task and returns the complete result once the agent finishes processing. It requires Bearer token authentication, validates task length, and includes a unique request ID for tracing. ```bash # Create a new Notion page curl -X POST http://localhost:7001/run \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{"task": "Create a page titled Sprint 42 Retro in my workspace"}' # Response: # { # "status": "success", # "result": "I've created a new page titled 'Sprint 42 Retro' in your workspace...", # "request_id": "550e8400-e29b-41d4-a716-446655440000" # } # Search for pages curl -X POST http://localhost:7001/run \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{"task": "Find all pages containing meeting notes from last week"}' # Update existing content curl -X POST http://localhost:7001/run \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{"task": "Add a new section called Action Items to the Sprint 42 Retro page"}' # Error response (500): # { # "status": "error", # "code": "agent_error", # "message": "MCP subprocess crashed", # "request_id": "550e8400-e29b-41d4-a716-446655440000" # } ``` -------------------------------- ### Run Task API Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Submits a task to the agent and returns the full result once completed. ```APIDOC ## POST /run ### Description Submits a task to the agent and returns the full result once completed. Requires authentication. ### Method POST ### Endpoint /run ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **task** (string) - Required - The natural language task to be executed by the agent. ### Request Example ```json { "task": "Create a page titled Sprint 42 Retro" } ``` ### Response #### Success Response (200) - **result** (string) - The complete result of the executed task. #### Response Example ```json { "result": "Page 'Sprint 42 Retro' created successfully." } ``` ``` -------------------------------- ### Run Task with AgentPool.run_task() in Python Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Executes a natural language task using the AgentPool and returns the complete result as a string. It initializes the pool, runs the task through the AutoGen team, and aggregates all messages into a single response. This method is suitable for scenarios where the full output is needed before proceeding. ```python from agent_pool import AgentPool async def process_user_request(task: str) -> str: # Run a task and get the full result result = await AgentPool.run_task("Create a page titled Weekly Standup Notes") print(result) # Output: "I've created a new page titled 'Weekly Standup Notes'...\n # The page is now available in your workspace. TERMINATE" # Search for content result = await AgentPool.run_task("Find all pages modified in the last 24 hours") # Summarize content result = await AgentPool.run_task("Summarize the contents of my Product Roadmap page") return result ``` -------------------------------- ### Streaming Task Endpoint (Bash & JavaScript) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /run/stream endpoint provides real-time Server-Sent Events (SSE) streaming of agent messages. This is ideal for long-running tasks where users want to see incremental progress. It requires Bearer token authentication. ```bash # Stream agent responses in real-time curl -X POST http://localhost:7001/run/stream \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{"task": "List all pages in my workspace and summarize their contents"}' \ --no-buffer # SSE Response stream: # data: Starting to search your Notion workspace... # data: Found 15 pages. Analyzing contents... # data: Page 1: Sprint 42 Retro - Contains retrospective notes from March 15... # data: Page 2: Product Roadmap - Q2 2024 planning document... # data: [DONE] ``` ```javascript const eventSource = new EventSource('/run/stream', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-api-key' }, body: JSON.stringify({ task: 'List all pages' }) }); eventSource.onmessage = (event) => { if (event.data === '[DONE]') { eventSource.close(); } else { console.log('Agent:', event.data); } }; ``` -------------------------------- ### Apply Retry Decorator with_retry() in Python Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt A decorator factory that enhances async functions with exponential backoff retry logic. It implements full jitter to mitigate thundering herd issues and offers configuration options for maximum retry attempts, base delay, maximum delay, and specific exceptions that should trigger a retry. This ensures resilience when calling unreliable external services. ```python from retries import with_retry # Basic usage with defaults (3 attempts, 1s base delay) @with_retry() async def call_external_api(): response = await httpx.get("https://api.example.com/data") response.raise_for_status() return response.json() ``` ```python # Custom retry configuration @with_retry(max_attempts=5, base_delay=0.5, max_delay=30.0) async def call_flaky_service(): return await some_unreliable_operation() ``` -------------------------------- ### Streaming Task Endpoint Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /run/stream endpoint provides real-time Server-Sent Events (SSE) streaming of agent messages as they are produced. This is ideal for long-running tasks where you want to show progress to users incrementally rather than waiting for the complete response. ```APIDOC ## POST /run/stream ### Description Streams agent messages in real-time using Server-Sent Events (SSE) for long-running tasks, providing incremental progress updates. ### Method POST ### Endpoint /run/stream ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **task** (string) - Required - The natural language instruction for the agent. ### Request Example ```bash curl -X POST http://localhost:7001/run/stream \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{"task": "List all pages in my workspace and summarize their contents"}' \ --no-buffer ``` ### Response #### Success Response (200 - SSE Stream) - **data** (string) - Each message from the agent, streamed incrementally. - **[DONE]** - A special message indicating the end of the stream. #### Response Example (Stream) ``` data: Starting to search your Notion workspace... data: Found 15 pages. Analyzing contents... data: Page 1: Sprint 42 Retro - Contains retrospective notes from March 15... data: Page 2: Product Roadmap - Q2 2024 planning document... data: [DONE] ``` #### JavaScript EventSource Client Example ```javascript const eventSource = new EventSource('/run/stream', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-api-key' }, body: JSON.stringify({ task: 'List all pages' }) }); eventSource.onmessage = (event) => { if (event.data === '[DONE]') { eventSource.close(); } else { console.log('Agent:', event.data); } }; ``` ``` -------------------------------- ### Stream Task with AgentPool.stream_task() in Python Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt Provides an async generator that yields agent messages incrementally as they are produced. This allows for real-time streaming of agent responses to clients without waiting for the entire task to complete. It's useful for interactive applications or when immediate feedback is desired. ```python from agent_pool import AgentPool async def stream_to_client(task: str): # Stream messages as they arrive async for message in AgentPool.stream_task("List all pages and describe each one"): print(f"Agent: {message}") # Yields each message incrementally: # "Searching your Notion workspace..." # "Found 12 pages. Let me describe each one..." # "1. Sprint Planning - Contains sprint goals and tickets..." # etc. ``` ```python from fastapi.responses import StreamingResponse async def sse_generator(task: str): async for message in AgentPool.stream_task(task): yield f"data: {message}\n\n" yield "data: [DONE]\n\n" @app.post("/run/stream") async def run_stream(body: RunRequest): return StreamingResponse( sse_generator(body.task), media_type="text/event-stream" ) ``` -------------------------------- ### Health Check Endpoint (Bash) Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /health endpoint provides a liveness check for container orchestration systems. It returns a simple status object indicating the service is operational and accessible without authentication. ```bash # Check if the service is healthy curl -X GET http://localhost:7001/health # Response: # { # "status": "ok", # "message": "Notion MCP Agent is healthy." # } ``` -------------------------------- ### Health Check API Source: https://github.com/umair-ds92/notion-mcp-agent/blob/main/README.md Provides a liveness check for the API service. ```APIDOC ## GET /health ### Description Liveness check for the API service. ### Method GET ### Endpoint /health ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example None ### Response #### Success Response (200) - **status** (string) - Indicates the health status of the service. #### Response Example ```json { "status": "ok" } ``` ``` -------------------------------- ### Health Check Endpoint Source: https://context7.com/umair-ds92/notion-mcp-agent/llms.txt The /health endpoint provides a liveness check for container orchestration systems and monitoring. It returns a simple status object indicating the service is operational and is accessible without authentication. ```APIDOC ## GET /health ### Description Provides a liveness check for the Notion MCP Agent service. ### Method GET ### Endpoint /health ### Parameters #### Path Parameters None #### Query Parameters None ### Request Example ```bash curl -X GET http://localhost:7001/health ``` ### Response #### Success Response (200) - **status** (string) - Indicates the operational status of the agent. - **message** (string) - A confirmation message that the agent is healthy. #### Response Example ```json { "status": "ok", "message": "Notion MCP Agent is healthy." } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.