Skip to main content
Glama
AravDharnikota

VoiceOS Instagram Integration

VoiceOS Instagram Integration

Run your Instagram account by voice from the Mac notch. Ask how the account is doing, read comments and DMs, and publish a photo or a carousel by dropping it on the notch and saying what to caption it.

Business or Creator account required. Instagram's API does not expose insights, comments, DMs, or publishing on a personal account — this is Meta's rule, not ours, and there is no way around it.

To convert: Instagram app → your profile → ☰ menuSettings and privacyAccount type and toolsSwitch to professional account. Pick Creator or Business, then follow the prompts. It is free, it is reversible, and it does not make your account public if it was private. Reconnect this integration afterwards.


Setup

Six steps. Steps 3 and 4 are only needed if you want to publish; reading works without them.

1. Install dependencies

cd instagram
bun install

2. Connect Instagram through Composio

Composio is the auth and API transport this integration runs on.

  1. Get an API key from the Composio dashboard.

  2. Add Instagram as an app in your Composio project. That creates the auth config the connect flow needs.

You approve the actual Instagram OAuth in step 6 — nothing to do here yet.

3. Create the photo relay bucket (Cloudflare R2)

Instagram never accepts image bytes. Meta fetches a public URL instead, with its own crawler. So a photo you drop on the notch is uploaded to your own R2 bucket, handed to Instagram as a link, and deleted seconds later.

In the Cloudflare dashboardR2:

  1. Create a bucket.

  2. Open it → SettingsPublic Development URLEnable. Copy that URL. The bucket must be public or Meta cannot fetch the photo.

  3. Manage API TokensCreate API token, scoped to that one bucket, with Object Read & Write. The secret is shown once — copy it now.

  4. Optional but recommended: add a lifecycle rule to delete objects after 1 day. The integration deletes each photo itself; this is the backstop for the rare miss.

Skip this whole step if you only want to read. account_pulse, post_insights, activity, and dm_thread all work without a bucket. Only create_post and schedule_post need one.

4. Give the server the keys

Create a .env file in this folder:

COMPOSIO_API_KEY=

# Cloudflare R2 — publishing only, leave blank if you are read-only
R2_ACCOUNT_ID=
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET=
R2_PUBLIC_URL=

R2_ACCOUNT_ID is on the Cloudflare R2 → Overview page, top right. R2_PUBLIC_URL is the Public Development URL from step 3.

If VoiceOS prompts you for these as setup fields, that injection wins and the file is only a fallback for running the server standalone.

5. Install into VoiceOS

Quit VoiceOS first. It holds config.json in memory and rewrites it on exit, so anything written while it is running is silently thrown away — with no error at all. The installer refuses to run if it sees VoiceOS alive.

osascript -e 'quit app "VoiceOS"'
python3 install-into-voiceos.py
open -a VoiceOS

That copies this folder into ~/Library/Application Support/VoiceOS/custom-mcps/, carries the keys from step 4 across, and registers it. A plain cp is not enough — VoiceOS also needs two entries in config.json (one saying how to launch the server, one carrying the manifest), and writing those is most of what the script does. It backs up config.json first.

Command

Does

python3 install-into-voiceos.py --check

Report what is installed. Changes nothing, safe while VoiceOS runs.

python3 install-into-voiceos.py --update

Re-copy after editing the source. The edit → test loop.

python3 install-into-voiceos.py --update --deps

Also refresh node_modules, after adding a dependency.

python3 install-into-voiceos.py --remove

Unregister and delete the installed copy.

--update re-derives confirmTools from the manifest every time. That matters more than it looks: it is the list VoiceOS uses to decide which tools need a confirmation card, and a stale entry left over from a rename would let a post publish with no card at all.

6. Connect your account

Say "How's my Instagram doing?" If Instagram isn't linked yet you get a Connect Instagram card with an OAuth link. Approve it once and you're set.

If it says the account is personal, go back to the box at the top of this page.


Tools

Tool

Does

Try saying

Confirms first?

instagram_account_pulse

Profile, follower and post counts, recent reach and profile views, plus a grid of your latest posts

"How's my Instagram doing?" · "How many followers do I have?"

No

instagram_post_insights

Everything on one post: likes, comments, shares, saves, reach, impressions, and the image

"How's my latest post doing?"

No

instagram_activity

New comments on your posts, recent DMs, and any scheduled post that failed or is still queued

