Open-source ad agent for LinkedIn Ads and Google Ads. Drafts campaigns, audiences and reports from Claude or any MCP client.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Documented (README)
git clone https://github.com/adwarp-dev/adwarp{
"mcpServers": {
"adwarp": {
"command": "node",
"args": ["/path/to/adwarp/dist/index.js"]
}
}
}MCP Servers overview
# Adwarp
[](https://www.npmjs.com/package/adwarp)
[](./LICENSE)
[Website](https://adwarp.dev) · [Docs](https://adwarp.dev/docs) · [Install guide](https://adwarp.dev/docs/install) · [npm package](https://www.npmjs.com/package/adwarp)
**Adwarp** (formerly Liam) is the open-source ad agent for LinkedIn Ads and Google Ads.
Create campaigns by talking to Claude (MCP) or from a CLI. Built for go-to-market teams
who want to spin up many campaigns from a contact list and a brief, then add creative
images themselves. Everything starts switched off: LinkedIn entities are created as **drafts** and
Google entities as **paused**. A LinkedIn campaign goes live only when you explicitly
ask Adwarp to turn it on or switch it on yourself in Campaign Manager, and Google
campaigns can only be switched on in the Google Ads UI.
> Unofficial and not affiliated with or endorsed by LinkedIn or Google.
> Covers creation, matched audiences (including building one straight from Salesforce or HubSpot),
> conversion selection, performance reporting/insights, competitor ad intelligence, and a
> change journal with before/after lift. See [ROADMAP.md](./ROADMAP.md) for what's shipped
> and what's planned next.
## What you can do with it
Once Adwarp is connected, you talk to your assistant in plain language. Real requests it
handles today, roughly in the order a campaign comes together:
- "How many VPs of demand gen at US SaaS companies can we reach?" (resolves targeting
facets, estimates reach before any money is involved)
- "Upload this CSV as a matched audience." (auto-cleans columns, hashes emails, converts
company domains to URLs)
- "Build an audience from Salesforce: every contact on an account flagged as a target."
(SOQL straight to a matched audience)
- "Turn our HubSpot target accounts list into a LinkedIn audience." (a HubSpot list or search
straight to a matched audience of contacts or companies)
- "Launch a draft campaign for that audience, $100/day, tracking the demo-booked
conversion." (campaign group + campaign + draft ads in one call)
- "What ads is our biggest competitor running right now, and what offers are they pushing?" (reads the
public Ad Library: copy, formats, and EU targeting metadata for any company)
- "How did retargeting do last month vs the month before?" (trend report with deltas)
- "Which ads should I pause this week?" (account rollup with top/bottom performers and
flags, then pauses the ads you pick, leaving the rest of each ad group running)
- "Rewrite the copy on the losing ad." (delete + recreate as a fresh draft; LinkedIn
ignores edits to a live ad's post)
- "Did the new headline actually help?" (change journal + before/after lift)
Adwarp resolves the details and reports back the ids. Every capability is also an `adwarp`
CLI command for scripted or batch use.
### Put it on a loop
There is no scheduler in Adwarp. Use the one in whatever client you drive it from.
Some loops that work well:
- "Every Monday at 9am, pull last week's performance summary, compare it to the week
before, and flag anything that moved more than 20%." (a Claude Code scheduled agent)
- "Every Friday, check what new ads our top three competitors shipped this week and
summarize the angles."
- "Check the audience match status every few hours and tell me when it clears 300
members." (the minimum for a matched audience to serve)
- Or skip the assistant entirely and put the CLI in cron:
`0 9 * * 1 adwarp report summary -p last_7_days`
## Hierarchy mapping (the two platforms disagree)
LinkedIn's names are shifted one level from everyone else's, which is the single
most common source of confusion when working across both:
| Common term | LinkedIn entity | Google Ads entity | Holds |
| ----------- | ------------------ | ----------------- | ---------------------------------------- |
| Campaign | **Campaign Group** | (none) | status, total/shared budget |
| Ad group | **Campaign** | **Campaign** | targeting, budget, bid, schedule, format |
| (none) | (none) | **Ad group** | keywords and the ads that answer them |
| Ad | **Creative** | **Ad group ad** | the rendered ad |
| Audience | **DMP Segment** | **User list** | attached to targeting |
So a LinkedIn "campaign" and a Google "campaign" are not the same thing: Google's
campaign holds the budget and targeting (LinkedIn's *campaign group* plus
*campaign*), and its ad group holds keywords.
## Google Ads
Search campaigns only, creation-first. What is there today:
```bash
adwarp google auth login
adwarp google accounts list # proves the token and OAuth client work
adwarp google keywords "revops automation" --url https://example.com/product
adwarp google conversions list
adwarp google launch --brief examples/google-brief.json # dry run
adwarp google launch --brief examples/google-brief.json --apply # create it, paused
adwarp google campaigns list
adwarp google report perf keyword -p last_30_days
```
A launch creates the budget, campaign, geo and language targeting, ad groups,
keywords, and responsive search ads in **one atomic mutate**: it either lands
whole or not at all, so a failure cannot leave half a campaign behind. Every
write is validated server-side first, which is a genuine dry run rather than a
local guess.
Three house rules are hard-coded, because all three default the wrong way in the
UI and quietly waste B2B budget:
- **Search network only.** Display expansion and search partners off.
- **Physical presence only.** "US" means people in the US, not people anywhere
who searched about it.
- **Manual CPC to start.** Smart bidding with no conversion history spends
unpredictably. Switch in the UI once there is data.
### Setup
Google Ads needs two things LinkedIn does not:
1. **A developer token**, from a Google Ads **manager (MCC)** account at
[ads.google.com/aw/apicenter](https://ads.google.com/aw/apicenter). A plain
client account cannot issue one. Approval usually lands on **Explorer** access
automatically (2,880 production ops/day).
**Explorer is not enough for `adwarp google keywords`.** Explorer blocks
KeywordPlanService, so keyword research needs **Basic** access (15,000
ops/day), which is a separate application on the same screen. Campaign
creation and reporting work fine on Explorer.
2. **An OAuth client**, from a Google Cloud project with the Google Ads API
enabled. Use the "Desktop app" type, which accepts any `localhost` redirect.
For the consent screen, **do not leave it in "Testing"**. That status issues
refresh tokens that stop working after 7 days. Beyond that it is a trade:
- **Internal** (Workspace orgs only) is what Google's OAuth docs recommend for
a single-company tool. Simplest, no verification, no 7-day expiry.
- **External + In production** is the precondition for *brand verification*,
the pilot that cuts Basic Access review from days to hours. The cost is that
`auth/adwords` is a **sensitive** scope, so a published external app can
require full OAuth app verification, potentially slower than the wait it
saves.
Internal is the better default for an internal tool. Choose External only if
the fast track is worth the verification risk.
Then write `~/.adwarp/google.json`:
```json
{
"clientId": "....apps.googleusercontent.com",
"clientSecret": "...",
"developerToken": "...",
"loginCustomerId": "1234567890",
"defaultCustomerId": "0987654321",
"defaultConversionActionNames": ["Demo Booked"]
}
```
`loginCustomerId` is the manager account and is only needed when you reach the
target account through one. Run `adwarp google auth login` and you are set.
[Set up Google Ads](https://adwarp.dev/docs/google-ads-setup) in the docs has the same
steps, plus the `ADWARP_GOOGLE_*` environment variables.
## Packages
- `@adwarp/shared`: the platform-neutral layer: OAuth, credential stores, retry policy, the change journal, period and KPI math.
- `@adwarp/core`: LinkedIn REST client, resource modules, CSV + SHA256 hashing, Salesforce and HubSpot readers.
- `@adwarp/google`: Google Ads REST client, GAQL reads, atomic mutate builder, Search campaign creation.
- `@adwarp/mcp`: MCP server (stdio for local; reused by the hosted app). **Primary interface.**
- `@adwarp/cli`: the `adwarp` CLI over the same engines, for scripted batch runs.
- `@adwarp/web`: Next.js app that hosts the MCP over HTTP on Vercel, at `https://mcp.adwarp.dev/api/mcp`. It serves no pages: its other paths redirect to adwarp.dev.
- `adwarp`: the published npm package. Bundles the CLI and the MCP server behind the `adwarp`, `adwarp-mcp` and `liam` commands.
## How it works
Both interfaces are thin layers over the same engine. Every MCP tool and CLI command builds
a client via `createLinkedInAds()` (`core/src/client.ts`), which loads config plus an
auto-refreshing OAuth token provider, then calls a typed resource module
(`campaigns.ts`, `audience.ts`, `report.ts`, ...) that wraps LinkedIn's versioned REST API
(`LinkedIn-Version` pinned in config). Input shapes live as zod schemas in
`core/src/schemas.ts` and are reused verbatim as the MCP tool input schemas, so the CLI and
MCP can never drift apart.
The drafts-first safety rule is enforced at creation: campaign groups, campaigns, and
creatives default to `DRAFT` status, and going live is always an explicit request (a
`status` of `ACTIVE`, `campaigns update --status ACTIVE --apply`, or `ad resume --apply`). On Google, no
create schema can express an enabled status at all. Every write also passes through one HTTP chokepoint that appends to a
local change journal (`~/.adwarp/changelog.jsonl`) for later lift analysis.
[AGENTS.md](./AGEWhat people ask about adwarp
What is adwarp-dev/adwarp?
+
adwarp-dev/adwarp is mcp servers for the Claude AI ecosystem. Open-source ad agent for LinkedIn Ads and Google Ads. Drafts campaigns, audiences and reports from Claude or any MCP client. It has 23 GitHub stars and its last recorded update is dated 2026-10-19.
How do I install adwarp?
+
You can install adwarp by cloning the repository (https://github.com/adwarp-dev/adwarp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is adwarp-dev/adwarp safe to use?
+
Our security agent has analyzed adwarp-dev/adwarp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains adwarp-dev/adwarp?
+
adwarp-dev/adwarp is maintained by adwarp-dev. The last recorded GitHub activity is dated 2026-10-19, with 0 open issues.
Are there alternatives to adwarp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy adwarp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/adwarp-dev-adwarp)<a href="https://claudewave.com/repo/adwarp-dev-adwarp"><img src="https://claudewave.com/api/badge/adwarp-dev-adwarp" alt="Featured on ClaudeWave: adwarp-dev/adwarp" width="320" height="64" /></a>More MCP Servers
Reverse engineer anything with agents, from app behavior down to native binaries.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev