instagram-mcp

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

MCP server for the Instagram Platform (Meta Graph API) — 28 professional-account tools (publishing, insights, comments, discovery) for LLM agents.

README.md

instagram-mcp-ai — Instagram MCP Server

npm version npm downloads node tools License: MIT
CI coverage last commit MCP Known Vulnerabilities

📖 Documentation site →

A locally-run, TypeScript Model Context Protocol
server that exposes an Instagram professional account (Business/Creator) over
the official Meta Graph API (graph.instagram.com / graph.facebook.com) —
content publishing, media management, comment moderation, insights and discovery,
as safe, well-annotated MCP tools. It talks only to official Meta endpoints:
no scraping, no instagram-private-api-style clients, no cookie/session reuse. It
ingests media by public HTTPS URL only. Credentials live in a local env file
and can be obtained/refreshed with a built-in CLI.

Status: published to npm as [email protected] (2026-10-13). The read
path (account, media, insights), the write path (content publishing, comment
moderation) and discovery are all implemented, unit-tested and CI-green across
Linux/macOS/Windows on Node 22 and 24. No tool has been exercised against a
live Instagram account by CI
— the suite is offline by construction, so what
is proven is behaviour against recorded Graph shapes, not against Meta's live
responses. That, not missing functionality, is what separates 0.8.0 from
1.0.0. The MCP-registry entry, the MCPB bundle and the plugin-marketplace
listing are separate submissions and are not live yet. The documents under
docs/ are the source of truth for the design.

Contents: What it does · Requirements ·
Quickstart · Setup ·
Configure credentials · Run / debug ·
Write safety · Package profiles ·
Tools · Configuration ·
Security notes ·
Project documentation · Support

Built and maintained in my own time — a
GitHub Sponsors tip keeps it going.

What it does

The server exposes an Instagram professional account through 29 MCP tools
grouped into six packages:

  • Content publishing — feed images, 2–10 image carousels, Reels and Stories
    via the container → publish flow, plus one-call helpers (instagram_post_image
    / _reel / _story) and publishing-limit reporting.
  • Media management — list/read own media (including album children) and
    the account's live stories.
  • Comment moderation — list threads, reply, hide/unhide (reversible,
    preferred over delete) and delete; toggle whether a post accepts comments;
    read tagged media.
  • Insights — account and media metrics on the post-2025 views-based metric
    set, audience demographics and online-follower distribution.
  • Discovery — hashtag search, hashtag top/recent media and public
    business/competitor discovery. (Path B / fb-login only — see below.)
  • Account — profile, linked Facebook Pages / IG accounts, and a token-status
    report (auth path, expiry, days-left, refresh warning).

Every tool carries MCP annotations (readOnlyHint, destructiveHint,
idempotentHint) so clients apply the right confirmation UX, and every mutation
passes through a preview-by-default write gate. All Graph URLs
are pinned to a single API version (v25.0).

Why build it

The Meta ads niche is saturated — including Meta's own hosted Ads MCP
(mcp.facebook.com/ads, ads-only) — while the organic Instagram side has
only thin coverage. The existing TypeScript servers ship without tool
annotations, structured output, token security or tests. A well-engineered
TypeScript Instagram MCP server with proper token security, rate-limit
compliance and honest Graph semantics fills that gap. It is a sibling of the
planned facebook-mcp (Pages) server and shares the layered architecture of the
production servicenow-mcp-ai.

The #1 constraint to know up front: Instagram ingests media by public
URL
— image_url / video_url must be reachable by Meta's servers.
Publishing a local file means hosting it somewhere public first; v1 accepts
URLs only.

Requirements

  • Node.js ≥ 22 (Node 20 is EOL). Enforced by engines and a runtime guard
    in the CLI launcher with a clear message. CI runs the full gate on Node 22
    and 24
    across Linux, macOS and Windows.

Quickstart

Register the server with an MCP client (Claude Desktop, VS Code Chat, the
Inspector…) by pointing the command at npx and supplying one auth path's
credentials:

// claude_desktop_config.json / .mcp.json
{
  "mcpServers": {
    "instagram": {
      "command": "npx",
      "args": ["-y", "instagram-mcp-ai"],
      "env": {
        "IG_ACCESS_TOKEN": "<long-lived ig-login token>",
        "IG_ACCOUNT_ID": "<ig professional account id>"
      }
    }
  }
}

That is Path A (Instagram Login). For the token, the simplest path is the
built-in login command — see Configure credentials.
Everything else is optional tuning; the full list is under
Configuration.

