Repository navigation
Send MCP uploads directly to storage that accepts them - #20630
Open
brandonkelly wants to merge 2 commits into
Open
brandonkelly wants to merge 2 commits into
brandonkelly wants to merge 2 commits into
Conversation
Adds craft\base\DirectUploadFsInterface, which filesystems can implement to issue URLs that store files directly, such as presigned S3 PUT URLs. When the temporary asset upload filesystem implements it, assets_upload_url returns its URL and the headers clients must send, rather than Craft's own upload URL, so files avoid request size limits such as Craft Cloud's 6 MB limit. Claims check the stored file's size, since direct URLs can't enforce maxUploadFileSize. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1c652-71e9-7674-ba66-cdb7cbecf509
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are reported for the direct-upload and fallback changes.
No open issues 🎉
What changed in this PR
Enables MCP uploads to bypass Craft’s web-request size limits by sending files directly to compatible temporary storage, while retaining Craft-hosted uploads as a fallback.
Changes:
- Adds a filesystem interface for direct upload URLs with required methods and headers.
- Updates upload creation and claiming to support direct storage uploads and enforce size limits.
- Adds regression coverage for direct uploads, oversized-file rejection, cleanup, and fallback behavior.
| File | Description |
|---|---|
tests/unit/mcp/AssetFieldUploadTest.php |
Tests direct uploads, size enforcement, cleanup, and fallback. |
src/mcp/capabilities/Assets.php |
Documents returned headers and client upload requirements. |
src/mcp/AssetUploads.php |
Supports direct upload URLs and validates stored files before claiming. |
src/base/DirectUploadFsInterface.php |
Defines the optional direct-upload filesystem contract. |
CHANGELOG.md |
Documents direct uploads and the new public interface. |
Review effort: Balanced
The scheme follows useSslOnTokenizedUrls, which differs in CI. Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-01a1c652-71e9-7674-ba66-cdb7cbecf509
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On Craft Cloud, web requests are capped at 6 MB (a Lambda limit), so files PUT to
assets_upload_url's Craft endpoint over that size never arrive. Cloud's control panel uploader avoids the limit by sending files straight to S3 through presigned URLs. This PR lets MCP uploads do the same.$pathis relative to the filesystem root. Null means "use Craft's endpoint". The file appears all at once. The URL may be reused until it expires, and orphaned files are left to stale-upload cleanup. The URL can't enforce a size limit, so the claim checks the size first.assets_upload_urlnow tells clients to sendmethodand every header inheaders. S3 rejects a PUT without the signedx-amz-meta-*headers withSignatureDoesNotMatch.Fs, with a shim for older Craft versions. It only takes effect once Create the default temp upload filesystem via the DI container #20628 makes Cloud'sTmpFsthe temp upload filesystem.@since 5.12.2.Evidence
AssetFieldUploadTest::testUploadUrlsSendFilesDirectlyToFilesystemsThatAcceptThemfails withFailed asserting that two strings are identical.The old code returns Craft's URL.After: it passes.
unit/mcp(77 tests) andfunctional/McpServersCest(9) pass locally. PHPStan and ECS are clean.