Skip to main content

Upload Media File

Immutable Catalog + Curated Guide

This lossless descriptor comes from the active Portal catalog and is enhanced with reviewed examples.

WRITEghl.upload_media_file
  • Contract tier: agent_ready
  • Risk: write
  • Catalog version: 2026-07-12.2
  • Descriptor hash: a7af7933fbcb442934e6ca0f6d6e84a6cb3253a225c4b0795674a669aecdbfa7

Upload one owned file to GHL Media Storage. Prefer dataUrl for generated files; direct uploads are limited to 25 MiB after decoding.

Request Body

{
"jsonrpc": "2.0",
"id": "ghl-upload-media-file-example",
"method": "tools/call",
"params": {
"name": "ghl.upload_media_file",
"arguments": {
"dataUrl": "data:image/jpeg;base64,<BASE64_JPEG_BYTES>",
"name": "approved-blog-hero.jpg",
"folderId": "folder_blog_images"
}
}
}

Arguments Schema

{
"type": "object",
"required": [],
"properties": {
"file": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"uri": {
"type": "string",
"description": "Compatibility alias for url; local filesystem URIs are rejected."
},
"url": {
"type": "string",
"description": "Public HTTP or HTTPS source URL for direct multipart upload."
},
"name": {
"type": "string",
"description": "Preferred filename for the uploaded media object."
},
"base64": {
"type": "string",
"description": "Raw base64 content containing decoded bytes of at most 25 MiB."
},
"dataUrl": {
"type": "string",
"description": "Base64 data URL containing decoded content of at most 25 MiB."
},
"fileName": {
"type": "string",
"description": "Compatibility alias for name."
},
"mimeType": {
"type": "string",
"description": "Compatibility alias for contentType."
},
"contentType": {
"type": "string",
"description": "MIME type for direct binary content, such as image/jpeg."
}
},
"additionalProperties": true
}
],
"description": "Backward-compatible file content field. For remote agents this may be base64, a data URL, or an object with a public HTTP/S url/uri. Direct decoded content is limited to 25 MiB. It must not be a local path."
},
"name": {
"type": "string",
"description": "Custom name for the uploaded file. Takes precedence over fileName."
},
"altId": {
"type": "string",
"description": "Location or agency ID. Defaults to the current GHL location."
},
"width": {
"type": "number",
"description": "Optional image width in pixels. For base64/data URL PNG/JPEG/SVG uploads this is auto-detected when possible so GHL can build media grid thumbnails."
},
"base64": {
"type": "string",
"description": "Raw base64 file content for generated image/file uploads. Decoded content is limited to 25 MiB. Provide contentType and fileName when possible."
},
"height": {
"type": "number",
"description": "Optional image height in pixels. For base64/data URL PNG/JPEG/SVG uploads this is auto-detected when possible so GHL can build media grid thumbnails."
},
"hosted": {
"type": "boolean",
"description": "When true or omitted with fileUrl, GHL ingests fileUrl as an already-hosted URL. Set hosted=false with fileUrl to fetch and multipart-upload the bytes through this MCP server."
},
"altType": {
"enum": [
"location",
"agency"
],
"type": "string",
"default": "location",
"description": "GHL media context type."
},
"dataUrl": {
"type": "string",
"description": "Base64 data URL, such as data:image/png;base64,..., for generated image uploads. Decoded content is limited to 25 MiB."
},
"fileUrl": {
"type": "string",
"description": "HTTP or HTTPS URL. By default this is sent to GHL as hosted=true for already-hosted media. Set hosted=false to make this MCP server fetch the URL and multipart-upload the bytes directly to GHL without base64 inflation."
},
"fileName": {
"type": "string",
"description": "Alias for name."
},
"folderId": {
"type": "string",
"description": "Alias for parentId. Use list_media_folders to discover IDs by folder name."
},
"parentId": {
"type": "string",
"description": "GHL media parent folder ID to upload into. Takes precedence over folderId."
},
"tenantId": {
"type": "string",
"description": "Tenant ID from list_tenants."
},
"sourceUrl": {
"type": "string",
"description": "Public HTTP or HTTPS source URL for direct binary upload. The MCP server fetches this URL, rejects local/private-network targets, enforces a 25 MiB non-video file limit, and sends the file to GHL as multipart/form-data."
},
"locationId": {
"type": "string",
"description": "GHL location ID. In BYOK runtime this must match the request header location."
},
"contentType": {
"type": "string",
"description": "MIME type for base64/data URL/direct uploads, such as image/png."
},
"blurHashCode": {
"type": "string",
"description": "Optional GHL-compatible blur hash metadata for image previews. Usually omitted unless already known."
},
"strictTenant": {
"type": "boolean",
"default": true,
"description": "Require tenantId to match locationId routing (default: true)."
}
}
}

Output Schema

{
"type": "object",
"required": [
"ok",
"data",
"error",
"meta"
],
"properties": {
"ok": {
"type": "boolean",
"description": "Whether the GHL MCP operation completed successfully."
},
"data": {
"anyOf": [
{
"type": "object",
"additionalProperties": true
},
{
"type": "array",
"items": {}
},
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Tool-specific GHL or local navigation result when ok is true."
},
"meta": {
"type": "object",
"description": "Safe execution, routing, and timing metadata.",
"additionalProperties": true
},
"error": {
"anyOf": [
{
"type": "object",
"additionalProperties": true
},
{
"type": "null"
}
],
"description": "Safe error details when ok is false; credential values are never returned."
}
},
"description": "Normalized GHL MCP response envelope.",
"additionalProperties": false
}

Code Examples

curl -X POST 'https://portal.madpanda3d.com/api/mcp' \
-H 'Authorization: Bearer mad_live_***' \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": "ghl-upload-media-file-example",
"method": "tools/call",
"params": {
"name": "ghl.upload_media_file",
"arguments": {
"dataUrl": "data:image/jpeg;base64,<BASE64_JPEG_BYTES>",
"name": "approved-blog-hero.jpg",
"folderId": "folder_blog_images"
}
}
}'

Example Responses

{
"success": true,
"status": "uploaded",
"source": "dataUrl",
"message": "Media uploaded successfully with ID: media_abc123",
"fileId": "media_abc123",
"id": "media_abc123",
"url": "https://storage.example.com/approved-blog-hero.jpg",
"hostedUrl": "https://storage.example.com/approved-blog-hero.jpg",
"name": "approved-blog-hero.jpg",
"parentId": "folder_blog_images",
"folderId": "folder_blog_images",
"contentType": "image/jpeg",
"mimeType": "image/jpeg",
"width": 1200,
"height": 675
}