upload_file_from_url
Upload a file from a URL to attach it to a specific record in a PocketBase collection, enabling remote file integration with database records.
Instructions
Upload a file from URL to a record in PocketBase
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| collection | Yes | The name or ID of the collection | |
| fileField | Yes | The name of the file field in the collection schema | |
| fileName | No | Optional custom name for the uploaded file. If not provided, will extract from URL | |
| recordId | Yes | The ID of the record to attach the file to | |
| url | Yes | The URL to download the file from |
Implementation Reference
- src/tools/handlers/file.ts:61-115 (handler)Main execution logic for the upload_file_from_url tool: downloads file from URL using fetch, handles filename extraction and MIME type extension mapping, creates Blob and FormData, uploads to PocketBase record via pb.collection().update().export function createUploadFileFromUrlHandler(pb: PocketBase): ToolHandler { return async (args: UploadFileFromUrlArgs) => { try { const { collection, recordId, fileField, url, fileName } = args; // Download the file from the URL const response = await fetch(url); if (!response.ok) { throw new Error(`Failed to download file from URL: ${response.status} ${response.statusText}`); } // Get the file content as ArrayBuffer const arrayBuffer = await response.arrayBuffer(); // Determine the filename let finalFileName = fileName; if (!finalFileName) { // Extract filename from URL const urlPath = new URL(url).pathname; finalFileName = urlPath.split('/').pop() || 'downloaded-file'; // If no extension, try to get from Content-Type header if (!finalFileName.includes('.')) { const contentType = response.headers.get('content-type'); if (contentType) { const extension = getExtensionFromMimeType(contentType); if (extension) { finalFileName += `.${extension}`; } } } } // Create a Blob from the downloaded content const blob = new Blob([arrayBuffer]); // Create a FormData object and append the file const formData = new FormData(); formData.append(fileField, blob, finalFileName); // Update the record with the file const record = await pb.collection(collection).update(recordId, formData); return createJsonResponse({ success: true, message: `File '${finalFileName}' uploaded successfully from URL to record ${recordId}`, fileName: finalFileName, sourceUrl: url, record }); } catch (error: unknown) { throw handlePocketBaseError("upload file from URL", error); } }; }
- src/tools/schemas/file.ts:47-72 (schema)Input schema (zod-like) defining parameters for the tool: collection, recordId, fileField, url (required), fileName (optional).export const uploadFileFromUrlSchema = { type: 'object', properties: { collection: { type: 'string', description: 'The name or ID of the collection' }, recordId: { type: 'string', description: 'The ID of the record to attach the file to' }, fileField: { type: 'string', description: 'The name of the file field in the collection schema' }, url: { type: 'string', description: 'The URL to download the file from' }, fileName: { type: 'string', description: 'Optional custom name for the uploaded file. If not provided, will extract from URL' } }, required: ['collection', 'recordId', 'fileField', 'url'] } as const;
- src/server.ts:231-236 (registration)Tool registration in the MCP server array, specifying name, description, inputSchema, and handler factory.{ name: "upload_file_from_url", description: "Upload a file from URL to a record in PocketBase", inputSchema: uploadFileFromUrlSchema, handler: createUploadFileFromUrlHandler(pb), },
- src/types/index.ts:214-220 (schema)TypeScript type interface matching the input schema for type safety.export interface UploadFileFromUrlArgs { collection: string; recordId: string; fileField: string; url: string; fileName?: string; }
- src/tools/handlers/file.ts:118-144 (helper)Helper function used by the handler to map MIME types to file extensions when filename lacks extension.function getExtensionFromMimeType(mimeType: string): string | null { const mimeToExt: Record<string, string> = { 'image/jpeg': 'jpg', 'image/png': 'png', 'image/gif': 'gif', 'image/webp': 'webp', 'image/svg+xml': 'svg', 'text/plain': 'txt', 'text/html': 'html', 'text/css': 'css', 'text/javascript': 'js', 'application/json': 'json', 'application/pdf': 'pdf', 'application/zip': 'zip', 'application/x-zip-compressed': 'zip', 'application/msword': 'doc', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx', 'application/vnd.ms-excel': 'xls', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx', 'video/mp4': 'mp4', 'video/webm': 'webm', 'audio/mpeg': 'mp3', 'audio/wav': 'wav' }; return mimeToExt[mimeType.toLowerCase()] || null; }