Skip to main content
Glama
Mike25app

scaleforge-mcp-meta-ads

update_ad

Update an ad's name, status, or creative. Provide the ad ID and optionally change the name, set the status (ACTIVE, PAUSED, DELETED, ARCHIVED), or replace the creative by passing a creative ID.

Instructions

WRITE: Update an ad's name, status, or swap its creative. To replace the creative pass creative: {creative_id: 'XXX'}.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
ad_idYes
nameNo
statusNo
creativeNoe.g. {creative_id: '123456'}

Implementation Reference

  • Handler function for the 'update_ad' tool. Destructures ad_id from the args, then calls metaPost to the ad's Graph API endpoint with the remaining fields (name, status, creative).
      handler: async (args) => {
        const { ad_id, ...rest } = args;
        return metaPost(`/${String(ad_id)}`, rest as Record<string, unknown>);
      },
    },
  • Input schema for 'update_ad'. Accepts ad_id (required string), name (optional string), status (optional enum: ACTIVE/PAUSED/DELETED/ARCHIVED), and creative (optional record, e.g. {creative_id: '123456'}).
    inputSchema: {
      ad_id: z.string(),
      name: z.string().optional(),
      status: STATUS.optional(),
      creative: z
        .record(z.unknown())
        .optional()
        .describe("e.g. {creative_id: '123456'}"),
    },
  • src/index.ts:65-90 (registration)
    Registration loop in stdio entry point (index.ts). Iterates allToolDefs (including adTools) and calls server.registerTool() for each, connecting the handler to the MCP server.
    for (const tool of allTools) {
      server.registerTool(
        tool.name,
        {
          description: tool.description,
          inputSchema: tool.inputSchema,
        },
        // The SDK's ToolCallback type infers the arg shape from inputSchema, but
        // our shared ToolDef uses a generic Record<string, unknown> signature for
        // portability. The cast here is intentional and isolated to the bridge.
        async (args: unknown) => {
          try {
            const result = await tool.handler(args as Record<string, unknown>);
            return {
              content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
            };
          } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            return {
              content: [{ type: "text" as const, text: `Error: ${message}` }],
              isError: true,
            };
          }
        },
      );
    }
  • src/http.ts:48-67 (registration)
    Registration loop in HTTP entry point (http.ts). Same pattern as index.ts but for the HTTP Streamable server.
    for (const tool of allTools) {
      server.registerTool(
        tool.name,
        { description: tool.description, inputSchema: tool.inputSchema },
        async (args: unknown) => {
          try {
            const result = await tool.handler(args as Record<string, unknown>);
            return {
              content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
            };
          } catch (err) {
            const message = err instanceof Error ? err.message : String(err);
            return {
              content: [{ type: "text" as const, text: `Error: ${message}` }],
              isError: true,
            };
          }
        },
      );
    }
  • The metaPost helper function used by the update_ad handler. Sends a POST request to the Meta Graph API with URL-encoded form body and access token.
    export async function metaPost<T = unknown>(
      path: string,
      body: Record<string, unknown> = {},
    ): Promise<T> {
      const form = buildQuery(body);
      form.append("access_token", getCurrentToken());
      const url = `${META_API_BASE}${normalizePath(path)}`;
    
      const res = await fetch(url, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: form.toString(),
      });
      if (!res.ok) {
        const text = await res.text().catch(() => "");
        throw new Error(enhanceMetaError(res.status, text));
      }
      const raw = await res.text();
      if (!raw) return {} as T;
      return JSON.parse(raw) as T;
    }
Behavior3/5

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

With no annotations, the description carries the full burden. It explicitly states this is a write operation and mentions updating status (includes DELETED via enum), but does not disclose implications of creative swap or any authentication or rate limit requirements.

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

Conciseness5/5

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

Two sentences, no fluff. The critical action is front-loaded with 'WRITE' prefix, and the second sentence provides a concrete example. Every word earns its place.

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

Completeness2/5

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

While the description lists updatable fields, it omits important context: return value, prerequisites, behavior of swapping creative (e.g., is the old creative deleted?), and that only ad_id is required. For a write tool with 4 params and no output schema, this is insufficient.

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

Parameters2/5

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

Schema description coverage is only 25% (creative param has description). The description adds minimal meaning: it lists name, status, and creative as updatable fields but does not explain ad_id, nor does it elaborate beyond what the schema already shows for creative. It does not compensate for low coverage.

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?

Description starts with 'WRITE: Update an ad's name, status, or swap its creative.' This clearly states the verb (update) and resource (ad) with specific modifiable fields, effectively distinguishing it from sibling tools like delete_ad or create_ad.

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

Usage Guidelines3/5

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

Provides a specific usage tip for replacing the creative, but lacks guidance on when to use this tool versus alternatives (e.g., update_adset) and does not exclude any scenarios.

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

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Mike25app/scaleforge-mcp-meta-ads'

If you have feedback or need assistance with the MCP directory API, please join our Discord server