Skip to main content
Glama
selvin-paul-raj

Instagram MCP Server

Instagram MCP Server

A production-quality Model Context Protocol server that exposes Instagram actions (posts, media containers/carousels, comments, direct messages, insights, Messenger profile) to Claude and ChatGPT. Built for personal, single-user use with Composio as the auth/action layer, deployed on Alpic.

This project mirrors the sibling Linkedin-alpic-mcp server's architecture exactly — same stack, same production fixes, just scoped to Instagram's Composio toolkit.

Features

  • Curated tool scope — the Composio session and tool discovery are both scoped to exactly the 34 Instagram actions enabled for this account (see ENABLED_INSTAGRAM_TOOLS in src/composio_client.py), not every action Composio's Instagram toolkit could theoretically expose. Call instagram_mcp_list_tools to see the current live list with full JSON Schemas.

  • Automatic Instagram auth — on startup, checks whether the fixed user is connected; if not, starts the OAuth flow, logs the authorization URL, and waits (bounded timeout) for the connection to complete.

  • Structured logging — JSON logs via the stdlib logging module, best-effort rotating log file under logs/ (falls back to stdout-only on a read-only filesystem, e.g. serverless deploys).

  • Local stats tracking — total/successful/failed calls, average latency, last execution, startup time, and uptime; best-effort persistence to a local JSON file (falls back to in-memory-only if unwritable).

  • Health reportinginstagram_mcp_health reports server, Instagram connection, and Composio reachability.

  • Never crashes — every Composio/network/auth failure (including Composio's own PermissionDeniedError for a playground-key/user_id mismatch) is caught and returned as a normal (but error-flagged) tool result, never an unhandled exception.

  • Streamable-HTTP transport, binding PORT/HOST — ready for Alpic's hosting model.

Architecture

src/
├── server.py           # FastMCP app + entrypoint; wires everything together
├── composio_client.py  # Thin wrapper around the Composio SDK (Instagram toolkit only)
├── tool_registry.py    # Dynamic MCP tool list/dispatch: static utility tools + every Instagram action
├── config.py           # Settings loaded from environment / .env
├── logger.py           # Logging setup (best-effort file handler)
├── stats.py            # JSON-backed call statistics tracker (best-effort persistence)
├── health.py            # Health status aggregation
├── models.py             # Shared Pydantic models
└── utils.py              # Retry/backoff decorator, Timer

The four static tools (instagram_mcp_ping, instagram_mcp_health, instagram_mcp_version, instagram_mcp_list_tools) are always available. Every other tool name is a Composio Instagram action slug (e.g. INSTAGRAM_CREATE_POST, INSTAGRAM_GET_USER_INFO, INSTAGRAM_SEND_TEXT_MESSAGE, ...) — call instagram_mcp_list_tools at any time to see the current live list with descriptions.

Available Instagram Tools

The server's Composio session is scoped to exactly these 34 actions. Parameters below are best-effort, inferred from action names and the Instagram Graph API's conventions (this project's Composio account hadn't completed its Instagram connection yet at doc-writing time, so schemas weren't live-fetched the way the LinkedIn project's were) — call instagram_mcp_list_tools once connected to confirm exact fields.

Tool

Likely parameters

Use case

INSTAGRAM_CREATE_POST

image/video URL, caption

Publish a single-media feed post.

INSTAGRAM_CREATE_MEDIA_CONTAINER

media URL, caption, media type

Stage a single media item before publishing (required step before ..._PUBLISH).

INSTAGRAM_CREATE_CAROUSEL_CONTAINER

list of child media container IDs, caption

Stage a multi-image/video carousel post from already-created media containers.

INSTAGRAM_POST_IG_USER_MEDIA

media container params

Create IG user media (container-based posting flow).

INSTAGRAM_POST_IG_USER_MEDIA_PUBLISH

creation_id (container id)

Publish a previously staged media container (single or carousel).

INSTAGRAM_GET_POST_STATUS

container/media id

Check whether a staged container has finished processing and is ready to publish.

INSTAGRAM_GET_IG_MEDIA

media id

Get metadata for one media item (post).

INSTAGRAM_GET_IG_MEDIA_CHILDREN

carousel media id

List the individual media items inside a carousel post.

INSTAGRAM_GET_USER_MEDIA / INSTAGRAM_GET_IG_USER_MEDIA

ig user id, pagination

List media (posts) on an account, paginated.

INSTAGRAM_GET_IG_USER_STORIES

ig user id

List currently active stories for an account.

INSTAGRAM_GET_IG_USER_LIVE_MEDIA

ig user id

List currently live video sessions for an account.

INSTAGRAM_GET_IG_USER_TAGS

ig user id

List media where the account has been tagged.

INSTAGRAM_GET_IG_USER_CONTENT_PUBLISHING_LIMIT

ig user id

Check remaining publish quota (IG rate-limits posts per 24h).

INSTAGRAM_GET_POST_COMMENTS / INSTAGRAM_GET_IG_MEDIA_COMMENTS

media id, pagination

List comments on a post.

INSTAGRAM_POST_IG_MEDIA_COMMENTS

media id, comment text

Add a top-level comment to a post.

INSTAGRAM_REPLY_TO_COMMENT / INSTAGRAM_POST_IG_COMMENT_REPLIES

comment id, reply text

Reply to an existing comment.

INSTAGRAM_GET_IG_COMMENT_REPLIES

comment id, pagination

List replies to a comment.

INSTAGRAM_DELETE_COMMENT

comment id

Delete a comment or reply.

INSTAGRAM_GET_USER_INFO

(none — authenticated user)

Get your own connected account's profile info (username, id, account type).

INSTAGRAM_GET_USER_INSIGHTS

ig user id, metrics, period

Account-level insights (reach, impressions, follower demographics).

INSTAGRAM_GET_POST_INSIGHTS / INSTAGRAM_GET_IG_MEDIA_INSIGHTS

media id, metrics

Per-post insights (impressions, engagement, saves).

INSTAGRAM_LIST_ALL_CONVERSATIONS / INSTAGRAM_GET_PAGE_CONVERSATIONS

ig user id, pagination

List Instagram Direct conversations for the account.

INSTAGRAM_GET_CONVERSATION

conversation id

Get one conversation's message history.

INSTAGRAM_LIST_ALL_MESSAGES

conversation id, pagination

List messages within a conversation.

INSTAGRAM_SEND_TEXT_MESSAGE

recipient id, text

Send a text DM.

INSTAGRAM_SEND_IMAGE

recipient id, image URL

Send an image DM.

INSTAGRAM_MARK_SEEN

conversation/message id

Mark a DM/conversation as read.

INSTAGRAM_POST_IG_USER_MENTIONS

media id, comment/mention id

Handle a mention notification (e.g. tag reply flows).

INSTAGRAM_GET_MESSENGER_PROFILE

(none)

Get the account's Messenger platform profile config (greeting text, ice breakers, etc.).

INSTAGRAM_UPDATE_MESSENGER_PROFILE

profile fields to update

Update the Messenger platform profile config.

INSTAGRAM_DELETE_MESSENGER_PROFILE

field names to clear

Remove specific Messenger profile fields.

Installation

Requires Python 3.12+ and uv.

git clone <this-repo>
cd instagram-mcp
uv venv
uv pip install -e ".[dev]"

Configuration

Copy .env.example to .env and fill in your Composio credentials:

cp .env.example .env

Variable

Required

Default

Description

COMPOSIO_API_KEY

Yes

Your Composio API key. A project-scoped key, not a playground key — playground keys are locked to one bound user and will 403 on any other user_id.

COMPOSIO_USER_ID

Yes

Your Composio account's user id — tool calls and the Instagram connection are scoped to this user.

INSTAGRAM_AUTH_CONFIG_ID

No

Composio default

Use a specific Instagram auth config instead of the default one

LOG_LEVEL

No

INFO

DEBUG / INFO / WARNING / ERROR

LOG_DIR

No

logs

Directory for the rotating log file (best-effort — falls back to stdout-only if unwritable)

STATS_FILE

No

logs/stats.json

Path to the persisted stats JSON file (best-effort — falls back to in-memory-only if unwritable)

CONNECT_TIMEOUT_MS

No

300000 (5 min)

Max time to wait for Instagram OAuth to complete at startup

PORT

No

8000

Bind port (Alpic sets this automatically at deploy time)

COMPOSIO_CACHE_DIR

No (baked into Dockerfile)

Composio's SDK writes a cache dir at import time; set to a writable path (e.g. /tmp/.composio) on read-only-home sandboxes like Alpic's. Already set in Dockerfile.

Never hardcode COMPOSIO_API_KEY anywhere — it's read exclusively from the environment.

Running locally

uv run python -m src.server

On first run, if Instagram isn't connected yet, the server logs an authorization URL and waits for you to complete the OAuth flow in a browser before finishing startup (or continues anyway on timeout — the server never crashes on this, it just starts without a working connection until you finish the OAuth link).

Test it's alive — note streamable-HTTP requires the MCP handshake (initializenotifications/initialized → your call, all carrying the same mcp-session-id response header), a bare tools/call will fail with "Missing session ID". Also: on Windows PowerShell, bare curl is aliased to Invoke-WebRequest and will silently mangle -X/-d — use curl.exe explicitly, or Git Bash's real curl.

curl -s -X POST http://localhost:8000/mcp \
  -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

Running with Docker

docker build -t instagram-mcp .
docker run --rm -p 8000:8000 --env-file .env instagram-mcp

Deploying to Alpic

npm install -g alpic   # once
alpic login            # or set ALPIC_API_KEY

alpic environment-variable add --env-file .env --environment-id <id>
alpic deploy --runtime python3.13

Alpic prints the live MCP server URL and a /try playground URL on success. Note: Alpic's managed Python runtime does not use this repo's Dockerfile — it builds directly from pyproject.toml with its own buildpack, running out of a sandboxed home directory that's read-only. That's why COMPOSIO_CACHE_DIR, best-effort file logging, and best-effort stats persistence all exist in this codebase — they were required to get a Composio-based server running on Alpic at all (see Troubleshooting below).

Connecting from Claude Desktop

  1. Deploy first (or run locally and expose it, e.g. with ngrok http 8000).

  2. In Claude Desktop: Settings → Connectors → Add custom connector.

  3. Paste the Alpic-hosted MCP URL (ends in /mcp).

  4. Claude will list instagram_mcp_ping, instagram_mcp_health, and every enabled Instagram action.

Connecting from ChatGPT

  1. In ChatGPT: Settings → Connectors → Advanced settings → Developer mode (required for full custom tool calling, not just search/fetch).

  2. Add custom connector, paste the Alpic-hosted MCP URL.

  3. Enable the connector in a chat and ChatGPT can call any Instagram action directly.

Troubleshooting

Symptom

Likely cause

Fix

Server won't start / crashes immediately

COMPOSIO_API_KEY or COMPOSIO_USER_ID missing

Both are mandatory — set them before first deploy/run

403 ... user_id does not match the user this playground API key is locked to

You're using a Composio playground key

Mint a project-scoped API key in the Composio dashboard instead — playground keys are hard-locked to one bound user server-side, no client-side user_id can override that

Alpic build fails: Read-only file system: '/home/.../.composio'

Composio's SDK creates a cache dir at import time; Alpic's sandbox $HOME is read-only

Set COMPOSIO_CACHE_DIR=/tmp/.composio (already in this repo's Dockerfile, but Alpic ignores the Dockerfile for its managed Python runtime — add it as an Alpic environment variable too: alpic environment-variable add --name COMPOSIO_CACHE_DIR --value /tmp/.composio --environment-id <id>)

Alpic build fails: Read-only file system: '.../logs/instagram-mcp.log'

Same read-only-filesystem class of issue, this time our own log/stats file writes

Already fixed in this codebase (logger.py/stats.py both fall back gracefully) — if you still see this, you're running an older copy

instagram_mcp_health shows instagram_connected: false

OAuth never completed

Check server logs for the authorization URL, visit it, then call instagram_mcp_list_tools to refresh

instagram_mcp_health shows composio_reachable: false

Bad API key or Composio outage

Verify COMPOSIO_API_KEY is valid; check https://status.composio.dev

A Instagram tool call errors out

Expired auth, missing scope, or bad input

The error message is returned verbatim from Composio/Instagram in the tool result — read it, it's usually actionable

curl from PowerShell gives Not Acceptable: Client must accept text/event-stream despite the header being set

curl in PowerShell is aliased to Invoke-WebRequest, which silently sends GET instead of your intended POST

Use curl.exe explicitly, Invoke-RestMethod, or Git Bash's real curl

Testing

uv run pytest

License

MIT — see LICENSE.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/selvin-paul-raj/Instagram-Alpic-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server