get_pbia
Get or auto-create a Page-Backed Instagram Account for a Facebook Page to enable Instagram ad placements when no linked Instagram account exists.
Instructions
Get (or auto-create) a Page-Backed Instagram Account for a Facebook Page. Use this when the Page has no linked Instagram account but you want to run ads with IG placements — Meta lets a Page act as its own IG presence via PBIA (same option as 'Use Facebook Page for Instagram' in Ads Manager).
Flow: GET the Page's access_token, list existing PBIAs, create one if none exists. Returns {page_backed_instagram_account_id, created (bool)}.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| page_id | Yes | Facebook Page ID |
Implementation Reference
- src/tools/pages.ts:49-111 (handler)Handler for get_pbia tool: fetches Page Access Token, lists existing PBIAs, creates one if none exists. Uses direct fetch with Page-scoped token instead of shared client.
handler: async (args) => { const pageId = String(args.page_id); // Step 1: Fetch the Page Access Token — PBIA endpoints require the // Page's own token, not the System User token directly. const pageInfo = await metaGet<PageAccessTokenResponse>(`/${pageId}`, { fields: "access_token", }); const pageToken = pageInfo.access_token; if (!pageToken) { throw new Error( `Could not fetch Page Access Token for ${pageId} — does the current token have pages_manage_metadata / MANAGE task permission?`, ); } // Step 2: Check for an existing PBIA using the page token. // metaGet uses the module-level META_ACCESS_TOKEN, so we do a direct // fetch here to use the Page-scoped token. const base = "https://graph.facebook.com/v24.0"; const listRes = await fetch( `${base}/${pageId}/page_backed_instagram_accounts?access_token=${encodeURIComponent(pageToken)}`, ); if (!listRes.ok) { const body = await listRes.text().catch(() => ""); throw new Error( `Failed to list PBIAs for page ${pageId} — HTTP ${listRes.status}: ${body.slice(0, 300)}`, ); } const listJson = (await listRes.json()) as PbiaListResponse; const existing = listJson.data?.[0]?.id; if (existing) { return { page_backed_instagram_account_id: existing, created: false }; } // Step 3: No PBIA — create one. const createForm = new URLSearchParams(); createForm.append("access_token", pageToken); const createRes = await fetch( `${base}/${pageId}/page_backed_instagram_accounts`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: createForm.toString(), }, ); if (!createRes.ok) { const body = await createRes.text().catch(() => ""); throw new Error( `Failed to create PBIA for page ${pageId} — HTTP ${createRes.status}: ${body.slice(0, 300)}`, ); } const created = (await createRes.json()) as PbiaCreateResponse; if (!created.id) { throw new Error( `PBIA create returned no id: ${JSON.stringify(created)}`, ); } // Swallow the unused metaPost import warning — we intentionally hand- // rolled the POST above to use the Page token rather than the default. void metaPost; return { page_backed_instagram_account_id: created.id, created: true }; }, }, - src/tools/pages.ts:46-48 (schema)Input schema for get_pbia: requires a page_id string.
inputSchema: { page_id: z.string().describe("Facebook Page ID"), }, - src/index.ts:29-57 (registration)Registration in stdio entrypoint: pageTools array is imported from pages.ts and registered via server.registerTool.
import { pageTools } from "./tools/pages.js"; import { adsLibraryTools } from "./tools/adslibrary.js"; import type { ToolDef } from "./tools/types.js"; // Stdio requires the token at launch — fail fast if missing, matching the // pre-0.3.0 behaviour for npm / Claude Desktop users. HTTP mode (src/http.ts) // does NOT do this check because the token arrives per-request via Smithery // Gateway session config. if (!process.env.META_ACCESS_TOKEN) { process.stderr.write( "ERROR: META_ACCESS_TOKEN env var is required for stdio mode.\n" + "Quick token (2 min, expires in ~2h): https://developers.facebook.com/tools/explorer/\n" + "Stable token (never expires) via Business Manager System User:\n" + " https://github.com/Mike25app/scaleforge-mcp-meta-ads#stable-tokens\n", ); process.exit(1); } const allTools: ToolDef[] = [ ...accountTools, ...campaignTools, ...adsetTools, ...adTools, ...creativeTools, ...mediaTools, ...insightsTools, ...bulkTools, ...pageTools, ...adsLibraryTools, - src/tools/pages.ts:10-17 (helper)Type helpers for PBIA API responses.
interface PbiaListResponse { data?: Array<{ id: string; username?: string }>; } interface PbiaCreateResponse { id?: string; } - src/http.ts:26-49 (registration)Registration in HTTP entrypoint: same pageTools array imported and registered via server.registerTool.
import { pageTools } from "./tools/pages.js"; import { adsLibraryTools } from "./tools/adslibrary.js"; import type { ToolDef } from "./tools/types.js"; const allTools: ToolDef[] = [ ...accountTools, ...campaignTools, ...adsetTools, ...adTools, ...creativeTools, ...mediaTools, ...insightsTools, ...bulkTools, ...pageTools, ...adsLibraryTools, ]; function buildServer(): McpServer { const server = new McpServer( { name: "mcp-meta-ads", version: "0.3.0" }, { capabilities: { tools: {} } }, ); for (const tool of allTools) { server.registerTool(