Skip to main content
Glama
IotA-asce
by IotA-asce

Social Harvest MCP

Local-first Instagram export, inbox search, and messaging automation for MCP-compatible AI agents.

Version Node.js License

Social Harvest connects Claude Code, Codex, OpenCode, and other MCP clients to Instagram through a browser session that you authenticate manually. It can export profiles and media, synchronize a searchable local inbox, send messages and attachments, manage common conversation actions, and monitor inbox changes.

Social Harvest executes locally, and all persistent data stays on your machine. Instagram traffic originates from the local authenticated browser session.

IMPORTANT

Social Harvest uses Instagram’s authenticated web experience—not Meta OAuth, the official Instagram APIs, or webhooks. Instagram can change its endpoints and controls without notice. Use this project only with accounts and content you are authorized to access.

Contents

Related MCP server: Instagram Download MCP Server

Highlights

Area

What Social Harvest provides

Profile export

Profile metadata, posts, reels, captions, hashtags, mentions, reported metrics, bounded comments, and optional active stories

Media archive

Streaming downloads for profile images, posts, reels, carousels, stories, thumbnails, and DM attachments, with SHA-256 metadata

Local inbox

Primary, General, Requests, groups, and spam/hidden system buckets synchronized into SQLite

Search

FTS5 full-text message search with thread, folder, sender, and date filters

Messaging

Text, local images, video, audio, GIF/sticker search, group-thread targeting, and replies

Conversation actions

React or unreact, mark read or unread, and accept or decline message requests

Automation

Background jobs, adaptive inbox monitoring, durable events, and optional idempotency keys

Agent safety

Bounded reads, explicit side-effect annotations, fail-closed message targeting, and confirmed purge operations

How it works

flowchart LR
    A[MCP client] --> B[Social Harvest MCP]
    C[CLI] --> D[Instagram services]
    B --> D
    D --> E[Shared Playwright session]
    E --> F[Instagram Web]
    D --> G[JSON and NDJSON exports]
    D --> H[SQLite inbox and FTS5]
    D --> I[Content-addressed media]
    H --> J[Durable event queue]

Social Harvest launches Chromium with a persistent profile directory. You complete login and any verification yourself; later CLI and MCP operations reuse that authenticated profile. Concurrent operations share one browser context while receiving isolated pages.

Quick start

Requirements

  • Node.js 20 or newer

  • npm

  • An Instagram account permitted to access the requested content

1. Install

git clone https://github.com/IotA-asce/social-harvest-mcp.git
cd social-harvest-mcp
npm install
npx playwright install chromium

2. Authenticate Instagram

npm run login

A visible browser opens. Log in, complete any verification, return to the terminal, and press Enter. The session is saved under .playwright-profile/instagram/, which is excluded from Git.

Social Harvest never asks for or stores your Instagram password directly.

3. Verify the environment

npm run doctor

The doctor checks the Node.js version, Playwright browser availability, profile directory, and authenticated Instagram session.

4. Start the MCP server

npm run mcp

For client-specific configuration, see Connect an MCP client.

Common workflows

Export a profile and its media

npm run scrape -- --username nasa --max-items 20 --max-comments 50

Media downloading is enabled by default. Normalized assets retain their remote URL and receive local path, MIME type, byte size, and SHA-256 metadata.

Exports use a deterministic run structure:

exports/
└── instagram/
    └── nasa/
        └── 2026-07-28T.../
            ├── manifest.json
            ├── profile.json
            ├── posts.ndjson
            ├── reels.ndjson
            ├── stories.ndjson
            ├── comments.ndjson
            ├── errors.ndjson
            ├── checkpoint.json
            └── media/

Only files containing records are created.

To backfill or resume media for an existing export:

npm run download-media -- --export-dir ./exports/instagram/nasa/2026-07-28T...

To watch the browser and include active stories:

npm run scrape -- \
  --username nasa \
  --max-items 20 \
  --include-stories true \
  --headless false
WARNING

Opening an active story creates Instagram’s normal story-view receipt. The story owner may see the authenticated account in their viewer list. Story export is disabled by default.

Synchronize the inbox

npm run sync-inbox -- --folders primary,general,requests,system
npm run inbox-status

Inbox sync stores normalized threads, participants, messages, attachments, reactions, receipts, and pagination state in SQLite. Attachments are stored by content hash so identical files can be reused safely.

