Skip to content

feat(mcp-server): enable action file fields via an upload side-channel - #1814

Open
stefanoamorelli wants to merge 1 commit into
ForestAdmin:mainfrom
stefanoamorelli:feat/mcp-server-action-file-uploads
Open

feat(mcp-server): enable action file fields via an upload side-channel#1814
stefanoamorelli wants to merge 1 commit into
ForestAdmin:mainfrom
stefanoamorelli:feat/mcp-server-action-file-uploads

Conversation

@stefanoamorelli

@stefanoamorelli stefanoamorelli commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Action forms with File fields cannot run over MCP today, because MCP itself has no file upload mechanism yet. Tool arguments are JSON, so a file has to travel as a base64 data URI through the model's context window, and it exceeds most clients' payload limits on the way. The spec is heading toward the same pattern this PR uses. SEP-13061 explored binary elicitation, SEP-23562 specified declarative file inputs as RFC 2397 data URIs, and the open SEP-26313 adds out-of-band upload negotiation (files/authorizeUpload). Its motivation states that implementations today rely on ad hoc argument conventions, hosted-storage handles, inline base64, or harness-specific rewriting.

I add an opt-in fileUploads option backed by a pluggable UploadStorage interface, with no new dependency in the package. POST /files returns a pre-authorized upload URL plus a signed handle bound to the requesting user, and executeAction swaps $uploadedFile: handles for the data:<mediatype>;name=<filename>;base64,... URI the agent already expects, the same shape SEP-2356 specifies. The model only ever exchanges the small handle. Redemption enforces a size cap, an optional sha256 pin, and a per-process download concurrency bound. Once SEP-2631 lands, this side-channel can map onto the standardized files/authorizeUpload flow without changing the storage contract. The README documents the flow with a sequence diagram and an S3 example.

Footnotes

  1. SEP-1306, binary mode elicitation for file uploads (superseded). https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1306

  2. SEP-2356, file input support for tools and elicitation (closed in favor of SEP-2631). https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2356

  3. SEP-2631, file objects and transfer (open). https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2631

The agent expects action file fields as base64 data URIs, which cannot
pass through an MCP client. The payload would transit the model's
context window and exceed most clients' body limits, so actions with
File fields could not run over MCP at all.

Add an opt-in fileUploads option backed by a pluggable UploadStorage
interface. POST /files (bearer-protected) returns a pre-authorized
upload URL plus a signed handle bound to the requesting user.
executeAction swaps "$uploadedFile:<handle>" values for the data URI
before calling the agent, so the model only ever exchanges the small
handle and the bytes bypass both the server and the model on upload.

The handle is a JWT signed with authSecret, so the server stays
stateless and horizontally scalable. Redemption enforces the size cap
(a pre-authorized upload URL cannot always cap the object size),
re-verifies an optional sha256 pin against the downloaded bytes so
substituted content cannot be redeemed, and runs under a per-process
concurrency bound so worst-case memory stays at maxBytes times the
slot count.

getActionForm leaves handles unresolved on purpose because it echoes
values back into the model's context. The route matcher only claims
/files when the feature is enabled, so a host app's own /files keeps
working otherwise.

Signed-off-by: Stefano Amorelli <stefano@amorelli.tech>
@Scra3

Scra3 commented Aug 10, 2026

Copy link
Copy Markdown
Member

Hello again @stefanoamorelli :),
Thank you for your contribution, I will take a look this week.

@Scra3

Scra3 commented Aug 17, 2026

Copy link
Copy Markdown
Member

Hello, thank you very much for your contribution.
We've included it in another pull request; please accept our apologies, but the topic was too broad to be covered in this pull request. 🙏
Enjoy downloading files on your MCP :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants