Ghedee Content Hub MCP Server
Enables managing a social media calendar workflow with AI-generated images/videos, including generating media, uploading to Google Drive, and downloading the latest calendar draft.
README
Ghedee Content Hub — MCP server
MCP server backing the Content Hub Cowork workflows for The Ghedee Centre. Planned to cover three content types — Blog Posts, Social Media Calendar, Emails. Phase 1 (this build) is the Social Calendar workflow only.
The canonical calendar is a living Google Sheet (Ghedee_Social_Calendar_<id>,
e.g. Ghedee_Social_Calendar_Q3_2026) in 00_Calendar & Docs, which the team edits
in place. The tools:
| Tool | What it does |
|---|---|
social_create_calendar |
Start a new calendar: create the Drive folder tree (folder named by the Calendar ID) + an empty, styled living-sheet shell in 00_Calendar & Docs, and write a local Ghedee_Social_Calendar_<id>_v1.xlsx into the caller's dest_dir for Cowork to fill in. |
social_generate_media |
Read the live sheet's Draft rows → generate the missing AI images/videos → upload to Drive → write each link / cost / model / notes back into the live sheet in place (Sheets API — no download/re-upload). |
social_upload_calendar |
Create the living Google Sheet from a local .xlsx at source_path (--replace to overwrite). |
social_download_calendar |
Export the living sheet to a local .xlsx in the caller's dest_dir so Cowork can ingest current edits. |
social_snapshot_calendar |
Export the living sheet to the next _v<N>.xlsx on Drive (a frozen approval-round record). |
social_build_preview |
Build an HTML review page from the live sheet and publish it next to the calendar as Ghedee_Social_Calendar_<id>_preview.html. |
Metricool publishing is planned for a later phase.
Architecture
Three content types are planned (Blog Posts, Social Calendar, Emails). Their
common thread — generate AI images/video, push files to a specific Drive
folder, pull files back for Cowork — lives in core/. Each content type is its
own package on top; social is the only one built so far.
server.py thin MCP tools (FastMCP, stdio)
content_hub/
core/ ← the common thread, content-agnostic
config.py env / Google credentials / paths / brand + model defaults
media.py generate images + video (the AI-image primitive)
drive.py push to a Drive folder / pull latest / exists-check
social/ ← workflow #1 (blog/ and email/ become siblings)
rules.py calendar naming, id→folder, aspect-ratio, Drive layout
calendar.py read the .xlsx → jobs; write Drive link + cost back
workflow.py orchestrator: generate → push → writeback (the 3 operations)
cli.py manual dry/mock/live test harness for the same 3 operations
The core engine never writes to stdout and never calls sys.exit — required for
an MCP stdio server, where stdout is the protocol channel. All progress goes to
stderr; tools return structured results. Adding a workflow = a new package
(e.g. blog/) that parses its own input format, defines its own Drive layout, and
reuses core.media + core.drive for the three shared primitives.
How a calendar row becomes media
Only rows with Status = Draft and Visual Type AI text-to-image /
AI text-to-video are generated. Recorded video of Wiah rows are left alone
(they need a film shoot). Aspect ratio is derived per row (Visual Type first,
Format second — the Format column alone is ambiguous):
| Visual Type | Format | Kind | Aspect | Files |
|---|---|---|---|---|
| AI text-to-video | any | video | 16:9 | 1 ({RowID}_{Plat}_{Slug}_v1.mp4) |
| AI text-to-image | Carousel |
carousel | 4:5 | N slides (slide-1..N_v1.png in a group folder) |
| AI text-to-image | anything else | image | 1:1 | 1 ({RowID}_{Plat}_{Slug}_v1.png) |
Carousels read a Slides column for the slide count (defaults to 4). The
Row ID is the stable key: the Drive existence check matches on the {RowID}_
prefix, so editing a hook never orphans an already-generated file.
Idempotency: a row is skipped if its asset already exists on Drive. Deleting the Drive file (or a carousel's group folder) is how you request a regeneration.
Three modes (every tool + CLI command)
| Mode | Drive | API/credits | Writes |
|---|---|---|---|
dry-run |
none | none | nothing — plans jobs + reports worst-case cost |
mock |
yes (safe) | none | placeholder files; upload + write-back routed to a mock destination and a *.mock.xlsx copy — production is never touched |
live |
yes | spends | real generation + upload + write-back to the working sheet |
Mock uploads go to SOCIAL_CALENDAR_MOCK_ROOT_ID if set, else a _mock rehearsal
subfolder under the calendar folder — so a rehearsal can never overwrite a real asset.
Setup
python -m venv .venv && .venv\Scripts\Activate.ps1 # PowerShell
pip install -r requirements.txt
cp .env.example .env # fill in OPENAI_API_KEY (+ GEMINI_API_KEY for video) + SOCIAL_CALENDAR_ROOT_ID
Media keys: images use OpenAI gpt-image-2 (OPENAI_API_KEY; your account may
need org verification to access it); video uses Google Veo (GEMINI_API_KEY). A run
only needs the key(s) for the media types it generates — an --only image run never
touches the Gemini key, and vice-versa.
Google auth (one-time, interactive): create a Desktop-app OAuth client in
Google Cloud Console → APIs & Services → Credentials, enable both the Drive
API and the Google Sheets API, save the client JSON as credentials.json.
Authorise once so the browser consent can run and cache token.json:
python -m content_hub.cli auth # grants Drive + Sheets, caches token.json
After that every headless run (server, mock, live) reuses token.json.
Never commit credentials.json, token.json, or .env.
The calendar lifecycle
# 0. Start a brand-new calendar: Drive folders + an empty living-sheet shell, and a
# local shell .xlsx to fill in. The Calendar ID is the Drive folder name verbatim
# (a quarter, a date range, or a single day). --out is where the shell is written:
python -m content_hub.cli social create Q3_2026 --out ./work # -> ./work/Ghedee_Social_Calendar_Q3_2026_v1.xlsx
# 1. Seed the living Google Sheet from a local Cowork draft (one-time), by file path:
python -m content_hub.cli social upload Q3_2026 ./work/Ghedee_Social_Calendar_Q3_2026_v1.xlsx
# 2. Generate media and write links/cost/model/notes back INTO the live sheet:
python -m content_hub.cli social generate Q3_2026 --mode dry-run # plan + cost only
python -m content_hub.cli social generate Q3_2026 --mode mock # rehearse (live sheet untouched)
python -m content_hub.cli social generate Q3_2026 --mode live # spends; edits the sheet in place
# 3. Review page from the live sheet, published beside the calendar on Drive:
python -m content_hub.cli social preview Q3_2026
# 4. Pull the live sheet down for Cowork, or freeze a versioned snapshot:
python -m content_hub.cli social download Q3_2026 --out ./work # -> ./work/Ghedee_Social_Calendar_Q3_2026.xlsx
python -m content_hub.cli social snapshot Q3_2026 # -> next _v<N>.xlsx on Drive
# generate options: --only image|video --video-model <id> --video-duration 30
generate reads the living Google Sheet and, in live mode, writes only the
machine-owned columns (Generated Asset Link / Est. Cost / AI Model / Notes) in
place via the Sheets API — so a teammate editing captions or Status at the same
time is never clobbered. dry-run touches nothing; mock writes a local
*.mock.xlsx instead of the live sheet.
Run as an MCP server
python server.py # serves over stdio
Register it as a local MCP/connector in Claude Cowork — copy
cowork-mcp-config.example.json, fill in the absolute paths and env values:
{
"mcpServers": {
"ghedee-content-hub": {
"command": "…\\content-hub-mcp\\.venv\\Scripts\\python.exe",
"args": ["…\\content-hub-mcp\\server.py"],
"env": {
"SOCIAL_CALENDAR_ROOT_ID": "your-social-calendar-folder-id",
"OPENAI_API_KEY": "your-openai-key-here",
"GEMINI_API_KEY": "your-gemini-key-here"
}
}
}
}
command should point at the venv's Python (so the deps resolve). The env block
is optional — the server also reads .env on startup — but keeping the connector
self-contained avoids surprises. The three social_* tools then drive the same
workflow, each taking a mode argument. Do the one-time Drive consent first
(above) so token.json exists before Cowork launches the server headless.
Notes
- Images: OpenAI
gpt-image-2. Rendered at native aspect ratios (1:1 → 1024×1024, 4:5 carousel → 1024×1280),quality=high,moderation=low. No crop step — the model renders the requested ratio directly. - Cost figures come from a rough price table in
core/media.py— a guide, not a bill. Images bill per output token (~$0.12–0.16/image at high quality); confirm with OpenAI's image-cost calculator. Video is per-second Veo pricing. - Model access / deprecations: if images 404, confirm your OpenAI account can use
gpt-image-2(org verification may be required). Google rotates Veo-previewnames — on a video model-not-found error, updateDEFAULT_VIDEO_MODELincore/config.py. - Veo resolution/duration:
1080ponly renders at 8s; hero clips default to 720p/6s. Validated before spending. - Reference docs (the Cowork workflow prompt and the Drive asset-structure layout) live in the Cowork Content Hub project, not this repo.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.