instagram-mcp
Provides integration with Instagram via its private mobile API, enabling reading of profiles, posts, stories, followers, comments, and DMs, plus optional write actions like posting, liking, commenting, following, and sending direct messages when explicitly enabled.
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-mcpcheck my recent Instagram DMs and tell me if anything needs a reply"
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
An MCP server that exposes instagrapi — Instagram's private mobile API — as 49 tools an agent can call.
Reading is enabled out of the box. Anything that changes the account (posting, liking, following, commenting, DMing, deleting) is refused until you explicitly turn writes on.
Setup
cp .env.example .envThen fill in .env with either a username and password, or a sessionid
cookie copied from a browser where you are already signed in (DevTools →
Application → Cookies → instagram.com). The sessionid route is less likely to
trigger a login challenge.
If the account uses two-factor auth, paste the authenticator "setup key" into
INSTAGRAM_TOTP_SEED and codes are generated for you. Otherwise, when Instagram
asks for a code, call instagram_login with verification_code.
Verify the install without touching Instagram:
.venv/Scripts/python smoke_test.pyRelated MCP server: Instagram MCP Server
Registering the server
Already registered for this project in ../.mcp.json. To use it elsewhere:
claude mcp add instagram -- "C:\Users\osami\OneDrive\Documents\GitHub\ayham project 2\instagram-mcp\.venv\Scripts\instagram-mcp.exe"The executable works from any directory — it always reads .env and writes
session.json next to this README.
Enabling write actions
INSTAGRAM_ALLOW_WRITES=trueRestart the server afterwards. While this is false, write tools fail with an
explanation rather than doing anything, so the read-only tools stay usable.
Tools
Group | Tools |
Writing DMs |
|
Persona search |
|
Session |
|
Users |
|
Posts |
|
Discovery |
|
Direct messages |
|
Engagement |
|
Publishing |
|
* requires INSTAGRAM_ALLOW_WRITES=true.
Users are addressed by username or user_id. Posts are addressed by a media
argument that accepts a post URL, a shortcode, or a numeric media id.
Writing DMs in your own voice
This is what the server is mainly for. The problem with letting a model write your messages is that it writes correctly — punctuated, capitalised, polite — and everyone who knows you can tell instantly.
So instagram_build_style_profile measures how you actually write, from your
own sent DMs: message length, capitalisation, terminal punctuation, emoji rate,
which emoji, how you spell laughter, shorthand, language mixing, and whether you
send bursts of short messages instead of one composed one. It records this
globally and per contact, because nobody writes to their mother the way they
write to their closest friend.
Run it once:
.venv/Scripts/python -c "import asyncio,json;from instagram_mcp.server import server;print(asyncio.run(server.call_tool('instagram_build_style_profile',{})).content[0].text[:400])"After that, instagram_prepare_dm(person="sarah") returns — in one call — the
recent conversation, the measured rules of your voice, and samples of how you
write to that specific person. That single call is the whole interface for
drafting; there is no need to stitch together the raw thread tools.
The profile is cached in style_profile.json and never sent to Instagram.
Refresh it occasionally as your writing drifts.
The skill
~/.claude/skills/instagram-dm/SKILL.md drives the whole workflow in normal
conversation — "reply to ahmed", "what should I say back to her", "check my
ig messages". It handles finding the person, loading your voice, drafting, and
holding the draft for your approval before anything sends.
Nothing sends without you seeing the exact words first.
Finding people who match a persona
The other thing the server is for. You describe someone — female, Amsterdam, fitness, mid-twenties, blonde — and get back ranked profiles with a confidence figure per attribute.
The hard part is that Instagram has no index for any of that. It indexes four things: handle and name text, hashtags, place geotags, and the follow graph. A persona is none of them. So every attribute is either compiled into a probe against one of those four, or inferred afterwards from what came back — which makes this a funnel that trades recall for precision, not a query.
recall hundreds of candidates, mostly wrong, from many cheap probes
gate free: drops private accounts and shops
expand chaining off the best survivors — the highest-precision channel
enrich ~3 API calls each. The expensive stage, so it runs on a ranked subset
signals free: name, pronouns, geotag clusters, captions, category, birth years
judge vision, on the shortlist only, from one contact sheet per candidate
results ranked, with every piece of evidence attachedWhat makes it work is instagram_similar_accounts, which reads Instagram's own
"Suggested for you" graph, built from co-follow behaviour it already models. Once
you have one good match, chaining outward from it beats any keyword search by a
wide margin — which is why the text and hashtag probes exist mainly to find that
first foothold.
Location is the other thing worth knowing about. Instagram's city field is
almost always null and occasionally wrong — one live probe returned a place
called "Hollanda" carrying coordinates in Alexandria, Egypt — and place names
fragment badly, with one city arriving as "Amsterdam, Netherlands", "Amsterdam
Canal District", "Red Light District, Amsterdam" and "Amsterdam Canal River".
Coordinates are always present, so geotags are clustered by position rather than
by name: the variants merge, and the mislabelled entry excludes itself.
One thing the design originally leaned on turned out not to exist. Instagram generates alt text for photos ("may be an image of 1 person, blonde hair, standing"), which would have been free coarse vision on every post — but it is only exposed to the web client, and came back empty on all thirty-two posts of a live probe. Appearance therefore costs a real look at real images, and the ceilings reflect that rather than pretending otherwise.
A search is a job on disk, not a function call: a real one is several hundred API calls over ten or twenty minutes against an account Instagram will rate limit, so it runs stage by stage, survives a crash, and lets you fix a bad probe plan after twenty calls instead of three hundred.
instagram_search_start(persona={"gender": {"value": "female", "required": true},
"city": "Amsterdam", "niche": ["fitness"],
"age_band": [24, 32], "hair": "blonde"})
instagram_search_recall(search_id, probes={"hashtags": [{"tag": "fitgirlnl"}],
"places": [{"query": "Amsterdam gym"}],
"accounts": [{"query": "amsterdam fitness"}]})
instagram_search_gate(search_id) # free
instagram_search_expand(search_id) # chain off the best
instagram_search_enrich(search_id, limit=40)
instagram_search_signals(search_id) # free, and resolves most personas outright
instagram_search_results(search_id, limit=20)Judging the pictures
Appearance is the one thing no free signal reaches, so it has to be looked at.
instagram_search_shortlist(download_images=true) fetches each candidate's
profile picture and recent thumbnails and composes them into a single numbered
contact sheet, rather than handing over a dozen loose files.
That is not just tidier. It costs a twelfth of the attention, the numbers let a
judgement cite the tile it came from, and it makes the hardest question
answerable: which of these faces is the account holder? Feeds are full of
friends, partners and clients, and a judgement made on the wrong face arrives
sounding exactly as confident as a right one. Seeing every picture side by side
turns that into something you can just look at - find the recurring face, check
it against the tile marked avatar, which is the only picture certain to be
them, and report the result as owner_face_confidence. A low value there
weakens how firmly every vision reading is held, rather than pretending the
person fits worse than they do.
A screenshot of the profile page would show much the same thing, but that page needs a logged-in browser to render at all, while these thumbnails have already been fetched and paid for.
Reading the confidence
Every attribute carries two numbers, never one: match is how well the evidence agrees, certainty is how far that evidence can be trusted. A model that reports a single "85%" has silently multiplied them and thrown away which one was weak.
Certainty is capped per attribute and per source, so the system cannot
overclaim. Hair colour read off one avatar caps at 0.45; read off several
daylight posts, 0.80. Country from Instagram's own "account based in" reaches
0.95. Height caps at 0.15 — a photograph carries no scale reference — and
height, ethnicity and build are advisory: reported, never allowed to move a
ranking, and rejected outright if you mark them required.
Unknown is not "no". An attribute nobody could observe lowers coverage, not
match, and the ranking shrinks toward the prior by how little was verified — so
a 0.9 scored on two observed attributes loses to a 0.75 on six. Anything labelled
unverified scored well on too little to act on.
Results are for public accounts. Private ones are dropped at the gate because
they cannot be verified. Nobody under 18 is ever returned: age is read from a
stated birth year and from Instagram's join date, the bottom of that estimate
decides, and the check runs when age first becomes readable and again at every
exit - an audit found the original gate-only version protected nothing, because
the gate runs before any age has been read. Every candidate keeps full provenance — which
probes found them, and what each conclusion rests on. Search jobs live in
searches/ and are gitignored: they hold other people's profiles and photos.
Staying unblocked
instagrapi drives the private API that the phone app uses. Instagram detects and blocks automated behaviour, and the account it blocks is yours — so:
Sessions are cached in
session.jsonand reused. Logging in from scratch repeatedly is the single fastest way to get flagged. Keep that file.Requests are spaced out by a random
INSTAGRAM_DELAY_MIN–INSTAGRAM_DELAY_MAXsecond pause. Raise it if Instagram starts asking you to wait.Back off on warnings. "Please wait a few minutes" and "action blocked" mean stop, not retry. The tools say so in their error messages.
Bulk reads are risky. Pulling thousands of followers in one go looks nothing like a human using the app.
Use a throwaway or secondary account if you are experimenting.
Layout
File | Contains |
| The 49 tool definitions |
| What a persona is, and the confidence maths |
| Reading a persona off a profile, free and offline |
| Given names to a gender prior, offline |
| The recall channels candidates come from |
| A persona search as a resumable job on disk |
| Candidate pictures composed into one judgeable sheet |
| Login, session persistence, the write guard, threading |
| Compact JSON views of instagrapi's models |
| Instagram exceptions turned into actionable advice |
| Offline check: schemas, guards, serializers |
.env and session.json hold credentials and live auth cookies, and searches/
holds other people's profiles and photos. All three are gitignored — keep them
that way.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables LLMs to interact with Instagram through a comprehensive toolkit for account management, content creation, messaging, social graph analysis, and content discovery.11
- AlicenseNot gradedqualityDmaintenanceEnables AI applications to interact with Instagram Business accounts through the Graph API, supporting profile management, media publishing, insights retrieval, and direct messaging capabilities.MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Instagram Business accounts by automating content publishing, scheduling posts, and analyzing performance metrics. Supports posts, stories, reels, and carousels with detailed audience insights and hashtag discovery.
- AlicenseAqualityCmaintenanceEnables AI assistants to manage Instagram and Threads accounts — publish content, handle comments, view insights, search hashtags, and manage DMs through the Meta Graph API.594610MIT
Related MCP Connectors
Instagram for AI agents: publish, read comments and DMs, insights, and engage from your account.
60+ Meta Ads tools for AI agents: audits, campaign management, audiences and CAPI tracking.
Give your agent live data from Twitter, Reddit, the web and GitHub. No API keys, no scraping stack.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/osAlhaddad1/instagram-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server