InstantGram

InstantGram

MCP server that enables AI agents to interact with Instagram DMs by managing sessions, sending messages, and configuring webhooks through the InstantGram API.

Category
访问服务器

README

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-api library, 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.test
  • AI-friendly surfaces — /openapi.json (full OpenAPI 3.1 spec), /llms.txt + /llms-full.txt docs, and a one-shot --json CLI mode
  • MCP server — Model Context Protocol tools over stdio (npm run mcp) or Streamable HTTP (/mcp), so AI assistants can create sessions, send DMs, and manage webhooks
  • Interactive 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.json and auto-loaded on boot

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 cli

Environment variables (.env)

Variable Default Description
PORT 3000 HTTP port for the API server
WEBHOOK_SECRET — Secret used to sign webhook payloads (X-Webhook-Signature header)
DEFAULT_POLL_INTERVAL 5000 Default inbox poll interval in ms
LOG_LEVEL info debug | info | warn | error
SESSION_DIR ./sessions Directory for persisted session states
HTTP_PROXY / per-session proxy — Proxy for Instagram API traffic
API_BASE_URL http://localhost:3000 Base URL the CLI, the JSON mode, and the stdio MCP server use to reach the API server
AUTH_TOKEN — Bearer auth — if set, every request except OPTIONS preflights and GET /health must send Authorization: Bearer <AUTH_TOKEN>. Opt-in kill-switch for locking down a public instance; CLI/JSON/stdio-MCP attach it automatically from the same .env
INSTAGRAM_USERNAME / INSTAGRAM_PASSWORD — Fallback credentials for npm run cli -- login (keeps secrets out of shell history)
IG_APP_VERSION / IG_APP_VERSION_CODE 347.0.0.25.106 / 441775334 Instagram app version fingerprint sent in the User-Agent. The library bundles an ancient version (222.x) that Instagram rejects with unsupported_version/checkpoint_required — bump these if sessions start getting flagged

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
GET / JSON service index — points agents at the endpoints below
GET /api Route-group index
GET /health Liveness probe ({ status, uptime, sessions })
GET /openapi.json OpenAPI 3.1 document of every endpoint, schema, and error — the single machine-readable API contract
GET /llms.txt LLM-friendly documentation index (llms.txt convention)
GET /llms-full.txt Full markdown reference for LLM ingestion
GET / POST / DELETE /mcp MCP server over Streamable HTTP (see below)

Sessions

Method Route Body Description
POST /api/session/create { userAgent?, cookies?, proxy? } Create a session; returns { sessionId }
POST /api/session/login { sessionId, username, password } Log in. If 2FA is required returns data.twoFactor; if a checkpoint is hit returns data.challenge
POST /api/session/2fa { sessionId, code, verificationMethod? } Complete a pending 2FA login. For approval-based 2FA (verification method 2 — a push to your phone, no code) send code: "" after approving on the device. Pass verificationMethod when Instagram didn't report it
POST /api/session/logout { sessionId } Log out
POST /api/session/restore { data: SerializedSessionFile, preferredId? } Restore a session from exported JSON
POST /api/session/restore-cookies { cookies, userAgent?, proxy? } Create a session from raw browser cookies (see below)
GET /api/session — List all sessions with status
GET /api/session/:id — Single session details
GET /api/session/:id/export — Export serialized session (cookies + device)
DELETE /api/session/:id — Delete a session (stops polling too)

Messages

Method Route Body / Query Description
POST /api/message/send { sessionId, recipient, text?, mediaBase64?, mediaType? } Send a DM. recipient may be a username or numeric user id. mediaBase64 is base64-encoded file data; mediaType is image | video (auto-detected from bytes if omitted)
GET /api/user/lookup/:username ?sessionId=… Resolve a username to a numeric user id

Webhooks

Method Route Body Description
POST /api/webhook/configure { sessionId, url, secret?, events? } Set the delivery URL (and optional per-session signing secret)
POST /api/webhook/start { sessionId, intervalMs? } Start inbox polling (min 1000 ms)
POST /api/webhook/stop { sessionId } Stop polling
POST /api/webhook/test { sessionId } Send a synthetic webhook.test event through the full pipeline
GET /api/webhook/status/:sessionId — Polling state, URL, interval, last delivery
GET /api/webhook/logs/:sessionId ?limit=50 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
event string message.received | message.sent | session.error | webhook.test
timestamp number Unix epoch ms
sessionId string The session that produced the event
payload.messageId string Instagram item id
payload.threadId string Direct thread id
payload.userId string The other party's user id
payload.username string Their username (when known)
payload.text string Message text (text items)
payload.mediaUrl string CDN URL for media items (photo/video/voice/clip)
payload.itemType string Raw Instagram item type
payload.error string Error detail (session.error events)

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.received

The 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", 200

Restoring 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 cli

The 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
└── Exit

One-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 mcp

Register 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 session

Point 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 events

Alternatively, 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
0 SMS Enter the code texted to your phone
1 Authenticator app (TOTP) Enter the 6-digit code from your app
2 Approval from another device A push notification appears on your logged-in phone — tap "It was me", then complete with an empty code (code: "")
3 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/export or CLI Utilities → Export session to file. The exported JSON can be moved to another machine and restored with POST /api/session/restore or 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

  1. 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.
  2. New incoming items become message.received events; outbound API sends become message.sent events; poll failures become session.error events.
  3. 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.
  4. 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
network Connection/parse failures 502
auth Bad password, invalid user, logged out 401
rate_limit Action spam / too many requests 429 (+ poll backoff)
not_found searchExact miss 404
challenge Checkpoint / unsupported version 403 (with solve URL)
two_factor Login-time flows handled inline

Why you might see checkpoint_required / unsupported_version: the bundled instagram-private-api reports an app version from ~2021 (222.0.0.13.114). Instagram flags that fingerprint. This project patches the version to 347.0.0.25.106 by default (overridable via IG_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 logging

Scripts

Script Purpose
npm run dev Run the API server with tsx watch (hot reload)
npm run build Compile TypeScript to dist/
npm start Run the compiled server
npm run cli Launch the interactive CLI
npm run cli -- <cmd> One-shot JSON mode (AI / scripting friendly)
npm run mcp Start the MCP server over stdio (requires the API server)
npm run typecheck Type-check without emitting

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选