mirror of
https://github.com/jlengrand/ghost-mcp.git
synced 2026-03-10 00:11:21 +00:00
✨ Support tier creating and updating
This commit is contained in:
@@ -90,6 +90,8 @@ GHOST_API_URL=your_ghost_api_url GHOST_STAFF_API_KEY=your_staff_api_key npx @mod
|
||||
### Tiers Management
|
||||
- `list_tiers`: List all available membership tiers
|
||||
- `read_tier`: Retrieve detailed information about a specific tier, including benefits and pricing
|
||||
- `create_tier`: Create a new membership tier with specified details
|
||||
- `update_tier`: Update an existing tier with new information
|
||||
|
||||
### Offers Management
|
||||
- `list_offers`: List promotional offers with relevant details
|
||||
|
||||
@@ -53,6 +53,8 @@ def create_server() -> FastMCP:
|
||||
mcp.tool()(tools.read_member)
|
||||
mcp.tool()(tools.list_tiers)
|
||||
mcp.tool()(tools.read_tier)
|
||||
mcp.tool()(tools.create_tier)
|
||||
mcp.tool()(tools.update_tier)
|
||||
mcp.tool()(tools.list_offers)
|
||||
mcp.tool()(tools.read_offer)
|
||||
mcp.tool()(tools.list_newsletters)
|
||||
|
||||
@@ -19,7 +19,9 @@ from .tools.members import (
|
||||
)
|
||||
from .tools.tiers import (
|
||||
list_tiers,
|
||||
read_tier
|
||||
read_tier,
|
||||
create_tier,
|
||||
update_tier
|
||||
)
|
||||
from .tools.offers import (
|
||||
list_offers,
|
||||
@@ -43,6 +45,8 @@ __all__ = [
|
||||
'read_member',
|
||||
'list_tiers',
|
||||
'read_tier',
|
||||
'create_tier',
|
||||
'update_tier',
|
||||
'list_offers',
|
||||
'read_offer',
|
||||
'list_newsletters',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from .posts import search_posts_by_title, list_posts, read_post, create_post, update_post, delete_post
|
||||
from .users import list_users, read_user
|
||||
from .members import list_members, read_member
|
||||
from .tiers import list_tiers, read_tier
|
||||
from .tiers import list_tiers, read_tier, create_tier, update_tier
|
||||
from .offers import list_offers, read_offer
|
||||
from .newsletters import list_newsletters, read_newsletter
|
||||
|
||||
@@ -20,6 +20,8 @@ __all__ = [
|
||||
'read_member',
|
||||
'list_tiers',
|
||||
'read_tier',
|
||||
'create_tier',
|
||||
'update_tier',
|
||||
'list_offers',
|
||||
'read_offer',
|
||||
'list_newsletters',
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"""Tier-related MCP tools for Ghost API."""
|
||||
|
||||
import json
|
||||
from typing import Optional, List
|
||||
from mcp.server.fastmcp import Context
|
||||
|
||||
from ..api import make_ghost_request, get_auth_headers
|
||||
from ..config import STAFF_API_KEY
|
||||
from mcp.server.fastmcp import Context
|
||||
|
||||
from ..api import make_ghost_request, get_auth_headers
|
||||
@@ -125,3 +130,201 @@ Benefits:
|
||||
if ctx:
|
||||
ctx.error(f"Failed to read tier: {str(e)}")
|
||||
return str(e)
|
||||
|
||||
async def create_tier(
|
||||
name: str,
|
||||
monthly_price: Optional[int] = None,
|
||||
yearly_price: Optional[int] = None,
|
||||
description: Optional[str] = None,
|
||||
benefits: Optional[List[str]] = None,
|
||||
welcome_page_url: Optional[str] = None,
|
||||
visibility: str = "public",
|
||||
currency: str = "usd",
|
||||
ctx: Context = None
|
||||
) -> str:
|
||||
"""Create a new tier in Ghost.
|
||||
|
||||
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
|
||||
"""
|
||||
if not name:
|
||||
raise ValueError("Name is required for creating a tier")
|
||||
|
||||
if ctx:
|
||||
ctx.info(f"Creating new tier: {name}")
|
||||
|
||||
# Construct tier data
|
||||
tier_data = {
|
||||
"tiers": [{
|
||||
"name": name,
|
||||
"description": description,
|
||||
"type": "paid" if (monthly_price or yearly_price) else "free",
|
||||
"active": True,
|
||||
"visibility": visibility,
|
||||
"welcome_page_url": welcome_page_url,
|
||||
"benefits": benefits or [],
|
||||
"currency": currency
|
||||
}]
|
||||
}
|
||||
|
||||
# Add pricing if provided
|
||||
if monthly_price is not None:
|
||||
tier_data["tiers"][0]["monthly_price"] = monthly_price
|
||||
if yearly_price is not None:
|
||||
tier_data["tiers"][0]["yearly_price"] = yearly_price
|
||||
|
||||
try:
|
||||
if ctx:
|
||||
ctx.debug("Getting auth headers")
|
||||
headers = await get_auth_headers(STAFF_API_KEY)
|
||||
|
||||
if ctx:
|
||||
ctx.debug("Making API request to create tier")
|
||||
response = await make_ghost_request(
|
||||
"tiers/",
|
||||
headers,
|
||||
ctx,
|
||||
http_method="POST",
|
||||
json_data=tier_data
|
||||
)
|
||||
|
||||
if ctx:
|
||||
ctx.debug("Processing created tier response")
|
||||
|
||||
tier = response.get("tiers", [{}])[0]
|
||||
|
||||
# Format response
|
||||
benefits_text = "\n- ".join(tier.get('benefits', [])) if tier.get('benefits') else "None"
|
||||
return f"""
|
||||
Tier created successfully:
|
||||
Name: {tier.get('name')}
|
||||
Type: {tier.get('type')}
|
||||
Description: {tier.get('description', 'No description')}
|
||||
Active: {tier.get('active', False)}
|
||||
Visibility: {tier.get('visibility', 'public')}
|
||||
Monthly Price: {tier.get('monthly_price', 'N/A')} {tier.get('currency', 'usd').upper()}
|
||||
Yearly Price: {tier.get('yearly_price', 'N/A')} {tier.get('currency', 'usd').upper()}
|
||||
Currency: {tier.get('currency', 'usd').upper()}
|
||||
Benefits:
|
||||
- {benefits_text}
|
||||
ID: {tier.get('id', 'Unknown')}
|
||||
"""
|
||||
except Exception as e:
|
||||
if ctx:
|
||||
ctx.error(f"Failed to create tier: {str(e)}")
|
||||
raise
|
||||
|
||||
async def update_tier(
|
||||
tier_id: str,
|
||||
name: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
monthly_price: Optional[int] = None,
|
||||
yearly_price: Optional[int] = None,
|
||||
benefits: Optional[List[str]] = None,
|
||||
welcome_page_url: Optional[str] = None,
|
||||
visibility: Optional[str] = None,
|
||||
currency: Optional[str] = None,
|
||||
active: Optional[bool] = None,
|
||||
ctx: Context = None
|
||||
) -> str:
|
||||
"""Update an existing tier in Ghost.
|
||||
|
||||
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
|
||||
"""
|
||||
if ctx:
|
||||
ctx.info(f"Updating tier with ID: {tier_id}")
|
||||
|
||||
# Construct update data with only provided fields
|
||||
update_data = {"tiers": [{}]}
|
||||
tier_updates = update_data["tiers"][0]
|
||||
|
||||
if name is not None:
|
||||
tier_updates["name"] = name
|
||||
if description is not None:
|
||||
tier_updates["description"] = description
|
||||
if monthly_price is not None:
|
||||
tier_updates["monthly_price"] = monthly_price
|
||||
if yearly_price is not None:
|
||||
tier_updates["yearly_price"] = yearly_price
|
||||
if benefits is not None:
|
||||
tier_updates["benefits"] = benefits
|
||||
if welcome_page_url is not None:
|
||||
tier_updates["welcome_page_url"] = welcome_page_url
|
||||
if visibility is not None:
|
||||
tier_updates["visibility"] = visibility
|
||||
if currency is not None:
|
||||
tier_updates["currency"] = currency
|
||||
if active is not None:
|
||||
tier_updates["active"] = active
|
||||
|
||||
try:
|
||||
if ctx:
|
||||
ctx.debug("Getting auth headers")
|
||||
headers = await get_auth_headers(STAFF_API_KEY)
|
||||
|
||||
if ctx:
|
||||
ctx.debug(f"Making API request to update tier {tier_id}")
|
||||
response = await make_ghost_request(
|
||||
f"tiers/{tier_id}/",
|
||||
headers,
|
||||
ctx,
|
||||
http_method="PUT",
|
||||
json_data=update_data
|
||||
)
|
||||
|
||||
if ctx:
|
||||
ctx.debug("Processing updated tier response")
|
||||
|
||||
tier = response.get("tiers", [{}])[0]
|
||||
|
||||
# Format response
|
||||
benefits_text = "\n- ".join(tier.get('benefits', [])) if tier.get('benefits') else "None"
|
||||
return f"""
|
||||
Tier updated successfully:
|
||||
Name: {tier.get('name')}
|
||||
Type: {tier.get('type')}
|
||||
Description: {tier.get('description', 'No description')}
|
||||
Active: {tier.get('active', False)}
|
||||
Visibility: {tier.get('visibility', 'public')}
|
||||
Monthly Price: {tier.get('monthly_price', 'N/A')} {tier.get('currency', 'usd').upper()}
|
||||
Yearly Price: {tier.get('yearly_price', 'N/A')} {tier.get('currency', 'usd').upper()}
|
||||
Currency: {tier.get('currency', 'usd').upper()}
|
||||
Benefits:
|
||||
- {benefits_text}
|
||||
ID: {tier.get('id')}
|
||||
"""
|
||||
except Exception as e:
|
||||
if ctx:
|
||||
ctx.error(f"Failed to update tier: {str(e)}")
|
||||
raise
|
||||
Reference in New Issue
Block a user