Skip to main content
Glama
RPriya2019

Ad Campaign MCP

by RPriya2019

Ad Campaign MCP

An MCP (Model Context Protocol) client/server integration built with TypeScript/Node.js. It connects an AI assistant to a small REST API over structured, typed tools — with real error handling for a down API or a missing record — rather than the assistant calling the API directly.

Architecture

MCP client (AI assistant)
      │  stdio, JSON-RPC
      ▼
MCP server (src/index.ts)
      │  HTTP
      ▼
Campaign REST API (src/api.ts, Express)
      │  SQL
      ▼
Postgres (docker-compose.yml)
  • Postgresadvertisers, campaigns, impressions, and clicks tables, created on API startup by src/db.ts.

  • REST API (src/api.ts) — GET /campaigns (optionally filtered by ?status=) and GET /campaigns/:id, backed by Postgres.

  • MCP server (src/index.ts) — exposes two tools that call the REST API and translate its responses (including non-2xx statuses and connection failures) into MCP tool results.

Related MCP server: Ads Analytics MCP

Getting started

docker compose up -d      # start Postgres
npm install
npm run api                # start the REST API on :3000
npm run build               # compile the MCP server to dist/

Run the MCP server directly during development with npm run dev (uses tsx, no build step needed), or run the compiled version with node dist/index.js. The compiled version starts noticeably faster, since it skips on-the-fly TypeScript transpilation — worth using for an MCP client that spawns the server, since Client.connect() has a default 60s handshake timeout.

The API URL defaults to http://localhost:3000; override it with the API_BASE_URL environment variable if the REST API runs elsewhere.

Sample API calls

There's no POST /campaigns endpoint yet, so the table starts empty — seed a row directly via SQL first, or the calls below just return [] / 404.

Seed a campaign (direct SQL)

docker exec -it ad-campaign-postgres psql -U postgres -d adplatform -c "
INSERT INTO advertisers (name) VALUES ('Acme Corp') RETURNING id;
-- suppose that returns id = 1
INSERT INTO campaigns (id, advertiser_id, name, status, budget, start_date, end_date)
VALUES ('camp_001', 1, 'Summer Launch', 'active', 5000.00, '2026-06-01', '2026-08-31');
"

GET /campaigns — list all

curl http://localhost:3000/campaigns
[
  {
    "id": "camp_001",
    "advertiser_id": 1,
    "name": "Summer Launch",
    "status": "active",
    "budget": "5000.00",
    "start_date": "2026-06-01T00:00:00.000Z",
    "end_date": "2026-08-31T00:00:00.000Z",
    "created_at": "2026-08-29T10:00:00.000Z",
    "updated_at": "2026-08-29T10:00:00.000Z"
  }
]

GET /campaigns?status=active — filtered by status

curl "http://localhost:3000/campaigns?status=active"

GET /campaigns/:id — single campaign

curl http://localhost:3000/campaigns/camp_001

Returns the same object as above, unwrapped from the array.

GET /campaigns/:id — not found

curl -i http://localhost:3000/campaigns/does-not-exist
HTTP/1.1 404 Not Found
{"error":"Campaign not found"}

Tools exposed

  • list_campaigns — list campaigns, optionally filtered by status (active | paused | draft).

  • get_campaign — fetch a single campaign by id; returns an error result (not a thrown exception) for a 404 or an unreachable API.

Trying it end-to-end

npm run build
node demo-mcp-client.mjs

This spawns the compiled MCP server, performs the MCP handshake, lists its tools, and calls each one — including the 404 case — printing the results.

Known limitations

  • The REST API has no authentication — anything reaching :3000 can read campaign data.

  • No POST/PUT endpoints yet — campaigns can only be seeded directly via SQL, not created through the API or the MCP tools.

License

MIT

Available Tools

2 tools
get_campaignB

Get a single advertising campaign by id

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesThe campaign id

TDQS

B3.3/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden for behavioral context. It only says 'Get', which implies a read operation, but it does not disclose return shape, behavior for nonexistent ids, error handling, or whether any side effects occur.

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?

