feat: Facebook Page integration

Four tools: facebook_get_page, facebook_get_posts, facebook_create_post
(text + optional link), facebook_create_photo_post (image URL + caption).

Uses Graph API v19.0 with Page access token. Credentials stored per-customer
in Redis under creds:{id}:facebook with pageId alongside the access token.
Env-var fallback: FACEBOOK_{ACCOUNT}_ACCESS_TOKEN + FACEBOOK_{ACCOUNT}_PAGE_ID.

Wired into Platform type, validPlatforms, /api/connections, manifest OpenAPI
spec, and manifest tool registry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Garfield
2026-05-08 12:47:20 -04:00
parent 6c7e56769e
commit ffb67560b9
5 changed files with 421 additions and 3 deletions

View File

@@ -473,6 +473,75 @@ export function getOpenApiSpec(serverUrl: string) {
},
},
// ── Facebook ───────────────────────────────────────────────
'/api/facebook/page': {
get: {
operationId: 'facebook_get_page',
summary: 'Get Facebook Page profile',
parameters: [
{ name: 'account', in: 'query', schema: { type: 'string' } },
],
responses: { '200': { description: 'Page info' } },
},
},
'/api/facebook/posts': {
get: {
operationId: 'facebook_get_posts',
summary: 'Get Facebook Page posts',
parameters: [
{ name: 'limit', in: 'query', schema: { type: 'integer' } },
{ name: 'account', in: 'query', schema: { type: 'string' } },
],
responses: { '200': { description: 'Post list' } },
},
},
'/api/facebook/post': {
post: {
operationId: 'facebook_create_post',
summary: 'Publish text post to Facebook Page',
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['message'],
properties: {
message: { type: 'string' },
link: { type: 'string' },
account: { type: 'string' },
},
},
},
},
},
responses: { '200': { description: 'Post created' } },
},
},
'/api/facebook/photo': {
post: {
operationId: 'facebook_create_photo_post',
summary: 'Publish photo post to Facebook Page',
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['image_url'],
properties: {
image_url: { type: 'string' },
caption: { type: 'string' },
account: { type: 'string' },
},
},
},
},
},
responses: { '200': { description: 'Photo posted' } },
},
},
// ── Twitter/X ───────────────────────────────────────────────
'/api/twitter/search': {
get: {
@@ -1234,6 +1303,107 @@ export function getManifest(serverUrl: string, authEnabled: boolean) {
examples: [{ image_url: 'https://example.com/photo.jpg', caption: 'New post!', account: 'default' }],
},
// ── Facebook tools ─────────────────────────────────────────────────────
{
name: 'facebook_get_page',
category: 'facebook',
description: 'Get a Facebook Page profile including name, category, fan count, and follower count',
when_to_use: 'User asks about their Facebook Page stats, followers, or account details.',
input_schema: {
type: 'object',
properties: {
account: { type: 'string', description: 'Which Facebook account to use (default: "default")' },
},
},
returns: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' },
category: { type: 'string' },
about: { type: 'string' },
fan_count: { type: 'number' },
followers_count: { type: 'number' },
link: { type: 'string' },
},
},
examples: [{ account: 'default' }],
},
{
name: 'facebook_get_posts',
category: 'facebook',
description: 'Get recent posts from a Facebook Page feed',
when_to_use: 'User wants to see recent Facebook Page posts or content history.',
input_schema: {
type: 'object',
properties: {
limit: { type: 'number', description: 'Max posts (default: 10)' },
account: { type: 'string', description: 'Which Facebook account to use (default: "default")' },
},
},
returns: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'string' },
message: { type: 'string' },
story: { type: 'string' },
created_time: { type: 'string' },
permalink_url: { type: 'string' },
},
},
},
examples: [{ limit: 5, account: 'default' }],
},
{
name: 'facebook_create_post',
category: 'facebook',
description: 'Publish a text post (optionally with a link) to a Facebook Page',
when_to_use: 'User wants to post a status update or share a link on their Facebook Page.',
input_schema: {
type: 'object',
required: ['message'],
properties: {
message: { type: 'string', description: 'Post text content' },
link: { type: 'string', description: 'Optional URL to attach' },
account: { type: 'string', description: 'Which Facebook account to use (default: "default")' },
},
},
returns: {
type: 'object',
properties: {
success: { type: 'boolean' },
post_id: { type: 'string' },
},
},
examples: [{ message: 'Something new is coming next week.', account: 'default' }],
},
{
name: 'facebook_create_photo_post',
category: 'facebook',
description: 'Publish a photo post to a Facebook Page using a public image URL',
when_to_use: 'User wants to post an image or photo to their Facebook Page.',
input_schema: {
type: 'object',
required: ['image_url'],
properties: {
image_url: { type: 'string', description: 'Publicly accessible URL of the image' },
caption: { type: 'string', description: 'Post caption text' },
account: { type: 'string', description: 'Which Facebook account to use (default: "default")' },
},
},
returns: {
type: 'object',
properties: {
success: { type: 'boolean' },
post_id: { type: 'string' },
photo_id: { type: 'string' },
},
},
examples: [{ image_url: 'https://example.com/image.jpg', caption: 'New post!', account: 'default' }],
},
// ── Twitter/X tools ────────────────────────────────────────────────────
{
name: 'twitter_search_tweets',
@@ -1526,6 +1696,10 @@ export function getManifest(serverUrl: string, authEnabled: boolean) {
description: 'Twitter/X search and profile lookup (read-only on free tier)',
icon: '🐦',
},
facebook: {
description: 'Facebook Page posting and management via Graph API',
icon: '📘',
},
},
};
}