@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.
package/dist/constants.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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\
|
|
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 followers — below 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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.
|
|
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",
|