Instagram MCP Server
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., "@Instagram MCP ServerShow my engagement insights for this week"
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.
📸 Instagram MCP Server
A production-ready Remote MCP (Model Context Protocol) Server that gives Claude direct, tool-based access to your Instagram Business account through the Meta Graph API — profile data, posts, comments, publishing, insights, analytics, hashtags, messaging, and real-time webhooks.
Built with TypeScript, Node.js, Express, and the official
@modelcontextprotocol/sdk.
Table of Contents
What this is (and isn't)
This project is a real, working integration between Claude and the Instagram Graph API for Professional (Business/Creator) accounts. It is not a wrapper around the consumer Instagram app, and it cannot do anything the Graph API itself doesn't support. Where Meta's API has a real limitation (no follower-list endpoint, no general story-history endpoint, no competitor-audience data), this server surfaces a clear error explaining the limitation instead of fabricating data — see Known API Limitations.
You need:
An Instagram Professional account (Business or Creator)
Linked to a Facebook Page
A Meta Developer App with the Instagram Graph API product added
Features / Tool Reference
Every feature is exposed as an MCP tool Claude can call directly.
Category | Tools |
Profile |
|
Media |
|
Comments |
|
Publishing |
|
Insights |
|
Analytics |
|
Messaging |
|
Hashtags |
|
Business |
|
Webhooks |
|
* getStories and competitorAnalysis intentionally return an explanatory
error — see Known API Limitations.
54 tools total. Run the server and call tools/list over MCP, or see
examples/api-requests.md, for the live list.
Architecture
instagram-mcp/
├── src/
│ ├── index.ts # process bootstrap (listen, graceful shutdown)
│ ├── server.ts # Express app assembly (middleware + routes)
│ ├── config/ # env validation (Zod) + constants
│ ├── routes/ # /mcp, /auth, /webhooks, /health
│ ├── controllers/ # OAuth setup controller
│ ├── services/
│ │ ├── graph/ # low-level Graph API HTTP client (auth, retries, error mapping)
│ │ └── instagram/ # profile, media, comments, publishing, insights, analytics, hashtags, messaging, business discovery
│ ├── mcp/
│ │ ├── mcpServer.ts # McpServer factory — registers every tool
│ │ └── tools/ # one file per tool category (Zod schemas + handlers)
│ ├── middlewares/ # auth, rate limiting, validation, error handling, logging
│ ├── utils/ # logger, errors, cache, retry, crypto
│ ├── types/ # shared TypeScript types
│ ├── auth/ # OAuth token exchange logic
│ ├── storage/ # encrypted-at-rest token store
│ └── webhooks/ # signature verification + event router
├── tests/
│ ├── unit/ # crypto, retry, cache, service-level (mocked via nock)
│ └── integration/ # full Express app via supertest
├── examples/ # sample MCP config + curl requests
├── Dockerfile / docker-compose.yml
├── render.yaml / railway.json / fly.toml
└── .github/workflows/ci.ymlDesign choices worth knowing about:
The Remote MCP endpoint (
POST /mcp) uses the SDK's stateless Streamable HTTP transport — a freshMcpServer+ transport pair per request. This makes the server trivially horizontally scalable. It does not support server-initiated push over a long-lived connection; use the polling-stylegetRecentMentions/getRecentCommentEventstools (fed by the webhook listener) instead.Tokens are encrypted at rest with AES-256-GCM using a key derived from
TOKEN_ENCRYPTION_KEY.All Graph API calls go through a single
GraphClientthat addsappsecret_proof, retries transient/rate-limited failures with backoff, and normalizes Meta's error shapes into typedAppErrorsubclasses.Analytics like "best posting time" and "compare posts" are computed locally from real data pulled via Graph API primitives — Meta does not expose these as first-class endpoints.
Quick Start
git clone <this-repo-url> instagram-mcp
cd instagram-mcp
npm install
cp .env.example .env
# edit .env with your Meta App credentials (see below)
npm run devServer starts on http://localhost:3000. Health check:
curl http://localhost:3000/health.
Meta App Setup
1. Create a Meta App
Go to https://developers.facebook.com/apps → Create App.
Choose type Business.
In the App Dashboard, add the Instagram Graph API product (search "Instagram" in "Add Product").
Note your App ID and App Secret (Settings → Basic) — these go in
META_APP_ID/META_APP_SECRET.
2. Link a Facebook Page + Instagram Business Account
The Instagram Graph API only works through a Facebook Page connection:
Convert your Instagram account to a Professional Account (Business or Creator) in the Instagram app: Settings → Account type.
Create or use an existing Facebook Page.
Link them: Instagram app → Settings → Account → Linked accounts → Facebook, or Facebook Page → Settings → Instagram → Connect Account.
Note the Facebook Page ID (Page → About → Page ID), used as
FACEBOOK_PAGE_ID.
3. Generate an Access Token
Option A — Graph API Explorer (fastest for personal use):
Select your app, select your Page, and add the permissions listed below.
Generate a User Access Token, then exchange it for a long-lived token (~60 days) using:
curl -G "https://graph.facebook.com/v21.0/oauth/access_token" \ -d "grant_type=fb_exchange_token" \ -d "client_id=$META_APP_ID" \ -d "client_secret=$META_APP_SECRET" \ -d "fb_exchange_token=$SHORT_LIVED_TOKEN"Put the resulting token in
IG_LONG_LIVED_ACCESS_TOKEN.Find your Instagram Business Account ID:
curl -G "https://graph.facebook.com/v21.0/$FACEBOOK_PAGE_ID" \ -d "fields=instagram_business_account" \ -d "access_token=$IG_LONG_LIVED_ACCESS_TOKEN"Put the returned
idinIG_BUSINESS_ACCOUNT_ID.
This is the simplest path for a single-account, self-hosted deployment — set
those three env vars and skip the /auth/* OAuth endpoints entirely.
Option B — Full OAuth flow (multi-user / production apps):
Set
META_REDIRECT_URItohttps://your-domain.com/auth/callbackand add it as a Valid OAuth Redirect URI in the Meta App Dashboard (Facebook Login product → Settings).GET /auth/authorizereturns a URL — open it in a browser, approve the permissions.Meta redirects to
/auth/callback, which exchanges the code for a long-lived token and stores it encrypted automatically.GET /auth/statusconfirms the connection.
4. Permissions & App Review
Required scopes (already requested by buildAuthorizationUrl):
instagram_basic
instagram_manage_insights
instagram_manage_comments
instagram_content_publish
instagram_manage_messages
pages_show_list
pages_read_engagement
pages_manage_metadata
business_managementFor personal/self-use on your own account, most of these work in Development
Mode with your own account added as a Test User — no App Review needed.
To let other Instagram accounts authorize your app, Meta requires App
Review for instagram_manage_comments, instagram_content_publish,
instagram_manage_messages, and instagram_manage_insights.
Configuration
See .env.example for the full, documented list. Key
variables:
Variable | Required | Description |
| ✅ | From your Meta App dashboard |
| ✅ | ≥32 chars, encrypts tokens at rest |
| Option A | Skip OAuth entirely |
| Option B | Needed only for the |
| Recommended | Bearer token required to call |
| Optional | Needed for real-time webhooks |
The server refuses to start if required variables are missing or malformed (validated with Zod on boot) — check the console output for the exact field that failed.
Running Locally
npm install
npm run dev # tsx watch mode
# or
npm run build && npm start # production buildOther scripts: npm run lint, npm run format, npm run typecheck,
npm test, npm run test:coverage.
Deployment
Docker
docker build -t instagram-mcp-server .
docker run -p 3000:3000 --env-file .env -v $(pwd)/data:/app/data instagram-mcp-serverOr with Compose:
docker compose up -d --buildRender
Push this repo to GitHub.
In Render: New → Blueprint, point at your repo —
render.yamlis auto-detected.Fill in the secret env vars flagged
sync: falsein the Render dashboard.Deploy. Your Remote MCP URL will be
https://<your-service>.onrender.com/mcp.
Railway
railway init
railway uprailway.json configures the Dockerfile build and health check
automatically. Set env vars via railway variables set KEY=value or the
dashboard.
Fly.io
fly launch --no-deploy # detects fly.toml
fly secrets set META_APP_ID=... META_APP_SECRET=... TOKEN_ENCRYPTION_KEY=... MCP_AUTH_TOKEN=...
fly deploySelf-host (bare metal / VM)
npm ci --omit=dev
npm run build
NODE_ENV=production node dist/index.jsPut it behind a reverse proxy (nginx/Caddy) for TLS termination — Claude's Remote MCP requires HTTPS in production.
Connecting Claude
Once deployed with a public HTTPS URL:
In claude.ai: Settings → Connectors → Add custom connector.
Enter your MCP URL:
https://your-domain.com/mcp.If you set
MCP_AUTH_TOKEN, add it as a Bearer token / custom header (Authorization: Bearer <token>) in the connector's auth settings.Claude will call
initializeandtools/listautomatically and the Instagram tools become available in your conversation.
For Claude Desktop or other MCP clients that read a JSON config file, see
examples/claude-mcp-config.json.
See examples/api-requests.md for raw
curl-based examples of the MCP JSON-RPC protocol if you want to test
independent of Claude.
Webhooks (real-time updates)
To receive comments/mentions in near-real-time instead of polling:
Set
META_WEBHOOK_VERIFY_TOKENto a random string.In the Meta App Dashboard → Webhooks → Instagram, subscribe to
comments,mentions(and others as needed) with callback URLhttps://your-domain.com/webhooksand the same verify token.Meta will
GET /webhooksonce to verify (handled automatically), thenPOST /webhookson every event.Call the
getRecentMentions/getRecentCommentEventsMCP tools to read the most recent events received (kept in an in-memory ring buffer — swap for persistent storage if you need durability across restarts).
Testing
npm test # everything
npm run test:unit # unit tests (crypto, retry, cache, services via nock mocks)
npm run test:integration # full Express app via supertest, including a live MCP handshake
npm run test:coverage27 tests ship with the project, covering encryption round-trips, retry/backoff
logic, caching, comment/publishing service behavior against a mocked Graph
API, and an end-to-end MCP initialize handshake against the real app.
Security Notes
Tokens are never logged (redacted in the pino logger config) and are encrypted at rest with AES-256-GCM.
.envis git-ignored; only.env.example(no real secrets) is committed.appsecret_proofis sent on every Graph API call by default (META_APP_SECRET_PROOF=true) to prevent token replay if a token leaks.Webhook payloads are (optionally) signature-verified against
X-Hub-Signature-256using your App Secret — wireverifySignatureintowebhookRoutes.tsif you want to reject unsigned/forged payloads outright (currently logged; enable strict rejection for production hardening).Set
MCP_AUTH_TOKENin any environment reachable from the public internet.
Known API Limitations
The Instagram Graph API does not support everything a full "clone" of the Instagram app would need. This server is honest about it:
Requested feature | Reality |
List of follower/following usernames | Not exposed — only aggregate counts, for user privacy. |
Reading Stories | Only stories this app itself published are readable, and only within 24h. No general story-history endpoint exists. |
Competitor analysis (ads, demographics, audience overlap) | Business Discovery exposes only public profile/media stats of other accounts — nothing beyond what's visible on their public profile. |
Native "schedule for later" | No such flag exists on the Graph API; this server creates the container immediately and defers the |
DM automation outside the 24h window | Meta restricts free-form messaging to a 24-hour window after the user last messaged you, or requires approved message tags — this is a platform policy, not a limitation of this code. |
Troubleshooting
"Environment validation failed" on startup Check the console output — it lists exactly which env var is missing/invalid.
AuthenticationError: Instagram access token is invalid or expired
Long-lived tokens last ~60 days. Call POST /auth/refresh, or re-run the
Graph API Explorer token exchange and update IG_LONG_LIVED_ACCESS_TOKEN.
GraphApiError with code 100 on publishing
Usually means the media URL isn't publicly reachable/valid, or the account
lacks instagram_content_publish permission.
Rate limit errors (RateLimitError)
The client retries automatically with backoff; if it persists, you're
hitting Meta's per-app/per-user call limits — space out requests or wait.
Claude can't connect to /mcp
Confirm the URL is HTTPS and publicly reachable, and that any
MCP_AUTH_TOKEN you configured matches exactly what's set in Claude's
connector settings.
FAQ
Do I need App Review to use this on my own account? No — Development Mode + adding your own account as a Test User is enough for personal use of all read/write tools.
Can this manage multiple Instagram accounts?
The current token store holds one account's credentials. For multi-account
support, extend TokenStore to key by account ID and add an accountId
parameter to the relevant tools.
Does this work with Creator accounts, not just Business? Yes — the Graph API treats Business and Creator accounts the same way for these endpoints.
Is there a database?
No — token storage is a single encrypted JSON file by default, so the
project runs anywhere without provisioning infrastructure. Swap
src/storage/tokenStore.ts for a Redis/Postgres-backed implementation if you
need multi-instance deployments.
License
MIT — see LICENSE.
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.
Latest Blog Posts
- 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/aayushjain1811/instagram-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server