The first successful sync of each account and folder is a silent seed: existing history is stored without generating a flood of “new message” events. Later syncs produce deduplicated events for observed changes.

Folder names exposed by the CLI and MCP are normalized as follows:

Folder

Meaning

primary

Instagram Primary, including the internal main label

general

Instagram General

requests

Pending message requests

system

Current spam and hidden-request buckets

Capture one conversation snapshot

Use instagram_get_messages when an agent needs a portable, bounded snapshot for an exact username. The complete requested history is written locally while the MCP response returns only a small preview.

dm-exports/
└── instagram/
    └── username/
        └── 2026-07-28T.../
            ├── manifest.json
            ├── thread.json
            ├── messages.ndjson
            └── media/

The configured message maximum is 1,000 records per snapshot.

NOTE

Opening or fetching a conversation may apply Instagram’s normal read-state behavior.

Send messages and attachments

instagram_send_message targets exactly one username or stable threadId. Thread targeting supports one-to-one conversations and groups.

Supported message parts:

  • text up to 1,000 characters;

  • up to 10 local JPEG, PNG, MP4, MOV, or supported audio files;

  • one GIF/sticker selected with gifQuery and optional gifIndex;

  • an optional replyToMessageId after the conversation has been synchronized.

Text, an attachment batch, and a GIF/sticker are submitted as separate message parts. Local .gif uploads are not accepted by the current Instagram composer; use gifQuery instead.

Example agent request:

Send “The draft is ready” and ./preview.png to the synchronized Instagram
thread 123456. Use clientRequestId "draft-preview-2026-07-28".
CAUTION

Messaging, reactions, read-state changes, and request decisions happen immediately. Social Harvest does not provide a draft-confirm step.

Monitor changes

instagram_start_inbox_monitor performs an immediate sync and then polls at a 60-second interval with ±15% jitter. Transient failures use exponential backoff capped at 15 minutes.

Authentication, checkpoint, or challenge failures pause the monitor and release its browser session hold. Monitors never restart automatically after a pause or process restart.

Use:

  • instagram_inbox_monitor_status to inspect the current process-local state;

  • instagram_stop_inbox_monitor to stop polling;

  • instagram_list_inbox_events to read durable local events;

  • instagram_ack_inbox_events to mark events acknowledged locally.

Acknowledgement does not change Instagram state and does not delete the event record.

MCP tools

Core, jobs, and exports

Tool

Purpose

Side effects

social_capabilities

Describe supported platforms, record types, and limits

None

instagram_start_export

Start a bounded profile export job

Reads Instagram; writes local files

social_job_status

Read status for any retained background job

None

social_export_status

Compatibility alias for social_job_status

None

social_list_export_files

List files in an export directory

None

social_read_export

Read bounded JSON or NDJSON records

None

Tool

Purpose

Side effects

instagram_start_inbox_sync

Synchronize selected inbox folders

Reads Instagram; writes local data

instagram_get_messages

Capture a bounded exact-username snapshot and index it locally

May mark a conversation read; writes local data

instagram_list_conversations

List locally synchronized threads with filters

None

instagram_get_conversation

Read bounded local history, optionally refreshing first

Optional Instagram read; optional local writes

instagram_search_messages

Search local messages through FTS5

None

Immediate Instagram actions

Tool

Purpose

Side effects

instagram_send_message

Send text, local attachments, GIF/sticker content, or a reply

Immediate Instagram write

instagram_set_message_reaction

Set or remove the viewer’s emoji reaction

Immediate Instagram write

instagram_set_conversation_state

Mark a thread read or unread

Immediate Instagram write

instagram_handle_message_request

Accept or decline a pending request

Immediate, potentially destructive Instagram write

Monitoring, events, and retention

Tool

Purpose

Side effects

instagram_start_inbox_monitor

Start process-local adaptive polling

Repeated Instagram reads and local writes

instagram_inbox_monitor_status

Read monitor state

None

instagram_stop_inbox_monitor

Stop polling and release the held session

Local process state only

instagram_list_inbox_events

Read durable local events

None

instagram_ack_inbox_events

Mark events acknowledged

Local database write only

instagram_purge_inbox_data

Delete scoped thread/message data and unreferenced media

Destructive local write; requires confirm=true

