Support update users

This commit is contained in:
Fanyang Meng
2025-02-11 23:54:23 -05:00
parent 18672a6977
commit 230a51d15a
6 changed files with 151 additions and 3 deletions

View File

@@ -82,6 +82,7 @@ GHOST_API_URL=your_ghost_api_url GHOST_STAFF_API_KEY=your_staff_api_key npx @mod
### Users Management
- `list_roles`: List all available roles
- `create_invite`: Create a new user invitation email and role_id
- `update_user`: Update an existing user's information **(Please note: Ghost has not implemented the ability to update user roles via the API even though they include it in the API documentation)**
- `list_users`: List all users with detailed role information
- `read_user`: Get comprehensive details of a specific user

View File

@@ -56,7 +56,7 @@ async def get_auth_headers(staff_api_key: str) -> Dict[str, str]:
token = await generate_token(staff_api_key)
return {
"Authorization": f"Ghost {token}",
"Accept-Version": "v5"
"Accept-Version": "v5.109"
}
async def make_ghost_request(

View File

@@ -49,6 +49,7 @@ def create_server() -> FastMCP:
mcp.tool()(tools.delete_post)
mcp.tool()(tools.list_users)
mcp.tool()(tools.read_user)
mcp.tool()(tools.update_user)
mcp.tool()(tools.list_members)
mcp.tool()(tools.read_member)
mcp.tool()(tools.create_member)

View File

@@ -11,7 +11,8 @@ from .tools.posts import (
)
from .tools.users import (
list_users,
read_user
read_user,
update_user
)
from .tools.members import (
list_members,
@@ -49,6 +50,7 @@ __all__ = [
'delete_post',
'list_users',
'read_user',
'update_user',
'list_members',
'read_member',
'create_member',

View File

@@ -1,7 +1,7 @@
"""Ghost MCP tools package."""
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 .users import list_users, read_user, update_user
from .members import list_members, read_member, create_member, update_member
from .tiers import list_tiers, read_tier, create_tier, update_tier
from .offers import list_offers, read_offer, create_offer, update_offer
@@ -18,6 +18,7 @@ __all__ = [
'delete_post',
'list_users',
'read_user',
'update_user',
'list_members',
'read_member',
'create_member',

View File

@@ -72,6 +72,149 @@ ID: {user.get('id', 'Unknown')}
ctx.error(f"Failed to list users: {str(e)}")
return str(e)
async def update_user(
user_id: str,
name: str = None,
slug: str = None,
email: str = None,
profile_image: str = None,
cover_image: str = None,
bio: str = None,
website: str = None,
location: str = None,
facebook: str = None,
twitter: str = None,
meta_title: str = None,
meta_description: str = None,
accessibility: str = None,
comment_notifications: bool = None,
free_member_signup_notification: bool = None,
paid_subscription_started_notification: bool = None,
paid_subscription_canceled_notification: bool = None,
mention_notifications: bool = None,
milestone_notifications: bool = None,
ctx: Context = None
) -> str:
"""Update an existing user in Ghost.
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
"""
# Check if at least one field to update is provided
update_fields = {
'name': name,
'slug': slug,
'email': email,
'profile_image': profile_image,
'cover_image': cover_image,
'bio': bio,
'website': website,
'location': location,
'facebook': facebook,
'twitter': twitter,
'meta_title': meta_title,
'meta_description': meta_description,
'accessibility': accessibility,
'comment_notifications': comment_notifications,
'free_member_signup_notification': free_member_signup_notification,
'paid_subscription_started_notification': paid_subscription_started_notification,
'paid_subscription_canceled_notification': paid_subscription_canceled_notification,
'mention_notifications': mention_notifications,
'milestone_notifications': milestone_notifications
}
if not any(v is not None for v in update_fields.values()):
raise ValueError("At least one field must be provided to update")
if ctx:
ctx.info(f"Updating user with ID: {user_id}")
# Construct update data with only provided fields
update_data = {"users": [{}]}
user_updates = update_data["users"][0]
for field, value in update_fields.items():
if value is not None:
user_updates[field] = value
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 user {user_id}")
response = await make_ghost_request(
f"users/{user_id}/",
headers,
ctx,
http_method="PUT",
json_data=update_data
)
if ctx:
ctx.debug("Processing updated user response")
user = response.get("users", [{}])[0]
roles = [role.get('name') for role in user.get('roles', [])]
return f"""
User updated successfully:
Name: {user.get('name', 'Unknown')}
Email: {user.get('email', 'Unknown')}
Slug: {user.get('slug', 'Unknown')}
Status: {user.get('status', 'Unknown')}
Roles: {', '.join(roles)}
Location: {user.get('location', 'Not specified')}
Website: {user.get('website', 'None')}
Bio: {user.get('bio', 'No bio')}
Profile Image: {user.get('profile_image', 'None')}
Cover Image: {user.get('cover_image', 'None')}
Facebook: {user.get('facebook', 'None')}
Twitter: {user.get('twitter', 'None')}
Created: {user.get('created_at', 'Unknown')}
Updated: {user.get('updated_at', 'Unknown')}
Last Seen: {user.get('last_seen', 'Never')}
Notifications:
- Comments: {user.get('comment_notifications', False)}
- Free Member Signup: {user.get('free_member_signup_notification', False)}
- Paid Subscription Started: {user.get('paid_subscription_started_notification', False)}
- Paid Subscription Canceled: {user.get('paid_subscription_canceled_notification', False)}
- Mentions: {user.get('mention_notifications', False)}
- Milestones: {user.get('milestone_notifications', False)}
"""
except Exception as e:
if ctx:
ctx.error(f"Failed to update user: {str(e)}")
raise
async def read_user(user_id: str, ctx: Context = None) -> str:
"""Get the details of a specific user.