Skip to main content
Glama
facebook-mcp

facebook-mcp

by IvanBBaev

Page Insights

facebook_page_insights
Read-onlyIdempotent

Reads Facebook Page Graph insights into per-metric rows and safe summaries, handling renamed metrics and eligibility limits, with aggregate/export modes for Page performance analysis.

Instructions

Read Graph insights for one Page in a compact flat shape: one row per metric per data point ({metric, date, value}, plus breakdown for by-action-type metrics) and one semantics-aware summary per metric: value is the one scalar to quote and aggregation says how it was derived (total removed; read value and aggregation). Follower stock is never summed, rolling windows are not double-counted, and unique or unknown multi-point metrics are left unaggregated rather than guessed; derived.followers reconciles page_follows with daily follows minus unfollows. Set aggregate:true to omit rows, or output:{format} to write the full uncapped series to a CSV/JSON file in FB_EXPORT_DIR and get only its path and the summaries back. The window is [since, until) in Pacific Time, at most 90 days per call. Metric names renamed by the 2024-09 / 2025-11 / 2026-06 waves are answered with their replacement instead of a Graph error, and a metric Graph accepts but has no data for is reported separately from a name Graph does not know. Empty series usually mean the eligibility floor (a Page under 100 followers) or a token missing read_insights + the ANALYZE Page task — not zero engagement; the result says which. Reel metrics are NOT available here: they live on /{video-id}/video_insights — use facebook_reel_insights for those.

Input Schema

