marketing-data-hub
Allows querying Google Ads campaign data (spend, clicks, conversions, etc.) when the Google Ads connector is activated.
Allows querying Google Analytics 4 data including reports on campaigns, traffic channels, landing pages, page behavior, audience, and visitors.
Allows querying Meta Ads campaign data when the Meta Ads connector is activated.
Allows querying YouTube Analytics data from configured channels.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@marketing-data-hubHow did my campaigns do last week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Marketing Data Hub
Your marketing data, on your machine, free. An open-source Windsor.ai alternative: pulls Google Analytics 4, Search Console (plus Google Ads, Meta Ads, YouTube) into one local database — queryable via a REST API, scheduled CSV exports, and by AI assistants like Claude (MCP). No hosted service, no subscription, your tokens never leave your computer.
Quick start (no config editing needed)
pip install marketing-data-hub
mkdir my-marketing-hub && cd my-marketing-hub
hub setup(Developers: git clone https://github.com/rallabandibhargava-dev/marketing-data-hub
and pip install -e ".[dev]" instead.)
hub setup opens a page in your browser where you:
Connect Google — sign in, done (multiple Google accounts supported)
Tick the GA4 properties / Search Console sites you want
Optionally paste Google Ads / Meta Ads tokens
Run the first sync and watch it load
Copy the Claude snippet to ask questions in plain English
One prerequisite: a Google OAuth client file at secrets/google_client.json
(one-time, ~5 minutes — see SETUP.md step 2; teams share one file).
Then ask Claude things like "How did organic traffic do in June vs May?" or "Top non-branded search queries this month?" — or automate a daily 6am sync (SETUP.md, step 8).
Related MCP server: Google Analytics MCP Server
Reports (analysis shapes)
Each source syncs several named reports — different dimensional shapes of the same data, stored side by side and never mixed (mixing granularities would double-count):
Source | Report | Answers |
ga4 |
| daily campaign totals (sessions, users, conversions, revenue) |
ga4 |
| traffic mix: organic vs paid vs direct, engagement, pageviews |
ga4 |
| entry-page performance per channel |
ga4 |
| page behaviour: views, engagement time, events per path |
ga4 |
| device × country segmentation |
ga4 |
| new vs returning (cohort-lite) |
gsc |
| exact daily search totals per site |
gsc |
| per-query performance (branded split = string-match) |
gsc |
| per-URL search performance |
gsc |
| mobile/desktop and geo splits |
ga4 |
| per-event counts by name (brand-specific: form_submit, call_click...) |
Pass report=<name> to the API/MCP query_metrics; default is core.
MCP query_metrics also supports compare= (prev_period / prev_day / prev_week /
prev_month / prev_year — returns value, previous, and %-change per metric for any
date range) and filters= (exact match on any dimension incl. report extras,
e.g. {"event": "form_submit"} or {"device": "MOBILE"}).
Rates are computed, not stored: engagement rate = engaged_sessions/sessions,
ctr = clicks/impressions, avg engagement time = engagement_seconds/pageviews.
GSC breakdown reports undercount totals slightly (Google anonymises rare
queries) — use core for toplines. True user-level cohorts need the GA4
BigQuery export; visitors + the live tools cover cohort-lite analysis.
For anything the synced reports don't cover, the MCP tools query_ga4_live
and query_gsc_live pass arbitrary dimension/metric combinations straight to
the APIs on demand.
Setup
New here / installing on another machine? Follow SETUP.md — a step-by-step guide including the Google Cloud OAuth setup. Quick version:
python -m pip install -e ".[dev]"Copy
config.yaml.example→config.yaml; fill in your GA4property_idand Search Consolesite_url. Have multiple GA4 properties or Search Console sites under the same Google login? Useproperty_ids: [...]/site_urls: [...]instead — all of them sync, and every row is tagged with its ownaccount_idso they stay distinguishable downstream.Copy
.env.example→.env; set a randomHUB_API_KEY.Google Cloud Console → create a project → enable Google Analytics Data API, Google Analytics Admin API, Search Console API, YouTube Analytics API → create an OAuth client (Desktop app) → download JSON to
secrets/google_client.json. (See SETUP.md for the OAuth consent-screen steps and the 7-day token-expiry gotcha.)hub doctor— first run opens a browser to authorize; then all checks go green.hub accounts --add— pick which GA4 properties / GSC sites to sync from everything your Google login can see.
Daily use
Command | What it does |
| sync every configured source (rolling 30-day window) |
| load history in 90-day chunks |
| row counts + last sync per source |
| query API on 127.0.0.1:8000 + cron scheduler |
| write configured CSVs to exports/ |
| MCP server (stdio) for Claude |
Query API
GET /connectors/all/data?fields=date,source,clicks,spend&date_preset=last_30d
X-API-Key: <HUB_API_KEY>format=csv for CSV, report=<name> for a breakdown report. /connectors
lists sources; /connectors/{source}/reports lists report shapes;
/connectors/{source}/fields?report=<name> lists fields.
Claude MCP
claude mcp add marketing-hub -- python -m hub.cli mcp --config <absolute-path>/config.yaml
Then ask Claude: "How did my campaigns do last week?"
Note: use an absolute path for --config; the MCP process may be launched from a different working directory.
trigger_sync starts the sync in the background and returns immediately
(output goes to logs/mcp_sync.log); poll sync_status to see when it
finishes. While a sync holds the write lock, query tools return a readable
"database is busy" error instead of hanging.
Activating the ad connectors
Google Ads: apply for a developer token (API Center), then uncomment
google_adsin config.yaml and fill options.Meta Ads: create a Meta app, generate a long-lived token with
ads_read, uncommentmeta_adsand fill options.
Known limitations
DuckDB allows one writer: run
hub mcpORhub serve, not both at once (trigger_sync from MCP spawns the CLI, which needs the write lock free). While any sync runs, MCP query tools report "database is busy" until it finishes (~3 min forsync all).Extras fields (e.g. position, ctr, views) are returned as strings by the query API — cast numerically as needed.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/Bhargava-R-dev/marketing-data-hub'
If you have feedback or need assistance with the MCP directory API, please join our Discord server