feat(mcp): add content_upload_media tool for image uploads - #314
feat(mcp): add content_upload_media tool for image uploads#314hectorcanaimero wants to merge 2 commits into
Conversation
Adds a server-resolved MCP tool that uploads an image into the Media library, closing the gap where connectors could list and assign media but never create it. Bytes arrive inline (base64) or via an https sourceUrl the host downloads under the plugin network layer's SSRF blocklist (https-only, DNS-resolved, per-hop redirect revalidation, size-capped). Reuses the shared acceptUploadedMedia core for magic-byte sniffing, SVG sanitisation, storage dispatch, and responsive variants. Hoists the 50MB limit to MAX_MEDIA_BYTES in the upload core so the HTTP route and the tool share one source of truth.
|
Thanks, this is useful. There are two changes needed before merge. First, the build is currently failing with: Second, please rename the new MCP tool from We’ll handle |
Address review on CoreBunch#314: - Type the decoded/downloaded image bytes as Uint8Array<ArrayBuffer> so the File constructor accepts them (fixes TS2322 in the Build & Typecheck CI job). - Rename the tool from content_upload_media to media_upload across the implementation, tests, descriptions, and docs, establishing the media_* namespace. The content_* namespace is reserved for the Content editor.
|
Thanks for the review — both addressed in a56a66b. Build fix: the decoded/downloaded bytes are now typed Rename: Verified in the |
What
Adds
content_upload_media, a server-resolved MCP tool that uploads an image into the Media library and returns itsid+publicPath.Why
The MCP surface could list and assign media but never create it — an external agent building a page had no way to get an image into the library. This closes that gap.
How
data:URI prefix tolerated) or via an httpssourceUrlthe host downloads.sourceUrlbranch is SSRF-guarded exactly like the plugin network layer: https-only, DNS-resolved, every resolved address checked against the sharedisBlockedAddressblocklist, redirects followed manually and re-validated per hop, and the download size-capped while streaming. Loopback / private / link-local (incl.169.254.169.254) targets are refused.acceptUploadedMediacore — magic-byte MIME sniffing, SVG sanitisation, storage dispatch, responsive variants. No new byte-handling path is introduced.MAX_MEDIA_BYTESin the upload core so the HTTP media route and the tool share one source of truth.ai.tools.write+media.write, following thesite_publishserver-tool precedent.Impact
content_list_media's description was corrected (it claimed uploads were impossible).Verification
bun test server/ai/mcp/tools/uploadMediaTool.test.ts server/ai/mcp/registry.test.ts— 11/11 pass, including SSRF-blocklist rejection cases (127.0.0.1,169.254.169.254,10.x,::1), non-https rejection, source XOR, and non-image rejection.bun run build/bun run lintleft to CI (dev toolchain not available in the author's environment).Docs updated:
docs/features/mcp-connectors.md.