Setup

From source (for development):

npm install
npm run build

Or run the published package directly, without cloning:

npx instagram-mcp-ai

Credentials are read from ~/.config/instagram-mcp-ai/.env (XDG), the project
.env, or real environment variables (which always win) — see below.

Two client-specific install channels wrap the same server: a Claude Desktop
extension
(docs/mcpb-install.md) and a Claude Code
plugin
(docs/plugin-install.md). Both prompt for the
access token at install time and keep it in the OS keychain rather than in a
settings file. The extension runs the server bundled inside the .mcpb; the
plugin runs the npm package at the version its manifest pins, which resolves only
once that version is published. Neither channel is listed yet: no .mcpb
bundle has been released and the plugin is in no marketplace beyond this repo's own
catalog. Each doc states its own status.

Configure credentials

All settings are environment variables with the uniform IG_ prefix; the
canonical copy with inline comments is .env.example. Choose
exactly one of the two Meta auth paths. Both read the account token from the
same variable, IG_ACCESS_TOKEN — the path decides which host it is sent to
and how it is signed:

Path IG_AUTH_MODE Host Also needs Notes
A — Instagram Login ig-login graph.instagram.com — IG_ACCESS_TOKEN holds a long-lived IG-login token. appsecret_proof is not supported and never sent. The simplest path.
B — Facebook Login fb-login graph.facebook.com IG_APP_ID + IG_APP_SECRET IG_ACCESS_TOKEN holds a Page / system-user token; requests carry an appsecret_proof HMAC. Required for the discovery tools (hashtag search, business discovery).

With IG_AUTH_MODE unset the path is inferred: fb-login when both
IG_APP_ID and IG_APP_SECRET are set, otherwise ig-login. Set it explicitly
to override (IG_AUTH_PATH is accepted as an alias). Discovery tools are
capability-filtered to Path B, so on Path A they are not registered at all.

login — obtain a long-lived token

