InstantGram
Provides tools for interacting with Instagram's API, enabling AI agents to manage sessions, send direct messages (text and media), look up users, and configure webhooks.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@InstantGramSend an Instagram DM to username 'joe_bloggs' saying 'Happy birthday!'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
InstantGram
A TypeScript Node.js Instagram DM API server with webhook capabilities, an interactive + JSON CLI, an OpenAPI 3.1 spec, and an MCP server for AI agents.
⚠️ Disclaimer: This project uses the unofficial
instagram-private-apilibrary, which is not affiliated with or endorsed by Instagram/Meta. Automating Instagram accounts may violate their Terms of Service and can lead to temporary or permanent account restrictions. Use at your own risk — use only with accounts you own, and rate-limit yourself sensibly.
Features
Multi-session management — create, login, restore, delete, and export sessions in memory, persisted to disk
Login with 2FA — detects two-factor requirements and completes them via a verification code; handles checkpoints (auto-solve attempt + manual challenge URL fallback)
Custom User-Agent & proxy support (http/https/socks5)
Messaging API — send text and media (image/video) DMs to a username or numeric user id
User lookup — resolve usernames to user ids
Webhook system — poll the inbox for new DMs and POST HMAC-SHA256-signed events to your URL, with retries and exponential backoff on rate limits
Events:
message.received,message.sent,session.error,webhook.testAI-friendly surfaces —
/openapi.json(full OpenAPI 3.1 spec),/llms.txt+/llms-full.txtdocs, and a one-shot--jsonCLI modeMCP server — Model Context Protocol tools over stdio (
npm run mcp) or Streamable HTTP (/mcp), so AI assistants can create sessions, send DMs, and manage webhooksInteractive CLI — create/login sessions, run the full send-message wizard, configure webhooks, watch live webhook events, export/import sessions
Session persistence — serialized states (cookies + device) saved to
./sessions/*.session.jsonand auto-loaded on boot
Related MCP server: instagram-personal-mcp
Installation
# Node.js >= 18 required
npm install
# Configure environment
cp .env.example .env
# Start the API server (development, with hot reload)
npm run dev
# Or production:
npm run build && npm start
# Interactive CLI (in a second terminal):
npm run cliEnvironment variables (.env)
Variable | Default | Description |
|
| HTTP port for the API server |
| — | Secret used to sign webhook payloads ( |
|
| Default inbox poll interval in ms |
|
|
|
|
| Directory for persisted session states |
| — | Proxy for Instagram API traffic |
|
| Base URL the CLI, the JSON mode, and the stdio MCP server use to reach the API server |
| — | Bearer auth — if set, every request except |
| — | Fallback credentials for |
|
| Instagram app version fingerprint sent in the User-Agent. The library bundles an ancient version (222.x) that Instagram rejects with |
API Reference
All responses use a consistent envelope:
{
"success": true,
"data": { },
"meta": { "timestamp": "2026-08-09T12:00:00.000Z", "sessionId": "…" }
}Errors return { "success": false, "error": "…", "meta": { … } }.
Bearer auth (AUTH_TOKEN)
If AUTH_TOKEN is set in .env, the server rejects every request (except CORS OPTIONS preflights and the GET /health liveness probe) unless it carries the header:
Authorization: Bearer <AUTH_TOKEN>This is an opt-in kill-switch: set the variable to instantly lock down a publicly exposed instance with no code changes, unset it to return to open access. The interactive CLI, one-shot JSON mode, and stdio MCP bridge read AUTH_TOKEN from the same .env and send it automatically, so local workflows keep working. Unauthorized requests get 401 with the standard error envelope.
curl -s -X POST localhost:3000/api/session/create \
-H 'Authorization: Bearer <AUTH_TOKEN>' \
-H 'Content-Type: application/json' -d '{}'AI-friendly surfaces
Method | Route | Description |
|
| JSON service index — points agents at the endpoints below |
|
| Route-group index |
|
| Liveness probe ( |
|
| OpenAPI 3.1 document of every endpoint, schema, and error — the single machine-readable API contract |
|
| LLM-friendly documentation index (llms.txt convention) |
|
| Full markdown reference for LLM ingestion |
|
| MCP server over Streamable HTTP (see below) |
Sessions
Method | Route | Body | Description |
|
|
| Create a session; returns |
|
|
| Log in. If 2FA is required returns |
|
|
| Complete a pending 2FA login. For approval-based 2FA (verification method |
|
|
| Log out |
|
|
| Restore a session from exported JSON |
|
|
| Create a session from raw browser cookies (see below) |
|
| — | List all sessions with status |
|
| — | Single session details |
|
| — | Export serialized session (cookies + device) |
|
| — | Delete a session (stops polling too) |
Messages
Method | Route | Body / Query | Description |
|
|
| Send a DM. |
|
|
| Resolve a username to a numeric user id |
Webhooks
Method | Route | Body | Description |
|
|
| Set the delivery URL (and optional per-session signing secret) |
|
|
| Start inbox polling (min 1000 ms) |
|
|
| Stop polling |
|
|
| Send a synthetic |
|
| — | Polling state, URL, interval, last delivery |
|
|
| Recent delivery log entries |
Webhook payloads
Every event is POSTed to your URL as JSON:
{
"event": "message.received",
"timestamp": 1786298000000,
"sessionId": "8f0e9a2b-…",
"payload": {
"messageId": "340282366841710300949128155123748551874",
"threadId": "340282366841710300949128155123748551874",
"userId": "123456789",
"username": "someone",
"text": "Hey! 👋",
"itemType": "text"
}
}Field | Type | Description |
|
|
|
|
| Unix epoch ms |
|
| The session that produced the event |
|
| Instagram item id |
|
| Direct thread id |
|
| The other party's user id |
|
| Their username (when known) |
|
| Message text (text items) |
|
| CDN URL for media items (photo/video/voice/clip) |
|
| Raw Instagram item type |
|
| Error detail ( |
Signature verification
Each request carries an X-Webhook-Signature header:
X-Webhook-Signature: sha256=<hex-encoded HMAC-SHA256 of the raw request body>
X-Webhook-Event: message.receivedThe signature is computed with the WEBHOOK_SECRET (or the per-session secret configured via /api/webhook/configure).
Node.js receiver example:
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const secret = process.env.WEBHOOK_SECRET;
const expected = `sha256=${crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex')}`;
if (!crypto.timingSafeEqual(
Buffer.from(req.get('x-webhook-signature')),
Buffer.from(expected),
)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(req.body.toString());
console.log(`${event.event} from session ${event.sessionId}`, event.payload);
res.sendStatus(200);
});Use
express.raw()(or read the raw body) so the signature covers the exact bytes that were POSTed — re-serializing parsed JSON will break verification.
Python receiver example:
import hashlib, hmac, json
from flask import Flask, request
app = Flask(__name__)
SECRET = b"your-webhook-secret-here"
@app.post("/webhook")
def webhook():
body = request.get_data()
expected = "sha256=" + hmac.new(SECRET, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(request.headers.get("X-Webhook-Signature", ""), expected):
return {"error": "invalid signature"}, 401
print(json.loads(body))
return "ok", 200Restoring a session from raw browser cookies
No username/password required — paste the cookies you can copy from your browser's DevTools (Application → Cookies → i.instagram.com). Only sessionid is mandatory; csrftoken is strongly recommended (state-changing requests like sending messages need it). The user id is derived from the first segment of the sessionid value when ds_user_id isn't provided.
curl -s -X POST localhost:3000/api/session/restore-cookies -H 'Content-Type: application/json' -d '{
"cookies": "sessionid=38499037450%3ABX1JtIMMfeCui8%3A10%3AAYhKmCtPNU97naqRsPuZpCUA49KbUT4SsWi2KDPUgg; csrftoken=abc123; ds_user_id=38499037450; mid=xyz",
"userAgent": "Instagram 276.0.0.24.105 Android (30/11; 420dpi; 1080x2340; samsung; SM-G991B; o1s; exynos2100; en_US; 319462287)"
}'
# → { "success": true, "data": { "sessionId": "…", "userId": "38499037450", "status": "logged_in" }, … }A cookie-header string and a structured object are both accepted:
// structured form
{ "cookies": { "sessionid": "…", "csrftoken": "…", "ds_user_id": "…" } }The server verifies the cookies in the background (account.currentUser()); if Instagram rejects them (expired/invalid/flagged), the session status flips to error with an explanatory message — check GET /api/session. Cookies are bound to the device fingerprint, so passing the matching userAgent you copied from the browser helps keep the session alive.
CLI usage
npm run cliThe CLI is a self-contained tester that talks to the running API server (start it with npm run dev). Menu map:
Main menu
├── Session Management
│ ├── Create new session (custom UA / cookies / proxy)
│ ├── Login to session (auto-detects 2FA and prompts for the code)
│ ├── Complete 2FA login
│ ├── Restore session from JSON file
│ ├── Restore session from raw cookies
│ ├── List active sessions
│ ├── Logout from session
│ └── Delete session
├── Send Message (select session → recipient → text/media → confirm)
├── Webhook Management
│ ├── Configure webhook URL (URL + optional secret + event filter)
│ ├── Start polling (custom interval)
│ ├── Stop polling
│ ├── Send test webhook
│ ├── View webhook status
│ ├── View webhook logs
│ └── Watch live webhook events (press any key to return)
├── Utilities
│ ├── Lookup user ID from username
│ ├── Export session to file
│ └── Import session from file
└── ExitOne-shot JSON mode (AI / scripting friendly)
npm run cli -- <command> [--flag value ...] runs a single command and prints exactly one JSON document to stdout — nothing else — so output pipes straight into jq, shells, and AI tooling:
npm run cli -- list-sessions
# → {"success":true,"data":[{"id":"…","status":"logged_in",…}]}
npm run cli -- send-message --session-id <id> --recipient friend --text "hi"
# → {"success":true,"data":{"messageId":"…","threadId":"…","recipientUserId":"…","itemType":"text"}}Errors print { "success": false, "error": "…" } and exit with code 1. Credentials for login can come from INSTAGRAM_USERNAME / INSTAGRAM_PASSWORD to keep secrets out of shell history.
Commands: health, create-session, login, complete-2fa, logout, restore-session (--file), restore-cookies, list-sessions, session-info, export-session, delete-session, send-message, lookup-user, webhook-configure, webhook-start, webhook-stop, webhook-test, webhook-status, webhook-logs, help. Run npm run cli -- help for per-command flags.
MCP server (Model Context Protocol)
InstantGram speaks MCP so AI assistants can drive it directly — create/login sessions, send DMs, look up users, manage webhooks. Every REST endpoint is exposed as a tool, and the docs are available as resources.
Tools: create_session, login, complete_2fa, logout, restore_session, restore_cookies, list_sessions, session_info, export_session, delete_session, send_message, lookup_user, webhook_configure, webhook_start, webhook_stop, webhook_test, webhook_status, webhook_logs, health
Resources: instantgram://openapi.json, instantgram://llms-full.txt
stdio (Claude Desktop, Cursor, …)
The MCP server bridges to the running API server via API_BASE_URL — start the API with npm run dev first, then:
npm run mcpRegister it in claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"instantgram": {
"command": "npm",
"args": ["run", "mcp"],
"cwd": "/absolute/path/to/instantgram"
}
}
}Prefer a compiled entry? npm run build then point command at node dist/mcp.js.
HTTP (Streamable HTTP)
The API server hosts MCP at /mcp (CORS-enabled; stateful sessions use the Mcp-Session-Id header):
GET http://localhost:3000/mcp # initialize / SSE handshake
POST http://localhost:3000/mcp # JSON-RPC messages
DELETE http://localhost:3000/mcp # end the sessionPoint any MCP client (MCP Inspector, web apps, remote assistants) at http://localhost:3000/mcp.
Quick start (end-to-end)
# Terminal 1 — run the server
cp .env.example .env
npm install
npm run dev
# Terminal 2 — run the CLI
npm run cli
# From the CLI:
# 1. Session Management → Create new session → Login to session
# 2. (if 2FA) → enter code
# 3. Webhook Management → Configure webhook URL → Start polling
# 4. Send Message → pick session → recipient → text → confirm
# 5. Webhook Management → Watch live webhook eventsAlternatively, drive everything with curl:
# Create a session
curl -s -X POST localhost:3000/api/session/create -H 'Content-Type: application/json' \
-d '{"userAgent":"Instagram 347.0.0.25.106 Android (30/11; 420dpi; 1080x2340; samsung; SM-G991B; o1s; exynos2100; en_US; 441775334)"}'
# → {"success":true,"data":{"sessionId":"<id>"},...}
# Login
curl -s -X POST localhost:3000/api/session/login -H 'Content-Type: application/json' \
-d '{"sessionId":"<id>","username":"myaccount","password":"hunter2"}'
# Send a DM to a username
curl -s -X POST localhost:3000/api/message/send -H 'Content-Type: application/json' \
-d '{"sessionId":"<id>","recipient":"some.friend","text":"Hello from InstantGram!"}'
# Look up a user id
curl -s "localhost:3000/api/user/lookup/some.friend?sessionId=<id>"
# Configure a webhook and start polling
curl -s -X POST localhost:3000/api/webhook/configure -H 'Content-Type: application/json' \
-d '{"sessionId":"<id>","url":"https://your-server.example.com/webhook"}'
curl -s -X POST localhost:3000/api/webhook/start -H 'Content-Type: application/json' \
-d '{"sessionId":"<id>","intervalMs":5000}'
# Send media (base64 of a jpg) — use mediaType image/video
IMG_B64=$(base64 -i photo.jpg | tr -d '\n')
curl -s -X POST localhost:3000/api/message/send -H 'Content-Type: application/json' \
-d "{\"sessionId\":\"<id>\",\"recipient\":\"some.friend\",\"mediaBase64\":\"$IMG_B64\",\"mediaType\":\"image\"}"2FA methods
Instagram's two_factor_info.verification_method tells you which challenge was triggered:
Method | Type | What to do |
| SMS | Enter the code texted to your phone |
| Authenticator app (TOTP) | Enter the 6-digit code from your app |
| Approval from another device | A push notification appears on your logged-in phone — tap "It was me", then complete with an empty code ( |
| Backup codes | Enter one of your one-time backup codes |
The CLI detects method 2 automatically: it tells you to approve on your phone and completes the login without asking for a code.
⏱️ Approval pushes are short-lived (usually one or two minutes). Approve on your phone and confirm in the CLI promptly — if it expires, just run Login to session again to trigger a fresh push. Tapping a stale notification from an earlier login attempt always shows "expired"; use the one from the current attempt. Pending challenges older than 10 minutes are auto-cleared.
# Approval-based 2FA via the API (verificationMethod: 2 = approval push)
curl -s -X POST localhost:3000/api/session/2fa -H 'Content-Type: application/json' \
-d '{"sessionId":"<id>","code":"","verificationMethod":"2"}'Session persistence
After a successful login (or 2FA completion), the session's serialized state — cookies, device fingerprint, and constants — is written to SESSION_DIR (default ./sessions) as <sessionId>.session.json.
On server boot, every file in that directory is loaded back into memory, so sessions stay logged in across restarts without re-entering credentials.
Export:
GET /api/session/:id/exportor CLI Utilities → Export session to file. The exported JSON can be moved to another machine and restored withPOST /api/session/restoreor CLI Import session from file.Rotation: If Instagram invalidates a session (e.g. password change), delete the session and its file, then log in again.
🔒 Treat
sessions/like passwords — it contains live auth cookies. It is git-ignored by default.
How it works
Instagram has no public DM webhooks — this server polls
ig.feed.directInbox()on a configurable interval and diffs new item ids against a per-session seen-set.New incoming items become
message.receivedevents; outbound API sends becomemessage.sentevents; poll failures becomesession.errorevents.Each event is signed with HMAC-SHA256 and delivered with up to 3 retries (1s/2s/4s backoff). On rate-limit or network errors the poll interval backs off exponentially up to 5 minutes.
Sessions are isolated in memory (
Map<sessionId, InstagramService>), each with its own device fingerprint, cookies, proxy, and webhook config.
Error classification
Instagram errors are normalized into categories that map to HTTP statuses and retry behavior:
Category | Trigger | API response |
| Connection/parse failures |
|
| Bad password, invalid user, logged out |
|
| Action spam / too many requests |
|
|
|
|
| Checkpoint / unsupported version |
|
| Login-time flows | handled inline |
Why you might see
checkpoint_required/unsupported_version: the bundledinstagram-private-apireports an app version from ~2021 (222.0.0.13.114). Instagram flags that fingerprint. This project patches the version to347.0.0.25.106by default (overridable viaIG_APP_VERSION/IG_APP_VERSION_CODE, or derived from your custom User-Agent). If Instagram tightens checks again, bump those env values.
Project structure
src/
├── index.ts # Express server entry (wires services + routes)
├── cli.ts # Inquirer.js interactive CLI
├── cli-json.ts # One-shot JSON mode (AI / scripting friendly)
├── mcp.ts # MCP server entry (stdio bridge to the REST API)
├── openapi.ts # OpenAPI 3.1 document (served at /openapi.json)
├── types/index.ts # All shared interfaces
├── services/
│ ├── InstagramService.ts # IgApiClient wrapper (auth, messaging, polling)
│ ├── SessionManager.ts # Multi-session registry + disk persistence
│ └── WebhookService.ts # Polling, HMAC delivery, retries, logs
├── routes/
│ ├── session.ts # /api/session/*
│ ├── message.ts # /api/message/*, /api/user/lookup/*
│ └── webhook.ts # /api/webhook/*
├── mcp/
│ ├── apiClient.ts # Envelope-aware REST client (shared by MCP + JSON CLI)
│ ├── tools.ts # MCP tool definitions (one per REST endpoint)
│ └── http.ts # Streamable HTTP transport mounted at /mcp
└── utils/
├── api.ts # Response envelope helpers
├── crypto.ts # HMAC-SHA256 sign/verify
└── logger.ts # Leveled, colored loggingScripts
Script | Purpose |
| Run the API server with |
| Compile TypeScript to |
| Run the compiled server |
| Launch the interactive CLI |
| One-shot JSON mode (AI / scripting friendly) |
| Start the MCP server over stdio (requires the API server) |
| Type-check without emitting |
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityFmaintenanceAn MCP server that integrates with Instagram's Graph API to enable AI-driven management of Instagram Business accounts. It provides tools for fetching profile data, publishing media, analyzing engagement metrics, and managing direct messages.165MIT
- Alicense-qualityDmaintenanceAn MCP server that wraps instagrapi to read, engage, and send DMs from a personal Instagram account, supporting 24 tools for auth, profile, engagement, and messages.MIT
- AlicenseBqualityAmaintenanceA professional, full-fidelity MCP server enabling AI agents to fully control and manage an Instagram account exactly like a human user.683MIT
- AlicenseBqualityCmaintenanceMCP server that connects AI agents to Instagram for reading statistics, insights, and comments via the official Meta Graph API.16MIT
Related MCP Connectors
Remote MCP server for The Colony — a social network for AI agents (posts, DMs, search, marketplace).
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Managed LinkedIn MCP server for AI agents: search, connect, message and enrich on accounts you own.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/Houloude9IOfficial/InstantGram'
If you have feedback or need assistance with the MCP directory API, please join our Discord server