mirror of
https://github.com/jlengrand/ghost-mcp.git
synced 2026-03-10 08:21:19 +00:00
✨ Support newsletter creating and updating
This commit is contained in:
@@ -100,6 +100,8 @@ GHOST_API_URL=your_ghost_api_url GHOST_STAFF_API_KEY=your_staff_api_key npx @mod
|
|||||||
### Newsletters Management
|
### Newsletters Management
|
||||||
- `list_newsletters`: List all newsletters associated with the blog
|
- `list_newsletters`: List all newsletters associated with the blog
|
||||||
- `read_newsletter`: Retrieve detailed settings and information for a specific newsletter
|
- `read_newsletter`: Retrieve detailed settings and information for a specific newsletter
|
||||||
|
- `create_newsletter`: Create a new newsletter with specified details
|
||||||
|
- `update_newsletter`: Update an existing newsletter with new information
|
||||||
|
|
||||||
## Available Resources
|
## Available Resources
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ def create_server() -> FastMCP:
|
|||||||
mcp.tool()(tools.read_offer)
|
mcp.tool()(tools.read_offer)
|
||||||
mcp.tool()(tools.list_newsletters)
|
mcp.tool()(tools.list_newsletters)
|
||||||
mcp.tool()(tools.read_newsletter)
|
mcp.tool()(tools.read_newsletter)
|
||||||
|
mcp.tool()(tools.create_newsletter)
|
||||||
|
mcp.tool()(tools.update_newsletter)
|
||||||
|
|
||||||
# Register prompts
|
# Register prompts
|
||||||
@mcp.prompt()
|
@mcp.prompt()
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ from .tools.offers import (
|
|||||||
)
|
)
|
||||||
from .tools.newsletters import (
|
from .tools.newsletters import (
|
||||||
list_newsletters,
|
list_newsletters,
|
||||||
read_newsletter
|
read_newsletter,
|
||||||
|
create_newsletter,
|
||||||
|
update_newsletter
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@@ -50,5 +52,7 @@ __all__ = [
|
|||||||
'list_offers',
|
'list_offers',
|
||||||
'read_offer',
|
'read_offer',
|
||||||
'list_newsletters',
|
'list_newsletters',
|
||||||
'read_newsletter'
|
'read_newsletter',
|
||||||
|
'create_newsletter',
|
||||||
|
'update_newsletter'
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from .users import list_users, read_user
|
|||||||
from .members import list_members, read_member
|
from .members import list_members, read_member
|
||||||
from .tiers import list_tiers, read_tier, create_tier, update_tier
|
from .tiers import list_tiers, read_tier, create_tier, update_tier
|
||||||
from .offers import list_offers, read_offer
|
from .offers import list_offers, read_offer
|
||||||
from .newsletters import list_newsletters, read_newsletter
|
from .newsletters import list_newsletters, read_newsletter, create_newsletter, update_newsletter
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'search_posts_by_title',
|
'search_posts_by_title',
|
||||||
@@ -25,5 +25,7 @@ __all__ = [
|
|||||||
'list_offers',
|
'list_offers',
|
||||||
'read_offer',
|
'read_offer',
|
||||||
'list_newsletters',
|
'list_newsletters',
|
||||||
'read_newsletter'
|
'read_newsletter',
|
||||||
|
'create_newsletter',
|
||||||
|
'update_newsletter'
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -126,3 +126,203 @@ Updated: {newsletter.get('updated_at', 'Unknown')}
|
|||||||
if ctx:
|
if ctx:
|
||||||
ctx.error(f"Failed to read newsletter: {str(e)}")
|
ctx.error(f"Failed to read newsletter: {str(e)}")
|
||||||
return str(e)
|
return str(e)
|
||||||
|
|
||||||
|
async def create_newsletter(
|
||||||
|
name: str,
|
||||||
|
description: str = None,
|
||||||
|
status: str = "active",
|
||||||
|
subscribe_on_signup: bool = True,
|
||||||
|
opt_in_existing: bool = False,
|
||||||
|
sender_reply_to: str = "newsletter",
|
||||||
|
show_header_icon: bool = True,
|
||||||
|
show_header_title: bool = True,
|
||||||
|
show_header_name: bool = True,
|
||||||
|
show_feature_image: bool = True,
|
||||||
|
title_font_category: str = "sans_serif",
|
||||||
|
title_alignment: str = "center",
|
||||||
|
body_font_category: str = "sans_serif",
|
||||||
|
show_badge: bool = True,
|
||||||
|
ctx: Context = None
|
||||||
|
) -> str:
|
||||||
|
"""Create a new newsletter.
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
if ctx:
|
||||||
|
ctx.info(f"Creating new newsletter: {name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if ctx:
|
||||||
|
ctx.debug("Getting auth headers")
|
||||||
|
headers = await get_auth_headers(STAFF_API_KEY)
|
||||||
|
|
||||||
|
newsletter_data = {
|
||||||
|
"newsletters": [{
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"status": status,
|
||||||
|
"subscribe_on_signup": subscribe_on_signup,
|
||||||
|
"sender_reply_to": sender_reply_to,
|
||||||
|
"show_header_icon": show_header_icon,
|
||||||
|
"show_header_title": show_header_title,
|
||||||
|
"show_header_name": show_header_name,
|
||||||
|
"show_feature_image": show_feature_image,
|
||||||
|
"title_font_category": title_font_category,
|
||||||
|
"title_alignment": title_alignment,
|
||||||
|
"body_font_category": body_font_category,
|
||||||
|
"show_badge": show_badge
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx:
|
||||||
|
ctx.debug("Making API request to create newsletter")
|
||||||
|
|
||||||
|
endpoint = f"newsletters/?opt_in_existing={'true' if opt_in_existing else 'false'}"
|
||||||
|
data = await make_ghost_request(
|
||||||
|
endpoint,
|
||||||
|
headers,
|
||||||
|
ctx,
|
||||||
|
http_method="POST",
|
||||||
|
json_data=newsletter_data
|
||||||
|
)
|
||||||
|
|
||||||
|
if ctx:
|
||||||
|
ctx.debug("Processing create newsletter response")
|
||||||
|
|
||||||
|
newsletter = data["newsletters"][0]
|
||||||
|
return f"""
|
||||||
|
Newsletter created successfully!
|
||||||
|
|
||||||
|
Name: {newsletter.get('name')}
|
||||||
|
Description: {newsletter.get('description', 'No description')}
|
||||||
|
Status: {newsletter.get('status')}
|
||||||
|
ID: {newsletter.get('id')}
|
||||||
|
"""
|
||||||
|
|
||||||
|
except GhostError as e:
|
||||||
|
if ctx:
|
||||||
|
ctx.error(f"Failed to create newsletter: {str(e)}")
|
||||||
|
return str(e)
|
||||||
|
|
||||||
|
async def update_newsletter(
|
||||||
|
newsletter_id: str,
|
||||||
|
name: str = None,
|
||||||
|
description: str = None,
|
||||||
|
sender_name: str = None,
|
||||||
|
sender_email: str = None,
|
||||||
|
sender_reply_to: str = None,
|
||||||
|
status: str = None,
|
||||||
|
subscribe_on_signup: bool = None,
|
||||||
|
sort_order: int = None,
|
||||||
|
header_image: str = None,
|
||||||
|
show_header_icon: bool = None,
|
||||||
|
show_header_title: bool = None,
|
||||||
|
show_header_name: bool = None,
|
||||||
|
title_font_category: str = None,
|
||||||
|
title_alignment: str = None,
|
||||||
|
show_feature_image: bool = None,
|
||||||
|
body_font_category: str = None,
|
||||||
|
footer_content: str = None,
|
||||||
|
show_badge: bool = None,
|
||||||
|
ctx: Context = None
|
||||||
|
) -> str:
|
||||||
|
"""Update an existing newsletter.
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
if ctx:
|
||||||
|
ctx.info(f"Updating newsletter with ID: {newsletter_id}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if ctx:
|
||||||
|
ctx.debug("Getting auth headers")
|
||||||
|
headers = await get_auth_headers(STAFF_API_KEY)
|
||||||
|
|
||||||
|
# Build update data with only provided fields
|
||||||
|
update_data = {"newsletters": [{"id": newsletter_id}]}
|
||||||
|
|
||||||
|
# Add non-None values to the update data
|
||||||
|
fields = locals()
|
||||||
|
for field in [
|
||||||
|
"name", "description", "sender_name", "sender_email",
|
||||||
|
"sender_reply_to", "status", "subscribe_on_signup",
|
||||||
|
"sort_order", "header_image", "show_header_icon",
|
||||||
|
"show_header_title", "show_header_name", "title_font_category",
|
||||||
|
"title_alignment", "show_feature_image", "body_font_category",
|
||||||
|
"footer_content", "show_badge"
|
||||||
|
]:
|
||||||
|
if fields[field] is not None:
|
||||||
|
update_data["newsletters"][0][field] = fields[field]
|
||||||
|
|
||||||
|
if ctx:
|
||||||
|
ctx.debug(f"Making API request to update newsletter {newsletter_id}")
|
||||||
|
|
||||||
|
data = await make_ghost_request(
|
||||||
|
f"newsletters/{newsletter_id}/",
|
||||||
|
headers,
|
||||||
|
ctx,
|
||||||
|
http_method="PUT",
|
||||||
|
json_data=update_data
|
||||||
|
)
|
||||||
|
|
||||||
|
if ctx:
|
||||||
|
ctx.debug("Processing update newsletter response")
|
||||||
|
|
||||||
|
newsletter = data["newsletters"][0]
|
||||||
|
return f"""
|
||||||
|
Newsletter updated successfully!
|
||||||
|
|
||||||
|
Name: {newsletter.get('name')}
|
||||||
|
Description: {newsletter.get('description', 'No description')}
|
||||||
|
Status: {newsletter.get('status')}
|
||||||
|
Sender Name: {newsletter.get('sender_name', 'Not set')}
|
||||||
|
Sender Email: {newsletter.get('sender_email', 'Not set')}
|
||||||
|
Sort Order: {newsletter.get('sort_order', 0)}
|
||||||
|
ID: {newsletter.get('id')}
|
||||||
|
"""
|
||||||
|
|
||||||
|
except GhostError as e:
|
||||||
|
if ctx:
|
||||||
|
ctx.error(f"Failed to update newsletter: {str(e)}")
|
||||||
|
return str(e)
|
||||||
Reference in New Issue
Block a user