instagram-mcp-server 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -0
- package/.github/dependabot.yml +50 -0
- package/.github/workflows/ci.yml +51 -0
- package/.github/workflows/release.yml +200 -0
- package/CONTRIBUTING.md +38 -0
- package/LICENSE +21 -0
- package/Makefile +16 -0
- package/README.md +141 -0
- package/dist/client.d.ts +57 -0
- package/dist/client.js +140 -0
- package/dist/client.test.d.ts +10 -0
- package/dist/client.test.js +212 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +87 -0
- package/dist/errors.test.d.ts +9 -0
- package/dist/errors.test.js +164 -0
- package/dist/first-comment.test.d.ts +10 -0
- package/dist/first-comment.test.js +56 -0
- package/dist/handlers.test.d.ts +23 -0
- package/dist/handlers.test.js +355 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.js +627 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +5 -0
- package/dist/lib/insights.d.ts +55 -0
- package/dist/lib/insights.js +59 -0
- package/dist/rate-limiter.d.ts +72 -0
- package/dist/rate-limiter.js +219 -0
- package/dist/rate-limiter.test.d.ts +1 -0
- package/dist/rate-limiter.test.js +153 -0
- package/dist/response.d.ts +24 -0
- package/dist/response.js +35 -0
- package/dist/response.test.d.ts +1 -0
- package/dist/response.test.js +71 -0
- package/dist/sanitize.d.ts +17 -0
- package/dist/sanitize.js +27 -0
- package/dist/sanitize.test.d.ts +1 -0
- package/dist/sanitize.test.js +43 -0
- package/dist/tools.test.d.ts +14 -0
- package/dist/tools.test.js +188 -0
- package/package.json +32 -0
- package/src/client.test.ts +285 -0
- package/src/client.ts +204 -0
- package/src/errors.test.ts +299 -0
- package/src/errors.ts +108 -0
- package/src/first-comment.test.ts +75 -0
- package/src/handlers.test.ts +460 -0
- package/src/index.ts +960 -0
- package/src/lib/index.ts +6 -0
- package/src/lib/insights.ts +182 -0
- package/src/rate-limiter.test.ts +185 -0
- package/src/rate-limiter.ts +257 -0
- package/src/response.test.ts +80 -0
- package/src/response.ts +43 -0
- package/src/sanitize.test.ts +52 -0
- package/src/sanitize.ts +35 -0
- package/src/tools.test.ts +251 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +10 -0
package/.env.example
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# npm dependencies
|
|
4
|
+
- package-ecosystem: "npm"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
open-pull-requests-limit: 5
|
|
10
|
+
labels:
|
|
11
|
+
- "dependencies"
|
|
12
|
+
commit-message:
|
|
13
|
+
prefix: "chore(deps)"
|
|
14
|
+
groups:
|
|
15
|
+
dev-dependencies:
|
|
16
|
+
patterns:
|
|
17
|
+
- "typescript"
|
|
18
|
+
- "tsx"
|
|
19
|
+
- "vitest"
|
|
20
|
+
- "@types/*"
|
|
21
|
+
- "prettier"
|
|
22
|
+
update-types:
|
|
23
|
+
- "minor"
|
|
24
|
+
- "patch"
|
|
25
|
+
runtime-dependencies:
|
|
26
|
+
patterns:
|
|
27
|
+
- "@modelcontextprotocol/*"
|
|
28
|
+
- "zod"
|
|
29
|
+
update-types:
|
|
30
|
+
- "patch"
|
|
31
|
+
|
|
32
|
+
# GitHub Actions
|
|
33
|
+
- package-ecosystem: "github-actions"
|
|
34
|
+
directory: "/"
|
|
35
|
+
schedule:
|
|
36
|
+
interval: "weekly"
|
|
37
|
+
day: "monday"
|
|
38
|
+
open-pull-requests-limit: 3
|
|
39
|
+
labels:
|
|
40
|
+
- "dependencies"
|
|
41
|
+
- "github-actions"
|
|
42
|
+
commit-message:
|
|
43
|
+
prefix: "chore(deps)"
|
|
44
|
+
groups:
|
|
45
|
+
github-actions:
|
|
46
|
+
patterns:
|
|
47
|
+
- "*"
|
|
48
|
+
update-types:
|
|
49
|
+
- "minor"
|
|
50
|
+
- "patch"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test-matrix:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
node-version: ["20", "22"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v7
|
|
18
|
+
|
|
19
|
+
- name: Set up Node.js ${{ matrix.node-version }}
|
|
20
|
+
uses: actions/setup-node@v6
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
cache: "npm"
|
|
24
|
+
|
|
25
|
+
- name: Install dependencies
|
|
26
|
+
run: npm ci
|
|
27
|
+
|
|
28
|
+
- name: Format check with prettier
|
|
29
|
+
run: npx prettier --check .
|
|
30
|
+
|
|
31
|
+
- name: Type check with tsc
|
|
32
|
+
run: npx tsc --noEmit
|
|
33
|
+
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: npm test
|
|
36
|
+
|
|
37
|
+
- name: Build
|
|
38
|
+
run: npm run build
|
|
39
|
+
|
|
40
|
+
test:
|
|
41
|
+
needs: [test-matrix]
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
if: always()
|
|
44
|
+
steps:
|
|
45
|
+
- name: Check test matrix status
|
|
46
|
+
run: |
|
|
47
|
+
if [ "${{ needs.test-matrix.result }}" != "success" ]; then
|
|
48
|
+
echo "Test matrix failed with result: ${{ needs.test-matrix.result }}"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo "All tests passed!"
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
packages: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
if: github.ref == 'refs/heads/main'
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v7
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
token: ${{ secrets.RELEASE_TOKEN }}
|
|
23
|
+
|
|
24
|
+
- name: Check for skip-release marker
|
|
25
|
+
id: check_skip
|
|
26
|
+
run: |
|
|
27
|
+
SUBJECT=$(git log -1 --pretty=%s)
|
|
28
|
+
if echo "$SUBJECT" | grep -q '\[skip-release\]'; then
|
|
29
|
+
echo "skip=true" >> $GITHUB_OUTPUT
|
|
30
|
+
echo "Skipping release: $SUBJECT"
|
|
31
|
+
else
|
|
32
|
+
echo "skip=false" >> $GITHUB_OUTPUT
|
|
33
|
+
echo "Proceeding with release check: $SUBJECT"
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
- name: Set up Node.js
|
|
37
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
38
|
+
uses: actions/setup-node@v6
|
|
39
|
+
with:
|
|
40
|
+
node-version: "20"
|
|
41
|
+
registry-url: "https://registry.npmjs.org"
|
|
42
|
+
cache: "npm"
|
|
43
|
+
|
|
44
|
+
- name: Install dependencies
|
|
45
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
46
|
+
run: npm ci
|
|
47
|
+
|
|
48
|
+
- name: Run tests
|
|
49
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
50
|
+
run: npm test
|
|
51
|
+
|
|
52
|
+
- name: Build
|
|
53
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
54
|
+
run: npm run build
|
|
55
|
+
|
|
56
|
+
- name: Configure Git
|
|
57
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
58
|
+
run: |
|
|
59
|
+
git config user.name "github-actions[bot]"
|
|
60
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
61
|
+
|
|
62
|
+
- name: Determine next version
|
|
63
|
+
id: version
|
|
64
|
+
if: steps.check_skip.outputs.skip != 'true'
|
|
65
|
+
run: |
|
|
66
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
67
|
+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
|
|
68
|
+
|
|
69
|
+
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
70
|
+
|
|
71
|
+
if [ -z "$LAST_TAG" ]; then
|
|
72
|
+
echo "new_release=true" >> $GITHUB_OUTPUT
|
|
73
|
+
echo "new_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
|
74
|
+
echo "bump=initial" >> $GITHUB_OUTPUT
|
|
75
|
+
echo "First release: $CURRENT_VERSION"
|
|
76
|
+
exit 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
COMMITS=$(git log "$LAST_TAG"..HEAD --pretty=%s)
|
|
80
|
+
|
|
81
|
+
if [ -z "$COMMITS" ]; then
|
|
82
|
+
echo "No new commits since $LAST_TAG"
|
|
83
|
+
echo "new_release=false" >> $GITHUB_OUTPUT
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
BUMP=""
|
|
88
|
+
if echo "$COMMITS" | grep -qiE '^[a-z]+(\(.+\))?!:|BREAKING CHANGE'; then
|
|
89
|
+
BUMP="major"
|
|
90
|
+
elif echo "$COMMITS" | grep -qiE '^feat(\(.+\))?:'; then
|
|
91
|
+
BUMP="minor"
|
|
92
|
+
elif echo "$COMMITS" | grep -qiE '^(fix|perf|refactor)(\(.+\))?:'; then
|
|
93
|
+
BUMP="patch"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [ -z "$BUMP" ]; then
|
|
97
|
+
echo "No release-worthy commits (feat/fix/perf/refactor) since $LAST_TAG"
|
|
98
|
+
echo "new_release=false" >> $GITHUB_OUTPUT
|
|
99
|
+
exit 0
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
|
|
103
|
+
case "$BUMP" in
|
|
104
|
+
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
|
|
105
|
+
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
|
|
106
|
+
patch) PATCH=$((PATCH + 1)) ;;
|
|
107
|
+
esac
|
|
108
|
+
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
|
|
109
|
+
|
|
110
|
+
echo "new_release=true" >> $GITHUB_OUTPUT
|
|
111
|
+
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
|
112
|
+
echo "bump=$BUMP" >> $GITHUB_OUTPUT
|
|
113
|
+
echo "Detected $BUMP bump: $CURRENT_VERSION → $NEW_VERSION"
|
|
114
|
+
|
|
115
|
+
- name: Bump version in package.json
|
|
116
|
+
if: steps.version.outputs.new_release == 'true'
|
|
117
|
+
run: |
|
|
118
|
+
if [ "${{ steps.version.outputs.bump }}" = "initial" ]; then
|
|
119
|
+
git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}"
|
|
120
|
+
else
|
|
121
|
+
npm version ${{ steps.version.outputs.new_version }} --no-git-tag-version
|
|
122
|
+
git add package.json package-lock.json
|
|
123
|
+
git commit -m "chore(release): ${{ steps.version.outputs.new_version }} [skip-release]"
|
|
124
|
+
git tag -a "v${{ steps.version.outputs.new_version }}" -m "Release v${{ steps.version.outputs.new_version }}"
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
- name: Push version commit and tag
|
|
128
|
+
if: steps.version.outputs.new_release == 'true'
|
|
129
|
+
run: |
|
|
130
|
+
git push origin main --follow-tags
|
|
131
|
+
|
|
132
|
+
- name: Generate release notes
|
|
133
|
+
id: notes
|
|
134
|
+
if: steps.version.outputs.new_release == 'true'
|
|
135
|
+
run: |
|
|
136
|
+
LAST_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
|
|
137
|
+
NEW_VERSION="v${{ steps.version.outputs.new_version }}"
|
|
138
|
+
|
|
139
|
+
{
|
|
140
|
+
echo "notes<<RELEASE_NOTES_EOF"
|
|
141
|
+
|
|
142
|
+
if [ -n "$LAST_TAG" ]; then
|
|
143
|
+
echo "## What's Changed"
|
|
144
|
+
echo ""
|
|
145
|
+
|
|
146
|
+
FEATS=$(git log "$LAST_TAG"..HEAD~1 --pretty="- %s" | grep -iE '^\- feat' || true)
|
|
147
|
+
FIXES=$(git log "$LAST_TAG"..HEAD~1 --pretty="- %s" | grep -iE '^\- fix' || true)
|
|
148
|
+
OTHERS=$(git log "$LAST_TAG"..HEAD~1 --pretty="- %s" | grep -viE '^\- (feat|fix|chore\(release\))' || true)
|
|
149
|
+
|
|
150
|
+
if [ -n "$FEATS" ]; then
|
|
151
|
+
echo "### Features"
|
|
152
|
+
echo "$FEATS"
|
|
153
|
+
echo ""
|
|
154
|
+
fi
|
|
155
|
+
if [ -n "$FIXES" ]; then
|
|
156
|
+
echo "### Bug Fixes"
|
|
157
|
+
echo "$FIXES"
|
|
158
|
+
echo ""
|
|
159
|
+
fi
|
|
160
|
+
if [ -n "$OTHERS" ]; then
|
|
161
|
+
echo "### Other Changes"
|
|
162
|
+
echo "$OTHERS"
|
|
163
|
+
echo ""
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/$LAST_TAG...$NEW_VERSION"
|
|
167
|
+
else
|
|
168
|
+
echo "Initial release"
|
|
169
|
+
fi
|
|
170
|
+
|
|
171
|
+
echo "RELEASE_NOTES_EOF"
|
|
172
|
+
} >> $GITHUB_OUTPUT
|
|
173
|
+
|
|
174
|
+
- name: Create GitHub Release
|
|
175
|
+
if: steps.version.outputs.new_release == 'true'
|
|
176
|
+
env:
|
|
177
|
+
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
178
|
+
run: |
|
|
179
|
+
gh release create "v${{ steps.version.outputs.new_version }}" \
|
|
180
|
+
--title "v${{ steps.version.outputs.new_version }}" \
|
|
181
|
+
--notes "${{ steps.notes.outputs.notes }}" \
|
|
182
|
+
--latest
|
|
183
|
+
|
|
184
|
+
- name: Publish to npm
|
|
185
|
+
if: steps.version.outputs.new_release == 'true'
|
|
186
|
+
env:
|
|
187
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
188
|
+
run: |
|
|
189
|
+
npm publish
|
|
190
|
+
|
|
191
|
+
- name: Release summary
|
|
192
|
+
if: steps.version.outputs.new_release == 'true'
|
|
193
|
+
run: |
|
|
194
|
+
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
|
|
195
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
196
|
+
echo "Released version: **v${{ steps.version.outputs.new_version }}** (${{ steps.version.outputs.bump }} bump)" >> $GITHUB_STEP_SUMMARY
|
|
197
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
198
|
+
echo "Published to:" >> $GITHUB_STEP_SUMMARY
|
|
199
|
+
echo "- GitHub Releases" >> $GITHUB_STEP_SUMMARY
|
|
200
|
+
echo "- npm (npx installable)" >> $GITHUB_STEP_SUMMARY
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing to Instagram MCP Server!
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork: `git clone https://github.com/your-username/instagram-mcp-server.git`
|
|
9
|
+
3. Install dependencies: `npm install`
|
|
10
|
+
4. Create a feature branch: `git checkout -b feat/my-feature`
|
|
11
|
+
|
|
12
|
+
## Development
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm run dev # Run with tsx (hot reload)
|
|
16
|
+
npm run build # Compile TypeScript
|
|
17
|
+
npm test # Run tests
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Pull Requests
|
|
21
|
+
|
|
22
|
+
- Keep PRs focused on a single change
|
|
23
|
+
- Add tests for new functionality
|
|
24
|
+
- Make sure `npm test` and `npm run build` pass
|
|
25
|
+
- Use clear, descriptive commit messages
|
|
26
|
+
|
|
27
|
+
## Reporting Issues
|
|
28
|
+
|
|
29
|
+
Open an issue with:
|
|
30
|
+
|
|
31
|
+
- What you expected to happen
|
|
32
|
+
- What actually happened
|
|
33
|
+
- Steps to reproduce
|
|
34
|
+
- Node.js version and OS
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Luminary Lane
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Makefile
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Instagram MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://modelcontextprotocol.io)
|
|
4
|
+
[](https://www.typescriptlang.org)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A Model Context Protocol (MCP) server that connects Claude Desktop (and other MCP clients) to the Instagram Graph API — read analytics, manage comments, publish photos, carousels, and reels.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### 11 Instagram Tools
|
|
12
|
+
|
|
13
|
+
**SENSE (read-only):**
|
|
14
|
+
| Tool | Description |
|
|
15
|
+
|------|-------------|
|
|
16
|
+
| `ig_get_account_insights` | Account insights: reach, follower growth, profile views over a period |
|
|
17
|
+
| `ig_get_post_insights` | Engagement metrics for a specific post: reach, likes, shares, saves |
|
|
18
|
+
| `ig_get_comments` | Comments on a post with username, timestamp, and replies |
|
|
19
|
+
| `ig_get_stories_insights` | Insights for an active story: reach, replies, interactions |
|
|
20
|
+
| `ig_get_audience_demographics` | Follower demographics: city, country, age/gender breakdown |
|
|
21
|
+
| `ig_get_hashtag_search` | Search public posts by hashtag (30 unique hashtags per 7-day window) |
|
|
22
|
+
|
|
23
|
+
**ACT (write):**
|
|
24
|
+
| Tool | Description |
|
|
25
|
+
|------|-------------|
|
|
26
|
+
| `ig_publish_photo` | Publish a photo post from a public URL |
|
|
27
|
+
| `ig_publish_carousel` | Publish a carousel (2-10 images) from public URLs |
|
|
28
|
+
| `ig_publish_reel` | Publish a reel (short video) from a public URL |
|
|
29
|
+
| `ig_reply_comment` | Reply to a comment on a post |
|
|
30
|
+
| `ig_delete_comment` | Delete a comment on one of your posts |
|
|
31
|
+
|
|
32
|
+
### Built-in Reliability
|
|
33
|
+
|
|
34
|
+
- **Per-tenant rate limiting** — token-bucket rate limiter keyed by IG Business Account ID
|
|
35
|
+
- **Exponential backoff retry** — automatic retry with jitter for transient API errors
|
|
36
|
+
- **Container-based publishing** — create container → poll status → publish (handles async video processing)
|
|
37
|
+
- **Input sanitization** — strips zero-width characters, normalizes whitespace, truncates to API limits
|
|
38
|
+
- **Prompt injection protection** — wraps external API data in randomized markers
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
- Node.js 18+
|
|
45
|
+
- An Instagram Business or Creator account connected to a Facebook Page
|
|
46
|
+
- A Facebook App with the Instagram Graph API enabled
|
|
47
|
+
- A long-lived Page Access Token
|
|
48
|
+
|
|
49
|
+
### Getting Your Access Token
|
|
50
|
+
|
|
51
|
+
1. Create a [Facebook App](https://developers.facebook.com/apps/)
|
|
52
|
+
2. Add the **Instagram Graph API** product
|
|
53
|
+
3. In [Graph API Explorer](https://developers.facebook.com/tools/explorer/), generate a Page Access Token with these permissions:
|
|
54
|
+
- `instagram_basic`, `instagram_content_publish`, `instagram_manage_comments`, `instagram_manage_insights`, `pages_show_list`, `pages_read_engagement`
|
|
55
|
+
4. [Extend the token](https://developers.facebook.com/tools/debug/accesstoken/) to a long-lived token (60 days)
|
|
56
|
+
|
|
57
|
+
### Installation
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
git clone https://github.com/luminarylane/instagram-mcp-server.git
|
|
61
|
+
cd instagram-mcp-server
|
|
62
|
+
npm install
|
|
63
|
+
npm run build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Configuration
|
|
67
|
+
|
|
68
|
+
**Claude Desktop (`claude_desktop_config.json`):**
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"instagram": {
|
|
74
|
+
"command": "node",
|
|
75
|
+
"args": ["/path/to/instagram-mcp-server/dist/index.js"],
|
|
76
|
+
"env": {
|
|
77
|
+
"INSTAGRAM_ACCESS_TOKEN": "your_long_lived_page_token",
|
|
78
|
+
"INSTAGRAM_BUSINESS_ACCOUNT_ID": "your_17_digit_ig_business_account_id"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Environment variables:**
|
|
86
|
+
|
|
87
|
+
| Variable | Required | Description |
|
|
88
|
+
| ------------------------------- | -------- | ------------------------------------- |
|
|
89
|
+
| `INSTAGRAM_ACCESS_TOKEN` | Yes\* | Long-lived Facebook Page Access Token |
|
|
90
|
+
| `INSTAGRAM_BUSINESS_ACCOUNT_ID` | Yes\* | 17-digit IG Business Account ID |
|
|
91
|
+
|
|
92
|
+
\*Can also be passed per-call via tool arguments.
|
|
93
|
+
|
|
94
|
+
### Finding Your Business Account ID
|
|
95
|
+
|
|
96
|
+
Use the Graph API Explorer:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
GET /me/accounts?fields=instagram_business_account
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The `instagram_business_account.id` field is your Business Account ID.
|
|
103
|
+
|
|
104
|
+
## Usage Examples
|
|
105
|
+
|
|
106
|
+
Once configured, ask Claude to:
|
|
107
|
+
|
|
108
|
+
- "Show me my Instagram account insights for the last 28 days"
|
|
109
|
+
- "What are the engagement metrics for my latest post?"
|
|
110
|
+
- "Get the comments on this post" (paste a media ID)
|
|
111
|
+
- "Show my follower demographics by country"
|
|
112
|
+
- "Publish this photo to Instagram" (provide a public image URL + caption)
|
|
113
|
+
- "Create a carousel post with these images"
|
|
114
|
+
- "Reply to this comment with 'Thanks!'"
|
|
115
|
+
- "Search recent posts with #startup"
|
|
116
|
+
|
|
117
|
+
## Publishing
|
|
118
|
+
|
|
119
|
+
Photo and carousel publishing is synchronous — the tool returns once the post is live. Reel publishing is asynchronous — the server polls the container status until processing completes, then publishes.
|
|
120
|
+
|
|
121
|
+
All publish tools accept an optional `firstComment` parameter to add a comment immediately after publishing (commonly used for hashtags).
|
|
122
|
+
|
|
123
|
+
## Rate Limiting
|
|
124
|
+
|
|
125
|
+
The server enforces per-account rate limits to stay within Instagram's API quotas. If you hit a rate limit, the tool will return an error with a suggested retry time. The built-in retry logic handles transient 429 responses automatically.
|
|
126
|
+
|
|
127
|
+
## Contributing
|
|
128
|
+
|
|
129
|
+
1. Fork the repo
|
|
130
|
+
2. Create a feature branch (`git checkout -b feat/my-feature`)
|
|
131
|
+
3. Make changes and run tests (`npm test`)
|
|
132
|
+
4. Submit a pull request
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
137
|
+
|
|
138
|
+
## Acknowledgments
|
|
139
|
+
|
|
140
|
+
- [Anthropic](https://anthropic.com) for the MCP specification
|
|
141
|
+
- [Meta Graph API](https://developers.facebook.com/docs/instagram-api/) for the underlying Instagram API
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Instagram Graph API client.
|
|
3
|
+
*
|
|
4
|
+
* Raw fetch wrapper against https://graph.instagram.com/v22.0/.
|
|
5
|
+
* No SDK — keeps dependencies minimal (Occam's Razor).
|
|
6
|
+
* Client instances are cached by credential hash.
|
|
7
|
+
*/
|
|
8
|
+
export interface Credentials {
|
|
9
|
+
accessToken: string;
|
|
10
|
+
accountId: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get or create a cached Instagram client.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createClient(creds: Credentials): InstagramClient;
|
|
16
|
+
/**
|
|
17
|
+
* Graph API error format from Facebook/Instagram.
|
|
18
|
+
*/
|
|
19
|
+
export interface GraphApiError {
|
|
20
|
+
error: {
|
|
21
|
+
message: string;
|
|
22
|
+
type: string;
|
|
23
|
+
code: number;
|
|
24
|
+
error_subcode?: number;
|
|
25
|
+
fbtrace_id?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown for Graph API failures. Carries structured error data
|
|
30
|
+
* for suggestAction() to inspect.
|
|
31
|
+
*/
|
|
32
|
+
export declare class InstagramApiError extends Error {
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly code: number;
|
|
35
|
+
readonly errorSubcode?: number;
|
|
36
|
+
readonly errorType: string;
|
|
37
|
+
readonly retryAfter?: number;
|
|
38
|
+
constructor(status: number, apiError: GraphApiError["error"], retryAfter?: number);
|
|
39
|
+
}
|
|
40
|
+
export declare class InstagramClient {
|
|
41
|
+
readonly accessToken: string;
|
|
42
|
+
readonly accountId: string;
|
|
43
|
+
constructor(creds: Credentials);
|
|
44
|
+
/**
|
|
45
|
+
* Make a GET request to the Graph API.
|
|
46
|
+
*/
|
|
47
|
+
get<T = unknown>(path: string, params?: Record<string, string>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* Make a POST request to the Graph API.
|
|
50
|
+
*/
|
|
51
|
+
post<T = unknown>(path: string, body?: Record<string, unknown>): Promise<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Make a DELETE request to the Graph API.
|
|
54
|
+
*/
|
|
55
|
+
delete<T = unknown>(path: string): Promise<T>;
|
|
56
|
+
private handleResponse;
|
|
57
|
+
}
|