instagram-mcp
# instagram-mcp-ai β Instagram MCP Server
<!--
Badge note: the npm-version, downloads, node and Snyk badges resolve as of the
2026-08-25 publish of 0.7.0. The coverage badge still renders "not found" β
Codecov is not enabled for this repo (it needs a token; see workplan T-R6) β
and downloads will read 0 until the package has a month of history. That is
expected (the block matches the published sibling servicenow-mcp-ai).
-->
| [](https://www.npmjs.com/package/instagram-mcp-ai) | [](https://www.npmjs.com/package/instagram-mcp-ai) | [](https://www.npmjs.com/package/instagram-mcp-ai) | [](#tools) | [](LICENSE) |
| :--: | :--: | :--: | :--: | :--: |
| [](https://github.com/IvanBBaev/instagram-mcp/actions/workflows/ci.yml) | [](https://codecov.io/gh/IvanBBaev/instagram-mcp) | [](https://github.com/IvanBBaev/instagram-mcp/commits/main) | [](https://modelcontextprotocol.io) | [](https://snyk.io/test/npm/instagram-mcp-ai) |
π **[Documentation site β](https://ivanbbaev.github.io/instagram-mcp/)**
A locally-run, TypeScript [Model Context Protocol](https://modelcontextprotocol.io)
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 `instagram-mcp-ai@0.8.0` (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/`](docs/) are the source of truth for the design.
**Contents:** [What it does](#what-it-does) Β· [Requirements](#requirements) Β·
[Quickstart](#quickstart) Β· [Setup](#setup) Β·
[Configure credentials](#configure-credentials) Β· [Run / debug](#run--debug) Β·
[Write safety](#write-safety) Β· [Package profiles](#package-profiles) Β·
[Tools](#tools) Β· [Configuration](#configuration) Β·
[Security notes](#security-notes) Β·
[Project documentation](#project-documentation) Β· [Support](#support)
_Built and maintained in my own time β a
[GitHub Sponsors](https://github.com/sponsors/IvanBBaev) 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](#write-safety). 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:
```jsonc
// 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](#configure-credentials).
Everything else is optional tuning; the full list is under
[Configuration](#configuration).
## Setup
From source (for development):
```bash
npm install
npm run build
```
Or run the published package directly, without cloning:
```bash
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](docs/mcpb-install.md)) and a **Claude Code
plugin** ([docs/plugin-install.md](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`](.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:
```bash
# 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](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](#write-safety)).
<!-- BEGIN AUTOGEN:tools -->
| 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). |
<!-- END AUTOGEN:tools -->
## Configuration
All settings are environment variables with the uniform `IG_` prefix; the
canonical copy with inline comments is [`.env.example`](.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.
<!-- BEGIN AUTOGEN:env -->
| 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 |
<!-- END AUTOGEN:env -->
## Project identity
| Item | Value |
| ---- | ----- |
| npm package | [`instagram-mcp-ai`](https://www.npmjs.com/package/instagram-mcp-ai) *(published; latest `0.7.0`)* |
| GitHub repository | [`IvanBBaev/instagram-mcp`](https://github.com/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](#write-safety) and [docs/security.md](docs/security.md).
## Project documentation
| Document | Contents |
| -------- | -------- |
| [docs/architecture.md](docs/architecture.md) | Layered architecture, tool registry, transports, config, testing strategy |
| [docs/auth.md](docs/auth.md) | The two Instagram auth paths, token types & lifetimes, scopes, app setup |
| [docs/tools.md](docs/tools.md) | Full tool catalog specification (names, annotations, inputs, Graph calls) |
| [docs/setup-guide.md](docs/setup-guide.md) | End-to-end setup walkthrough |
| [docs/troubleshooting.md](docs/troubleshooting.md) | Common failures and fixes |
| [docs/security.md](docs/security.md) | Token storage, redaction, SSRF policy, write safety, supply chain |
| [docs/operations.md](docs/operations.md) | Rate limits, retry/backoff, pagination, error taxonomy, versioning |
| [docs/stability.md](docs/stability.md) | Stability contract and versioning policy |
| [docs/corner-cases.md](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](docs/roadmap.md) | Implementation roadmap: design gates D1βD3, phases M0βM6 with exit gates |
| [docs/workplan.md](docs/workplan.md) | Parallel work plan: agent-sized tasks, file ownership, dependency graph |
| [docs/release-checklist.md](docs/release-checklist.md) | Pre-publish release checklist |
| [docs/reviews/](docs/reviews/summary.md) | Six role-based senior design reviews β start with the consolidated summary |
The rendered [documentation site](https://ivanbbaev.github.io/instagram-mcp/)
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](https://github.com/sponsors/IvanBBaev)** β one-off or
recurring, with no platform fee taken out (the preferred option).
- **[Ko-fi](https://ko-fi.com/ivanbbaev)** β quick one-off support; it also
accepts **PayPal**, so it's the fallback for anyone without a GitHub account.
- **[Donate (Donatree)](https://donatr.ee/ivanbbaev/)** β a no-account donation
page (card, PayPal and more) for a one-off tip.
[](https://github.com/sponsors/IvanBBaev)
[](https://ko-fi.com/ivanbbaev)
[](https://donatr.ee/ivanbbaev/)
## 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](LICENSE); that license
covers the source code and grants no rights to use the Instagram or Meta
trademarks.
TDQS
Scored across 25 tools
Most tools target clearly distinct resources and actions (comments, insights, media, account, publishing). The main ambiguity is the dual publishing path: instagram_create_media_container + instagram_get_container_status + instagram_publish_media overlaps with instagram_post_image/reel/story, which wrap the same flow. Descriptions mitigate this, but an agent must still choose between low-level and high-level tools for the same outcome.
All 25 tools follow the instagram_ prefix with snake_case verb_noun naming (create_, get_, list_, post_, hide_, etc.). No mixed conventions; the pattern is predictable and readable throughout.
25 tools is on the heavy side for a single server; the domain is broad, but some capabilities (e.g., hide/unhide, multiple insight entry points) could potentially be consolidated. Each tool maps to a distinct API operation, so it's borderline rather than excessive.
The surface covers the core professional account lifecycle: profile, media publishing (image/reel/story/carousel), container status, publishing limit, media listing, comments moderation, and insights. Minor gaps include no tool for @mentions retrieval (explicitly noted as a separate capability) and no token refresh tool, but agents can work around these.