Skip to main content
Glama

ghost-content-mcp

A read-only MCP server that turns any Ghost site into a semantic content-discovery source for AI assistants.

Point it at a Ghost site (URL + Content API key) and it exposes tools an LLM can call to search, summarize, and read that site's posts, pages, and tags β€” ranked by a hybrid of lexical (BM25) and local semantic embeddings. It's designed to power visitor-facing chatbots and RAG, not to manage the blog.

How this differs from other Ghost MCP servers. Most existing ones wrap the Admin API for content management (create/edit/delete posts, members, newsletters) β€” tools for the site owner. This one is the opposite: public, read-only, retrieval-focused. Its job is to answer "what does this site say about X?" well.

Features

  • πŸ”Ž Hybrid search β€” Okapi BM25 (lexical) + all-MiniLM-L6-v2 embeddings (semantic), so natural-language questions match even without shared keywords. Runs fully locally (model bundled in the image, no external inference calls).

  • 🧭 9 tools β€” search_all, search_posts, get_related_posts, get_site_summary, get_post, get_page, list_posts, list_pages, list_tags.

  • βš™οΈ Zero-config identity β€” auto-detects the site's name/description/URL from Ghost's own /settings endpoint (override with env vars if you want).

  • πŸ”„ Self-updating β€” in-memory index with a ~10-min TTL refresh; new content appears automatically. Optional internal POST /refresh for webhook-driven instant updates.

  • πŸ™ Optional GitHub companions β€” if a post links a repo you own, its README can be indexed and surfaced next to the article (off by default).

  • πŸ™ˆ #noindex β€” tag any post/page #noindex to keep it out of discovery search (still fetchable by direct slug).

Related MCP server: Knowledge Base MCP Server (Qdrant)

Quick start

cp .env.example .env      # set GHOST_URL + GHOST_CONTENT_API_KEY
npm install
npm run build
npm start

Or with Docker:

docker build -t ghost-content-mcp .
docker run -p 3000:3000 --env-file .env ghost-content-mcp

Or with Docker Compose (see docker-compose.yml β€” includes a memory cap and healthcheck):

cp .env.example .env      # set GHOST_URL + GHOST_CONTENT_API_KEY
docker compose up -d

The MCP endpoint is POST /mcp (Streamable HTTP, stateless JSON). GET /health reports index status.

Getting a Ghost Content API key

Ghost Admin β†’ Settings β†’ Integrations β†’ Add custom integration β†’ copy the Content API key. (Content keys are read-only and safe to use for a public endpoint.)

Connecting a client

Any MCP client that speaks Streamable HTTP. Example (Claude Desktop-style config):

{
  "mcpServers": {
    "ghost-content": { "url": "https://your-host/mcp" }
  }
}

Configuration

Env var

Required

Default

Notes

GHOST_URL

βœ…

http://localhost:2368

Your Ghost site URL

GHOST_CONTENT_API_KEY

βœ…

β€”

Content API key (read-only)

PORT

3000

HTTP port

SITE_NAME / SITE_URL / SITE_DESCRIPTION

from Ghost /settings

Identity overrides

GITHUB_COMPANION_OWNERS

β€” (off)

Comma-separated owner allowlist to enable repo companions

GITHUB_TOKEN

β€”

Raises GitHub API rate limits

INDEX_TTL_MS

600000

Auto-refresh interval

REFRESH_TOKEN

β€”

If set, POST /refresh requires header x-refresh-token

EMBEDDINGS_MODEL

Xenova/all-MiniLM-L6-v2

Sentence-embedding model

EMBEDDINGS_BATCH_SIZE

8

Lower = lower peak RAM during index build

Tools

Tool

Purpose

search_all

Search posts + pages (+ repos) by keyword/question, ranked by relevance. Start here.

search_posts

Same ranking, posts only.

get_related_posts

"More like this" for a given post slug.

get_site_summary

One-call overview: what the site is, topics, counts, recent posts, pages.

get_post / get_page

Full content as Markdown by slug.

list_posts / list_pages

Paginated listings (filter by tag/date, sort).

list_tags

All public tags with post counts.

Relevance is 0.5Β·BM25 + 0.5Β·cosine(embeddings), range 0–1. As a rule of thumb: β‰₯0.5 is a strong match, 0.3–0.5 weak, <0.3 noise.

How updates work

The index rebuilds automatically every ~10 minutes (TTL); publishing in Ghost is enough. For instant updates, wire a Ghost "post published/updated" webhook to the internal POST /refresh (optionally guarded by REFRESH_TOKEN).

Notes

  • Requires glibc (Node node:22-slim, not Alpine) β€” onnxruntime-node's native binding doesn't load on musl.

  • The embedding model (~90 MB) is downloaded at image build time and bundled, so there are no network calls at runtime.

License

MIT

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers