Back to Browse

Gam Seller Mcp Node MCP Server

Developer ToolsLow Risk10.0MCP RegistryLocal
Free

Server data from the Official MCP Registry

Governed, read-only MCP server exposing Google Ad Manager inventory discovery to buyer agents

About

Governed, read-only MCP server exposing Google Ad Manager inventory discovery to buyer agents

Security Report

10.0
Low Risk10.0Low Risk

Valid MCP server (2 strong, 4 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry.

4 files analyzed · 1 issue found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

HTTP Network Access

Connects to external APIs or services over the internet.

What You'll Need

Set these up before or after installing:

Directory holding your deployment.json/catalog.json/entitlements.json/pricing.json. Omit it to run the bundled demo.Optional

Environment variable: MCP_CONFIG_DIR

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-juan-sibbo-gam-seller-mcp-node": {
      "env": {
        "MCP_CONFIG_DIR": "your-mcp-config-dir-here"
      },
      "args": [
        "-y",
        "gam-seller-mcp-node"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

GAM Seller MCP Node

npm version npm downloads CI License: MIT TypeScript MCP

AI buyer agents are about to participate in programmatic advertising. When they do, they need a governed interface to sell-side inventory — one that cannot be tricked into revealing sensitive data, and that cannot execute transactions it shouldn't.

This is that interface.

A governed Model Context Protocol server that exposes sell-side ad inventory (Google Ad Manager and compatible systems) to buyer-side AI agents: discovery, firm pricing, and a soft commitment primitive. It performs no writes to the ad server — the only mutation it allows is a buyer's own soft commitment (a revocable, TTL-bound intent), never a GAM order or an inventory hold. No raw ad-server access. No sensitive data in responses. Every decision audited.


What problem does this solve?

Sell-side ad inventory (availability, pricing, product structure) lives inside ad servers that hold commercially sensitive and sometimes personal data. Giving an AI buyer agent direct API access to GAM or a similar system creates three risks:

RiskWithout this projectWith this project
Data over-exposureAgent can read raw avails, deal IDs, exact floor pricesOnly coarse buckets and pre-declared families
Accidental writesAgent SDK can create orders, modify line itemsNo ad-server writes exist; the only write is a buyer's own soft commitment, which can never become a GAM order or an inventory hold
No accountabilityAPI calls are logged but not auditableHash-chained audit ledger; every allow/deny recorded

How it works

A buyer agent connects via MCP and gets five tools — three read-only, plus a buyer-scoped commitment primitive (create/revoke) that is the sole write surface:

Buyer agent
    │
    ├── well_known_capabilities   ← Signed trust anchor. Check this first.
    │       Returns: RS256-signed capability document, node identity, privacy posture.
    │
    ├── discover_products         ← What can I buy here, and at what firm price?
    │       Returns: product families the buyer is entitled to see (e.g. "Pre-Roll Video"),
    │               each with its firm list price when the publisher has configured one.
    │       Never returns: deal IDs, internal IDs, raw inventory, exact per-impression pricing.
    │
    ├── get_forecast              ← How available is this family next quarter?
    │       Returns: Low / Mid / High availability bucket.
    │       Never returns: exact impression counts, CPM curves, floor prices.
    │
    ├── create_intent             ← Commit to a product at its current firm price (with TTL).
    │       Records a firm, time-boxed buying intent — fail-closed if the price is stale or
    │       mismatched. NOT a GAM order and NOT an inventory hold; it is the handoff artifact
    │       the classic sales rails pick up. Buyer-scoped: you can only ever commit as yourself.
    │
    └── revoke_intent             ← Withdraw one of your own active intents by id.

Every call flows through the same pipeline before any domain logic runs:

  Buyer request
       │
       ▼
  [SEC-GATE-3]  Replay detection — deduplicate client_request_id
       │
       ▼
  [Auth]        RS256 token validation → identity confirmed or AUTH_FAILED
       │
       ▼
  [Policy]      Surface denylist → entitlement check → scope check (Default-Deny)
       │
       ▼
  [Rate limit]  N=1 / T=30s per buyer_id
       │
       ▼
  [Domain]      Catalog / ForecastEngine — synthetic today, real GAM adapter in progress
       │
       ▼
  [Audit]       Append-only hash-chained ledger, buyer pseudonymized (HMAC)
       │
       ▼
  Response to buyer

A bug in any gate fails closed, not open.

create_intent runs the same gates and adds one more before it records anything: the buyer's price_ref must match the family's current firm price, or the request is rejected — fail-closed on a stale or mismatched offer, so an intent can never pin a price the publisher is no longer offering.

Quick start

Install in an MCP client (via npx)

Add the server to your MCP client (Claude Desktop, Claude Code, Cursor, …):

{
  "mcpServers": {
    "gam-seller": {
      "command": "npx",
      "args": ["-y", "gam-seller-mcp-node"]
    }
  }
}

Or run it directly (stdio transport — the default for MCP clients):

npx -y gam-seller-mcp-node

Demo mode. With no config of your own, the node boots on a bundled pilot-publisher example (illustrative catalog, prices and forecasts) and says so on stderr — it starts instead of failing, so you can try the tools immediately. Because buyer surfaces always require a token (there is no anonymous path, even in demo), the node prints a ready-to-use demo buyer token on startup: copy it and pass it as the token argument to discover_products / get_forecast to see the example families, prices and forecasts.

For a real deployment, point MCP_CONFIG_DIR at a directory holding your own deployment.json, catalog.json, entitlements.json and pricing.json:

MCP_CONFIG_DIR=/etc/gam-seller/config npx -y gam-seller-mcp-node

From source

git clone https://github.com/juan-sibbo/gam-seller-mcp-node.git
cd gam-seller-mcp-node
npm install
npm run build
npm run start:http   # HTTP transport on 127.0.0.1:3900

Run the full buyer-agent walkthrough (scripted demo):

npx tsx demo/run-demo.ts

With Docker

docker compose up

The node starts on 127.0.0.1:3900. The well-known document is at /.well-known/seller-mcp-capabilities. Persistent volumes for keys and audit data are pre-configured in docker-compose.yml.

Configure for your publisher

Four JSON files drive all publisher-specific behaviour — no code changes needed. Place them in config/ (from-source) or in the directory named by MCP_CONFIG_DIR (npx/containerised):

deployment.json     # DSR contact, controller model, data retention window
catalog.json        # product families + per-buyer access grants
entitlements.json   # which buyers are entitled to which MCP surfaces
pricing.json        # firm list prices per family (fail-closed on expiry)

Invalid config always fails closed: a malformed file stops the node rather than running with a silently different access policy. Absent config (no config/ and no MCP_CONFIG_DIR) drops to the bundled config/examples/pilot-publisher/ example — demo mode, announced on stderr — so the node is never a broken install, only ever a real deployment or a clearly-labelled demo.

Why not just use the GAM API directly?

ApproachData exposureWritabilityAuditabilityAI-agent friendly
Raw GAM APIEverything in the accountFull CRUDLogging onlyPoor (SOAP/REST, no MCP)
OpenRTB bid requestsUser-level data, floor pricesBid-onlyNonePoor
This serverCoarse families + bucket forecastsBuyer's own soft commitment only (no GAM writes)Hash-chained ledgerNative MCP

Current status

Working MVP. The full request pipeline (auth → policy → rate-limit → domain → audit), the buyer-scoped commitment primitive (create_intent / revoke_intent, with TTL expiry), the audit ledger, GDPR data-subject-rights toolkit, Docker packaging, HTTP transport, and a live interop probe (Python buyer agent simulation) are all implemented and tested.

Not yet wired: a live Google Ad Manager connection. The catalog and forecast data are synthetic, loaded from local config. The GAM ForecastService SOAP adapter interface exists (src/forecast/source.ts) and is the next major milestone. See the open issues for the roadmap.

Architecture

See docs/ARCHITECTURE.md for the full module map and data-flow diagrams.

Key modules:

ModuleRole
src/server.tsMCP tool definitions + request pipeline
src/policy/Default-Deny engine, entitlement store, surface allowlist/denylist
src/identity/RS256 key management, token issuance/validation, revocation denylist
src/audit/Hash-chained ledger, HMAC pseudonymization, external anchoring
src/pricing/Firm list price store, expiry-aware (fail-closed on stale prices)
src/forecast/Bucket engine + GAM adapter seam (synthetic today)
src/dsr/GDPR Art. 15/17/18/20 data-subject-rights toolkit
src/catalog/Product family store, per-buyer access grants

Security model

Default-Deny. Every request is denied unless an explicit entitlement says otherwise — there is no "allow by default" path in the code.

Structural allow/denylist (SEC-GATE-*). Response surfaces are governed by a fixed list enforced at the policy layer, independent of which tool was called. Exact pricing, deal IDs, raw availability numbers, cross-buyer state, real inventory holds (soft-lock), and any ad-server write are permanently denied. The one permitted write is a buyer's own commitment (create_intent / revoke_intent), which required an explicit amendment to the surface allowlist and stays buyer-scoped. Adding a new tool in the future cannot bypass this.

Opaque errors. A denied request, a failed authentication, and a revoked token all return the same generic AUTH_FAILED code. Internal reasons never reach the buyer.

Audit-first. Every allow/deny is written to the ledger before the response is sent. Buyer buyer_id values are pseudonymized (HMAC-SHA256) before entering the chain.

Privacy by construction. Responses carry only inventory-level data (product family, coarse bucket). User-level attributes don't exist in any response path.

See docs/DESIGN-PRINCIPLES.md for the full reasoning.

Testing

npm test                              # full suite (vitest)
python3 sandbox/buyer-agent-probe.py  # external Python interop probe (no shared code with server)

The test suite includes:

  • Unit tests for each module (policy, pricing, identity, audit, catalog, forecast, DSR)
  • Integration tests over real in-memory MCP transports (tests/server.test.ts)
  • HTTP transport tests over a real ephemeral-port HTTP server (tests/http.test.ts)
  • End-to-end session tests simulating a full buyer-agent session (tests/buyer-agent-session.test.ts)
  • External Python probe that exercises the HTTP transport without any shared Node.js code

CI runs on every push via GitHub Actions.

Data protection

Raw buyer_id values never enter the audit ledger — only an HMAC pseudonym. The src/dsr/toolkit.ts implements export, restriction, and erasure of a buyer's audit data (GDPR Art. 15/17/18/20). The node stores nothing about end users; the DSR scope is exactly what it records — B2B buyer organization pseudonyms and their request events.

Roadmap

See the open issues for the full roadmap. Highlights:

  • Real GAM adapter — wire getAvailabilityForecast via the ForecastService SOAP API
  • Buyer agent SDKs — Python and TypeScript client libraries for the MCP buyer flow
  • Multi-publisher federation — let buyer agents discover across multiple seller nodes
  • OIDC buyer authentication — replace manual entitlements with federated identity
  • OpenRTB 3.0 taxonomy — align family_id scheme with IAB standards
  • Prometheus metrics — observability endpoint for production deployments

Contributing

See CONTRIBUTING.md. Issues tagged good first issue are a good starting point.

License

MIT — see LICENSE.

Reviews

No reviews yet

Be the first to review this server!