NameRequiredDescriptionDefault
sinceNoInclusive start boundary as a calendar date "YYYY-MM-DD". The range is [since, until); Page period=day boundaries are Pacific Time (America/Los_Angeles), post and Reel boundaries UTC. Omitted ⇒ Graph's own default window. The since..until boundary span may not exceed 90 days per call (checked before the request); read longer histories in slices.
untilNoEXCLUSIVE end boundary as a calendar date "YYYY-MM-DD": for Page period=day, until=2026-08-30 includes the 2026-08-29 Pacific day but not 2026-08-30, and since = until is refused as an empty window. Each returned `date` is Graph's exclusive end boundary of its period, so a window reaching today ends in a partial, still-being-computed bucket. Omitted ⇒ today (Pacific Time for a Page, UTC otherwise).
outputNoWrite the FULL series to a local file in FB_EXPORT_DIR instead of returning rows. The row cap does not apply to the file; the inline result is the aggregate-mode summary (no rows, max_rows and aggregate are ignored) plus `export: {path, format, rows, bytes, sha256}`. Use it for long daily series that would otherwise be truncated.
periodNoAggregation window Graph applies per data point. "day" is a daily series (the Page default); "lifetime" is one cumulative value per metric (the post default); "week"/"days_28" are rolling windows; "month" is calendar-monthly; "total_over_range" collapses since..until into a single value. Not every metric supports every period — a metric queried with an unsupported period comes back empty, which the notes call out.
metricsYesGraph insights metric names to read, e.g. ["page_media_view","page_follows"] (1-20 per call; trimmed and lower-cased). Names are Graph-version dependent and Meta renamed most of them in the 2024-09, 2025-11 and 2026-06 waves: pre-wave names such as "page_impressions" or "page_fans" are dropped before the request and answered with their replacement instead of an error. Graph fails the WHOLE call when one surviving name is invalid: when Graph says which entry it rejected, that name is dropped, the rest are re-read and it is reported in rejectedMetrics; otherwise isolate a suspect name by requesting it alone. Page metrics (page_*) are read on the Page, post metrics (post_*) on a post or Reel.
profileNoPage profile key (e.g. "brand-a") or a raw Page ID. Omitted ⇒ the default Page (FB_PAGE_ID).
max_rowsNoLower the per-point row cap for this call (1-250; the default and the ceiling are both 250 — this argument can only shrink it). Rows past the cap are dropped and the result reports how many; prefer aggregate:true over a tiny cap when you only need per-metric summaries.
aggregateNoTrue ⇒ return per-metric summaries only and NO per-point rows. Each summary states its `kind` (flow, gauge, unique, unknown) and its `aggregation`, and carries `value` only when one scalar is safe: known flows over disjoint day/month buckets are summed, gauges such as page_follows take the latest value (plus `change`), week/days_28 rolling windows and lifetime counters take the latest window, and unique-audience or unknown day/month series and breakdown maps get aggregation "none" rather than a guess. Use it for wide windows or many metrics when the daily rows would otherwise be truncated.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv0.8.0
    • changedInput schema / properties / aggregate / description
      Previous value: -"True ⇒ return per-metric totals only (period, points, total, first/last boundary) and NO per-point rows. Use it for wide windows or many metrics: it is the cheapest way to stay inside the result budget when a daily series would otherwise be truncated."New value: +"True ⇒ return per-metric summaries only and NO per-point rows. Each summary states its `kind` (flow, gauge, unique, unknown) and its `aggregation`, and carries `value` only when one scalar is safe: known flows over disjoint day/month buckets are summed, gauges such as page_follows take the latest value (plus `change`), week/days_28 rolling windows and lifetime counters take the latest window, and unique-audience or unknown day/month series and breakdown maps get aggregation \"none\" rather than a guess. Use it for wide windows or many metrics when the daily rows would otherwise be truncated."
    • changedInput schema / properties / max_rows / description
      Previous value: -"Lower the per-point row cap for this call (1-250; the default and the ceiling are both 250 — this argument can only shrink it). Rows past the cap are dropped and the result reports how many; prefer aggregate:true over a tiny cap when you only need totals."New value: +"Lower the per-point row cap for this call (1-250; the default and the ceiling are both 250 — this argument can only shrink it). Rows past the cap are dropped and the result reports how many; prefer aggregate:true over a tiny cap when you only need per-metric summaries."
    • changedInput schema / properties / metrics / description
      Previous value: -"Graph insights metric names to read, e.g. [\"page_media_view\",\"page_follows\"] (1-20 per call; trimmed and lower-cased). Names are Graph-version dependent and Meta renamed most of them in the 2024-09, 2025-11 and 2026-06 waves: pre-wave names such as \"page_impressions\" or \"page_fans\" are dropped before the request and answered with their replacement instead of an error. Graph fails the WHOLE call when one surviving name is invalid, so isolate a suspect name by requesting it alone."New value: +"Graph insights metric names to read, e.g. [\"page_media_view\",\"page_follows\"] (1-20 per call; trimmed and lower-cased). Names are Graph-version dependent and Meta renamed most of them in the 2024-09, 2025-11 and 2026-06 waves: pre-wave names such as \"page_impressions\" or \"page_fans\" are dropped before the request and answered with their replacement instead of an error. Graph fails the WHOLE call when one surviving name is invalid: when Graph says which entry it rejected, that name is dropped, the rest are re-read and it is reported in rejectedMetrics; otherwise isolate a suspect name by requesting it alone. Page metrics (page_*) are read on the Page, post metrics (post_*) on a post or Reel."
    • addedInput schema / properties / metrics / items / pattern
      Added value: +"^[^,]+$"
    • addedInput schema / properties / output
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "Write the FULL series to a local file in FB_EXPORT_DIR instead of returning rows. The row cap does not apply to the file; the inline result is the aggregate-mode summary (no rows, max_rows and aggregate are ignored) plus `export: {path, format, rows, bytes, sha256}`. Use it for long daily series that would otherwise be truncated.",
      +  "properties": {
      +    "file_name": {
      +      "description": "Optional bare file name (1-80 of A-Z a-z 0-9 . _ -, no path, no leading dot). The extension is added when missing. Omitted ⇒ <scope>-<objectId>-<since>-<until>-<timestamp>. An existing file is never overwritten; a numeric suffix is added instead.",
      +      "pattern": "^[A-Za-z0-9_-][A-Za-z0-9._-]{0,79}$",
      +      "type": "string"
      +    },
      +    "format": {
      +      "description": "File format: \"csv\" (one row per data point, spreadsheet-ready) or \"json\" (the summaries plus every row).",
      +      "enum": [
      +        "csv",
      +        "json"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "format"
      +  ],
      +  "type": "object"
      +}
    • changedInput schema / properties / since / description
      Previous value: -"Start of the window as a calendar date \"YYYY-MM-DD\" (inclusive, Page timezone). Omitted ⇒ Graph's own default window. The since..until span may not exceed 90 days per call (checked before the request); read longer histories in slices."New value: +"Inclusive start boundary as a calendar date \"YYYY-MM-DD\". The range is [since, until); Page period=day boundaries are Pacific Time (America/Los_Angeles), post and Reel boundaries UTC. Omitted ⇒ Graph's own default window. The since..until boundary span may not exceed 90 days per call (checked before the request); read longer histories in slices."
    • changedInput schema / properties / until / description
      Previous value: -"End of the window as a calendar date \"YYYY-MM-DD\". Each returned `date` is the END of the period the value covers, so a window reaching today ends in a partial, still-being-computed bucket. Omitted ⇒ today."New value: +"EXCLUSIVE end boundary as a calendar date \"YYYY-MM-DD\": for Page period=day, until=2026-08-30 includes the 2026-08-29 Pacific day but not 2026-08-30, and since = until is refused as an empty window. Each returned `date` is Graph's exclusive end boundary of its period, so a window reaching today ends in a partial, still-being-computed bucket. Omitted ⇒ today (Pacific Time for a Page, UTC otherwise)."
  2. First observedv0.7.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover only the safety profile (readOnly/openWorld/idempotent/non-destructive); the description adds a large amount of non-structured behavior: the [since, until) Pacific-Time window capped at 90 days, that file exports never overwrite (numeric suffix), that rows past the cap are dropped and reported, and that unknown-vs-empty metrics are distinguished. The 'empty series usually mean the eligibility floor or a missing permission — not zero engagement' note is exactly the kind of trap-avoidance context annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the return shape before any caveats, and every sentence carries substantive information (aggregation semantics, export mode, window bounds, rename waves, empty-series diagnosis). It is dense and long-claused, and a couple of clauses (90-day window, [since, until)) duplicate the schema, so it stops short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden and discharges it: it describes row shape ({metric, date, value, breakdown}), summary shape (value vs. aggregation, kind, change), the export object, and how multi-point/unique metrics are left unaggregated. For an 8-parameter tool with a nested output object, an agent has everything needed to call it and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema descriptions are already detailed, so the baseline is 3; the prose nevertheless adds cross-parameter meaning the schema does not state in one place — that aggregate:true suppresses rows and carries `value` only when one scalar is safe, and that output:{format} ignores max_rows/aggregate and returns only path plus summaries. It also explains the `derived.followers` reconciliation for page_follows. Not a 5 because much of the window/period/rename detail restates what the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read Graph insights for one Page') and immediately names the output shape (one row per metric per data point, plus a summary per metric). It also explicitly excludes a sibling domain ('Reel metrics are NOT available here ... use facebook_reel_insights'), so an agent can route correctly without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use for the two alternate modes ('Set aggregate:true to omit rows, or output:{format} to write the full uncapped series') and a hard exclusion routing Reels to facebook_reel_insights. Prerequisite/eligibility conditions (100-follower floor, read_insights + ANALYZE task) are also stated, which is the kind of guidance that prevents wasted calls.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.