upload_clipboard_image
Automatically uploads copied images from your clipboard to Supabase Storage and provides a public URL for easy sharing.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/server.ts:30-52 (registration)Registration of the upload_clipboard_image MCP tool for stdio transport, with inline handler delegating to uploadCurrentClipboardImageserver.tool( "upload_clipboard_image", {}, // empty object for no parameters async () => { try { const url = await uploadCurrentClipboardImage(); logger.info(`MCP tool called: upload_clipboard_image → ${url}`); return { content: [ { type: "text", text: url } ] }; } catch (error) { const errorMessage = `Error uploading clipboard image: ${error instanceof Error ? error.message : 'Unknown error'}`; logger.error(errorMessage); return { content: [ { type: "text", text: `Error: Failed to upload image` } ] }; } } );
- src/server-http.ts:32-54 (registration)Registration of the upload_clipboard_image MCP tool for HTTP transport, with inline handler delegating to uploadCurrentClipboardImageserver.tool( "upload_clipboard_image", {}, // empty object for no parameters async () => { try { const url = await uploadCurrentClipboardImage(); logger.info(`MCP tool called: upload_clipboard_image → ${url}`); return { content: [ { type: "text", text: url } ] }; } catch (error) { const errorMessage = `Error uploading clipboard image: ${error instanceof Error ? error.message : 'Unknown error'}`; logger.error(errorMessage); return { content: [ { type: "text", text: `Error: Failed to upload image` } ] }; } } );
- src/daemon.ts:276-332 (handler)Core handler function that captures the current clipboard image using platform-specific logic, saves to temp file, uploads to Supabase storage, and returns the public URLexport const uploadCurrentClipboardImage = asyncHandler(async (): Promise<string> => { const filename = path.join(TMP, `${uuid()}.png`); try { // Check if platform is supported if (!isPlatformSupported()) { return `Unsupported platform: ${getPlatformName()}`; } // Try to get image from clipboard using platform-specific implementation logger.debug('MCP request: Checking clipboard for image'); const hasImage = await getImageFromClipboard(filename); if (!hasImage) { return 'No image in clipboard'; } // Verify the file exists and has content try { const stats = statSync(filename); if (stats.size === 0) { logger.debug('Empty image file detected'); return 'No valid image in clipboard'; } // Log image size for debugging logger.debug(`Image size: ${Math.round(stats.size / 1024)}KB`); } catch (err) { logger.debug('Image file not found or inaccessible'); return 'Failed to capture clipboard image'; } logger.info('MCP request: Image found in clipboard, preparing to upload'); // Read image file const data = await fs.readFile(filename); // Create unique path for Supabase const filePath = `clips/${path.basename(filename)}`; // Upload to Supabase and get URL const publicUrl = await uploadFileToSupabase(data, filePath); logger.info(`MCP request: Successfully uploaded ${filePath} → ${publicUrl}`); // Return URL (don't write to clipboard in this case) return publicUrl; } catch (error) { const errorMessage = `Error uploading clipboard image: ${error instanceof Error ? error.message : 'Unknown error'}`; logger.error(errorMessage); return `Error: ${error instanceof AppError ? error.message : 'Upload failed'}`; } finally { // Safely clean up temp file (ignores ENOENT errors) await safeRemove(filename); } });
- src/daemon.ts:60-145 (helper)Helper function that uploads image buffer to Supabase storage with multiple fallback methods and returns public URLasync function uploadFileToSupabase(buffer: Buffer, filePath: string): Promise<string> { // Reject large images early if (buffer.byteLength > MAX_IMAGE_SIZE) { throw new AppError(`Image too large (${Math.round(buffer.byteLength / 1024 / 1024)}MB > 8MB)`, 'IMAGE_TOO_LARGE'); } logger.debug(`Starting Supabase upload for ${filePath} (${buffer.byteLength} bytes)`); // Try different methods of uploading try { // First try: Use buffer directly logger.debug('Attempting upload with Buffer directly'); const { error: error1 } = await supabase.storage .from(BUCKET) .upload(filePath, buffer, { contentType: 'image/png', upsert: true }); if (!error1) { logger.debug('Upload succeeded with direct Buffer'); const { data: urlData } = supabase.storage .from(BUCKET) .getPublicUrl(filePath); return urlData.publicUrl; } logger.debug(`First upload attempt failed: ${error1.message || 'Unknown error'}`); // Second try: Use buffer.buffer (ArrayBuffer) logger.debug('Attempting upload with buffer.buffer (ArrayBuffer)'); const { error: error2 } = await supabase.storage .from(BUCKET) .upload(filePath, buffer.buffer, { contentType: 'image/png', upsert: true }); if (!error2) { logger.debug('Upload succeeded with buffer.buffer'); const { data: urlData } = supabase.storage .from(BUCKET) .getPublicUrl(filePath); return urlData.publicUrl; } logger.debug(`Second upload attempt failed: ${error2.message || 'Unknown error'}`); // Third try: Use Uint8Array logger.debug('Attempting upload with Uint8Array conversion'); const uint8Array = new Uint8Array(buffer); const { error: error3 } = await supabase.storage .from(BUCKET) .upload(filePath, uint8Array, { contentType: 'image/png', upsert: true }); if (!error3) { logger.debug('Upload succeeded with Uint8Array'); const { data: urlData } = supabase.storage .from(BUCKET) .getPublicUrl(filePath); return urlData.publicUrl; } logger.debug(`Third upload attempt failed: ${error3.message || 'Unknown error'}`); // All attempts failed, throw detailed error throw new AppError( `Supabase upload failed after 3 attempts. Last error: ${error3.message || 'Unknown error'}`, 'UPLOAD_ERROR' ); } catch (err) { if (err instanceof AppError) { throw err; } // Catch and log any other errors with as much detail as possible const errorMsg = err instanceof Error ? err.message : String(err); logger.error(`Unexpected error during upload: ${errorMsg}`); logger.error(`Error details: ${JSON.stringify(err)}`); throw new AppError(`Supabase upload failed: ${errorMsg}`, 'UPLOAD_ERROR'); } }