Ghost MCP Server
Server Configuration
Describes the environment variables required to run the server.
Name | Required | Description | Default |
---|---|---|---|
GHOST_API_URL | Yes | Your Ghost Admin API URL | |
GHOST_STAFF_API_KEY | Yes | Your Ghost Staff API key |
Schema
Prompts
Interactive templates invoked by user choice
Name | Description |
---|---|
search_blog | Prompt template for searching blog posts |
create_summary | Create a prompt to summarize a blog post |
Resources
Contextual data attached and managed by the client
Name | Description |
---|---|
blog://info |
Tools
Functions exposed to the LLM to take actions
Name | Description |
---|---|
batchly_update_post | Update multiple blog posts that match the filter criteria. Copy Args:
filter_criteria: Dictionary containing fields to filter posts by, example:
{
"status": "draft",
"tag": "news",
"featured": True
}
Supported filter fields:
- status: Post status (draft, published, etc)
- tag: Filter by tag name
- author: Filter by author name
- featured: Boolean to filter featured posts
- visibility: Post visibility (public, members, paid)
update_data: Dictionary containing the fields to update. The updated_at field is required.
All fields supported by the Ghost API can be updated:
- slug: Unique URL slug for the post
- title: The title of the post
- lexical: JSON string representing the post content in lexical format
- html: HTML version of the post content
- comment_id: Identifier for the comment thread
- feature_image: URL to the post's feature image
- feature_image_alt: Alternate text for the feature image
- feature_image_caption: Caption for the feature image
- featured: Boolean flag indicating if the post is featured
- status: The publication status (e.g., published, draft)
- visibility: Visibility setting (e.g., public, private)
- created_at: Timestamp when the post was created
- updated_at: Timestamp when the post was last updated (REQUIRED)
- published_at: Timestamp when the post was published
- custom_excerpt: Custom excerpt text for the post
- codeinjection_head: Code to be injected into the head section
- codeinjection_foot: Code to be injected into the footer section
- custom_template: Custom template assigned to the post
- canonical_url: The canonical URL for SEO purposes
- tags: List of tag objects associated with the post
- authors: List of author objects for the post
- primary_author: The primary author object
- primary_tag: The primary tag object
- og_image: Open Graph image URL for social sharing
- og_title: Open Graph title for social sharing
- og_description: Open Graph description for social sharing
- twitter_image: Twitter-specific image URL
- twitter_title: Twitter-specific title
- twitter_description: Twitter-specific description
- meta_title: Meta title for SEO
- meta_description: Meta description for SEO
- email_only: Boolean flag indicating if the post is for email distribution only
- newsletter: Dictionary containing newsletter configuration details
- email: Dictionary containing email details related to the post
Example:
{
"updated_at": "2025-02-11T22:54:40.000Z",
"status": "published",
"featured": True,
"tags": [{"name": "news"}, {"name": "featured"}],
"meta_title": "My Updated Title",
"og_description": "New social sharing description"
}
ctx: Optional context for logging
Returns:
Formatted string containing summary of updated posts
Raises:
GhostError: If there is an error accessing the Ghost API or missing required fields |
browse_tags | Get the list of tags from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of tags per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing tag information
Raises:
GhostError: If there is an error accessing the Ghost API |
create_invite | Create a staff user invite in Ghost. Copy Args:
role_id: ID of the role to assign to the invited user (required)
email: Email address to send the invite to (required)
ctx: Optional context for logging
Returns:
String representation of the created invite
Raises:
GhostError: If the Ghost API request fails
ValueError: If required parameters are missing or invalid |
create_member | Create a new member in Ghost. Copy Args:
email: Member's email address (required)
name: Member's name (optional)
note: Notes about the member (optional)
labels: List of labels to apply to the member. Each label should be a dict with 'name' and 'slug' (optional)
newsletter_ids: List of newsletter IDs to subscribe the member to (optional)
ctx: Optional context for logging
Returns:
String representation of the created member
Raises:
GhostError: If the Ghost API request fails
ValueError: If required parameters are missing or invalid |
create_newsletter | Create a new newsletter. Copy Args:
name: Name of the newsletter (required)
description: Newsletter description
status: Newsletter status ("active" or "archived")
subscribe_on_signup: Whether to subscribe new members automatically
opt_in_existing: Whether to subscribe existing members
sender_reply_to: Reply-to setting ("newsletter" or "support")
show_header_icon: Whether to show header icon
show_header_title: Whether to show header title
show_header_name: Whether to show header name
show_feature_image: Whether to show feature image
title_font_category: Font category for titles
title_alignment: Title alignment
body_font_category: Font category for body text
show_badge: Whether to show badge
ctx: Optional context for logging
Returns:
Formatted string containing the created newsletter details |
create_offer | Create a new offer in Ghost. Copy Args:
name: Internal name for the offer (required)
code: Shortcode for the offer (required)
type: Either 'percent' or 'fixed' (required)
cadence: Either 'month' or 'year' (required)
amount: Discount amount - percentage or fixed value (required)
tier_id: ID of the tier to apply offer to (required)
duration: Either 'once', 'forever' or 'repeating' (required)
display_title: Name displayed in the offer window (optional)
display_description: Text displayed in the offer window (optional)
currency: Required when type is 'fixed', must match tier's currency (optional)
duration_in_months: Required when duration is 'repeating' (optional)
ctx: Optional context for logging
Returns:
String representation of the created offer
Raises:
GhostError: If the Ghost API request fails
ValueError: If required parameters are missing or invalid |
create_post | Create a new blog post. Copy Args:
post_data: Dictionary containing post data with required fields:
- title: The title of the post
- lexical: The lexical content as a JSON string
Additional optional fields:
- status: Post status ('draft' or 'published', defaults to 'draft')
- tags: List of tags
- authors: List of authors
- feature_image: URL of featured image
Example:
{
"title": "My test post",
"lexical": "{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello World","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}"
"status": "draft",
}
ctx: Optional context for logging
Returns:
Formatted string containing the created post details
Raises:
GhostError: If there is an error accessing the Ghost API or invalid post data |
create_tag | Create a new tag. Copy Args:
tag_data: Dictionary containing tag data with required fields:
- name: The name of the tag
Additional optional fields:
- slug: URL slug for the tag
- description: Description of the tag
- feature_image: URL to the tag's feature image
- visibility: Tag visibility ('public' or 'internal')
- accent_color: CSS color hex value for the tag
- meta_title: Meta title for SEO
- meta_description: Meta description for SEO
- canonical_url: The canonical URL
- og_image: Open Graph image URL
- og_title: Open Graph title
- og_description: Open Graph description
- twitter_image: Twitter card image URL
- twitter_title: Twitter card title
- twitter_description: Twitter card description
- codeinjection_head: Code to inject in header
- codeinjection_foot: Code to inject in footer
Example:
{
"name": "Technology",
"description": "Posts about technology",
"visibility": "public"
}
ctx: Optional context for logging
Returns:
Formatted string containing the created tag details
Raises:
GhostError: If there is an error accessing the Ghost API or invalid tag data |
create_tier | Create a new tier in Ghost. Copy Args:
name: Name of the tier (required)
monthly_price: Optional monthly price in cents (e.g. 500 for $5.00)
yearly_price: Optional yearly price in cents (e.g. 5000 for $50.00)
description: Optional description of the tier
benefits: Optional list of benefits for the tier
welcome_page_url: Optional URL for the welcome page
visibility: Visibility of tier, either "public" or "none" (default: "public")
currency: Currency for prices (default: "usd")
ctx: Optional context for logging
Returns:
String representation of the created tier
Raises:
GhostError: If the Ghost API request fails |
create_webhook | Create a new webhook in Ghost. Copy Args:
event: Event to trigger the webhook (required)
target_url: URL to send the webhook to (required)
integration_id: ID of the integration (optional - only needed for user authentication)
name: Name of the webhook (optional)
secret: Secret for the webhook (optional)
api_version: API version for the webhook (optional)
ctx: Optional context for logging
Returns:
String representation of the created webhook
Raises:
GhostError: If the Ghost API request fails
ValueError: If required parameters are missing or invalid |
delete_post | Delete a blog post. Copy Args:
post_id: The ID of the post to delete
ctx: Optional context for logging
Returns:
Success message if post was deleted
Raises:
GhostError: If there is an error accessing the Ghost API or the post doesn't exist |
delete_tag | Delete a tag. Copy Args:
tag_id: The ID of the tag to delete
ctx: Optional context for logging
Returns:
Success message if tag was deleted
Raises:
GhostError: If there is an error accessing the Ghost API or the tag doesn't exist |
delete_user | Delete a user from Ghost. Copy Args:
user_id: ID of the user to delete (required)
ctx: Optional context for logging
Returns:
Success message if deletion was successful
Raises:
GhostError: If the Ghost API request fails or if attempting to delete the Owner
ValueError: If user_id is not provided |
delete_webhook | Delete a webhook from Ghost. Copy Args:
webhook_id: ID of the webhook to delete (required)
ctx: Optional context for logging
Returns:
Success message if deletion was successful
Raises:
GhostError: If the Ghost API request fails
ValueError: If webhook_id is not provided |
get_auth_headers | Get authenticated headers for Ghost API requests. Copy Args:
staff_api_key: API key in 'id:secret' format
api_version: Ghost API version to use (default: v5.109)
Returns:
Dictionary of request headers including authorization and version
Example:
>>> headers = await get_auth_headers("1234:abcd5678")
>>> headers
{
'Authorization': 'Ghost eyJ0eXAiOiJKV1...',
'Accept-Version': 'v5.109'
} |
get_close_matches | Use SequenceMatcher to return list of the best "good enough" matches. Copy word is a sequence for which close matches are desired (typically a
string).
possibilities is a list of sequences against which to match word
(typically a list of strings).
Optional arg n (default 3) is the maximum number of close matches to
return. n must be > 0.
Optional arg cutoff (default 0.6) is a float in [0, 1]. Possibilities
that don't score at least that similar to word are ignored.
The best (no more than n) matches among the possibilities are returned
in a list, sorted by similarity score, most similar first.
>>> get_close_matches("appel", ["ape", "apple", "peach", "puppy"])
['apple', 'ape']
>>> import keyword as _keyword
>>> get_close_matches("wheel", _keyword.kwlist)
['while']
>>> get_close_matches("Apple", _keyword.kwlist)
[]
>>> get_close_matches("accept", _keyword.kwlist)
['except'] |
import_module | Import a module. Copy The 'package' argument is required when performing a relative import. It
specifies the package to use as the anchor point from which to resolve the
relative import to an absolute import. |
list_members | Get the list of members from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of members per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing member information |
list_newsletters | Get the list of newsletters from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of newsletters per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing newsletter information |
list_offers | Get the list of offers from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of offers per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing offer information |
list_posts | Get the list of posts from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of posts per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing post information
Raises:
GhostError: If there is an error accessing the Ghost API |
list_roles | Get the list of roles from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of roles per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing role information |
list_tiers | Get the list of tiers from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of tiers per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing tier information |
list_users | Get the list of users from your Ghost blog. Copy Args:
format: Output format - either "text" or "json" (default: "text")
page: Page number for pagination (default: 1)
limit: Number of users per page (default: 15)
ctx: Optional context for logging
Returns:
Formatted string containing user information |
make_ghost_request | Make an authenticated request to the Ghost API. Copy Args:
endpoint: API endpoint to call (e.g. "posts" or "users")
headers: Request headers from get_auth_headers()
ctx: Optional context for logging (not used for resources)
is_resource: Whether this request is for a resource
http_method: HTTP method to use (GET, POST, PUT, or DELETE)
json_data: Optional JSON data for POST/PUT requests
Returns:
Parsed JSON response from the Ghost API
Raises:
GhostError: For any Ghost API errors including:
- Network connectivity issues
- Invalid authentication
- Rate limiting
- Server errors
ValueError: For invalid HTTP methods
Example:
>>> headers = await get_auth_headers("1234:abcd5678")
>>> response = await make_ghost_request(
... "posts",
... headers,
... http_method=GET
... ) |
read_member | Get the details of a specific member. Copy Args:
member_id: The ID of the member to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing the member details |
read_newsletter | Get the details of a specific newsletter. Copy Args:
newsletter_id: The ID of the newsletter to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing the newsletter details |
read_offer | Get the details of a specific offer. Copy Args:
offer_id: The ID of the offer to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing the offer details |
read_post | Get the full content and metadata of a specific blog post. Copy Args:
post_id: The ID of the post to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing all post details including:
- Basic info (title, slug, status, etc)
- Content in both HTML and Lexical formats
- Feature image details
- Meta fields (SEO, Open Graph, Twitter)
- Authors and tags
- Email settings
- Timestamps
Raises:
GhostError: If there is an error accessing the Ghost API |
read_tag | Get the full metadata of a specific tag. Copy Args:
tag_id: The ID of the tag to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing all tag details
Raises:
GhostError: If there is an error accessing the Ghost API |
read_tier | Get the details of a specific tier. Copy Args:
tier_id: The ID of the tier to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing the tier details |
read_user | Get the details of a specific user. Copy Args:
user_id: The ID of the user to retrieve
ctx: Optional context for logging
Returns:
Formatted string containing the user details |
search_posts_by_title | Search for posts by title. Copy Args:
query: The title or part of the title to search for
exact: If True, only return exact matches (default: False)
ctx: Optional context for logging
Returns:
Formatted string containing matching post information
Raises:
GhostError: If there is an error accessing the Ghost API |
update_member | Update an existing member in Ghost. Copy Args:
member_id: ID of the member to update (required)
email: New email address for the member (optional)
name: New name for the member (optional)
note: New notes about the member (optional)
labels: New list of labels. Each label should be a dict with 'name' and 'slug' (optional)
newsletter_ids: New list of newsletter IDs to subscribe the member to (optional)
ctx: Optional context for logging
Returns:
String representation of the updated member
Raises:
GhostError: If the Ghost API request fails
ValueError: If no fields to update are provided |
update_newsletter | Update an existing newsletter. Copy Args:
newsletter_id: ID of the newsletter to update (required)
name: New newsletter name
description: New newsletter description
sender_name: Name shown in email clients
sender_email: Email address newsletters are sent from
sender_reply_to: Reply-to setting ("newsletter" or "support")
status: Newsletter status ("active" or "archived")
subscribe_on_signup: Whether to subscribe new members automatically
sort_order: Order in lists
header_image: URL of header image
show_header_icon: Whether to show header icon
show_header_title: Whether to show header title
show_header_name: Whether to show header name
title_font_category: Font category for titles
title_alignment: Title alignment
show_feature_image: Whether to show feature image
body_font_category: Font category for body text
footer_content: Custom footer content
show_badge: Whether to show badge
ctx: Optional context for logging
Returns:
Formatted string containing the updated newsletter details |
update_offer | Update an existing offer in Ghost. Copy Args:
offer_id: ID of the offer to update (required)
name: New internal name for the offer (optional)
code: New shortcode for the offer (optional)
display_title: New name displayed in the offer window (optional)
display_description: New text displayed in the offer window (optional)
ctx: Optional context for logging
Returns:
String representation of the updated offer
Raises:
GhostError: If the Ghost API request fails
ValueError: If no fields to update are provided |
update_post | Update a blog post with new data. Copy Args:
post_id: The ID of the post to update
update_data: Dictionary containing the updated data and updated_at timestamp.
Note: 'updated_at' is required. If 'lexical' is provided, it must be a valid JSON string.
The lexical content must be a properly escaped JSON string in this format:
{
"root": {
"children": [
{
"children": [
{
"detail": 0,
"format": 0,
"mode": "normal",
"style": "",
"text": "Your content here",
"type": "text",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"type": "paragraph",
"version": 1
}
],
"direction": "ltr",
"format": "",
"indent": 0,
"type": "root",
"version": 1
}
}
Example usage:
update_data = {
"post_id": "67abcffb7f82ac000179d76f",
"update_data": {
"updated_at": "2025-02-11T22:54:40.000Z",
"lexical": "{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":"Hello World","type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}"
}
}
Updatable fields for a blog post:
- slug: Unique URL slug for the post.
- id: Identifier of the post.
- uuid: Universally unique identifier for the post.
- title: The title of the post.
- lexical: JSON string representing the post content in lexical format.
- html: HTML version of the post content.
- comment_id: Identifier for the comment thread.
- feature_image: URL to the post's feature image.
- feature_image_alt: Alternate text for the feature image.
- feature_image_caption: Caption for the feature image.
- featured: Boolean flag indicating if the post is featured.
- status: The publication status (e.g., published, draft).
- visibility: Visibility setting (e.g., public, private).
- created_at: Timestamp when the post was created.
- updated_at: Timestamp when the post was last updated.
- published_at: Timestamp when the post was published.
- custom_excerpt: Custom excerpt text for the post.
- codeinjection_head: Code to be injected into the head section.
- codeinjection_foot: Code to be injected into the footer section.
- custom_template: Custom template assigned to the post.
- canonical_url: The canonical URL for SEO purposes.
- tags: List of tag objects associated with the post.
- authors: List of author objects for the post.
- primary_author: The primary author object.
- primary_tag: The primary tag object.
- url: Direct URL link to the post.
- excerpt: Short excerpt or summary of the post.
- og_image: Open Graph image URL for social sharing.
- og_title: Open Graph title for social sharing.
- og_description: Open Graph description for social sharing.
- twitter_image: Twitter-specific image URL.
- twitter_title: Twitter-specific title.
- twitter_description: Twitter-specific description.
- meta_title: Meta title for SEO.
- meta_description: Meta description for SEO.
- email_only: Boolean flag indicating if the post is for email distribution only.
- newsletter: Dictionary containing newsletter configuration details.
- email: Dictionary containing email details related to the post.
ctx: Optional context for logging
Returns:
Formatted string containing the updated post details
Raises:
GhostError: If there is an error accessing the Ghost API or missing required fields |
update_tag | Update a tag with new data. Copy Args:
tag_id: The ID of the tag to update
update_data: Dictionary containing the updated data. Fields that can be updated:
- name: The name of the tag
- slug: URL slug for the tag
- description: Description of the tag
- feature_image: URL to the tag's feature image
- visibility: Tag visibility ('public' or 'internal')
- accent_color: CSS color hex value for the tag
- meta_title: Meta title for SEO
- meta_description: Meta description for SEO
- canonical_url: The canonical URL
- og_image: Open Graph image URL
- og_title: Open Graph title
- og_description: Open Graph description
- twitter_image: Twitter card image URL
- twitter_title: Twitter card title
- twitter_description: Twitter card description
- codeinjection_head: Code to inject in header
- codeinjection_foot: Code to inject in footer
Example:
{
"name": "Updated Name",
"description": "Updated description"
}
ctx: Optional context for logging
Returns:
Formatted string containing the updated tag details
Raises:
GhostError: If there is an error accessing the Ghost API |
update_tier | Update an existing tier in Ghost. Copy Args:
tier_id: ID of the tier to update (required)
name: New name for the tier
description: New description for the tier
monthly_price: New monthly price in cents (e.g. 500 for $5.00)
yearly_price: New yearly price in cents (e.g. 5000 for $50.00)
benefits: New list of benefits for the tier
welcome_page_url: New URL for the welcome page
visibility: New visibility setting ("public" or "none")
currency: New currency for prices
active: New active status
ctx: Optional context for logging
Returns:
String representation of the updated tier
Raises:
GhostError: If the Ghost API request fails |
update_user | Update an existing user in Ghost. Copy Args:
user_id: ID of the user to update (required)
name: User's full name (optional)
slug: User's slug (optional)
email: User's email address (optional)
profile_image: URL for profile image (optional)
cover_image: URL for cover image (optional)
bio: User's bio (optional)
website: User's website URL (optional)
location: User's location (optional)
facebook: Facebook username (optional)
twitter: Twitter username (optional)
meta_title: Meta title for SEO (optional)
meta_description: Meta description for SEO (optional)
accessibility: Accessibility settings (optional)
comment_notifications: Enable comment notifications (optional)
free_member_signup_notification: Enable free member signup notifications (optional)
paid_subscription_started_notification: Enable paid subscription started notifications (optional)
paid_subscription_canceled_notification: Enable paid subscription canceled notifications (optional)
mention_notifications: Enable mention notifications (optional)
milestone_notifications: Enable milestone notifications (optional)
ctx: Optional context for logging
Returns:
String representation of the updated user
Raises:
GhostError: If the Ghost API request fails
ValueError: If no fields to update are provided |
update_webhook | Update an existing webhook in Ghost. Copy Args:
webhook_id: ID of the webhook to update (required)
event: New event to trigger the webhook (optional)
target_url: New URL to send the webhook to (optional)
name: New name of the webhook (optional)
api_version: New API version for the webhook (optional)
ctx: Optional context for logging
Returns:
String representation of the updated webhook
Raises:
GhostError: If the Ghost API request fails
ValueError: If no fields to update are provided or if the event is invalid |