A live login needs a registered Meta app (an app id/secret and a redirect
URI whitelisted in the app's OAuth settings). With those in place:

# Path A (Instagram Login)
IG_APP_ID=... IG_APP_SECRET=... npx instagram-mcp-ai login --path ig

# Path B (Facebook Login)
IG_APP_ID=... IG_APP_SECRET=... npx instagram-mcp-ai login --path fb

It opens the browser, captures the loopback redirect, exchanges the code for a
long-lived (~60-day) token and writes it to the env file (chmod 0600 on POSIX).
No token or secret is ever printed. Run npx instagram-mcp-ai login --help for
all options (--profile, --app-id, --app-secret, --account-id, --scopes,
--redirect-uri). See
docs/auth.md for the full token model, scopes and app setup.

Run / debug

The published instagram-mcp-ai binary (run it directly or via npx) has three
subcommands; with no subcommand it starts the MCP server on the configured
transport. All connection settings come from environment variables / the env file.

Command What it does
instagram-mcp-ai Starts the MCP server. Transport is stdio (default) or http, chosen by IG_TRANSPORT.
instagram-mcp-ai login --path <ig|fb> One-time browser OAuth to obtain and persist a long-lived token (see above).
instagram-mcp-ai doctor Read-only health check for the active profile: config, token/auth, and one reachability GET. Exit 0 healthy, non-zero on failure.
instagram-mcp-ai refresh Refresh the active profile's long-lived token and write it back (ig_refresh_token on Path A, fb_exchange_token on Path B).
instagram-mcp-ai --help Prints this usage to stderr and exits 0.

Anything else is a usage error: an unknown subcommand (docter), or an argument
after doctor / refresh (they take none), is refused on stderr with exit 2
before any configuration is read — it never starts the server by accident.

  • stdio (default) — for local MCP clients. stdout is the protocol channel;
    all diagnostics go to stderr.
  • Streamable HTTP — opt in with IG_TRANSPORT=http. Loopback-bound
    (127.0.0.1:3000 by default via IG_HTTP_HOST / IG_PORT); set
    IG_HTTP_TOKEN to require an Authorization: Bearer <token> header
    (constant-time compared).
    Leaving IG_HTTP_TOKEN unset means no authentication at all — every local
    process can call every tool, writes included. It is allowed on loopback and
    logged at error level on startup; binding a non-loopback address without a token
    is refused outright, and a blank token is refused either way.

Write safety

Every mutating tool passes through a single write gate (design gate D3):

  • Preview by default. A write returns a non-mutating preview describing
    exactly what would change; nothing is sent to Meta.
  • Apply explicitly. Pass apply: true on the call, or set
    IG_WRITE_MODE=apply for standing consent, to actually perform the write.
  • Destructive ops are double-gated. Irreversible actions (e.g.
    instagram_delete_comment) additionally require IG_ALLOW_DESTRUCTIVE=true.
  • Journaled. Every applied write is appended to a local, append-only JSONL
    journal (~/.local/state/instagram-mcp-ai/writes.jsonl, or IG_WRITE_JOURNAL)
    for auditing — best-effort, so a broken journal never fails an authorized write.

Package profiles

Tools are grouped into packages so you can expose only what a client needs (fewer
tools keep the model focused). Set IG_TOOL_PACKAGES to a profile name or an
explicit comma list of packages:

Profile IG_TOOL_PACKAGES=… Packages Tools
core (default) account, media, publishing, comments, insights the everyday read + publish + moderate set 26
reader account, media, insights, comments, discovery read, insights and discovery — forced read-only (Path B for discovery) 16
publisher account, media, publishing, comments publish and moderate 22
all every package the full surface 29

The six packages are account, media, insights, publishing, comments
and discovery. Two more knobs refine a selection: IG_PACKAGES_DENY removes
packages after the profile resolves, and IG_PACKAGES_READONLY forces a
package's write tools off (its read tools stay).

reader is read-only by name, not by arithmetic: its comments package
does contain write tools, so selecting it forces every package it resolves
to read-only, exactly as if IG_PACKAGES_READONLY had listed them all. No tool
that posts, hides, deletes or toggles anything is ever registered under reader
— that is why it exposes 16 tools and not 22. A hand-written package list is not
a read-only boundary; only the profile name (or IG_PACKAGES_READONLY) is.

Auth-path capability filtering runs on top: a tool restricted to one login path
is registered only when at least one configured profile is on that path, and the
per-call guard still rejects a mismatched account argument. So a deployment
with Path A credentials only drops the four fb-login-only tools
(instagram_list_linked_accounts plus the three discovery tools), while adding a
single Path B profile alongside brings them back.

Tools

The full v1 tool surface, generated from the tool registry — do not edit the
table by hand; run npm run gen:readme. Auth paths is the login path a tool
is valid for (both when unrestricted); Access is Read for read-only tools
and Write for mutating ones (writes preview by default — see
Write safety).

Tool Package Auth paths Access Summary
instagram_get_account account both Read Fetch the profile of the operated Instagram professional account: username, display name, biography, website, profile-picture URL, and follower / following / media counts.
instagram_list_linked_accounts account fb-login Read Enumerate the Facebook Pages this token can act on and the Instagram business account linked to each (GET /me/accounts).
instagram_token_status account both Read Report the active credential: auth path (A = ig-login / B = fb-login), whether a token is configured, the resolved account ID, and — on Path B, via debug_token — validity, granted scopes, absolute expiry and days-left (with a refresh warning as the threshold nears).
instagram_get_media media both Read Fetch a single media object by id, including its carousel children (album items) under children.
instagram_list_media media both Read List the operated account's own media (feed posts, reels, albums), newest first, cursor-paginated.
instagram_list_stories media both Read List the operated account's live stories — only those still inside Instagram's 24-hour window, newest first, cursor-paginated.
instagram_get_account_insights insights both Read Account-level insights for the operated Instagram professional account (GET /{ig-id}/insights).
instagram_get_audience_demographics insights both Read Follower / engaged-audience demographics for the operated account (GET /{ig-id}/insights with metric_type=total_value).
instagram_get_media_insights insights both Read Insights for a single media object (GET /{media-id}/insights).
instagram_get_online_followers insights both Read Hourly distribution of when the account's followers are online (GET /{ig-id}/insights?metric=online_followers&period=lifetime).
instagram_create_media_container publishing both Write Phase 1 of publishing: create a media container that Instagram ingests from a public HTTPS URL.
instagram_get_container_status publishing both Read Read a media container's processing state: status_code is IN_PROGRESS, FINISHED, ERROR, EXPIRED, or PUBLISHED.
instagram_get_publishing_limit publishing both Read Report the account's content-publishing usage against its rolling-window quota.
instagram_post_image publishing both Write Publish a single feed image, or a 2–10 image carousel, in one call: create the container(s), wait for processing, then publish.
instagram_post_reel publishing both Write Publish a reel in one call: create the REELS container, wait for processing (reels can take a while), then publish.
instagram_post_story publishing both Write Publish a photo or video story in one call: create the STORIES container, wait for processing, then publish.
instagram_publish_media publishing both Write Phase 2 of publishing: publish a media container that has finished processing, returning the new media id.
instagram_create_comment comments both Write Post a new top-level comment on a media object (POST /{media-id}/comments).
instagram_delete_comment comments both Write Permanently delete a comment (DELETE /{comment-id}).
instagram_get_comment comments both Read Fetch a single comment by id, including its moderation state (hidden), parent/media context, and inline replies (repliesTruncated=true when Instagram returned only the first page of them).
instagram_hide_comment comments both Write Hide a comment (POST /{comment-id}?hide=true) — reversible moderation, preferred over delete.
instagram_list_comments comments both Read List the top-level comments on a media object, newest first, cursor-paginated, with threaded replies expanded inline under replies (repliesTruncated=true marks a thread Instagram cut at its first page of replies).
instagram_list_tagged_media comments both Read List media the operated account has been TAGGED IN (the /tags edge), newest first, cursor-paginated.
instagram_reply_to_comment comments both Write Post a threaded reply under an existing comment (POST /{comment-id}/replies).
instagram_set_comments_enabled comments both Write Toggle whether a media object accepts new comments (POST /{media-id}?comment_enabled=true|false).
instagram_unhide_comment comments both Write Unhide a previously hidden comment (POST /{comment-id}?hide=false).
instagram_discover_business discovery fb-login Read Fetch another business/creator's PUBLIC profile and recent media by handle via GET /{ig-id}?fields=business_discovery.username(<handle>){followers_count,media_count,media{...}}.
instagram_get_hashtag_media discovery fb-login Read List PUBLIC media under a hashtag id via GET /{hashtag-id}/top_media or /{hashtag-id}/recent_media (choose via edge), which require the operated account's id as user_id.
instagram_search_hashtag discovery fb-login Read Resolve a hashtag name to its Instagram hashtag id(s) via GET /ig_hashtag_search?user_id={ig-id}&q=<hashtag> (the returned id feeds instagram_get_hashtag_media).

Configuration

All settings are environment variables with the uniform IG_ prefix; the
canonical copy with inline comments is .env.example, and the
table below is generated from it — do not edit it by hand; run
npm run gen:readme. Real environment variables always take precedence over the
file. Writes preview by default; a write is performed when the call passes
apply: true, or when IG_WRITE_MODE=apply and the call does not pass
apply: false. Deletes additionally need IG_ALLOW_DESTRUCTIVE=true, and a
client that supports MCP elicitation is asked to confirm each applied write.

Variable Default Description
IG_AUTH_MODE ig-login | fb-login; alias IG_AUTH_PATH (inferred fb-login when IG_APP_ID+IG_APP_SECRET are set)
IG_ACCESS_TOKEN The account's long-lived token, whichever path (secret)
IG_ACCOUNT_ID IG professional-account ID; unset, calls address me (no lookup) — set it on Path B
IG_APP_ID Meta app id (token exchange/refresh, appsecret_proof, debug_token)
IG_APP_SECRET Meta app secret (secret)
IG_ENV_FILE Env-file location override (default: XDG path); read alone, and written by login/refresh; must be absolute (a leading ~ is the home directory)
IG_ACTIVE_PROFILE default Profile used when a tool call passes no account
IG_TOOL_PACKAGES core core | reader | publisher | all, or an explicit list
IG_PACKAGES_DENY Packages to remove after profile resolution
IG_PACKAGES_READONLY Packages forced read-only
IG_WRITE_MODE preview preview | apply (standing consent for writes)
IG_ALLOW_DESTRUCTIVE false Second gate for irreversible ops (delete_comment)
IG_WRITE_JOURNAL Applied-write audit log (default: $XDG_STATE_HOME/instagram-mcp-ai/writes.jsonl)
IG_TRANSPORT stdio stdio | http
IG_HTTP_HOST 127.0.0.1
IG_PORT 3000
IG_HTTP_TOKEN HTTP bearer token (secret; constant-time compare)
IG_MAX_CONCURRENT 4 Per-host concurrency semaphore
IG_MAX_ITEMS 200 fetchAll hard item cap
IG_REFRESH_AFTER_DAYS 45 Days-left threshold for the expiring_soon warning (token_status, doctor); no auto-refresh
IG_TIMEOUT_MS 30000 Timeout per Graph HTTP attempt, not per call (retries and backoff are extra)
IG_LOG_LEVEL info debug | info | warn | error
IG_PRETTY_JSON false Pretty-print JSON results

Project identity

Item Value
npm package instagram-mcp-ai (published; latest 0.7.0)
GitHub repository IvanBBaev/instagram-mcp
MCP registry name io.github.IvanBBaev/instagram-mcp-ai
Language / runtime TypeScript (ESM), Node.js ≥ 22
MCP SDK @modelcontextprotocol/server + @modelcontextprotocol/node v2 (registerTool + zod 4)
Transports stdio (default), Streamable HTTP (opt-in, loopback-bound)
Env var prefix IG_
Graph API version pinned v25.0 in every URL
License MIT

Note on names: the npm package and MCP registry entry use instagram-mcp-ai
(the unscoped instagram-mcp was already squatted on npm); the GitHub
repository and the local working folder are instagram-mcp. The difference is
cosmetic and does not affect the build or runtime.

Non-goals

  • Ads / Marketing API — covered by Meta's official Ads MCP; out of scope permanently.
  • Unofficial APIs — no instagram-private-api-style clients, no cookie/session reuse,
    no scraping. Official Graph API only.
  • Consumer (personal) accounts — the Instagram Platform API only serves
    professional (Business/Creator) accounts; this server does not work around that.
  • Multi-tenant SaaS hosting — this is a personal, locally-run server (single
    operator, one or few accounts). Streamable HTTP stays loopback-bound.

Security notes

  • The env file is git-ignored and written owner-only (0600) — it holds
    plaintext tokens/secrets; do not commit real credentials.
  • The server uses the stdio transport by default and only logs to stderr.
    Access tokens, app secrets and appsecret_proof HMACs are masked by a secret
    redactor before anything reaches a log sink; the login/refresh/doctor
    commands never print a token or secret.
  • SSRF guard: Graph calls are restricted to the two allowlisted hosts
    (graph.instagram.com, graph.facebook.com) with the API version pinned, so a
    redirected or mistyped host cannot silently receive a token.
  • Media ingestion is URL-only and by public HTTPS URL — no local files are
    uploaded, so the server never exfiltrates local content.
  • Writes are preview-by-default, applied writes are journaled, and
    irreversible ops need a second explicit gate (IG_ALLOW_DESTRUCTIVE). See
    Write safety and docs/security.md.

Project documentation

Document Contents
docs/architecture.md Layered architecture, tool registry, transports, config, testing strategy
docs/auth.md The two Instagram auth paths, token types & lifetimes, scopes, app setup
docs/tools.md Full tool catalog specification (names, annotations, inputs, Graph calls)
docs/setup-guide.md End-to-end setup walkthrough
docs/troubleshooting.md Common failures and fixes
docs/security.md Token storage, redaction, SSRF policy, write safety, supply chain
docs/operations.md Rate limits, retry/backoff, pagination, error taxonomy, versioning
docs/stability.md Stability contract and versioning policy
docs/corner-cases.md Corner-case catalog (CC-* IDs) with expected behavior, the live-probe register (§9) and the open owner-decision register (§10)
docs/roadmap.md Implementation roadmap: design gates D1–D3, phases M0–M6 with exit gates
docs/workplan.md Parallel work plan: agent-sized tasks, file ownership, dependency graph
docs/release-checklist.md Pre-publish release checklist
docs/reviews/ Six role-based senior design reviews — start with the consolidated summary

The rendered documentation site
mirrors these documents.

Support

This project is built and maintained in my own time. If it saves you or your team
time, please consider supporting its continued development — sponsorship directly
funds new tools, bug fixes and keeping pace with Meta's Graph surface.

  • GitHub Sponsors — one-off or
    recurring, with no platform fee taken out (the preferred option).
  • Ko-fi — quick one-off support; it also
    accepts PayPal, so it's the fallback for anyone without a GitHub account.
  • Donate (Donatree) — a no-account donation
    page (card, PayPal and more) for a one-off tip.

Sponsor on GitHub
Support on Ko-fi
Donate via Donatree

Trademark

Instagram and Meta are trademarks of Meta Platforms, Inc. This project is
independent and not affiliated with or endorsed by Meta. The marks are used
only nominatively — to identify the platform this software interoperates
with. This project is licensed under the MIT License; that license
covers the source code and grants no rights to use the Instagram or Meta
trademarks.

Reviews (0)

No results found