upload_media
Upload a local file to get a media key. Automatically detects content type, obtains a signed URL, and returns the media key and type for post creation.
Instructions
Upload a local file to PostFast and get back a media key for use in create_posts. Handles the full flow: detects content type, gets a signed URL, uploads the file, and returns the key and type.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filePath | Yes | Absolute path to the local file (e.g. /Users/me/photo.jpg) |
Implementation Reference
- src/tools/files.ts:73-118 (handler)The upload_media tool handler: reads a local file, detects content type, gets a signed upload URL from PostFast API, PUTs the file to that URL, and returns the media key, type (VIDEO/IMAGE), and content type.
server.tool( 'upload_media', 'Upload a local file to PostFast and get back a media key for use in create_posts. Handles the full flow: detects content type, gets a signed URL, uploads the file, and returns the key and type.', { filePath: z .string() .describe( 'Absolute path to the local file (e.g. /Users/me/photo.jpg)', ), }, async (input) => { const contentType = detectContentType(input.filePath); const isVideo = contentType.startsWith('video/'); const [uploadUrl] = await client.post<SignedUploadUrl[]>( '/file/get-signed-upload-urls', { contentType, count: 1 }, ); const fileBuffer = await readFile(input.filePath); const uploadResponse = await fetch(uploadUrl.signedUrl, { method: 'PUT', headers: { 'Content-Type': contentType }, body: fileBuffer, }); if (!uploadResponse.ok) { throw new Error( `Upload failed (${uploadResponse.status}): ${await uploadResponse.text()}`, ); } const result = { key: uploadUrl.key, type: isVideo ? 'VIDEO' : 'IMAGE', contentType, }; return { content: [ { type: 'text' as const, text: JSON.stringify(result, null, 2) }, ], }; }, ); - src/tools/files.ts:76-82 (schema)Input schema for upload_media: requires a single string filePath parameter validated with Zod, described as absolute path to a local file.
{ filePath: z .string() .describe( 'Absolute path to the local file (e.g. /Users/me/photo.jpg)', ), }, - src/tools/files.ts:73-118 (registration)Tool registration via server.tool() in the registerFileTools function, which is called from src/index.ts.
server.tool( 'upload_media', 'Upload a local file to PostFast and get back a media key for use in create_posts. Handles the full flow: detects content type, gets a signed URL, uploads the file, and returns the key and type.', { filePath: z .string() .describe( 'Absolute path to the local file (e.g. /Users/me/photo.jpg)', ), }, async (input) => { const contentType = detectContentType(input.filePath); const isVideo = contentType.startsWith('video/'); const [uploadUrl] = await client.post<SignedUploadUrl[]>( '/file/get-signed-upload-urls', { contentType, count: 1 }, ); const fileBuffer = await readFile(input.filePath); const uploadResponse = await fetch(uploadUrl.signedUrl, { method: 'PUT', headers: { 'Content-Type': contentType }, body: fileBuffer, }); if (!uploadResponse.ok) { throw new Error( `Upload failed (${uploadResponse.status}): ${await uploadResponse.text()}`, ); } const result = { key: uploadUrl.key, type: isVideo ? 'VIDEO' : 'IMAGE', contentType, }; return { content: [ { type: 'text' as const, text: JSON.stringify(result, null, 2) }, ], }; }, ); - src/tools/files.ts:27-36 (helper)Helper function detectContentType maps file extensions to MIME types (jpg/png/gif/webp/mp4/webm/mov). Used by upload_media to determine the Content-Type.
function detectContentType(filePath: string): string { const ext = extname(filePath).toLowerCase(); const mime = MIME_MAP[ext]; if (!mime) { throw new Error( `Unsupported file extension "${ext}". Supported: ${Object.keys(MIME_MAP).join(', ')}`, ); } return mime; }