Export and inbox-sync tools return immediately with a job ID. Poll them with social_job_status. Jobs are retained in memory for the lifetime of the MCP server process.

Connect an MCP client

Use the included templates and replace the example project path with an absolute path to your clone.

Client

Configuration template

Claude Code

examples/claude-code.json

Codex

examples/codex.toml

OpenCode

examples/opencode.json

A typical agent workflow looks like this:

Use Social Harvest to synchronize my Instagram inbox without downloading media.
Poll the job until it completes, list unread conversations, and summarize the
five most recent messages without sending or changing anything.

Storage and privacy

Social Harvest excludes its default private-data directories from Git:

Path

Contents

.playwright-profile/

Authenticated browser state and cookies

exports/

Profile exports and public/session-visible media

dm-exports/

Private bounded conversation snapshots

inbox-data/

SQLite inbox, event queue, mutation audit, and private media

The inbox layout is:

inbox-data/
├── instagram.sqlite
├── instagram.sqlite-wal
├── instagram.sqlite-shm
└── media/
    └── ab/
        └── abcdef...<original-extension>

On POSIX platforms, Social Harvest forces inbox directories to mode 0700 and the database/media files it creates to mode 0600.

WARNING

The database, media, exports, and browser profile are plaintext. Filesystem permissions and the security of your device and backups are the only protection in this release.

instagram_purge_inbox_data removes a selected thread or messages before a timestamp and garbage-collects only media no longer referenced by another stored message. Durable event and mutation-audit rows remain in the SQLite database. To erase all local inbox state, stop Social Harvest and remove inbox-data/ yourself.

See SECURITY.md for acceptable-use boundaries and handling guidance.

Operational semantics

Submitted is not delivered

A mutation result with status: "submitted" means Instagram accepted the browser request or composer interaction. It is not a delivery receipt, read receipt, or guarantee that Instagram will retain the message.

Retry safety

Mutation tools accept an optional clientRequestId. Once a request ID completes, retrying it returns the stored result without repeating the browser interaction. Reusing the same ID for a different operation is rejected.

Calls without a request ID are not idempotent and can repeat an action or send duplicate content.

Partial sends

When a call includes text, attachments, and a GIF/sticker, Instagram receives separate parts. A later part can fail after an earlier part was submitted. Social Harvest reports this as direct_send_partial; inspect submitted_parts before retrying.

Fail-closed message mapping

Replies and reactions map a synchronized message ID to one unique rendered text fingerprint. If the message is not rendered, contains no uniquely usable text, or matches multiple visible messages, Social Harvest refuses the action instead of risking interaction with the wrong message. Media-only and duplicate-text messages can therefore require a different target or a later adapter improvement.

Completeness

“Complete” means all records discoverable by the authenticated browser session within the configured bounds. It does not include deleted content, expired stories, inaccessible private content, platform-hidden content, or records Instagram did not load.

Absence is never treated as deletion. Only explicit tombstones or unsend state are stored as deleted messages. Media download failures do not roll back successfully synchronized message metadata.

Limitations

  • Instagram’s private web endpoints, response shapes, numeric folder selectors, and rendered controls can change without notice.

  • Comments and stories are best-effort and bounded.

  • Inbox history is bounded by configured folder, thread, and message pagination limits.

  • Disappearing or unsupported message types may retain metadata without usable content.

  • Story collection creates a normal story-view receipt.

  • Reading conversations can create normal read-state behavior.

  • The project does not solve CAPTCHAs, bypass access controls, rotate proxies, or attempt anti-bot evasion.

  • Eligible professional accounts should prefer an official Instagram API when its permissions and data coverage satisfy the use case.

Development

Run the complete test suite and syntax checks:

npm test
npm run check

Useful diagnostics:

npm run doctor
npm run inbox-status
npm audit

The project uses Node.js ESM, Playwright, the Model Context Protocol TypeScript SDK, Zod, better-sqlite3, SQLite WAL/FTS5, and the built-in Node.js test runner.

License

Released under the MIT License.

A
license - permissive license
-
quality - not tested
B
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 Servers

View all related MCP servers

Related MCP Connectors

  • Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.

  • Mastodon MCP — public Mastodon data via mastodon.social (no auth required)

  • Hosted MCP for X/Twitter and Reddit. 12 read-only tools, no API keys, free during beta.

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/IotA-asce/social-harvest-mcp'

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