The description is one short, front-loaded sentence with no filler. It clearly communicates the action, resource, and required parameter in minimal words.

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

Completeness3/5

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

For a simple get-by-id tool with one documented parameter, the description is mostly adequate. However, there is no output schema and the description does not state return values or error behavior, nor does it provide usage guidance versus list_campaigns, leaving some gaps in completeness.

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

Parameters3/5

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

The input schema already fully describes the single parameter with 100% coverage. The description’s 'by id' adds no new semantics beyond what the schema provides, so the baseline 3 is appropriate.

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?

The description states a specific verb (Get), a specific resource (advertising campaign), and the selection mechanism (by id). The word 'single' differentiates it from the sibling tool list_campaigns, making the tool's scope unmistakable.

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

Usage Guidelines2/5

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

No explicit guidance is given about when to use get_campaign versus list_campaigns. The distinction is implied by the word 'single', but the description does not name the alternative or state conditions like 'use list_campaigns to fetch multiple campaigns'.

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

list_campaignsC

List advertising campaigns

ParametersJSON Schema
NameRequiredDescriptionDefault
statusNoFilter campaigns by status

TDQS

C2.9/5.0
Behavior2/5

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

No annotations are provided, so the description must communicate behavioral aspects itself. It only states that campaigns are listed, revealing a read-like operation, but it does not mention pagination, return format, filtering behavior beyond the status parameter, authentication needs, or whether results are limited.

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?

The description is a single short phrase with no filler or redundancy. It is front-loaded and easy to parse, though it is extremely brief.

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?

The tool is simple, but with no output schema and no annotations, the description leaves important context unstated, such as what fields are returned, whether results are paginated, and what the default behavior is when no status filter is provided.

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

Parameters3/5

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

The schema covers both parameters: 'status' has an enum and a description. The tool description adds no additional parameter meaning, but with 100% schema coverage, the baseline of 3 is appropriate.

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

Purpose4/5

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

The description uses a clear verb ('List') and resource ('advertising campaigns'), which tells the agent what the tool does. It is naturally distinguishable from the sibling 'get_campaign' by pluralization (list of campaigns vs single campaign), though it does not explicitly state that distinction.

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

Usage Guidelines2/5

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

There is no guidance about when to use this tool versus 'get_campaign'. The plural form implies it returns multiple campaigns and the sibling returns one, but no explicit usage context, exclusions, or alternative criteria are provided.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 2 tool updatesv1.0.0
    • First observedget_campaign
    • First observedlist_campaigns

TDQS

B3.2/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one lists all campaigns and the other retrieves a single campaign by id. There is no ambiguity or overlap between them.

Naming Consistency5/5

Both tool names follow the consistent verb_noun pattern (list_campaigns, get_campaign), making the naming predictable and easy to understand.

Tool Count3/5

With only two tools, the server feels thin for a domain like ad campaigns, which typically involves more than just reading. However, the count is acceptable if the server is intentionally scoped to read-only operations.

Completeness2/5

The tool surface only covers listing and retrieving campaigns; there is no create, update, or delete functionality. This is a significant gap for an ad campaign management server, leaving agents unable to perform any lifecycle actions.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Enables users to manage Uber advertising campaigns through natural language by providing access to Uber's External Ads API. Supports campaign creation, retrieval, updating, and deletion with comprehensive filtering and configuration options.
    5
    -
  • A
    license
    A
    quality
    D
    maintenance
    Provides read access to campaign performance data from Google Ads, Meta Ads, and TikTok Ads via live API calls, enabling AI assistants to analyze and audit advertising campaigns.
    16
    1
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to interact with the Amazon Advertising API to manage campaigns, keywords, product ads, and retrieve performance metrics.
    9
    34 npm
    3
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI assistants to monitor outbound campaigns in ICTContact/ICTDialer, including listing campaigns, checking status, reading summaries and per-call results, and optionally starting and stopping campaigns when write access is enabled.
    4
    37 npm
    16
    MIT