Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
GHOST_ADMIN_URLYesThe URL of your Ghost admin (e.g., https://yourblog.example.com)
GHOST_API_VERSIONNoGhost API version (default v6.0)v6.0
GHOST_STAFF_ACCESS_TOKENYesYour staff access token in the format <id>:<secret>

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
extract_brandA

Distil a live site's brand into clean tokens to theme against.

Step one of theming a customer's blog: point this at their public product or marketing site and it returns the brand to match, so you design against real colours and fonts instead of guessing or hand-reading a stylesheet. Fetches the page and its CSS (public http(s) only; private/localhost hosts refused).

It also reads the site's menus, so you can offer to reuse them on the blog (write them with update_navigation). navigation.primary / navigation.secondary are the header/footer content links; navigation.membership holds login/sign-up/account links, which are kept OUT of the suggested menu -- they are usually the parent app's own auth, not blog nav. Ask the user what to do with any membership links rather than adding them to the menu automatically.

get_theme_structureA

Inspect a live Ghost page and return its markup and CSS.

Fetches the public, rendered page at path along with the stylesheets it links to, so styling changes can target selectors that actually exist rather than guesses. The homepage and individual posts use different templates, so pass the path of the page you intend to restyle.

check_contrastA

Check the WCAG contrast ratio between two colours before shipping a theme.

Guards against unreadable text-on-accent: pass two colours -- as hex (#d97706) or rgb()/rgba() -- such as a button's text vs. its accent background, or body text vs. the page background. Use it on the palette and accent from extract_brand when picking text colours.

create_themeA

Generate a complete, valid, previewable Ghost theme on disk.

Writes a ready-to-use theme (layout, home/post/page templates, page handling, the Koenig CSS classes Ghost requires, and package.json) to a local directory. Supply styles (CSS) to design the look; the site's brand accent colour is available in CSS as var(--ghost-accent-color), so the theme respects the user's existing branding.

Width convention: the base stylesheet keeps the structural chrome classes (.site-header/.site-footer/.post-feed/.post/.page) at full width and centres their contents with an inner .gh-inner wrapper. So in a custom layout, cap a region by wrapping its content in your own inner element (or reuse .gh-inner) and set max-width there -- setting it on a child of an un-capped region works, but a child can't widen past a capped parent.

Optionally override the home/post/page templates, and the default.hbs layout itself, with your own Handlebars. Stay within the previewable helper subset: {{#if}}/{{#unless}}, {{#foreach}} (with limit=/to=, but not from=), {{#post}}, partials, and bare fields like {{title}} and {{content}}. Avoid block params (as |x|) and the helpers Ghost evaluates server-side ({{#get}}, {{#match}}, {{#is}}, {{date}}) -- block params and from= are rejected outright, and the rest render blank in the local preview.

For content templates (index/post/page), layout inheritance is handled for you: the {{!< default}} directive is injected if an override omits it. A default_template override replaces the whole layout, so it MUST include {{{body}}} (where child templates inject) -- a layout without it is rejected, since every page would render empty. The stylesheet <link> and {{ghost_head}}/{{ghost_foot}} are auto-injected before </head> / </body> if you omit them, so styling, SEO, the accent colour, and members keep working. Note {{asset "built/screen.css"}} only emits the URL -- to load the CSS it must sit inside a real <link rel="stylesheet" href="{{asset "built/screen.css"}}">. See docs/theme-conventions.md for the full contract.

After generating, call preview_theme with the returned path to view it, then upload_theme to install it (activation stays manual).

preview_themeA

Render a Ghost theme locally and serve it for preview in a browser.

Builds a static render of the theme's home, post, and page templates using sample content, then serves it on localhost. Open the returned URL in a browser to check layout and styling before activating the theme on the live site. The render is a style-focused mockup: structure and CSS are faithful, while content is sampled and some dynamic helpers are stubbed.

Only one preview runs at a time: each call stops the previous server and replaces it, so older preview URLs go dead. Always hand the user the URL from the most recent call.

upload_themeA

Package a theme directory and upload it to Ghost WITHOUT activating it.

The live site keeps its current theme; the uploaded theme is installed but inactive, so it can be reviewed and activated manually. Ghost validates the theme on upload; any errors or warnings are returned.

list_themesA

List the themes installed on the blog and which one is active.

download_themeA

Download an installed theme's source as a ZIP to a local temp file.

Useful for grabbing a theme's assets, branding, or package.json as a reference. Returns the path to the downloaded file and its size.

restyle_themeA

Restyle an installed theme by editing its stylesheet, then re-upload it.

Iterate a theme already on the blog without regenerating it: this downloads the named theme, rewrites its assets/built/screen.css -- appending new rules by default, or mode="replace" to swap the whole stylesheet -- and re-uploads it. The upload itself does NOT activate a theme. But if name is the ACTIVE theme, the new CSS is what visitors see, so this changes the live look; confirm that's intended. Ghost re-validates on upload, so any errors/warnings are returned.

activate_themeA

Activate an installed theme, making it the LIVE theme. Changes the site.

This is the one theme tool that alters what visitors see: it switches the blog's active theme. Call it ONLY on the user's explicit instruction to activate a specific theme -- never as an automatic follow-on to generating, uploading, or restyling one. Upload installs inactive on purpose so a theme can be reviewed first; activation is the deliberate, separate go-live step.

get_site_settingsA

Read the blog's brand and SEO settings.

Returns the site identity (title, description), branding (accent colour, logo, icon, cover), and SEO/social metadata (meta title/description and the Open Graph and Twitter card fields). Use it to review the current state before updating, or to keep the blog aligned with the main site.

update_site_metadataA

Update the blog's identity and SEO/social metadata.

Sets the site title/description, the search-result metadata (meta_title/meta_description), and the Open Graph and Twitter card fields used when posts are shared. Only the arguments you provide are changed; omit the rest. Good meta_* and social fields help the blog present and rank well.

Returns the fields that were updated, with their new values.

update_brandingA

Update the blog's brand accent colour.

accent_color is a hex value such as #4a7c59. Keeping it aligned with the main site's brand makes the blog feel like part of the same product.

Returns the fields that were updated.

update_navigationA

Set the blog's navigation menus (primary header and secondary/footer).

Each menu is a list of {"label": ..., "url": ...} items. The whole menu is REPLACED, not appended to, so send the complete set you want; pass only the menu(s) you mean to change and the other is left untouched. URLs are usually site-relative (/about/) or absolute. Extra keys on an item (such as the external/kind hints from extract_brand) are ignored, so links read from a site can be passed straight through.

Membership actions (login/sign-up/account) belong in the theme as Ghost Portal buttons (data-portal), not here -- don't add them as menu links. Confirm the menus with the user before calling this; it changes the live site.

list_postsC

List blog posts.

get_postA

Read a single post by id or slug, including its rendered HTML.

Provide either post_id or slug. The result includes a preview_url for viewing the post in the active theme.

create_postA

Create a blog post from HTML content.

Defaults to a draft; pass status="published" to publish immediately. tags are given as names and created if they don't already exist. meta_title/meta_description set the post's search-snippet metadata.

Returns the created post's summary, including a preview_url for reviewing the draft in the active theme before publishing.

update_postA

Update an existing post by id; only the fields you pass are changed.

Pass status="published" to publish a draft, or status="draft" to unpublish. An empty html is treated as "leave the body unchanged" (same as create), so it never blanks a post. Returns the updated post summary.

publish_postA

Publish a post AND email it to a newsletter's subscribers. SENDS REAL EMAIL.

This is outward-facing and irreversible: it emails the post to members the moment it publishes (or at scheduled_at). Only call it on explicit user instruction to send. To publish WITHOUT emailing, use update_post(status="published") instead.

delete_postB

Delete a post by id. This cannot be undone.

list_pagesA

List pages (standalone content outside the post feed).

get_pageA

Read a single page by id or slug, including its rendered HTML.

Provide either page_id or slug. The result includes a preview_url for viewing the page in the active theme.

create_pageA

Create a page from HTML content.

Defaults to a draft; pass status="published" to publish immediately. Pages are standalone (about, contact, …) with no tags or feed placement. meta_title/meta_description set the page's search-snippet metadata.

Returns the created page's summary, including a preview_url for reviewing the draft in the active theme before publishing.

update_pageA

Update an existing page by id; only the fields you pass are changed.

Pass status="published" to publish a draft, or status="draft" to unpublish. An empty html is treated as "leave the body unchanged", so it never blanks a page. Returns the updated page summary.

delete_pageA

Delete a page by id. This cannot be undone.

upload_imageA

Upload a local image file to the blog and return its hosted URL.

Use the returned URL for a post's feature_image, the site logo/icon (via update_branding), or a newsletter header_image.

upload_image_from_urlA

Fetch a public image by URL and re-upload it to the blog, returning the URL.

The source is fetched under the same SSRF guard as the vision tools (public http(s) only; private/localhost hosts and oversized responses are refused), then uploaded to Ghost so the image is served from the blog itself.

list_tagsB

List tags, with how many posts use each.

get_tagA

Read a single tag by id or slug. Provide either tag_id or slug.

create_tagA

Create a tag.

Only name is required; slug is derived from it if omitted. Returns the created tag's summary.

update_tagB

Update a tag by id; only the fields you pass are changed.

delete_tagA

Delete a tag by id. Posts keep existing; they just lose the tag.

list_membersA

List members (newest first), with their labels and subscribed newsletters.

get_memberC

Read a single member by id, including labels, newsletters, and tiers.

create_memberA

Create a member from an email address.

Only email is required; the member is created as a free member. labels are given as names (created if new); newsletter_ids subscribe the member to those newsletters (get the ids from list_newsletters). Creating a member sends no email. Returns the created member's summary.

update_memberA

Update a member by id; only the fields you pass are changed.

labels and newsletter_ids REPLACE the member's current sets, so pass the full list you want to keep. subscribed=false unsubscribes the member from all newsletters. Returns the updated member summary.

list_newslettersC

List newsletters (active and archived).

get_newsletterB

Read a single newsletter by id.

create_newsletterA

Create a newsletter.

Only name is required. sender_reply_to is either "newsletter" (use the sender address) or "support" (use the Portal support address). Set opt_in_existing=true to also subscribe existing subscribed members to this new newsletter. To set a custom sender_email, create the newsletter first, then update_newsletter (the address needs email verification). Returns the created newsletter's summary.

update_newsletterA

Update a newsletter by id; only the fields you pass are changed.

Set status="archived" to retire a newsletter (there is no delete) or "active" to restore it. Changing sender_email starts an email verification: Ghost emails the new address and it does NOT take effect until the link is clicked, so sender_email may still read as its old value right after this call. sender_reply_to is "newsletter" or "support". Returns the updated newsletter summary.

list_tiersB

List tiers (paid plans), including their prices and benefits.

get_tierB

Read a single tier by id, including its prices and benefits.

create_tierB

Create a tier (paid plan).

Only name is required. Prices are in the smallest currency unit (e.g. 1000 = $10.00) and pair with a currency (three-letter ISO code). benefits is a list of short strings shown on the tier. Returns the created tier summary.

update_tierA

Update a tier by id; only the fields you pass are changed.

There is no delete for tiers; retire one with active=False instead. Returns the updated tier summary.

list_offersB

List discount offers, each with its linked tier.

get_offerA

Read a single offer by id, including its linked tier.

create_offerB

Create a discount offer against a tier.

update_offerA

Update an offer by id.

Ghost only allows editing name, code, and the display title/description of an existing offer; the pricing terms are fixed once created. Returns the updated offer summary.

list_labelsB

List member labels.

get_labelA

Read a single label by id or slug. Provide either label_id or slug.

create_labelA

Create a member label. Only name is required; slug is derived if omitted.

update_labelB

Update a label by id; only the fields you pass are changed.

delete_labelA

Delete a label by id. Members keep existing; they just lose the label.

list_usersA

List users (authors/staff). Read-only: the Admin API forbids integrations from writing users.

get_userB

Read a single user by id or slug. Provide either user_id or slug.

Prompts

Interactive templates invoked by user choice

NameDescription
theme-a-siteGuided flow to design and build a custom Ghost theme matched to a brand.

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

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/stemcreations/ghost-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server