facebook-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 +112 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/dist/client.d.ts +57 -0
- package/dist/client.js +140 -0
- package/dist/client.test.d.ts +9 -0
- package/dist/client.test.js +211 -0
- package/dist/create-post.d.ts +39 -0
- package/dist/create-post.js +85 -0
- package/dist/create-post.test.d.ts +11 -0
- package/dist/create-post.test.js +175 -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 +162 -0
- package/dist/first-comment.test.d.ts +10 -0
- package/dist/first-comment.test.js +54 -0
- package/dist/handlers.test.d.ts +19 -0
- package/dist/handlers.test.js +333 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.js +374 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.js +8 -0
- package/dist/lib/insights.d.ts +53 -0
- package/dist/lib/insights.js +47 -0
- package/dist/rate-limiter.d.ts +71 -0
- package/dist/rate-limiter.js +214 -0
- package/dist/rate-limiter.test.d.ts +1 -0
- package/dist/rate-limiter.test.js +154 -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 +16 -0
- package/dist/tools.test.js +150 -0
- package/package.json +29 -0
- package/src/client.test.ts +284 -0
- package/src/client.ts +204 -0
- package/src/create-post.test.ts +196 -0
- package/src/create-post.ts +118 -0
- package/src/errors.test.ts +297 -0
- package/src/errors.ts +108 -0
- package/src/first-comment.test.ts +73 -0
- package/src/handlers.test.ts +431 -0
- package/src/index.ts +540 -0
- package/src/lib/index.ts +9 -0
- package/src/lib/insights.ts +150 -0
- package/src/rate-limiter.test.ts +186 -0
- package/src/rate-limiter.ts +252 -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 +195 -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,112 @@
|
|
|
1
|
+
# Contributing to Facebook MCP Server
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! This guide will help you get started.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 18+
|
|
10
|
+
- Git
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
git clone https://github.com/luminarylane/facebook-mcp-server.git
|
|
16
|
+
cd facebook-mcp-server
|
|
17
|
+
npm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Environment Setup
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
cp .env.example .env
|
|
24
|
+
# Add your Facebook Page credentials to .env
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Development Workflow
|
|
28
|
+
|
|
29
|
+
### 1. Create a Branch
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git checkout -b feature/your-description
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Make Changes
|
|
36
|
+
|
|
37
|
+
Follow the existing code style and conventions.
|
|
38
|
+
|
|
39
|
+
### 3. Test
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm test
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 4. Build
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 5. Push and Create PR
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
git push origin your-branch-name
|
|
55
|
+
gh pr create --title "Description" --body "Details..."
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Code Style
|
|
59
|
+
|
|
60
|
+
- TypeScript strict mode
|
|
61
|
+
- Prettier for formatting
|
|
62
|
+
- Vitest for testing
|
|
63
|
+
- No external SDK dependencies — raw `fetch` against the Graph API
|
|
64
|
+
|
|
65
|
+
## Testing
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Run all tests
|
|
69
|
+
npm test
|
|
70
|
+
|
|
71
|
+
# Type check
|
|
72
|
+
npx tsc --noEmit
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Writing Tests
|
|
76
|
+
|
|
77
|
+
- Place tests alongside source files as `*.test.ts`
|
|
78
|
+
- Use `vi.stubGlobal("fetch", ...)` to stub network calls
|
|
79
|
+
- Every tool handler should have happy-path and error-path coverage
|
|
80
|
+
|
|
81
|
+
## Project Structure
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
facebook-mcp-server/
|
|
85
|
+
├── src/
|
|
86
|
+
│ ├── index.ts # MCP server + tool registration
|
|
87
|
+
│ ├── client.ts # Graph API HTTP client
|
|
88
|
+
│ ├── create-post.ts # Post creation validation
|
|
89
|
+
│ ├── errors.ts # Error mapping + agent action hints
|
|
90
|
+
│ ├── rate-limiter.ts # Token-bucket rate limiter
|
|
91
|
+
│ ├── response.ts # MCP response helpers
|
|
92
|
+
│ ├── sanitize.ts # Prompt injection protection
|
|
93
|
+
│ ├── lib/
|
|
94
|
+
│ │ ├── index.ts # Public API surface
|
|
95
|
+
│ │ └── insights.ts # SENSE/insights functions
|
|
96
|
+
│ └── *.test.ts # Tests alongside source
|
|
97
|
+
├── .env.example
|
|
98
|
+
├── package.json
|
|
99
|
+
├── tsconfig.json
|
|
100
|
+
└── vitest.config.ts
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Pull Request Process
|
|
104
|
+
|
|
105
|
+
1. Ensure tests pass: `npm test`
|
|
106
|
+
2. Ensure types check: `npx tsc --noEmit`
|
|
107
|
+
3. Write a clear PR description
|
|
108
|
+
4. Link to related issues
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
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/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Facebook Pages MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://modelcontextprotocol.io)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for the Facebook Graph API (Pages). Enables Claude Desktop and other MCP clients to read insights, create posts, manage comments, and more — all through the Facebook Pages API.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### SENSE Tools (Read)
|
|
12
|
+
|
|
13
|
+
| Tool | Description |
|
|
14
|
+
| ---------------------- | ------------------------------------------------------------------- |
|
|
15
|
+
| `fb_get_page_insights` | Page-level metrics: impressions, reach, engagements, follower count |
|
|
16
|
+
| `fb_get_post_insights` | Post-level metrics: impressions, clicks, reactions |
|
|
17
|
+
| `fb_get_comments` | Comments on a post with author info, likes, replies |
|
|
18
|
+
| `fb_get_page_feed` | Your published posts with permalinks, shares, timestamps |
|
|
19
|
+
|
|
20
|
+
### ACT Tools (Write)
|
|
21
|
+
|
|
22
|
+
| Tool | Description |
|
|
23
|
+
| ------------------ | ------------------------------------------------------------------------- |
|
|
24
|
+
| `fb_create_post` | Create text, link, photo, or video posts. Supports first-comment for CTAs |
|
|
25
|
+
| `fb_reply_comment` | Reply to a comment on a post |
|
|
26
|
+
| `fb_delete_post` | Delete a post you published |
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
### Prerequisites
|
|
31
|
+
|
|
32
|
+
- Node.js 18+
|
|
33
|
+
- A Facebook Page Access Token ([how to get one](https://developers.facebook.com/docs/pages/access-tokens))
|
|
34
|
+
- Your Facebook Page ID
|
|
35
|
+
|
|
36
|
+
### Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/luminarylane/facebook-mcp-server.git
|
|
40
|
+
cd facebook-mcp-server
|
|
41
|
+
npm install
|
|
42
|
+
npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Configure
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
cp .env.example .env
|
|
49
|
+
# Edit .env with your credentials:
|
|
50
|
+
# FACEBOOK_ACCESS_TOKEN=your_long_lived_facebook_page_token_here
|
|
51
|
+
# FACEBOOK_PAGE_ID=your_facebook_page_id_here
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Run
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Development
|
|
58
|
+
npm run dev
|
|
59
|
+
|
|
60
|
+
# Production
|
|
61
|
+
npm start
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Claude Desktop Configuration
|
|
65
|
+
|
|
66
|
+
Add to your `claude_desktop_config.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"facebook": {
|
|
72
|
+
"command": "node",
|
|
73
|
+
"args": ["/path/to/facebook-mcp-server/dist/index.js"],
|
|
74
|
+
"env": {
|
|
75
|
+
"FACEBOOK_ACCESS_TOKEN": "your_token_here",
|
|
76
|
+
"FACEBOOK_PAGE_ID": "your_page_id_here"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Architecture
|
|
84
|
+
|
|
85
|
+
- **Transport**: stdio (standard MCP protocol)
|
|
86
|
+
- **API**: Facebook Graph API v21.0
|
|
87
|
+
- **Rate Limiting**: Built-in token-bucket rate limiter (200 calls/hour global, 25 publishes/day) with per-tenant isolation
|
|
88
|
+
- **Retry**: Automatic exponential backoff on 429s (up to 3 retries)
|
|
89
|
+
- **Security**: Input sanitization against prompt injection (zero-width chars, whitespace abuse, context flooding)
|
|
90
|
+
- **Error Handling**: Structured errors with actionable `action` hints for agents
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Run tests
|
|
96
|
+
npm test
|
|
97
|
+
|
|
98
|
+
# Development server (auto-reload)
|
|
99
|
+
npm run dev
|
|
100
|
+
|
|
101
|
+
# Type check
|
|
102
|
+
npx tsc --noEmit
|
|
103
|
+
|
|
104
|
+
# Build
|
|
105
|
+
npm run build
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Testing
|
|
109
|
+
|
|
110
|
+
The test suite covers:
|
|
111
|
+
|
|
112
|
+
- **client.test.ts** — Graph API HTTP client, URL construction, error parsing
|
|
113
|
+
- **create-post.test.ts** — Post creation validation and endpoint routing
|
|
114
|
+
- **errors.test.ts** — Error mapping and agent-action hint strings
|
|
115
|
+
- **first-comment.test.ts** — First-comment partial-success contract
|
|
116
|
+
- **handlers.test.ts** — Full tool handler integration tests
|
|
117
|
+
- **rate-limiter.test.ts** — Token bucket, per-tenant isolation, retry logic
|
|
118
|
+
- **response.test.ts** — MCP response formatting
|
|
119
|
+
- **sanitize.test.ts** — Prompt injection protection
|
|
120
|
+
- **tools.test.ts** — safeHandler and credential resolution
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm test
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
[MIT](LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Facebook Graph API client.
|
|
3
|
+
*
|
|
4
|
+
* Raw fetch wrapper against https://graph.facebook.com/v21.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
|
+
pageId: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get or create a cached Facebook client.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createClient(creds: Credentials): FacebookClient;
|
|
16
|
+
/**
|
|
17
|
+
* Graph API error format from Facebook.
|
|
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 FacebookApiError 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 FacebookClient {
|
|
41
|
+
readonly accessToken: string;
|
|
42
|
+
readonly pageId: 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
|
+
}
|