@praise25/meta-mcp-server 0.1.0

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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +292 -0
  3. package/dist/config.d.ts +15 -0
  4. package/dist/config.js +46 -0
  5. package/dist/constants.d.ts +21 -0
  6. package/dist/constants.js +28 -0
  7. package/dist/context.d.ts +9 -0
  8. package/dist/context.js +8 -0
  9. package/dist/errors.d.ts +41 -0
  10. package/dist/errors.js +90 -0
  11. package/dist/helpers/cache.d.ts +6 -0
  12. package/dist/helpers/cache.js +28 -0
  13. package/dist/helpers/format.d.ts +17 -0
  14. package/dist/helpers/format.js +28 -0
  15. package/dist/helpers/graph-client.d.ts +56 -0
  16. package/dist/helpers/graph-client.js +169 -0
  17. package/dist/helpers/schema.d.ts +30 -0
  18. package/dist/helpers/schema.js +69 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +36 -0
  21. package/dist/logger.d.ts +3 -0
  22. package/dist/logger.js +18 -0
  23. package/dist/server.d.ts +7 -0
  24. package/dist/server.js +14 -0
  25. package/dist/tools/ads/get-account.d.ts +29 -0
  26. package/dist/tools/ads/get-account.js +45 -0
  27. package/dist/tools/ads/get-creative.d.ts +29 -0
  28. package/dist/tools/ads/get-creative.js +37 -0
  29. package/dist/tools/ads/get-insights.d.ts +129 -0
  30. package/dist/tools/ads/get-insights.js +151 -0
  31. package/dist/tools/ads/list-accounts.d.ts +54 -0
  32. package/dist/tools/ads/list-accounts.js +59 -0
  33. package/dist/tools/ads/list-ads.d.ts +53 -0
  34. package/dist/tools/ads/list-ads.js +59 -0
  35. package/dist/tools/ads/list-adsets.d.ts +49 -0
  36. package/dist/tools/ads/list-adsets.js +54 -0
  37. package/dist/tools/ads/list-campaigns.d.ts +45 -0
  38. package/dist/tools/ads/list-campaigns.js +64 -0
  39. package/dist/tools/ads/list-custom-audiences.d.ts +41 -0
  40. package/dist/tools/ads/list-custom-audiences.js +41 -0
  41. package/dist/tools/business/list-assets.d.ts +37 -0
  42. package/dist/tools/business/list-assets.js +136 -0
  43. package/dist/tools/business/list-businesses.d.ts +37 -0
  44. package/dist/tools/business/list-businesses.js +81 -0
  45. package/dist/tools/business/list-system-users.d.ts +41 -0
  46. package/dist/tools/business/list-system-users.js +73 -0
  47. package/dist/tools/catalog/get-diagnostics.d.ts +29 -0
  48. package/dist/tools/catalog/get-diagnostics.js +26 -0
  49. package/dist/tools/catalog/list-products.d.ts +45 -0
  50. package/dist/tools/catalog/list-products.js +49 -0
  51. package/dist/tools/catalog/list.d.ts +54 -0
  52. package/dist/tools/catalog/list.js +48 -0
  53. package/dist/tools/instagram/get-account.d.ts +29 -0
  54. package/dist/tools/instagram/get-account.js +34 -0
  55. package/dist/tools/instagram/get-audience-demographics.d.ts +41 -0
  56. package/dist/tools/instagram/get-audience-demographics.js +46 -0
  57. package/dist/tools/instagram/get-media-insights.d.ts +29 -0
  58. package/dist/tools/instagram/get-media-insights.js +43 -0
  59. package/dist/tools/instagram/list-accounts.d.ts +33 -0
  60. package/dist/tools/instagram/list-accounts.js +63 -0
  61. package/dist/tools/instagram/list-media.d.ts +41 -0
  62. package/dist/tools/instagram/list-media.js +42 -0
  63. package/dist/tools/meta/graph-read.d.ts +33 -0
  64. package/dist/tools/meta/graph-read.js +71 -0
  65. package/dist/tools/overview/business-overview.d.ts +49 -0
  66. package/dist/tools/overview/business-overview.js +188 -0
  67. package/dist/tools/pages/get-insights.d.ts +41 -0
  68. package/dist/tools/pages/get-insights.js +49 -0
  69. package/dist/tools/pages/get-post-insights.d.ts +29 -0
  70. package/dist/tools/pages/get-post-insights.js +36 -0
  71. package/dist/tools/pages/get.d.ts +29 -0
  72. package/dist/tools/pages/get.js +50 -0
  73. package/dist/tools/pages/list-posts.d.ts +53 -0
  74. package/dist/tools/pages/list-posts.js +54 -0
  75. package/dist/tools/pages/list-reviews.d.ts +41 -0
  76. package/dist/tools/pages/list-reviews.js +37 -0
  77. package/dist/tools/pages/list-videos.d.ts +41 -0
  78. package/dist/tools/pages/list-videos.js +40 -0
  79. package/dist/tools/pages/list.d.ts +41 -0
  80. package/dist/tools/pages/list.js +39 -0
  81. package/dist/tools/pixels/get-stats.d.ts +41 -0
  82. package/dist/tools/pixels/get-stats.js +34 -0
  83. package/dist/tools/pixels/list.d.ts +41 -0
  84. package/dist/tools/pixels/list.js +38 -0
  85. package/dist/tools/register.d.ts +3 -0
  86. package/dist/tools/register.js +82 -0
  87. package/dist/tools/shared.d.ts +20 -0
  88. package/dist/tools/shared.js +55 -0
  89. package/dist/tools/token/health.d.ts +17 -0
  90. package/dist/tools/token/health.js +59 -0
  91. package/dist/tools/token/inspect.d.ts +26 -0
  92. package/dist/tools/token/inspect.js +88 -0
  93. package/dist/tools/whatsapp/get-analytics.d.ts +57 -0
  94. package/dist/tools/whatsapp/get-analytics.js +66 -0
  95. package/dist/tools/whatsapp/list-phone-numbers.d.ts +41 -0
  96. package/dist/tools/whatsapp/list-phone-numbers.js +35 -0
  97. package/dist/tools/whatsapp/list-templates.d.ts +45 -0
  98. package/dist/tools/whatsapp/list-templates.js +44 -0
  99. package/dist/tools/whatsapp/list-wabas.d.ts +54 -0
  100. package/dist/tools/whatsapp/list-wabas.js +48 -0
  101. package/dist/types/meta.d.ts +46 -0
  102. package/dist/types/meta.js +1 -0
  103. package/package.json +74 -0
