# meta-mcp

> Enables AI assistants to manage Instagram and Threads accounts — publish content, handle comments, view insights, search hashtags, and manage DMs through the Meta Graph API.

## Package

- npm: `@exileum/meta-mcp`
- Run: `npx @exileum/meta-mcp`
- GitHub: https://github.com/exileum/meta-mcp

## Environment Variables

- `INSTAGRAM_ACCESS_TOKEN` (for Instagram) — Instagram Graph API access token
- `INSTAGRAM_USER_ID` (for Instagram) — Instagram Business/Creator account ID (numeric string, or `"me"` for the authenticated user)
- `THREADS_ACCESS_TOKEN` (for Threads) — Threads API access token
- `THREADS_USER_ID` (for Threads) — Threads user ID (numeric string, or `"me"` for the authenticated user)
- `META_APP_ID` (for token/webhook tools) — Meta App ID (numeric string)
- `META_APP_SECRET` (for token/webhook tools) — Meta App Secret
- `META_API_VERSION` (optional) — Meta Graph API version for Instagram and Facebook endpoints, defaults to `v25.0` (format `vMAJOR.MINOR`; malformed values fall back to default with a stderr warning)
- `THREADS_API_VERSION` (optional) — Threads API version, defaults to `v1.0` (separate single-major-version track from the Graph API)
- `MCP_TRANSPORT` (optional) — transport to serve MCP over: `stdio` (default) or `http` (Streamable HTTP, for remote/multi-client/cloud deployments)
- `MCP_HTTP_PORT` (optional, http only) — TCP port for the HTTP transport, defaults to `3000` (integer 1–65535)
- `MCP_HTTP_HOST` (optional, http only) — bind address for the HTTP transport, defaults to `127.0.0.1` (loopback only); set `0.0.0.0` to expose it, only behind a TLS/auth reverse proxy
- `MCP_HTTP_ALLOWED_HOSTS` (optional, http only) — comma-separated `host:port` allowlist for DNS-rebinding protection; defaults to loopback variants at the bound port

Only set variables for the platforms you use. The server validates these at startup: malformed values for `INSTAGRAM_USER_ID`, `THREADS_USER_ID`, or `META_APP_ID` exit with `Invalid meta-mcp configuration: …`; setting only one half of a credential pair prints a stderr warning and continues.

## MCP Config

```json
{
  "mcpServers": {
    "meta": {
      "command": "npx",
      "args": ["-y", "@exileum/meta-mcp"],
      "env": {
        "INSTAGRAM_ACCESS_TOKEN": "your_ig_token",
        "INSTAGRAM_USER_ID": "your_ig_user_id",
        "THREADS_ACCESS_TOKEN": "your_threads_token",
        "THREADS_USER_ID": "your_threads_user_id"
      }
    }
  }
}
```

## Account Requirements

- Instagram: Business or Creator account (free to switch in settings)
- Threads: Any account
- Meta token/webhook tools: Meta Developer App

## Error Responses

Tool failures return `isError: true` and a JSON-encoded body in `content[0].text` with this shape: `{ error: true, error_type: "auth"|"validation"|"rate_limit"|"server"|"network"|"internal", http_status?, code?, subcode?, type?, step?, container_id?, message, remediation?, fbtrace_id?, raw }`. `remediation` is populated for `auth`, `rate_limit`, `server`, `network`. Categories map from Meta API HTTP status, error code/subcode (e.g., `190`/`OAuthException` → `auth`; `4`/`17`/`80001-80008` → `rate_limit`). On publish tools (`ig_publish_*`, `threads_publish_*`, `threads_reply`), `step` names the failing phase (`container creation` / `processing` / `publishing`; carousels also use `child …` and `parent …` prefixes) and `container_id` is set once a container has been created — branch on these to decide whether to retry, clean up, or reuse the container.

