threads-mcp-server
Version:
Professional Threads MCP Server - Fixed API issues, enhanced setup validation, and enterprise features
1,139 lines • 154 kB
JavaScript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
import dotenv from 'dotenv';
import { ThreadsAPIClient } from './api/client.js';
dotenv.config();
const server = new Server({
name: 'threads-mcp-server',
version: '4.0.1',
}, {
capabilities: {
tools: {},
},
});
let apiClient = null;
const initializeClient = () => {
const accessToken = process.env.THREADS_ACCESS_TOKEN;
if (!accessToken) {
throw new Error('THREADS_ACCESS_TOKEN environment variable is required');
}
apiClient = new ThreadsAPIClient(accessToken);
return apiClient;
};
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'get_my_profile',
description: 'Get your own Threads profile information',
inputSchema: {
type: 'object',
properties: {
fields: {
type: 'array',
items: { type: 'string' },
description: 'Profile fields to retrieve',
},
},
},
},
{
name: 'get_my_threads',
description: 'Get your own threads/posts',
inputSchema: {
type: 'object',
properties: {
fields: {
type: 'array',
items: { type: 'string' },
description: 'Thread fields to retrieve',
},
limit: {
type: 'number',
description: 'Number of threads to retrieve',
},
since: {
type: 'string',
description: 'ISO 8601 date for filtering',
},
until: {
type: 'string',
description: 'ISO 8601 date for filtering',
},
},
},
},
{
name: 'publish_thread',
description: 'Create and publish a new thread',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The text content of the thread',
},
media_type: {
type: 'string',
enum: ['TEXT', 'IMAGE', 'VIDEO'],
description: 'Type of media (default: TEXT)',
},
media_url: {
type: 'string',
description: 'URL of media to include (for IMAGE/VIDEO)',
},
location_name: {
type: 'string',
description: 'Location name for location tagging',
},
},
required: ['text'],
},
},
{
name: 'delete_thread',
description: 'Delete one of your threads',
inputSchema: {
type: 'object',
properties: {
thread_id: {
type: 'string',
description: 'ID of the thread to delete',
},
},
required: ['thread_id'],
},
},
{
name: 'search_my_threads',
description: 'Search within your own threads using keywords',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query/keywords',
},
limit: {
type: 'number',
description: 'Number of threads to search through',
},
},
required: ['query'],
},
},
{
name: 'get_thread_replies',
description: 'Get replies to your specific thread',
inputSchema: {
type: 'object',
properties: {
thread_id: {
type: 'string',
description: 'ID of your thread',
},
fields: {
type: 'array',
items: { type: 'string' },
description: 'Reply fields to retrieve',
},
},
required: ['thread_id'],
},
},
{
name: 'manage_reply',
description: 'Hide or show replies to your threads',
inputSchema: {
type: 'object',
properties: {
reply_id: {
type: 'string',
description: 'ID of the reply to manage',
},
hide: {
type: 'boolean',
description: 'Whether to hide (true) or show (false) the reply',
},
},
required: ['reply_id', 'hide'],
},
},
{
name: 'get_my_insights',
description: 'Get analytics and insights for your account',
inputSchema: {
type: 'object',
properties: {
metrics: {
type: 'array',
items: { type: 'string' },
description: 'Metrics to retrieve',
},
period: {
type: 'string',
enum: ['day', 'week', 'days_28', 'month', 'lifetime'],
description: 'Time period for metrics',
},
since: {
type: 'string',
description: 'ISO 8601 start date',
},
until: {
type: 'string',
description: 'ISO 8601 end date',
},
},
required: ['metrics'],
},
},
{
name: 'get_thread_insights',
description: 'Get performance metrics for your specific thread',
inputSchema: {
type: 'object',
properties: {
thread_id: {
type: 'string',
description: 'ID of your thread',
},
metrics: {
type: 'array',
items: { type: 'string' },
description: 'Metrics to retrieve',
},
period: {
type: 'string',
enum: ['day', 'week', 'days_28', 'month', 'lifetime'],
description: 'Time period for metrics',
},
},
required: ['thread_id', 'metrics'],
},
},
{
name: 'get_mentions',
description: 'Get threads where you are mentioned',
inputSchema: {
type: 'object',
properties: {
fields: {
type: 'array',
items: { type: 'string' },
description: 'Fields to retrieve from mentions',
},
limit: {
type: 'number',
description: 'Number of mentions to retrieve',
},
},
},
},
{
name: 'get_publishing_limit',
description: 'Check your current publishing quotas and limits',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'create_reply',
description: 'Reply to a specific thread/post',
inputSchema: {
type: 'object',
properties: {
reply_to_id: {
type: 'string',
description: 'ID of the thread/post to reply to',
},
text: {
type: 'string',
description: 'Reply text content',
},
media_type: {
type: 'string',
enum: ['TEXT', 'IMAGE', 'VIDEO'],
description: 'Type of media (default: TEXT)',
},
media_url: {
type: 'string',
description: 'URL of media to include (for IMAGE/VIDEO)',
},
reply_control: {
type: 'string',
enum: ['everyone', 'accounts_you_follow', 'mentioned_only', 'parent_post_author_only', 'followers_only'],
description: 'Who can reply to this reply',
},
},
required: ['reply_to_id', 'text'],
},
},
{
name: 'create_thread_chain',
description: 'Create a thread chain (multiple connected replies)',
inputSchema: {
type: 'object',
properties: {
parent_thread_id: {
type: 'string',
description: 'ID of the parent thread to start the chain',
},
replies: {
type: 'array',
items: {
type: 'object',
properties: {
text: { type: 'string' },
reply_control: { type: 'string', enum: ['everyone', 'accounts_you_follow', 'mentioned_only', 'parent_post_author_only', 'followers_only'] }
},
required: ['text']
},
description: 'Array of reply texts to create as a chain',
},
},
required: ['parent_thread_id', 'replies'],
},
},
{
name: 'quote_post',
description: 'Quote another thread/post with your own text',
inputSchema: {
type: 'object',
properties: {
quoted_post_id: {
type: 'string',
description: 'ID of the post to quote',
},
text: {
type: 'string',
description: 'Your quote text/commentary',
},
media_type: {
type: 'string',
enum: ['TEXT', 'IMAGE', 'VIDEO'],
description: 'Type of media (default: TEXT)',
},
media_url: {
type: 'string',
description: 'URL of media to include (for IMAGE/VIDEO)',
},
reply_control: {
type: 'string',
enum: ['everyone', 'accounts_you_follow', 'mentioned_only', 'parent_post_author_only', 'followers_only'],
description: 'Who can reply to this quote',
},
},
required: ['quoted_post_id', 'text'],
},
},
{
name: 'repost_thread',
description: 'Repost/share another thread',
inputSchema: {
type: 'object',
properties: {
post_id: {
type: 'string',
description: 'ID of the post to repost',
},
},
required: ['post_id'],
},
},
{
name: 'unrepost_thread',
description: 'Remove a repost you previously shared',
inputSchema: {
type: 'object',
properties: {
post_id: {
type: 'string',
description: 'ID of the post to unrepost',
},
},
required: ['post_id'],
},
},
{
name: 'like_post',
description: 'Like a thread/post',
inputSchema: {
type: 'object',
properties: {
post_id: {
type: 'string',
description: 'ID of the post to like',
},
},
required: ['post_id'],
},
},
{
name: 'unlike_post',
description: 'Remove like from a thread/post',
inputSchema: {
type: 'object',
properties: {
post_id: {
type: 'string',
description: 'ID of the post to unlike',
},
},
required: ['post_id'],
},
},
{
name: 'get_post_likes',
description: 'Get list of users who liked a post',
inputSchema: {
type: 'object',
properties: {
post_id: {
type: 'string',
description: 'ID of the post to get likes for',
},
limit: {
type: 'number',
description: 'Number of likes to retrieve',
},
},
required: ['post_id'],
},
},
{
name: 'create_post_with_restrictions',
description: 'Create post with advanced reply and audience restrictions',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The text content of the thread',
},
media_type: {
type: 'string',
enum: ['TEXT', 'IMAGE', 'VIDEO'],
description: 'Type of media (default: TEXT)',
},
media_url: {
type: 'string',
description: 'URL of media to include (for IMAGE/VIDEO)',
},
reply_control: {
type: 'string',
enum: ['everyone', 'accounts_you_follow', 'mentioned_only', 'parent_post_author_only', 'followers_only'],
description: 'Who can reply to this post',
},
audience_control: {
type: 'string',
enum: ['public', 'followers_only', 'close_friends'],
description: 'Who can see this post',
},
location_name: {
type: 'string',
description: 'Location name for location tagging',
},
hashtags: {
type: 'array',
items: { type: 'string' },
description: 'Array of hashtags to include (without #)',
},
mentions: {
type: 'array',
items: { type: 'string' },
description: 'Array of usernames to mention (without @)',
},
},
required: ['text'],
},
},
{
name: 'schedule_post',
description: 'Schedule a post to be published at a future time',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'The text content of the thread',
},
scheduled_publish_time: {
type: 'string',
description: 'ISO 8601 datetime when to publish (e.g., "2025-08-25T10:00:00+07:00")',
},
media_type: {
type: 'string',
enum: ['TEXT', 'IMAGE', 'VIDEO'],
description: 'Type of media (default: TEXT)',
},
media_url: {
type: 'string',
description: 'URL of media to include (for IMAGE/VIDEO)',
},
reply_control: {
type: 'string',
enum: ['everyone', 'accounts_you_follow', 'mentioned_only', 'parent_post_author_only', 'followers_only'],
description: 'Who can reply to this post',
},
location_name: {
type: 'string',
description: 'Location name for location tagging',
},
},
required: ['text', 'scheduled_publish_time'],
},
},
{
name: 'search_posts',
description: 'Search for posts using keywords',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search keyword or phrase',
},
search_type: {
type: 'string',
enum: ['TOP', 'RECENT'],
description: 'Search results order: TOP (popular) or RECENT (chronological)',
},
limit: {
type: 'number',
description: 'Number of results to return (max 100, default 25)',
},
since: {
type: 'string',
description: 'ISO 8601 date to search from',
},
until: {
type: 'string',
description: 'ISO 8601 date to search until',
},
},
required: ['query'],
},
},
{
name: 'search_mentions',
description: 'Search for posts that mention you or specific users',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to search mentions for (defaults to current user)',
},
limit: {
type: 'number',
description: 'Number of mentions to retrieve',
},
since: {
type: 'string',
description: 'ISO 8601 date to search from',
},
until: {
type: 'string',
description: 'ISO 8601 date to search until',
},
},
},
},
{
name: 'search_by_hashtags',
description: 'Search for posts by hashtag or topic tags',
inputSchema: {
type: 'object',
properties: {
hashtags: {
type: 'array',
items: { type: 'string' },
description: 'Hashtags to search for (without #)',
},
search_type: {
type: 'string',
enum: ['TOP', 'RECENT'],
description: 'Search results order',
},
limit: {
type: 'number',
description: 'Number of results to return',
},
},
required: ['hashtags'],
},
},
{
name: 'search_by_topics',
description: 'Search for posts by topic tags',
inputSchema: {
type: 'object',
properties: {
topics: {
type: 'array',
items: { type: 'string' },
description: 'Topic tags to search for',
},
search_type: {
type: 'string',
enum: ['TOP', 'RECENT'],
description: 'Search results order',
},
limit: {
type: 'number',
description: 'Number of results to return',
},
},
required: ['topics'],
},
},
{
name: 'get_trending_posts',
description: 'Get trending/popular posts in various categories',
inputSchema: {
type: 'object',
properties: {
category: {
type: 'string',
description: 'Trending category (optional)',
},
limit: {
type: 'number',
description: 'Number of trending posts to retrieve',
},
timeframe: {
type: 'string',
enum: ['hour', 'day', 'week'],
description: 'Trending timeframe',
},
},
},
},
{
name: 'search_users',
description: 'Search for users by username or display name',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Username or display name to search for',
},
limit: {
type: 'number',
description: 'Number of users to return',
},
},
required: ['query'],
},
},
{
name: 'get_user_followers',
description: 'Get followers list for a user',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to get followers for (defaults to current user)',
},
limit: {
type: 'number',
description: 'Number of followers to retrieve',
},
},
},
},
{
name: 'get_user_following',
description: 'Get following list for a user',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to get following for (defaults to current user)',
},
limit: {
type: 'number',
description: 'Number of following to retrieve',
},
},
},
},
{
name: 'follow_user',
description: 'Follow a user',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to follow',
},
},
required: ['user_id'],
},
},
{
name: 'unfollow_user',
description: 'Unfollow a user',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to unfollow',
},
},
required: ['user_id'],
},
},
{
name: 'block_user',
description: 'Block a user',
inputSchema: {
type: 'object',
properties: {
user_id: {
type: 'string',
description: 'User ID to block',
},
},
required: ['user_id'],
},
},
{
name: 'get_enhanced_insights',
description: 'Get advanced analytics including views, clicks, shares, and demographics',
inputSchema: {
type: 'object',
properties: {
thread_id: {
type: 'string',
description: 'Thread ID for media insights (optional for user insights)',
},
metrics: {
type: 'array',
items: { type: 'string' },
description: 'Metrics to retrieve: views, likes, replies, reposts, quotes, shares, clicks, followers_count, follower_demographics',
},
period: {
type: 'string',
enum: ['day', 'week', 'days_28', 'month', 'lifetime'],
description: 'Time period for insights',
},
breakdown: {
type: 'array',
items: {
type: 'string',
enum: ['country', 'city', 'age', 'gender']
},
description: 'Demographic breakdown options',
},
since: {
type: 'string',
description: 'ISO 8601 start date',
},
until: {
type: 'string',
description: 'ISO 8601 end date',
},
},
},
},
{
name: 'get_audience_demographics',
description: 'Get detailed audience demographic analysis',
inputSchema: {
type: 'object',
properties: {
breakdown_by: {
type: 'array',
items: {
type: 'string',
enum: ['country', 'city', 'age', 'gender']
},
description: 'Demographic categories to analyze',
},
period: {
type: 'string',
enum: ['day', 'week', 'days_28', 'month', 'lifetime'],
description: 'Time period for demographic data',
},
},
},
},
{
name: 'get_engagement_trends',
description: 'Analyze engagement patterns and trends over time',
inputSchema: {
type: 'object',
properties: {
metrics: {
type: 'array',
items: {
type: 'string',
enum: ['views', 'likes', 'replies', 'reposts', 'quotes', 'shares', 'clicks']
},
description: 'Engagement metrics to track',
},
timeframe: {
type: 'string',
enum: ['week', 'month', 'quarter'],
description: 'Analysis timeframe',
},
granularity: {
type: 'string',
enum: ['daily', 'weekly'],
description: 'Data point frequency',
},
},
},
},
{
name: 'get_follower_growth_analytics',
description: 'Track follower growth patterns and projections',
inputSchema: {
type: 'object',
properties: {
period: {
type: 'string',
enum: ['week', 'month', 'quarter', 'year'],
description: 'Growth analysis period',
},
include_projections: {
type: 'boolean',
description: 'Include growth projections based on trends',
},
},
},
},
{
name: 'analyze_best_posting_times',
description: 'AI-driven analysis of optimal posting times based on engagement',
inputSchema: {
type: 'object',
properties: {
analysis_period: {
type: 'string',
enum: ['month', 'quarter', 'year'],
description: 'Historical data period for analysis',
},
timezone: {
type: 'string',
description: 'Timezone for recommendations (e.g., "America/New_York")',
},
content_type: {
type: 'string',
enum: ['all', 'text', 'image', 'video'],
description: 'Content type to analyze',
},
},
},
},
{
name: 'get_content_performance_report',
description: 'Comprehensive performance report across all content',
inputSchema: {
type: 'object',
properties: {
report_type: {
type: 'string',
enum: ['summary', 'detailed', 'top_performers', 'underperformers'],
description: 'Type of performance report',
},
period: {
type: 'string',
enum: ['week', 'month', 'quarter'],
description: 'Report time period',
},
metrics: {
type: 'array',
items: { type: 'string' },
description: 'Metrics to include in report',
},
include_comparisons: {
type: 'boolean',
description: 'Include period-over-period comparisons',
},
},
},
},
// Phase 3B: Professional Content Creation & Automation
{
name: 'create_carousel_post',
description: 'Create multi-media carousel posts with up to 20 items (September 2024 update)',
inputSchema: {
type: 'object',
properties: {
media_urls: {
type: 'array',
items: { type: 'string' },
description: 'Array of image/video URLs for carousel (2-20 items supported)',
minItems: 2,
maxItems: 20,
},
text: {
type: 'string',
description: 'Post caption text',
},
alt_texts: {
type: 'array',
items: { type: 'string' },
description: 'Alt text for each media item (accessibility)',
},
carousel_settings: {
type: 'object',
properties: {
auto_alt_text: { type: 'boolean', description: 'Generate alt text automatically' },
aspect_ratio: { type: 'string', enum: ['square', 'portrait', 'landscape'], description: 'Preferred aspect ratio' },
thumbnail_selection: { type: 'string', enum: ['auto', 'first', 'custom'], description: 'Thumbnail selection method' },
},
},
},
required: ['media_urls', 'text'],
},
},
{
name: 'schedule_post',
description: 'Schedule posts with advanced automation and optimal timing',
inputSchema: {
type: 'object',
properties: {
text: {
type: 'string',
description: 'Post content',
},
media_url: {
type: 'string',
description: 'Optional media URL',
},
schedule_time: {
type: 'string',
description: 'ISO 8601 datetime for scheduling',
},
automation_settings: {
type: 'object',
properties: {
auto_optimize_time: { type: 'boolean', description: 'Automatically optimize posting time based on audience' },
recurring: { type: 'string', enum: ['none', 'daily', 'weekly', 'monthly'], description: 'Recurring schedule' },
auto_hashtags: { type: 'boolean', description: 'Automatically add relevant hashtags' },
content_variation: { type: 'boolean', description: 'Create slight variations for recurring posts' },
},
},
timezone: {
type: 'string',
description: 'Timezone for scheduling (e.g., America/New_York)',
},
},
required: ['text'],
},
},
{
name: 'auto_hashtag_suggestions',
description: 'AI-powered hashtag suggestions based on content analysis',
inputSchema: {
type: 'object',
properties: {
content: {
type: 'string',
description: 'Post content to analyze for hashtag suggestions',
},
media_url: {
type: 'string',
description: 'Optional media URL for visual analysis',
},
suggestion_settings: {
type: 'object',
properties: {
count: { type: 'number', description: 'Number of hashtag suggestions (1-10)', minimum: 1, maximum: 10 },
style: { type: 'string', enum: ['trending', 'niche', 'branded', 'mixed'], description: 'Hashtag style preference' },
exclude_overused: { type: 'boolean', description: 'Exclude overused hashtags' },
industry_focus: { type: 'string', description: 'Industry/niche to focus on' },
},
},
},
required: ['content'],
},
},
{
name: 'content_optimization_analysis',
description: 'Advanced content analysis with optimization recommendations',
inputSchema: {
type: 'object',
properties: {
content: {
type: 'string',
description: 'Content to analyze',
},
analysis_type: {
type: 'string',
enum: ['engagement', 'reach', 'accessibility', 'seo', 'comprehensive'],
description: 'Type of optimization analysis',
},
target_audience: {
type: 'object',
properties: {
demographics: { type: 'array', items: { type: 'string' }, description: 'Target demographic groups' },
interests: { type: 'array', items: { type: 'string' }, description: 'Target interests' },
timezone: { type: 'string', description: 'Primary audience timezone' },
},
},
optimization_goals: {
type: 'array',
items: { type: 'string', enum: ['increase_engagement', 'expand_reach', 'improve_accessibility', 'boost_shares', 'drive_traffic'] },
description: 'Optimization objectives',
},
},
required: ['content'],
},
},
{
name: 'bulk_post_management',
description: 'Manage multiple posts with bulk operations and analytics',
inputSchema: {
type: 'object',
properties: {
action: {
type: 'string',
enum: ['analyze_performance', 'bulk_edit', 'content_audit', 'export_data'],
description: 'Bulk operation to perform',
},
filters: {
type: 'object',
properties: {
date_range: { type: 'object', properties: { start: { type: 'string' }, end: { type: 'string' } } },
performance_threshold: { type: 'string', enum: ['low', 'medium', 'high'], description: 'Performance level filter' },
content_type: { type: 'string', enum: ['text', 'image', 'video', 'carousel'], description: 'Content type filter' },
engagement_range: { type: 'object', properties: { min: { type: 'number' }, max: { type: 'number' } } },
},
},
bulk_operations: {
type: 'object',
properties: {
add_hashtags: { type: 'array', items: { type: 'string' }, description: 'Hashtags to add to filtered posts' },
update_alt_text: { type: 'boolean', description: 'Update alt text for accessibility' },
archive_low_performers: { type: 'boolean', description: 'Archive underperforming posts' },
},
},
},
required: ['action'],
},
},
{
name: 'website_integration_setup',
description: 'Setup Threads integration for websites and external platforms',
inputSchema: {
type: 'object',
properties: {
integration_type: {
type: 'string',
enum: ['embed_feed', 'share_buttons', 'auto_crosspost', 'webhook_setup'],
description: 'Type of integration to setup',
},
website_config: {
type: 'object',
properties: {
domain: { type: 'string', description: 'Website domain' },
platform: { type: 'string', enum: ['wordpress', 'shopify', 'custom', 'react', 'vue', 'angular'], description: 'Website platform' },
styling_preferences: {
type: 'object',
properties: {
theme: { type: 'string', enum: ['light', 'dark', 'auto'] },
layout: { type: 'string', enum: ['grid', 'list', 'carousel'] },
post_count: { type: 'number', minimum: 1, maximum: 20 }
}
},
},
},
automation_settings: {
type: 'object',
properties: {
auto_sync: { type: 'boolean', description: 'Automatically sync new posts' },
crosspost_enabled: { type: 'boolean', description: 'Enable cross-posting from website' },
webhook_url: { type: 'string', description: 'Webhook endpoint URL' },
notification_settings: { type: 'object', properties: { email: { type: 'string' }, slack_webhook: { type: 'string' } } },
},
},
},
required: ['integration_type'],
},
},
// NEW: Token validation and diagnostics
{
name: 'validate_setup',
description: 'Validate access token, check scopes, and verify business account setup',
inputSchema: {
type: 'object',
properties: {
check_scopes: {
type: 'boolean',
description: 'Check if all required scopes are present',
default: true,
},
required_scopes: {
type: 'array',
items: { type: 'string' },
description: 'Custom list of required scopes to check',
},
},
},
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (!apiClient) {
apiClient = initializeClient();
}
const { name, arguments: args } = request.params;
try {
let result;
switch (name) {
case 'get_my_profile':
const { fields } = args;
const fieldsParam = fields?.join(',') || 'id,username,name,threads_profile_picture_url,threads_biography';
result = await apiClient.get('/me', { fields: fieldsParam });
break;
case 'get_my_threads':
const { fields: threadFields, limit, since, until } = args;
const threadsFields = threadFields?.join(',') || 'id,media_type,media_url,text,timestamp,permalink,username';
// Get current user ID first
const currentUser = await apiClient.get('/me', { fields: 'id' });
result = await apiClient.paginate(`/${currentUser.id}/threads`, {
fields: threadsFields,
limit: limit || 25,
since,
until,
});
break;
case 'publish_thread':
const { text, media_type, media_url, location_name } = args;
// Get current user ID first
const user = await apiClient.get('/me', { fields: 'id' });
// Build the proper container data based on media type
const containerData = {
media_type: media_type || 'TEXT',
};
// Add text if provided
if (text) {
containerData.text = text;
}
// Handle different media types with correct parameter names
if (media_type === 'IMAGE' && media_url) {
containerData.image_url = media_url; // Use image_url for images
}
else if (media_type === 'VIDEO' && media_url) {
containerData.video_url = media_url; // Use video_url for videos
}
else if (media_url && !media_type) {
// Auto-detect media type from URL
if (media_url.match(/\.(jpg|jpeg|png|gif|webp)$/i)) {
containerData.media_type = 'IMAGE';
containerData.image_url = media_url;
}
else if (media_url.match(/\.(mp4|mov|av