@@ -0,0 +1,56 @@
1
+ import type { Config } from "../config.js";
2
+ import type { Logger } from "../logger.js";
3
+ export interface GraphGetOptions {
4
+ /** Path segments after the API version, e.g. "me/businesses" or "act_123/insights". */
5
+ path: string;
6
+ /** Query-string params. `access_token` and `appsecret_proof` are added automatically. */
7
+ params?: Record<string, string | number | boolean | undefined>;
8
+ /** Skip cache for this request. */
9
+ noCache?: boolean;
10
+ /** Override the API version for this call. */
11
+ apiVersion?: string;
12
+ }
13
+ export interface GraphPagedResponse<T = unknown> {
14
+ data: T[];
15
+ paging?: {
16
+ cursors?: {
17
+ before?: string;
18
+ after?: string;
19
+ };
20
+ next?: string;
21
+ previous?: string;
22
+ };
23
+ /** Some endpoints (e.g. /me) return a scalar — preserved on the response object. */
24
+ [extra: string]: unknown;
25
+ }
26
+ export interface GraphRateLimitHeaders {
27
+ businessUseCase?: string;
28
+ adAccountUsage?: string;
29
+ appUsage?: string;
30
+ }
31
+ export declare class GraphClient {
32
+ private readonly config;
33
+ private readonly logger;
34
+ private readonly http;
35
+ private readonly cache;
36
+ private lastRateLimit;
37
+ constructor(config: Config, logger: Logger);
38
+ get rateLimit(): GraphRateLimitHeaders;
39
+ clearCache(): void;
40
+ get<T = GraphPagedResponse>(opts: GraphGetOptions): Promise<T>;
41
+ /**
42
+ * Follow `paging.next` cursors and concatenate `data` arrays up to maxPages.
43
+ * Returns the combined data plus the final cursor so callers can resume.
44
+ */
45
+ getAllPages<TItem = unknown>(opts: GraphGetOptions, maxPages?: number): Promise<{
46
+ data: TItem[];
47
+ pages: number;
48
+ nextAfter: string | undefined;
49
+ }>;
50
+ private optsFromNextUrl;
51
+ private buildParams;
52
+ private appsecretProof;
53
+ private cacheKeyFor;
54
+ private requestWithRetry;
55
+ private captureRateLimit;
56
+ }
@@ -0,0 +1,169 @@
1
+ import axios from "axios";
2
+ import crypto from "node:crypto";
3
+ import { BASE_RETRY_DELAY_MS, GRAPH_BASE_URL, MAX_RETRIES, } from "../constants.js";
4
+ import { MetaError, ReadOnlyViolationError, normalizeAxiosError } from "../errors.js";
5
+ import { createCache } from "./cache.js";
6
+ export class GraphClient {
7
+ config;
8
+ logger;
9
+ http;
10
+ cache;
11
+ lastRateLimit = {};
12
+ constructor(config, logger) {
13
+ this.config = config;
14
+ this.logger = logger;
15
+ this.http = axios.create({
16
+ baseURL: GRAPH_BASE_URL,
17
+ timeout: config.httpTimeoutMs,
18
+ headers: { Accept: "application/json" },
19
+ // Never follow redirects to non-GET — defence in depth even though we only GET.
20
+ maxRedirects: 3,
21
+ validateStatus: () => true, // handle status manually
22
+ });
23
+ this.cache = createCache(config.cacheTtlSeconds);
24
+ // Hard read-only guard — defence in depth. Catches misuse if new code ever
25
+ // calls http.post/patch/delete directly.
26
+ this.http.interceptors.request.use((cfg) => {
27
+ const method = (cfg.method ?? "get").toUpperCase();
28
+ if (method !== "GET") {
29
+ throw new ReadOnlyViolationError(method, cfg.url ?? "");
30
+ }
31
+ return cfg;
32
+ });
33
+ }
34
+ get rateLimit() {
35
+ return { ...this.lastRateLimit };
36
+ }
37
+ clearCache() {
38
+ this.cache.clear();
39
+ }
40
+ async get(opts) {
41
+ const version = opts.apiVersion ?? this.config.apiVersion;
42
+ const path = opts.path.replace(/^\/+/, "");
43
+ const url = `/${version}/${path}`;
44
+ const params = this.buildParams(opts.params);
45
+ const cacheKey = this.cacheKeyFor(url, params);
46
+ if (!opts.noCache) {
47
+ const cached = this.cache.get(cacheKey);
48
+ if (cached)
49
+ return cached;
50
+ }
51
+ const result = await this.requestWithRetry({ method: "GET", url, params });
52
+ if (!opts.noCache) {
53
+ this.cache.set(cacheKey, result);
54
+ }
55
+ return result;
56
+ }
57
+ /**
58
+ * Follow `paging.next` cursors and concatenate `data` arrays up to maxPages.
59
+ * Returns the combined data plus the final cursor so callers can resume.
60
+ */
61
+ async getAllPages(opts, maxPages) {
62
+ const cap = maxPages ?? this.config.maxAutoPages;
63
+ const collected = [];
64
+ let pages = 0;
65
+ let nextAfter;
66
+ let currentOpts = opts;
67
+ while (currentOpts && pages < cap) {
68
+ const page = await this.get(currentOpts);
69
+ pages += 1;
70
+ if (Array.isArray(page.data))
71
+ collected.push(...page.data);
72
+ nextAfter = page.paging?.cursors?.after;
73
+ if (page.paging?.next && pages < cap) {
74
+ currentOpts = this.optsFromNextUrl(page.paging.next);
75
+ }
76
+ else {
77
+ currentOpts = null;
78
+ }
79
+ }
80
+ return { data: collected, pages, nextAfter };
81
+ }
82
+ optsFromNextUrl(nextUrl) {
83
+ const u = new URL(nextUrl);
84
+ const segments = u.pathname.replace(/^\/+/, "").split("/");
85
+ const version = segments.shift() ?? this.config.apiVersion;
86
+ const path = segments.join("/");
87
+ const params = {};
88
+ for (const [k, v] of u.searchParams.entries()) {
89
+ if (k === "access_token" || k === "appsecret_proof")
90
+ continue;
91
+ params[k] = v;
92
+ }
93
+ return { path, params, apiVersion: version };
94
+ }
95
+ buildParams(params) {
96
+ const out = {};
97
+ for (const [k, v] of Object.entries(params ?? {})) {
98
+ if (v === undefined || v === null)
99
+ continue;
100
+ out[k] = v;
101
+ }
102
+ out.access_token = this.config.accessToken;
103
+ if (this.config.appSecret) {
104
+ out.appsecret_proof = this.appsecretProof();
105
+ }
106
+ return out;
107
+ }
108
+ appsecretProof() {
109
+ // appsecret_proof = HMAC-SHA256(access_token, app_secret)
110
+ return crypto
111
+ .createHmac("sha256", this.config.appSecret)
112
+ .update(this.config.accessToken)
113
+ .digest("hex");
114
+ }
115
+ cacheKeyFor(url, params) {
116
+ const { access_token: _at, appsecret_proof: _ap, ...rest } = params;
117
+ const ordered = Object.keys(rest)
118
+ .sort()
119
+ .map((k) => `${k}=${rest[k]}`)
120
+ .join("&");
121
+ return `${url}?${ordered}`;
122
+ }
123
+ async requestWithRetry(cfg) {
124
+ let lastError = null;
125
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
126
+ try {
127
+ const response = await this.http.request(cfg);
128
+ this.captureRateLimit(response.headers);
129
+ if (response.status >= 200 && response.status < 300) {
130
+ return response.data;
131
+ }
132
+ // Non-2xx: construct as if axios threw.
133
+ lastError = normalizeAxiosError({
134
+ isAxiosError: true,
135
+ response,
136
+ message: `HTTP ${response.status}`,
137
+ config: cfg,
138
+ });
139
+ }
140
+ catch (err) {
141
+ if (err instanceof ReadOnlyViolationError)
142
+ throw err;
143
+ lastError = normalizeAxiosError(err);
144
+ }
145
+ if (!lastError.retryable || attempt === MAX_RETRIES - 1) {
146
+ throw lastError;
147
+ }
148
+ const delay = BASE_RETRY_DELAY_MS * Math.pow(2, attempt);
149
+ this.logger.warn({ code: lastError.code, attempt, delay_ms: delay }, "meta api retrying after error");
150
+ await sleep(delay);
151
+ }
152
+ // Unreachable, but TypeScript needs it.
153
+ throw lastError ?? new MetaError("Unknown request failure");
154
+ }
155
+ captureRateLimit(headers) {
156
+ const get = (k) => {
157
+ const v = headers[k] ?? headers[k.toLowerCase()];
158
+ return typeof v === "string" ? v : undefined;
159
+ };
160
+ this.lastRateLimit = {
161
+ businessUseCase: get("x-business-use-case-usage"),
162
+ adAccountUsage: get("x-ad-account-usage"),
163
+ appUsage: get("x-app-usage"),
164
+ };
165
+ }
166
+ }
167
+ function sleep(ms) {
168
+ return new Promise((resolve) => setTimeout(resolve, ms));
169
+ }
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ import { ResponseFormat } from "./format.js";
3
+ /**
4
+ * Canonical pagination input shared across list-style tools.
5
+ * - `limit`: items per page (capped)
6
+ * - `after`: opaque Graph cursor to resume from
7
+ * - `auto_paginate`: if true, follow `paging.next` up to max_pages
8
+ */
9
+ export declare const paginationShape: {
10
+ limit: z.ZodDefault<z.ZodNumber>;
11
+ after: z.ZodOptional<z.ZodString>;
12
+ auto_paginate: z.ZodDefault<z.ZodBoolean>;
13
+ };
14
+ export declare const responseFormatShape: {
15
+ response_format: z.ZodDefault<z.ZodNativeEnum<typeof ResponseFormat>>;
16
+ };
17
+ /** Meta's expected ID shapes. Loose on purpose — Graph accepts numeric or prefixed forms. */
18
+ export declare const metaIdSchema: z.ZodString;
19
+ export declare const adAccountIdSchema: z.ZodString;
20
+ export declare const datePresetSchema: z.ZodEnum<["today", "yesterday", "this_month", "last_month", "this_quarter", "maximum", "last_3d", "last_7d", "last_14d", "last_28d", "last_30d", "last_90d", "last_week_mon_sun", "last_week_sun_sat", "last_quarter", "last_year", "this_week_mon_today", "this_week_sun_today", "this_year"]>;
21
+ export declare const timeRangeSchema: z.ZodObject<{
22
+ since: z.ZodString;
23
+ until: z.ZodString;
24
+ }, "strip", z.ZodTypeAny, {
25
+ since: string;
26
+ until: string;
27
+ }, {
28
+ since: string;
29
+ until: string;
30
+ }>;
@@ -0,0 +1,69 @@
1
+ import { z } from "zod";
2
+ import { ResponseFormat } from "./format.js";
3
+ /**
4
+ * Canonical pagination input shared across list-style tools.
5
+ * - `limit`: items per page (capped)
6
+ * - `after`: opaque Graph cursor to resume from
7
+ * - `auto_paginate`: if true, follow `paging.next` up to max_pages
8
+ */
9
+ export const paginationShape = {
10
+ limit: z
11
+ .number()
12
+ .int()
13
+ .min(1)
14
+ .max(500)
15
+ .default(25)
16
+ .describe("Items per page (1-500). Meta may cap lower for some endpoints."),
17
+ after: z
18
+ .string()
19
+ .optional()
20
+ .describe("Opaque Graph `paging.cursors.after` value from a previous response."),
21
+ auto_paginate: z
22
+ .boolean()
23
+ .default(false)
24
+ .describe("If true, follow `paging.next` up to META_MAX_AUTO_PAGES and return the concatenated data."),
25
+ };
26
+ export const responseFormatShape = {
27
+ response_format: z
28
+ .nativeEnum(ResponseFormat)
29
+ .default(ResponseFormat.JSON)
30
+ .describe("Output format: 'json' for machine-readable, 'markdown' for human-readable."),
31
+ };
32
+ /** Meta's expected ID shapes. Loose on purpose — Graph accepts numeric or prefixed forms. */
33
+ export const metaIdSchema = z
34
+ .string()
35
+ .min(1)
36
+ .describe("Meta object ID. Numeric ID or prefixed form (e.g. ad accounts use 'act_<digits>').");
37
+ export const adAccountIdSchema = z
38
+ .string()
39
+ .regex(/^act_\d+$/, "Ad account ID must start with 'act_' (e.g. 'act_1234567890').")
40
+ .describe("Ad account ID in the 'act_<digits>' form.");
41
+ export const datePresetSchema = z
42
+ .enum([
43
+ "today",
44
+ "yesterday",
45
+ "this_month",
46
+ "last_month",
47
+ "this_quarter",
48
+ "maximum",
49
+ "last_3d",
50
+ "last_7d",
51
+ "last_14d",
52
+ "last_28d",
53
+ "last_30d",
54
+ "last_90d",
55
+ "last_week_mon_sun",
56
+ "last_week_sun_sat",
57
+ "last_quarter",
58
+ "last_year",
59
+ "this_week_mon_today",
60
+ "this_week_sun_today",
61
+ "this_year",
62
+ ])
63
+ .describe("Meta date preset. See Marketing API insights docs for the full set.");
64
+ export const timeRangeSchema = z
65
+ .object({
66
+ since: z.string().describe("ISO date, e.g. '2026-01-01'."),
67
+ until: z.string().describe("ISO date, e.g. '2026-01-31'."),
68
+ })
69
+ .describe("Explicit date range. Overrides date_preset when both are supplied.");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { loadConfig } from "./config.js";
4
+ import { createLogger } from "./logger.js";
5
+ import { buildServer } from "./server.js";
6
+ async function main() {
7
+ let config;
8
+ try {
9
+ config = loadConfig();
10
+ }
11
+ catch (err) {
12
+ process.stderr.write(`[meta-mcp] configuration error: ${err.message}\n`);
13
+ process.exit(1);
14
+ }
15
+ const logger = createLogger(config.logLevel);
16
+ logger.info({ api_version: config.apiVersion, appsecret_proof: Boolean(config.appSecret) }, "starting meta-business-manager-mcp-server");
17
+ const { server } = buildServer(config, logger);
18
+ const transport = new StdioServerTransport();
19
+ await server.connect(transport);
20
+ logger.info("stdio transport connected");
21
+ const shutdown = async (signal) => {
22
+ logger.info({ signal }, "shutting down");
23
+ try {
24
+ await server.close();
25
+ }
26
+ finally {
27
+ process.exit(0);
28
+ }
29
+ };
30
+ process.on("SIGINT", () => void shutdown("SIGINT"));
31
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
32
+ }
33
+ main().catch((err) => {
34
+ process.stderr.write(`[meta-mcp] fatal: ${err.stack ?? err}\n`);
35
+ process.exit(1);
36
+ });
@@ -0,0 +1,3 @@
1
+ import pino from "pino";
2
+ export declare function createLogger(level: string): pino.Logger<never, boolean>;
3
+ export type Logger = ReturnType<typeof createLogger>;
package/dist/logger.js ADDED
@@ -0,0 +1,18 @@
1
+ import pino from "pino";
2
+ export function createLogger(level) {
3
+ return pino({
4
+ name: "meta-mcp",
5
+ level,
6
+ redact: {
7
+ paths: [
8
+ "access_token",
9
+ "*.access_token",
10
+ "params.access_token",
11
+ "headers.authorization",
12
+ "appsecret_proof",
13
+ "*.appsecret_proof",
14
+ ],
15
+ censor: "[redacted]",
16
+ },
17
+ }, pino.destination(2));
18
+ }
@@ -0,0 +1,7 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { Config } from "./config.js";
3
+ import type { Logger } from "./logger.js";
4
+ export declare function buildServer(config: Config, logger: Logger): {
5
+ server: McpServer;
6
+ ctx: import("./context.js").ToolContext;
7
+ };
package/dist/server.js ADDED
@@ -0,0 +1,14 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { createContext } from "./context.js";
3
+ import { SERVER_NAME, SERVER_VERSION } from "./constants.js";
4
+ import { registerTools } from "./tools/register.js";
5
+ export function buildServer(config, logger) {
6
+ const server = new McpServer({
7
+ name: SERVER_NAME,
8
+ version: SERVER_VERSION,
9
+ });
10
+ const ctx = createContext(config, logger);
11
+ const toolNames = registerTools(server, ctx);
12
+ logger.info({ tools: toolNames, count: toolNames.length }, "tools registered");
13
+ return { server, ctx };
14
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { ToolContext } from "../../context.js";
3
+ export declare const inputSchema: z.ZodObject<{
4
+ ad_account_id: z.ZodString;
5
+ fields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
6
+ }, "strict", z.ZodTypeAny, {
7
+ fields: string[];
8
+ ad_account_id: string;
9
+ }, {
10
+ ad_account_id: string;
11
+ fields?: string[] | undefined;
12
+ }>;
13
+ export type Input = z.infer<typeof inputSchema>;
14
+ export declare const definition: {
15
+ readonly name: "meta_ads_get_account";
16
+ readonly title: "Get ad account details";
17
+ readonly description: "Reads account-level details for a single ad account: status, currency, spend cap, current balance, amount_spent lifetime, funding source, capabilities, business owner. Use to verify an account is active and has headroom before drilling into insights.";
18
+ readonly inputSchema: {
19
+ ad_account_id: z.ZodString;
20
+ fields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
21
+ };
22
+ readonly annotations: {
23
+ readonly readOnlyHint: true;
24
+ readonly destructiveHint: false;
25
+ readonly idempotentHint: true;
26
+ readonly openWorldHint: true;
27
+ };
28
+ };
29
+ export declare function handler(input: Input, ctx: ToolContext): Promise<import("../../helpers/format.js").ToolTextResult>;
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ import { assertAllowed } from "../../config.js";
3
+ import { adAccountIdSchema } from "../../helpers/schema.js";
4
+ import { runGet } from "../shared.js";
5
+ export const inputSchema = z
6
+ .object({
7
+ ad_account_id: adAccountIdSchema,
8
+ fields: z
9
+ .array(z.string())
10
+ .default([
11
+ "id",
12
+ "account_id",
13
+ "name",
14
+ "currency",
15
+ "timezone_name",
16
+ "account_status",
17
+ "disable_reason",
18
+ "spend_cap",
19
+ "balance",
20
+ "amount_spent",
21
+ "funding_source_details",
22
+ "business",
23
+ "capabilities",
24
+ "age",
25
+ "created_time",
26
+ ])
27
+ .describe("Fields to return."),
28
+ })
29
+ .strict();
30
+ export const definition = {
31
+ name: "meta_ads_get_account",
32
+ title: "Get ad account details",
33
+ description: `Reads account-level details for a single ad account: status, currency, spend cap, current balance, amount_spent lifetime, funding source, capabilities, business owner. Use to verify an account is active and has headroom before drilling into insights.`,
34
+ inputSchema: inputSchema.shape,
35
+ annotations: {
36
+ readOnlyHint: true,
37
+ destructiveHint: false,
38
+ idempotentHint: true,
39
+ openWorldHint: true,
40
+ },
41
+ };
42
+ export async function handler(input, ctx) {
43
+ assertAllowed("ad_account", input.ad_account_id, ctx.config);
44
+ return runGet(ctx, { path: input.ad_account_id, params: { fields: input.fields.join(",") } });
45
+ }
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { ToolContext } from "../../context.js";
3
+ export declare const inputSchema: z.ZodObject<{
4
+ creative_id: z.ZodString;
5
+ fields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
6
+ }, "strict", z.ZodTypeAny, {
7
+ fields: string[];
8
+ creative_id: string;
9
+ }, {
10
+ creative_id: string;
11
+ fields?: string[] | undefined;
12
+ }>;
13
+ export type Input = z.infer<typeof inputSchema>;
14
+ export declare const definition: {
15
+ readonly name: "meta_ads_get_creative";
16
+ readonly title: "Get ad creative details";
17
+ readonly description: "Reads ad creative body: headline, copy, image or video, CTA, link URL, attached object story. Use alongside insights to explain why a particular ad performed well.";
18
+ readonly inputSchema: {
19
+ creative_id: z.ZodString;
20
+ fields: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
21
+ };
22
+ readonly annotations: {
23
+ readonly readOnlyHint: true;
24
+ readonly destructiveHint: false;
25
+ readonly idempotentHint: true;
26
+ readonly openWorldHint: true;
27
+ };
28
+ };
29
+ export declare function handler(input: Input, ctx: ToolContext): Promise<import("../../helpers/format.js").ToolTextResult>;
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import { metaIdSchema } from "../../helpers/schema.js";
3
+ import { runGet } from "../shared.js";
4
+ export const inputSchema = z
5
+ .object({
6
+ creative_id: metaIdSchema.describe("Creative ID (as returned by meta_ads_list_ads.creative.id)."),
7
+ fields: z
8
+ .array(z.string())
9
+ .default([
10
+ "id",
11
+ "name",
12
+ "title",
13
+ "body",
14
+ "object_story_id",
15
+ "object_type",
16
+ "image_url",
17
+ "thumbnail_url",
18
+ "video_id",
19
+ "call_to_action_type",
20
+ "link_url",
21
+ "effective_object_story_id",
22
+ "instagram_permalink_url",
23
+ "object_story_spec",
24
+ ])
25
+ .describe("Creative fields."),
26
+ })
27
+ .strict();
28
+ export const definition = {
29
+ name: "meta_ads_get_creative",
30
+ title: "Get ad creative details",
31
+ description: `Reads ad creative body: headline, copy, image or video, CTA, link URL, attached object story. Use alongside insights to explain why a particular ad performed well.`,
32
+ inputSchema: inputSchema.shape,
33
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
34
+ };
35
+ export async function handler(input, ctx) {
36
+ return runGet(ctx, { path: input.creative_id, params: { fields: input.fields.join(",") } });
37
+ }