See [README.md "Troubleshooting"](https://github.com/exileum/meta-mcp#troubleshooting) for setup-time issues (expired tokens, account type, missing scopes, rate limits, "Messaging is not supported", wrong user-ID format).

## Tools (59)

### Meta Platform (6)
- meta_exchange_token — Exchange short-lived token for long-lived (~60 days). Requires `platform` (instagram or threads). On success the new token is also auto-applied in-memory to the running server, so subsequent tool calls use it without restart
- meta_refresh_token — Refresh a long-lived token before expiration. Requires `platform` (instagram or threads). On success the new token is also auto-applied in-memory to the running server, so subsequent tool calls use it without restart
- meta_debug_token — Inspect token validity, expiration, and scopes
- meta_get_app_info — Get Meta App information
- meta_subscribe_webhook — Subscribe to webhook notifications
- meta_get_webhook_subscriptions — List current webhook subscriptions

### Instagram — Publishing (6)
- ig_publish_photo — Publish a photo post (supports alt_text, collaborators)
- ig_publish_video — [DEPRECATED] Use ig_publish_reel instead; publishes as a Reel (legacy VIDEO media_type retired by Meta Nov 9, 2023; supports collaborators)
- ig_publish_carousel — Publish a carousel/album (2-10 items, alt_text per IMAGE item, collaborators)
- ig_publish_reel — Publish a Reel (supports collaborators)
- ig_publish_story — Publish a Story (24hr)
- ig_get_container_status — Check media container processing status

### Instagram — Media (5)
- ig_get_media_list — List published media
- ig_get_media — Get media details
- ig_delete_media — Delete a media post (Facebook Login only)
- ig_get_media_insights — Get media analytics (default views, reach — override `metric` per media type)
- ig_toggle_comments — Enable/disable comments on a post

### Instagram — Comments (7)
- ig_get_comments — Get comments on a post
- ig_get_comment — Get comment details
- ig_post_comment — Post a comment
- ig_get_replies — Get replies to a comment
- ig_reply_to_comment — Reply to a comment
- ig_hide_comment — Hide/unhide a comment
- ig_delete_comment — Delete a comment

### Instagram — Profile & Insights (5)
- ig_get_profile — Get account profile info
- ig_get_account_insights — Get account-level analytics (views, reach, follower_count). Optional `metric_type` (`total_value` or `time_series`) controls aggregation shape
- ig_business_discovery — Look up another business account
- ig_get_collaboration_invites — Get pending collaboration invites
- ig_respond_collaboration_invite — Accept/decline a collaboration invite by media_id

### Instagram — Hashtags (4)
- ig_search_hashtag — Search hashtag by name
- ig_get_hashtag — Get hashtag info
- ig_get_hashtag_recent — Get recent media for a hashtag
- ig_get_hashtag_top — Get top media for a hashtag

### Instagram — Mentions & Tags (2)
- ig_get_mentioned_comment — Get details of a specific comment mentioning you (by comment_id from a mention webhook)
- ig_get_tagged_media — Get media you're tagged in

### Instagram — Messaging (4)
- ig_get_conversations — List DM conversations
- ig_get_messages — Get messages in a conversation
- ig_send_message — Send a DM (optional messaging_type=RESPONSE/UPDATE/MESSAGE_TAG; tag=HUMAN_AGENT extends the messaging window to 7 days for human-sent support replies)
- ig_get_message — Get message details

### Threads — Publishing (9)
- threads_publish_text — Publish text post in a single API call by default (auto_publish_text=true; set auto_publish=false for legacy two-step flow). Supports polls, GIFs, link attachments, topic tags, quote, spoiler, cross-share to IG Stories, geo-gating via allowlisted_country_codes, location tagging via location_id, text attachments up to 10K chars with styling
- threads_publish_image — Publish image post (alt_text, topic tags, spoiler, cross-share to IG Stories, geo-gating via allowlisted_country_codes, location tagging via location_id)
- threads_publish_video — Publish video post (alt_text, topic tags, spoiler, cross-share to IG Stories, geo-gating via allowlisted_country_codes, location tagging via location_id)
- threads_publish_carousel — Publish carousel (2-20 items, alt_text per item, cross-share to IG Stories, geo-gating via allowlisted_country_codes and location tagging via location_id on the parent container)
- threads_delete_post — Delete a post (max 100/day)
- threads_get_container_status — Check container processing status (unpublished containers only)
- threads_get_publishing_limit — Check remaining quota (250 posts/day)
- threads_repost — Repost an existing thread to your profile (requires threads_content_publish)
- threads_search_locations — Search Threads-supported locations by query (q) or coordinates (latitude+longitude) to obtain a location_id for the four threads_publish_* tools (requires threads_location_tagging permission)

### Threads — Media & Search (3)
- threads_get_posts — List published posts (optional `fields` to override the default field list)
- threads_get_post — Get post details
- threads_search_posts — Search public posts by keyword or tag (requires threads_keyword_search permission)

### Threads — Replies (4)
- threads_get_replies — Get replies to a post (mode='top_level' default, or mode='full_tree' for the entire conversation flattened)
- threads_reply — Reply to a post. Text-only replies publish in a single API call by default (auto_publish_text=true); media replies (image/video) use the two-step flow
- threads_hide_reply — Hide a reply
- threads_unhide_reply — Unhide a reply

### Threads — Mentions (1)
- threads_get_mentions — Posts where the user was @mentioned (requires threads_manage_mentions)

### Threads — Profile (1)
- threads_get_profile — Get Threads profile info (includes is_verified and is_eligible_for_geo_gating)

### Threads — Insights (2)
- threads_get_post_insights — Post analytics (views, likes, replies, reposts, quotes, shares)
- threads_get_user_insights — Account-level analytics (period: day/lifetime)

## Resources
- meta-mcp://instagram/profile — Instagram account profile data
- meta-mcp://threads/profile — Threads account profile data

## Prompts
- content_publish — Cross-post content to Instagram and Threads. Optional args: platform (instagram|threads|both), content_type (text|image|video|carousel), media_url, caption
- analytics_report — Generate combined analytics report. Optional args: platform (instagram|threads|both), time_range (7d|30d|90d), focus (engagement|growth|content)
