igagent
This MCP server harvests and inspects public Instagram posts without login, API keys, or a browser.
extract_post: Decode a post URL, share link, or bare shortcode and download every exposed photo/video toout_dirwith verification, returning a summary plus full manifest.lookup_post: Run the same decode pipeline metadata-only, without writing media files, returning author, caption, timestamps, media URLs, and carousel shape.read_manifest: Return the full envelope from an existingpost_manifest.json, refusing files with any other name.get_schema: Return the draft-07 JSON Schema for the manifest envelope (schema_version1.0).Outputs can include media URLs/local files, errors, decode-slot provenance, carousel info, and honest empty/partial statuses; large carousels may take a minute.
Harvests public Instagram posts without login, cookies, or API keys. Given a post URL, reel/tv link, share link, or bare shortcode, it decodes post metadata (caption, created_at, author username/followers/verified, carousel membership) via public embed/OpenGraph surfaces, downloads the associated images and videos from allowlisted CDN hosts with atomic writes and magic-byte verification, and emits a verified media directory plus a JSON manifest. Available as both a CLI and MCP tools (extract_post, lookup_post, read_manifest, get_schema) for metadata-only lookups or full media harvests, with honest empty results for deleted posts.
Click on "Deploy 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., "@igagent harvest this post: https://www.instagram.com/p/ABC123/ — media plus manifest"
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.
igagent
An agentic Instagram content & media harvester for AI agents — no login, no API keys, no browser. MCP wrapper included.
igagent is the Instagram sibling of xthread-agent (X/Twitter threads) and ytagent (YouTube). Same doctrine: a deterministic, slot-based, stdlib-only state machine that a cloud agent can call with one URL and read back one JSON contract.
python igagent.py "https://www.instagram.com/p/<CODE>/"
# → verified media on disk + post_manifest.jsonWhy this exists
Cloud-based AI agents (GitHub Actions runners, sandboxed VMs, MCP hosts) cannot log into Instagram, and Instagram keeps proving that a login is not even the interesting boundary — the interesting boundary is which door a machine is allowed through with no session at all. Public embed pages are exactly such a door: Instagram serves them to any referrer, and for link unfurlers it renders the actual media straight into the HTML. igagent is built entirely on that observation.
What it gives you:
One input, one artifact. A post URL (or share link, or bare shortcode) in; a verified media directory plus
post_manifest.jsonout.Honest negatives. A deleted post is not an exception — it is
status: "empty"with structured errors and a slot-by-slot provenance trace.Slots, not brands. The three decode surfaces are interchangeable implementations of one contract. When Instagram kills one, you replace the slot — the pipeline never restructures.
Verified delivery. Files exist only after passing the CDN allowlist, a
Content-Lengthcheck, and a magic-byte identity check. A tool that reports a file is vouching for its bytes.Truth layers over heuristics. Carousel membership comes only from the payload (
edge_sidecar_to_children) and is flaggedcarousel.known— never inferred from page layout. The shortcode itself decodes to the numeric media id by pure math, cross-checked against Instagram'sig_cache_key.Politeness as a hard constraint. Bounded retries, 0.6 s decode sleeps, response caps, one post per invocation. The public surfaces this tool depends on are free; restraint is the rent.
Related MCP server: reelminner
Architecture
┌──────────────────────────────────────────────────────┐
│ DISCOVERY │
│ normalize p/reel/reels/tv URLs · instagr.am & │
│ ddinstagram mirrors · share links (1 hop) · bare │
│ shortcodes · shortcode ↔ media-id base64 math │
└───────────────────────────┬──────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ DECODE (slots) │
│ 1. embed_json — legacy rich payload │
│ (caption, metrics, sidecar children, author) │
│ 2. embed_html — unfurler SSR page │
│ (media img/video, author, followers, cache key) │
│ 3. og_meta — OpenGraph tags │
│ (title/caption, og:image, og:video:secure_url) │
│ provenance trace [{"slot","outcome"}] on every run │
└───────────────────────────┬──────────────────────────┘
▼
┌──────────────────────────────────────────────────────┐
│ DELIVER │
│ https + *.cdninstagram.com / *.fbcdn.net only │
│ stream → .part → Content-Length ✓ → magic bytes ✓ │
│ → os.replace (atomic) → files + post_manifest.json │
└──────────────────────────────────────────────────────┘Each tier fails closed: a slot that finds nothing hands control to the next slot and the attempt is recorded; only "everything failed" becomes a run-level error.
Quickstart
# full harvest (decode + verified downloads)
python igagent.py "https://www.instagram.com/p/<CODE>/" --out ./ig_media
# metadata only
python igagent.py "<CODE>" --no-download
# the machine contract: exactly one JSON object on stdout
python igagent.py "<input>" --json --quietFor AI agents
python igagent.py agent-instructions 2>/dev/null || true # not needed —
# the operating manual IS agent.md: read that file and nothing else.The three-command contract:
command | returns | exit |
| summary JSON on stdout, full envelope at | 0 ok/partial · 1 empty · 2 invalid |
| same, no files on disk | same |
|
| 0 |
CLI reference
igagent.py <input> [--out DIR] [--no-download] [--json] [--quiet] [--version]
<input> instagram.com /p|reel|reels|tv/<code>/ · mirror hosts ·
share links (instagram.com/share/…) · bare shortcodes
--out DIR output directory (default: ig_media)
--no-download decode only; manifest still written
--json one JSON summary object on stdout (stderr silenced)
--quiet silence human logs on stderrAccepted input shapes: https://www.instagram.com/p/<CODE>/,
instagram.com/reel/<CODE>?utm_source=…, m./l./ddinstagram/instagr.am
mirrors, https://www.instagram.com/share/<token>/, and bare shortcodes
(5–32 chars of A-Za-z0-9_- that decode to a positive media id).
JSON output (for AI agents)
{
"ok": true,
"status": "ok",
"shortcode": "<CODE>",
"media_id": "1949525278281554174",
"canonical_url": "https://www.instagram.com/p/<CODE>/",
"post_type": "image",
"extraction_source": "embed_html",
"images": 1, "videos": 0,
"downloaded": 1, "failed_downloads": 0,
"out_dir": "ig_media",
"manifest_path": "ig_media/post_manifest.json",
"errors": [],
"duration_sec": 2.2
}The full envelope (post_manifest.json) adds the post object: caption,
created_at, author (username, followers, verified, … — explicit
nulls when a slot does not expose them), media.images[] /
media.videos[] with url / file / downloaded / downloadable / reason,
carousel{known, child_count}, errors[] with stable codes, and
metadata.decode_slots_tried — the provenance trace. The draft-07 schema
is bundled at schema/post-result.schema.json.
For MCP hosts
python mcp_server.py speaks newline-delimited JSON-RPC 2.0 on stdio —
stdlib only, no mcp package. Register it in Claude Desktop / Zed:
tool | what it does |
| full harvest → verified files + envelope |
| metadata-only decode (no downloads) |
| return an existing |
| the draft-07 envelope schema |
Error policy: an honest empty result is not an MCP error; a bad tool argument, timeout, or crash is.
Documentation
file | role |
the operating manual for AI agents — read this file and nothing else | |
perfection-based role prompts for the five pipeline roles | |
maintainer manifesto: why, load-bearing walls, fragile parts, debts | |
living endpoint status table + maintenance protocol | |
the output contract, machine-checkable | |
version history |
Constraints (non-negotiable)
No login, no cookies, no OAuth, no browser. Public content only; everything fails closed.
No GUI, no interactive prompts. 100% non-interactive CLI.
No LLM at runtime. Deterministic state machine — the "agent" is designed for AI agents, not made of one.
stdlib only. Single file, zero pip dependencies, Python 3.9+.
Logs on stderr, data on stdout. Always pipe-safe.
Files stay under the output directory. CDN allowlist, ID validation, atomic writes, magic-byte verification.
Requirements
Python 3.9+ and outbound HTTPS. Nothing else — no pip, no ffmpeg, no browser, no env vars, no config files.
Installation
# as a tool (after PyPI publish)
pip install igagent
igagent "<url>" --json
# from source
git clone https://github.com/Bilal140202/igagent.git
python igagent/igagent.py "<url>"
# or
python -m igagent "<url>"Testing
python -m unittest discover -s tests -p "test_*.py"
# 69 tests, ~1s, zero network — synthetic fixtures only, never real IDsVerified behavior (as shipped)
claim | evidence |
| live run: |
shortcode ↔ media-id math is exact | round-trip property tests (50 random ids) |
dead posts produce honest empties | live run: |
magic-byte gate rejects HTML masquerading as media | offline tests |
lookalike CDN hosts ( | offline tests |
MCP handshake + 4-tool registry | offline stdio probe |
Re-verify against your own vantage point and update
docs/endpoint-matrix.md — that is the protocol.
Limitations (the honest section)
Reel/video URLs are frequently not exposed by the embed surface. The video entry then reports
downloadable: false, reason: "no_video_url_exposed"— this is the truth, not a bug. Stories, live, and private accounts are out of scope entirely.Carousel depth is slot-dependent. The commonly-served unfurler view shows only the primary item;
carousel.known=falsesays so honestly. Full sidecars require the legacyembed_jsonpayload.Datacenter IPs get walls. Instagram's structured APIs (graphql, media info) are walled from cloud ranges and deliberately not slots;
og_metaoften needs a residential IP.Instagram changes surfaces without notice. The slot architecture and the endpoint matrix exist precisely because everything upstream of this tool is borrowed ground.
Legal / ethics
igagent accesses only publicly served documents over unauthenticated HTTP(S), with politeness sleeps and hard caps, and it never circumvents a paywall, a login, or a private post. Respect creators: media and captions remain the property of their authors; downstream use is your responsibility. Do not use this tool at volumes that constitute abuse.
FAQ
Why is there no login option? Because the calling agent is a cloud VM by definition — no session, no cookies. The whole design is "what can a sessionless machine legitimately get?" — and the answer is documented, versioned, and fail-closed.
Why is status often partial instead of ok? partial means the
post was decoded but something failed (e.g. a video URL was never
exposed so nothing could be downloaded). The media entries carry the
per-item reason. errors[] is the full story.
A decode stopped working — is igagent broken? Check
docs/endpoint-matrix.md first. Surfaces flip; the matrix is the
impersonal record of flips, and slots are how they get absorbed.
Does it work for stories or private accounts? No, by design — both require authentication, which violates constraint 1.
License
MIT — see LICENSE.
Acknowledgments
xthread-agent— the architecture, the docs-as-contract system, the MCP wrapper, and the phrase "restraint is the rent".ytagent— "never trust a method's self-report", the verification doctrine this project merged into its delivery tier.The mirror/unfurler ecosystem — the doors that were already open.
Links
Repository: https://github.com/Bilal140202/igagent
Siblings:
xthread-agent·ytagent
Project status
Completed project — verified in the portfolio audit of 7 November 2026 (README, codebase and project state reviewed).
Last verified: 7 November 2026
Available Tools
4 toolsextract_postA
Harvest a public Instagram post/carousel/reel: given a post URL, share link or bare shortcode, decodes the public embed surface and downloads every exposed photo and video (magic-byte verified) to out_dir. Returns the summary plus the full post_manifest envelope (author, caption, media URLs, local files, errors, decode-slot provenance). No login, no API keys. Large carousels can take a minute.
Inputs: url (required), out_dir, download_media.
get_schemaA
Return the JSON Schema (draft-07) describing the post_manifest envelope (schema_version 1.0) — use it to validate or explore the output contract.
Inputs: no named parameters.
lookup_postA
Fast metadata-only lookup of a public Instagram post: same decode pipeline as extract_post but with --no-download — author, caption, timestamps, media URLs, carousel shape, without writing media files. Use this when you only need to read the post.
Inputs: url (required), out_dir.
read_manifestA
Read an existing post_manifest.json produced by a previous extract/lookup and return the full envelope. Refuses any file not named post_manifest.json.
Inputs: path (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 4 tools
extract_post and lookup_post share the same decode pipeline and differ only in whether media is downloaded, which is the main potential confusion, but their descriptions clearly state the download vs metadata-only distinction. read_manifest and get_schema are cleanly distinct from each other and from the extraction tools.
All four tools follow a consistent verb_noun snake_case pattern (read_manifest, get_schema, extract_post, lookup_post). No mixed conventions or vague verbs.
Four tools is a tight, well-scoped set for an Instagram post extraction utility. It is on the lean side but each tool earns its place, with no redundancy.
The surface covers the full round-trip: discover the contract (get_schema), fetch metadata (lookup_post), fetch media (extract_post), and re-read prior output (read_manifest). No obvious dead ends, though there is no batch/multi-post operation for repeated use.
Maintenance
Related MCP Connectors
Instagram for AI agents: publish, read comments and DMs, insights, and engage from your account.
Scrape X, Reddit, LinkedIn, GitHub, Instagram and TikTok data as tools for AI agents.
Live public Instagram and TikTok data for AI assistants: profiles, posts, stories, followers.
Instagram search and posts for AI agents, with images and videos AI-parsed to text.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI assistants to download Instagram content including posts, videos, reels, stories, highlights, and profile pictures using Instaloader, with optional metadata and caption extraction.5MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to scrape Instagram Reels and public profile data (metadata, engagement, owner info) without the official API, via tools for scraping, status checks, cookie import, stopping, and exporting results.1MIT
- AlicenseAqualityBmaintenanceEnables MCP clients like Claude and Cursor to query public Instagram data read-only — profiles, posts, reels, stories, highlights, comments, likers, followers, hashtags, places, audio and search — over local stdio without writing files or storing anything.28MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to retrieve and analyze Instagram posts and profiles, including captions, media, video frames, transcripts, and engagement metrics, through MCP tools.53 PyPIMIT