Aident AI

Notion MCP Cannot Upload Files? Use the Native File Upload API
Notion's hosted MCP server cannot currently upload images or files. Notion documents that limitation explicitly and recommends its File Upload API as the interim path. The reliable fix is a three-step flow: create a File Upload object, send the file bytes, then attach the returned file_upload ID to a page, block, cover, icon, or database files property.
Do not base64-encode a PDF into Markdown or make a private receipt public just to give a connector a URL. Use an agent integration that exposes Notion's native upload actions, or call the File Upload API from a runtime that can reach api.notion.com.
Confirm the Connector Is the Boundary
First inspect the tools your agent can actually call. A file-related tool that accepts only inline UTF-8 content or a public source_url is not the same as Notion's native File Upload API.
The native flow needs all three capabilities:
Create a File Upload object and receive an
idand upload destination.Send binary file contents to that upload.
Reference the uploaded file by ID when creating or updating Notion content.
If step 1 or 2 is missing from the tool schema, changing your prompt will not add binary transport. This is a capability boundary, not a wording problem.
Prerequisites
Before uploading, confirm:
The Notion connection can edit the destination page or database.
You know the destination page or block ID.
The file has a supported extension and correct MIME type.
A single-part upload fits Notion's 20 MB API limit and your workspace's file-size limit.
You can complete the upload and attach it within one hour.
For direct API calls, keep the Notion token in an environment variable. Do not paste it into a prompt, shell history, source file, or shared MCP configuration.
Upload a File Through an AI Agent
Aident Loadout gives Claude Code, Codex, and other agents a way to discover the current Notion action contract before a write. Install or update it by giving your agent this exact instruction:
Then give the agent the file as an attachment and use a bounded prompt:
Expected result: the create action returns a pending upload ID, the send action changes its status to uploaded, and the final Notion write references that same ID. The page readback should show report.pdf as a Notion-hosted file.
If your current agent surface cannot pass an attached local file into the send action, use a protected short-lived file-transfer action rather than exposing a caller-local path to a remote runtime. Delete the temporary copy after Notion has imported and attached the file.
Reproduce the Native Flow With cURL
Use this direct API path when your runtime can reach Notion and you manage the integration token yourself. It follows Notion's current 2026-03-11 API version.
Set the inputs without printing the token:
1. Create the upload
Expected result: the final test exits successfully and FILE_UPLOAD_ID contains a UUID. The create response has status pending.
2. Send the bytes
Expected result:
3. Attach the upload to a page
Expected result: Notion returns a new block with type file. Open the destination page and confirm that the file renders and downloads. Once attached, the file becomes a persistent part of the workspace; future API reads return temporary download URLs that must be refreshed after they expire.
Attach the File to a Database Property Instead
A database page with a files property uses the same upload ID. Update the page and set the property to a file object with:
This is useful for expense receipts, contracts, creative assets, and support evidence. If you are building a wider Notion workflow, keep the upload as one bounded stage inside the automation rather than mixing file transport with every database write. The same separation improves Notion CRM and email automations.
Common Failure Modes
The connector accepts only content or source_url
You are on a connector surface that does not expose binary upload. Use an integration with native create and send actions, or move the call to a runtime that can reach the Notion API. A public URL import is appropriate only when the source is intentionally public and returns a direct file response without cookies, redirects, or private-network access.
cURL returns exit code 000
The runtime likely cannot reach api.notion.com. Confirm DNS and outbound HTTPS from that exact runtime. If a hosted agent sandbox blocks the destination, route the operation through a reviewed Notion action instead of weakening the sandbox.
The send step returns validation_error
Check the file size, extension, MIME type, and upload state. A single-part file must fit the applicable workspace limit and the API's 20 MB ceiling. Files above 20 MB require a paid Notion workspace, multi_part mode, 5-20 MB chunks, and a separate complete step before attachment.
The upload stays pending
Creating the File Upload object does not transmit the bytes. Call the send action or /send endpoint with multipart form data and keep the form field named file.
The upload expires before it appears on a page
Attach the uploaded ID within one hour of creation. If it has expired, create a new upload and repeat the send step. Do not reuse a pending or archived upload ID.
Notion returns 401 or 403
Reconnect the Notion account or verify the token, workspace, and destination permissions. The destination page must be shared with the integration. Keep the granted access as narrow as the workflow allows.
Why This Fix Works
The three stages separate transport from content placement:
Notion MCP currently omits the first two stages. A native integration or direct API call restores those stages without forcing binary data through a text field. The final page operation still uses Notion's ordinary block and page APIs, so one uploaded object can be reused across supported blocks or properties.
This is also a useful example of when an API is the right fallback for MCP: MCP standardizes the agent-facing connection, but the available tool set still determines which provider operations the agent can perform.
Ready to test the flow without exposing a private file? Set up Aident Loadout and inspect the Notion upload actions.
Sources
Notion: connect to the hosted MCP server and current file-upload limitation
Notion: supported upload methods, file types, and attachment targets
Community reproduction: hosted Notion connector lacks binary file input
Review this article when Notion adds file uploads to its hosted MCP tool set, changes the File Upload API version or limits, or changes the create, send, complete, or attachment contracts.



The one tool
for every tool
your agent needs.
Give any AI agent real capabilities in seconds. Connect 1,000+ tools once, skip the setup headache, and let your agents execute.