upload_and_attach_file_to_page
Upload files to Notion and attach them to specific pages, generating temporary download URLs with file metadata for sharing and access.
Instructions
Upload a file to Notion and attach it to a specific page, returning download URL.
This function performs the complete workflow:
1. Upload file to Notion
2. Create file block and attach to specified page
3. Extract and return download URL with metadata
Args:
file_path: Path to the file to upload
page_id: Notion page ID to attach the file to (with or without dashes)
notion_token: Notion API token for authentication (optional if NOTION_API_TOKEN env var is set)
file_name: Optional custom filename (defaults to original filename)
caption: Optional caption for the file block
Returns:
Dictionary containing:
- file_upload_id: The uploaded file ID
- file_block_id: The created file block ID
- download_url: Temporary download URL (expires in 1 hour)
- expiry_time: ISO timestamp when download URL expires
- filename: Name of the file
- content_type: MIME type of the file
- file_size: Size of the file in bytes
Raises:
Exception: If file doesn't exist, exceeds size limit, or API call fails
Example:
result = await upload_and_attach_file_to_page(
"document.pdf",
"2785bbc0e5c281f48dfae9a48f53f6a6",
notion_token="ntn_xxx"
)
download_url = result["download_url"]
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| caption | No | ||
| file_name | No | ||
| file_path | Yes | ||
| notion_token | No | ||
| page_id | Yes |
Implementation Reference
- mcp_notion_upload.py:98-269 (handler)The core handler function for the 'upload_and_attach_file_to_page' tool. Decorated with @mcp.tool() for registration. Implements file upload to Notion, attachment as a block to the specified page, and returns metadata including the temporary download URL.@mcp.tool() async def upload_and_attach_file_to_page( file_path: str, page_id: str, notion_token: Optional[str] = None, file_name: Optional[str] = None, caption: Optional[str] = None ) -> Dict[str, Any]: """ Upload a file to Notion and attach it to a specific page, returning download URL. This function performs the complete workflow: 1. Upload file to Notion 2. Create file block and attach to specified page 3. Extract and return download URL with metadata Args: file_path: Path to the file to upload page_id: Notion page ID to attach the file to (with or without dashes) notion_token: Notion API token for authentication (optional if NOTION_API_TOKEN env var is set) file_name: Optional custom filename (defaults to original filename) caption: Optional caption for the file block Returns: Dictionary containing: - file_upload_id: The uploaded file ID - file_block_id: The created file block ID - download_url: Temporary download URL (expires in 1 hour) - expiry_time: ISO timestamp when download URL expires - filename: Name of the file - content_type: MIME type of the file - file_size: Size of the file in bytes Raises: Exception: If file doesn't exist, exceeds size limit, or API call fails Example: result = await upload_and_attach_file_to_page( "document.pdf", "2785bbc0e5c281f48dfae9a48f53f6a6", notion_token="ntn_xxx" ) download_url = result["download_url"] """ # Get token from parameter or environment variable token = notion_token or os.environ.get('NOTION_API_TOKEN') if not token: raise Exception("Notion API token is required. Pass it as a parameter or set NOTION_API_TOKEN environment variable") # Validate file exists file_path_obj = Path(file_path) if not file_path_obj.exists(): raise Exception(f"File not found: {file_path}") # Check file size (max 20MB) file_size = file_path_obj.stat().st_size max_size = 20 * 1024 * 1024 # 20MB in bytes if file_size > max_size: raise Exception(f"File size ({file_size / 1024 / 1024:.2f}MB) exceeds 20MB limit") # Use custom filename if provided, otherwise use original upload_filename = file_name or file_path_obj.name # Notion API headers headers = { "Authorization": f"Bearer {token}", "Notion-Version": "2022-06-28" } async with httpx.AsyncClient() as client: try: # Step 1: Upload file to Notion # Create file upload object create_upload_response = await client.post( "https://api.notion.com/v1/file_uploads", headers={**headers, "Content-Type": "application/json"}, json={"name": upload_filename} ) create_upload_response.raise_for_status() upload_data = create_upload_response.json() file_upload_id = upload_data.get("id") upload_url = upload_data.get("upload_url") if not file_upload_id or not upload_url: raise Exception("Failed to get upload ID or URL from Notion API") # Upload file contents to the upload URL with open(file_path, 'rb') as f: files = {"file": (upload_filename, f)} upload_response = await client.post( upload_url, headers=headers, files=files ) upload_response.raise_for_status() # Step 2: Create file block and attach to page file_block_payload = { "children": [ { "object": "block", "type": "file", "file": { "type": "file_upload", "file_upload": { "id": file_upload_id }, "caption": [ { "type": "text", "text": { "content": caption or upload_filename } } ] if caption or upload_filename else [] } } ] } # Normalize page ID (remove dashes) normalized_page_id = page_id.replace("-", "") attach_response = await client.patch( f"https://api.notion.com/v1/blocks/{normalized_page_id}/children", headers={**headers, "Content-Type": "application/json"}, json=file_block_payload ) attach_response.raise_for_status() # Step 3: Extract file block information and download URL attach_data = attach_response.json() if not attach_data.get("results"): raise Exception("Failed to create file block") file_block = attach_data["results"][0] file_block_id = file_block.get("id") # Extract file information file_info = file_block.get("file", {}) file_data = file_info.get("file", {}) download_url = file_data.get("url") expiry_time = file_data.get("expiry_time") content_type = file_data.get("content_type", "application/octet-stream") if not download_url: raise Exception("File block created but no download URL available") # Return comprehensive file information return { "file_upload_id": file_upload_id, "file_block_id": file_block_id, "download_url": download_url, "expiry_time": expiry_time, "filename": upload_filename, "content_type": content_type, "file_size": file_size, "status": "success", "message": f"File '{upload_filename}' uploaded and attached successfully" } except httpx.HTTPStatusError as e: error_detail = "" try: error_detail = e.response.json().get("message", e.response.text) except: error_detail = e.response.text raise Exception(f"Notion API error: {e.response.status_code} - {error_detail}") except Exception as e: raise Exception(f"Upload and attach failed: {str(e)}")
- mcp_notion_upload.py:8-8 (registration)FastMCP server initialization and tool decorators register the 'upload_and_attach_file_to_page' tool.mcp = FastMCP("mcp_notion_upload")
- mcp_notion_upload.py:99-105 (schema)Type hints and docstring define the input parameters and return type/schema for the tool.async def upload_and_attach_file_to_page( file_path: str, page_id: str, notion_token: Optional[str] = None, file_name: Optional[str] = None, caption: Optional[str] = None ) -> Dict[str, Any]: