@praise25/meta-mcp-server 0.1.10 → 0.1.11

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.
@@ -4,7 +4,7 @@ export declare const CHARACTER_LIMIT = 25000;
4
4
  export declare const DEFAULT_PAGE_LIMIT = 25;
5
5
  export declare const MAX_PAGE_LIMIT = 500;
6
6
  export declare const SERVER_NAME = "meta-business-manager-mcp-server";
7
- export declare const SERVER_VERSION = "0.1.10";
7
+ export declare const SERVER_VERSION = "0.1.11";
8
8
  export declare const META_ERROR_CODES: {
9
9
  readonly UNKNOWN: 1;
10
10
  readonly SERVICE_TEMPORARILY_UNAVAILABLE: 2;
package/dist/constants.js CHANGED
@@ -4,7 +4,7 @@ export const CHARACTER_LIMIT = 25_000;
4
4
  export const DEFAULT_PAGE_LIMIT = 25;
5
5
  export const MAX_PAGE_LIMIT = 500;
6
6
  export const SERVER_NAME = "meta-business-manager-mcp-server";
7
- export const SERVER_VERSION = "0.1.10";
7
+ export const SERVER_VERSION = "0.1.11";
8
8
  export const META_ERROR_CODES = {
9
9
  UNKNOWN: 1,
10
10
  SERVICE_TEMPORARILY_UNAVAILABLE: 2,
@@ -5,16 +5,19 @@ export declare const inputSchema: z.ZodObject<{
5
5
  metric: z.ZodDefault<z.ZodEnum<["follower_demographics", "engaged_audience_demographics", "reached_audience_demographics"]>>;
6
6
  breakdown: z.ZodDefault<z.ZodEnum<["age", "gender", "country", "city", "audience_city"]>>;
7
7
  metric_type: z.ZodDefault<z.ZodEnum<["total_value", "time_series"]>>;
8
+ period: z.ZodDefault<z.ZodEnum<["lifetime", "day"]>>;
8
9
  timeframe: z.ZodDefault<z.ZodEnum<["last_14_days", "last_30_days", "last_90_days", "prev_month", "this_month", "this_week"]>>;
9
10
  }, "strict", z.ZodTypeAny, {
10
11
  ig_user_id: string;
11
12
  metric: "follower_demographics" | "engaged_audience_demographics" | "reached_audience_demographics";
13
+ period: "day" | "lifetime";
12
14
  breakdown: "age" | "gender" | "country" | "city" | "audience_city";
13
15
  metric_type: "total_value" | "time_series";
14
16
  timeframe: "this_month" | "last_14_days" | "last_30_days" | "last_90_days" | "prev_month" | "this_week";
15
17
  }, {
16
18
  ig_user_id: string;
17
19
  metric?: "follower_demographics" | "engaged_audience_demographics" | "reached_audience_demographics" | undefined;
20
+ period?: "day" | "lifetime" | undefined;
18
21
  breakdown?: "age" | "gender" | "country" | "city" | "audience_city" | undefined;
19
22
  metric_type?: "total_value" | "time_series" | undefined;
20
23
  timeframe?: "this_month" | "last_14_days" | "last_30_days" | "last_90_days" | "prev_month" | "this_week" | undefined;
@@ -23,12 +26,13 @@ export type Input = z.infer<typeof inputSchema>;
23
26
  export declare const definition: {
24
27
  readonly name: "meta_ig_get_audience_demographics";
25
28
  readonly title: "Get IG audience demographics";
26
- readonly description: "Reads demographic breakdown of an IG Business account's followers, engaged audience, or reached audience. Use breakdown='age'|'gender'|'country'|'city' to slice.\n\n**Requirements (in order of frequency-of-failure):**\n1. Token has 'instagram_manage_insights' scope.\n2. The Hodusoft app must be approved for **Standard Access** on `instagram_manage_insights` via Meta App Review. In development tier, Meta returns `(#10) Application does not have permission for this action` on this endpoint specifically even if the scope is on the token.\n3. The IG Business account must have ≥ 100 followers (Meta hides smaller accounts' demographics for privacy).\n\nIf you see code (#10), it's almost always #2. Track the App Review request and surface the gap to the operator; this tool is functioning correctly when it returns that error.";
29
+ readonly description: "Reads demographic breakdown of an IG Business account's followers, engaged audience, or reached audience. Use breakdown='age'|'gender'|'country'|'city' to slice.\n\nUSE FOR: \"audience demographics\", \"age / gender / country / city breakdown of my followers\", \"who follows me\", \"audience profile\".\n\nRequirements:\n1. Token has 'instagram_manage_insights' scope (the insights app / META_INSIGHTS_* token).\n2. The IG Business account must have 100 followersbelow that Meta returns empty for privacy.\n3. Meta requires period='lifetime' for demographics metrics (sent automatically by this tool).\n\nIf you see '(#10) Application does not have permission', the configured app lacks instagram_manage_insights relay the hint. If you see '(#100) period is required', upgrade the server (fixed in v0.1.11+).";
27
30
  readonly inputSchema: {
28
31
  ig_user_id: z.ZodString;
29
32
  metric: z.ZodDefault<z.ZodEnum<["follower_demographics", "engaged_audience_demographics", "reached_audience_demographics"]>>;
30
33
  breakdown: z.ZodDefault<z.ZodEnum<["age", "gender", "country", "city", "audience_city"]>>;
31
34
  metric_type: z.ZodDefault<z.ZodEnum<["total_value", "time_series"]>>;
35
+ period: z.ZodDefault<z.ZodEnum<["lifetime", "day"]>>;
32
36
  timeframe: z.ZodDefault<z.ZodEnum<["last_14_days", "last_30_days", "last_90_days", "prev_month", "this_month", "this_week"]>>;
33
37
  };
34
38
  readonly annotations: {
@@ -17,6 +17,10 @@ export const inputSchema = z
17
17
  .describe("Which audience cohort."),
18
18
  breakdown: BREAKDOWN.default("age").describe("Demographic dimension."),
19
19
  metric_type: METRIC_TYPE.default("total_value"),
20
+ period: z
21
+ .enum(["lifetime", "day"])
22
+ .default("lifetime")
23
+ .describe("Required by Meta for demographics metrics — almost always 'lifetime'. Omitting it triggers '(#100) The parameter period is required'."),
20
24
  timeframe: z
21
25
  .enum(["last_14_days", "last_30_days", "last_90_days", "prev_month", "this_month", "this_week"])
22
26
  .default("last_30_days")
@@ -28,12 +32,14 @@ export const definition = {
28
32
  title: "Get IG audience demographics",
29
33
  description: `Reads demographic breakdown of an IG Business account's followers, engaged audience, or reached audience. Use breakdown='age'|'gender'|'country'|'city' to slice.
30
34
 
31
- **Requirements (in order of frequency-of-failure):**
32
- 1. Token has 'instagram_manage_insights' scope.
33
- 2. The Hodusoft app must be approved for **Standard Access** on \`instagram_manage_insights\` via Meta App Review. In development tier, Meta returns \`(#10) Application does not have permission for this action\` on this endpoint specifically — even if the scope is on the token.
34
- 3. The IG Business account must have ≥ 100 followers (Meta hides smaller accounts' demographics for privacy).
35
+ USE FOR: "audience demographics", "age / gender / country / city breakdown of my followers", "who follows me", "audience profile".
35
36
 
36
- If you see code (#10), it's almost always #2. Track the App Review request and surface the gap to the operator; this tool is functioning correctly when it returns that error.`,
37
+ Requirements:
38
+ 1. Token has 'instagram_manage_insights' scope (the insights app / META_INSIGHTS_* token).
39
+ 2. The IG Business account must have ≥ 100 followers — below that Meta returns empty for privacy.
40
+ 3. Meta requires period='lifetime' for demographics metrics (sent automatically by this tool).
41
+
42
+ If you see '(#10) Application does not have permission', the configured app lacks instagram_manage_insights — relay the hint. If you see '(#100) period is required', upgrade the server (fixed in v0.1.11+).`,
37
43
  inputSchema: inputSchema.shape,
38
44
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
39
45
  };
@@ -43,6 +49,7 @@ export async function handler(input, ctx) {
43
49
  path: `${input.ig_user_id}/insights`,
44
50
  params: {
45
51
  metric: input.metric,
52
+ period: input.period,
46
53
  breakdown: input.breakdown,
47
54
  metric_type: input.metric_type,
48
55
  timeframe: input.timeframe,
@@ -272,13 +272,39 @@ export async function handler(input, ctx) {
272
272
  const parentPageId = p.owner_id;
273
273
  const creds = insightsCreds(ctx.config);
274
274
  const pageToken = await ctx.graph.getPageAccessToken(parentPageId, creds ? { token: creds.token, appSecret: creds.appSecret } : undefined);
275
- const r = await ctx.graph.get({
276
- path: `${p.post_id}/insights`,
277
- params: { metric: "post_impressions,post_impressions_unique,post_engaged_users" },
278
- accessTokenOverride: pageToken,
279
- appSecretOverride: creds?.appSecret,
280
- });
281
- p.insights = { data: r.data ?? [] };
275
+ // Meta deprecated the post_impressions* / post_engaged_users family
276
+ // on the post /insights edge (v22+), and rejects the WHOLE call if
277
+ // any single metric is invalid for the post type. So try
278
+ // post-type-appropriate candidate sets in order and keep the first
279
+ // that succeeds; the per-post engagement counts already display
280
+ // regardless, so this is best-effort enrichment.
281
+ const candidates = p.type === "video"
282
+ ? [["post_video_views", "post_clicks"], ["post_video_views"], ["post_clicks"]]
283
+ : [["post_clicks", "post_reactions_by_type_total"], ["post_clicks"]];
284
+ let captured = false;
285
+ let lastErr = "no metric set succeeded";
286
+ for (const metrics of candidates) {
287
+ try {
288
+ const r = await ctx.graph.get({
289
+ path: `${p.post_id}/insights`,
290
+ params: { metric: metrics.join(",") },
291
+ accessTokenOverride: pageToken,
292
+ appSecretOverride: creds?.appSecret,
293
+ });
294
+ p.insights = { data: r.data ?? [] };
295
+ captured = true;
296
+ break;
297
+ }
298
+ catch (err) {
299
+ lastErr = err instanceof MetaError ? err.message : err.message;
300
+ }
301
+ }
302
+ if (!captured) {
303
+ p.insights = {
304
+ error: lastErr,
305
+ note: "Facebook post-level reach via Insights API is best-effort; engagement counts above are authoritative.",
306
+ };
307
+ }
282
308
  }
283
309
  }
284
310
  catch (err) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@praise25/meta-mcp-server",
3
3
  "description": "Read-only Model Context Protocol server for Meta Business Manager — Pages, Instagram, Ads insights, Pixels, Catalog, WhatsApp.",
4
- "version": "0.1.10",
4
+ "version": "0.1.11",
5
5
  "author": "Stephen A.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/feladeveloper/meta-mcp-server#readme",