Instagram MCP Server
Exposes Instagram actions (posts, media, comments, DMs, insights, Messenger profile) to Claude and ChatGPT via MCP.
README
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_TOOLSinsrc/composio_client.py), not every action Composio's Instagram toolkit could theoretically expose. Callinstagram_mcp_list_toolsto 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
loggingmodule, best-effort rotating log file underlogs/(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 reporting —
instagram_mcp_healthreports server, Instagram connection, and Composio reachability. - Never crashes — every Composio/network/auth failure (including Composio's own
PermissionDeniedErrorfor 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 (initialize →
notifications/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
- Deploy first (or run locally and expose it, e.g. with
ngrok http 8000). - In Claude Desktop: Settings → Connectors → Add custom connector.
- Paste the Alpic-hosted MCP URL (ends in
/mcp). - Claude will list
instagram_mcp_ping,instagram_mcp_health, and every enabled Instagram action.
Connecting from ChatGPT
- In ChatGPT: Settings → Connectors → Advanced settings → Developer mode (required for full custom tool calling, not just search/fetch).
- Add custom connector, paste the Alpic-hosted MCP URL.
- 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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。