"What's new on Instagram?" · "Did my scheduled post go out?"

No

instagram_dm_thread

Recent messages with one person, and marks them seen

"Show me my messages with Jonah" · "Did Kai reply?"

No

instagram_create_post

Publishes a photo or carousel you dropped on the notch, with a caption you speak or one written for you

"Post this picture on Instagram"

Yes

instagram_schedule_post

Queues that same post to publish later, up to 24 hours out

"Schedule this for tomorrow at 9am"

Yes

Drop the photos onto the notch and speak in the same breath — "post these two with a caption about the hackathon". Both writing tools show you the photos, the caption, and (for a schedule) the exact time on a card before anything goes live.


How your photos are handled

Worth reading once, because one step surprises people.

  1. The photo is converted to JPEG on your Mac with sips (built into macOS). Instagram accepts nothing else.

  2. It is uploaded to your R2 bucket under a random unguessable name, and is publicly readable for a few seconds. This is unavoidable: Meta's crawler is anonymous and cannot log in, so a public URL is the only way Instagram will take a photo.

  3. Instagram fetches it and publishes the post.

  4. The file is deleted from the bucket — on success and on failure, in a finally block. The lifecycle rule from step 3 is the backstop.

The bucket is yours. Nothing is stored on anyone else's server, and this integration keeps no copy of your photos.

Scheduled posts run on your Mac, not on Instagram's servers — Instagram has no scheduling API. A macOS launchd timer wakes at the minute you named and publishes then. So the Mac has to be on and awake. If it was shut when the post was due, the post is recorded as missed rather than published hours late, and instagram_activity tells you next time you ask.


Not in v1

Cut deliberately, so you know before you try:

  • Sending DMs. Meta blocks API DM sends through Composio's shared Instagram app — it returns "outside the allowed window" errors even with the 24-hour window provably open. The integration reads DMs but cannot send them. Reply in the Instagram app.

  • Replying to comments. Same transport limitation.

  • Video and Reels. Photos and photo carousels only. Video publishing needs a resumable upload path this build does not have.

  • Stories. Not exposed by the toolkit.

  • Scheduling further than 24 hours out. The ceiling is deliberate: every extra hour is another way a deferred job rots where nobody can see it — the photo gets deleted, a key is rotated, the connection is revoked.

  • Reading other accounts. Your connected account only.


Troubleshooting

Symptom

Cause

"Instagram isn't supported yet" or the tools do not appear

The install did not register. Run --check; if it reports "not installed", re-run the installer with VoiceOS quit.

Everything returns the Connect card

Token expired, or the connection was revoked. Approve the OAuth link on the card again.

Publishing says the relay isn't set up

One of the five R2_* values is missing or blank.

Publishing fails with "Instagram rejected that image"

Wrong aspect ratio (Instagram allows 4:5 to 1.91:1), or over 8 MB after conversion.

A scheduled post never happened

Ask "what's new on Instagram?" — a failed or missed post is reported there with the reason.


Development

bun install
bun test          # 224 unit and failure-injection tests
bunx tsc --noEmit -p tsconfig.json

Three rules the tests exist to protect, worth knowing before editing:

  • stdout is the MCP wire. One console.log in shipped code and VoiceOS cannot parse the JSON-RPC stream, so the integration silently vanishes from routing until the app restarts. Everything logs through console.error; stdoutGuard.ts is the first import in server.ts and rebinds the console for dependencies that do not.

  • Never build a shell string from a file path. Photos come from the user dragging a file onto the notch. execFile(cmd, [args]) only — a file named holiday.png; rm -rf ~ is one opaque argument to sips, and test/media-paths.test.ts asserts it.

  • Tool names and descriptions must match the manifest exactly, in both directions. server.ts and voiceos.integration.json are two copies of one contract.

confirmations/post_composer.html is the source of truth for the pre-publish card; the manifest carries a copy of it as a string. Edit the HTML and the copy must be regenerated, or the card shown before an irreversible publish is the stale one.

-
license - not tested
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Publish, schedule and verify social posts across seven networks from your AI assistant.

  • Boost posts and launch community growth campaigns from your AI assistant. OAuth, credit-billed.

  • Create, schedule and publish social posts to TikTok, Instagram, Facebook and YouTube.

View all MCP Connectors

Latest Blog Posts

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/AravDharnikota/voiceos-instagram-integration'

If you have feedback or need assistance with the MCP directory API, please join our Discord server