From 6b40edce55971218bfdb8b8bb5360fea5e9546c5 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Fri, 15 May 2026 16:24:14 -0300 Subject: [PATCH] refactor(mcp): extract MCP upload caps to trypost.mcp.upload config --- app/Http/Requests/Api/StoreUploadRequest.php | 4 +++- app/Mcp/Tools/Post/RequestMediaUploadTool.php | 9 ++++++--- config/trypost.php | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/Http/Requests/Api/StoreUploadRequest.php b/app/Http/Requests/Api/StoreUploadRequest.php index 11706af5..df5a1c3d 100644 --- a/app/Http/Requests/Api/StoreUploadRequest.php +++ b/app/Http/Requests/Api/StoreUploadRequest.php @@ -24,11 +24,13 @@ public function rules(): array MediaType::Video->allowedMimeTypes(), )); + $maxKb = (int) config('trypost.mcp.upload.max_size_mb') * 1024; + return [ 'media' => [ 'required', 'file', - 'max:51200', + "max:{$maxKb}", "mimetypes:{$allowed}", ], ]; diff --git a/app/Mcp/Tools/Post/RequestMediaUploadTool.php b/app/Mcp/Tools/Post/RequestMediaUploadTool.php index e61dcd84..b455ccd4 100644 --- a/app/Mcp/Tools/Post/RequestMediaUploadTool.php +++ b/app/Mcp/Tools/Post/RequestMediaUploadTool.php @@ -14,7 +14,7 @@ use Laravel\Mcp\Server\Attributes\Description; use Laravel\Mcp\Server\Tool; -#[Description('Issue a one-shot signed POST URL that lets the user upload a local file (image up to 10 MB, video up to 50 MB hard cap) directly to this workspace. Returns an upload_token and upload_url. Hand the URL to the user (e.g. as a curl command with `-F media=@path/to/file`) or to the MCP client. After upload, call AttachMediaFromUploadTool(post_id, upload_token) to attach the result to a post.')] +#[Description('Issue a one-shot signed POST URL that lets the user upload a local file (image or video, up to the workspace upload cap — 50 MB by default) directly to this workspace. Returns an upload_token and upload_url. Hand the URL to the user (e.g. as a curl command with `-F media=@path/to/file`) or to the MCP client. After upload, call AttachMediaFromUploadTool(post_id, upload_token) to attach the result to a post.')] class RequestMediaUploadTool extends Tool { public function handle(Request $request): Response|ResponseFactory @@ -22,8 +22,11 @@ public function handle(Request $request): Response|ResponseFactory $user = $request->user(); $workspaceId = $user->current_workspace_id; + $maxBytes = (int) config('trypost.mcp.upload.max_size_mb') * 1024 * 1024; + $ttlMinutes = (int) config('trypost.mcp.upload.url_ttl_minutes'); + $token = (string) Str::uuid(); - $expiresAt = CarbonImmutable::now()->addMinutes(15); + $expiresAt = CarbonImmutable::now()->addMinutes($ttlMinutes); $uploadUrl = URL::temporarySignedRoute( 'api.uploads.store', @@ -35,7 +38,7 @@ public function handle(Request $request): Response|ResponseFactory 'upload_token' => $token, 'upload_url' => $uploadUrl, 'expires_at' => $expiresAt->toIso8601String(), - 'max_bytes' => 52428800, + 'max_bytes' => $maxBytes, 'field_name' => 'media', ]); } diff --git a/config/trypost.php b/config/trypost.php index 9ab2e2b9..2280ac2e 100644 --- a/config/trypost.php +++ b/config/trypost.php @@ -34,6 +34,24 @@ ], ], + /* + |-------------------------------------------------------------------------- + | MCP Media Upload + |-------------------------------------------------------------------------- + | + | Settings for the MCP signed-URL upload flow. The hard cap is enforced + | per upload regardless of media type and is intentionally smaller than + | the per-type caps above because uploads flow through the app server. + | + */ + + 'mcp' => [ + 'upload' => [ + 'max_size_mb' => (int) env('MCP_UPLOAD_MAX_SIZE_MB', 50), + 'url_ttl_minutes' => (int) env('MCP_UPLOAD_URL_TTL_MINUTES', 15), + ], + ], + /* |-------------------------------------------------------------------------- | Google Authentication