diff --git a/README.md b/README.md index 9531927..699aef3 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ GHOST_API_URL=your_ghost_api_url GHOST_STAFF_API_KEY=your_staff_api_key npx @mod - `delete_post`: Delete a specific post ### Users Management +- `list_roles`: List all available roles - `list_users`: List all users with detailed role information - `read_user`: Get comprehensive details of a specific user diff --git a/src/ghost_mcp/server.py b/src/ghost_mcp/server.py index 966d5a6..8164888 100644 --- a/src/ghost_mcp/server.py +++ b/src/ghost_mcp/server.py @@ -65,6 +65,7 @@ def create_server() -> FastMCP: mcp.tool()(tools.read_newsletter) mcp.tool()(tools.create_newsletter) mcp.tool()(tools.update_newsletter) + mcp.tool()(tools.list_roles) # Register prompts @mcp.prompt() diff --git a/src/ghost_mcp/tools.py b/src/ghost_mcp/tools.py index 52c9736..b72b59f 100644 --- a/src/ghost_mcp/tools.py +++ b/src/ghost_mcp/tools.py @@ -37,6 +37,7 @@ from .tools.newsletters import ( create_newsletter, update_newsletter ) +from .tools.roles import list_roles __all__ = [ 'search_posts_by_title', @@ -61,5 +62,6 @@ __all__ = [ 'list_newsletters', 'read_newsletter', 'create_newsletter', - 'update_newsletter' + 'update_newsletter', + 'list_roles' ] diff --git a/src/ghost_mcp/tools/__init__.py b/src/ghost_mcp/tools/__init__.py index 9208c09..631f635 100644 --- a/src/ghost_mcp/tools/__init__.py +++ b/src/ghost_mcp/tools/__init__.py @@ -6,6 +6,7 @@ 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 from .newsletters import list_newsletters, read_newsletter, create_newsletter, update_newsletter +from .roles import list_roles __all__ = [ 'search_posts_by_title', @@ -31,5 +32,6 @@ __all__ = [ 'list_newsletters', 'read_newsletter', 'create_newsletter', - 'update_newsletter' + 'update_newsletter', + 'list_roles' ] diff --git a/src/ghost_mcp/tools/roles.py b/src/ghost_mcp/tools/roles.py new file mode 100644 index 0000000..e51fde7 --- /dev/null +++ b/src/ghost_mcp/tools/roles.py @@ -0,0 +1,72 @@ +"""Role-related MCP tools for Ghost API.""" + +import json +from mcp.server.fastmcp import Context + +from ..api import make_ghost_request, get_auth_headers +from ..config import STAFF_API_KEY +from ..exceptions import GhostError + +async def list_roles( + format: str = "text", + page: int = 1, + limit: int = 15, + ctx: Context = None +) -> str: + """Get the list of roles from your Ghost blog. + + 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 + """ + if ctx: + ctx.info(f"Listing roles (page {page}, limit {limit}, format {format})") + + try: + if ctx: + ctx.debug("Getting auth headers") + headers = await get_auth_headers(STAFF_API_KEY) + + if ctx: + ctx.debug("Making API request to /roles/ with pagination") + data = await make_ghost_request( + f"roles/?page={page}&limit={limit}", + headers, + ctx + ) + + if ctx: + ctx.debug("Processing roles list response") + + roles = data.get("roles", []) + if not roles: + if ctx: + ctx.info("No roles found in response") + return "No roles found." + + if format.lower() == "json": + if ctx: + ctx.debug("Returning JSON format") + return json.dumps(roles, indent=2) + + formatted_roles = [] + for role in roles: + formatted_role = f""" +Name: {role.get('name', 'Unknown')} +Description: {role.get('description', 'No description')} +Created: {role.get('created_at', 'Unknown')} +Updated: {role.get('updated_at', 'Unknown')} +ID: {role.get('id', 'Unknown')} +""" + formatted_roles.append(formatted_role) + return "\n---\n".join(formatted_roles) + + except GhostError as e: + if ctx: + ctx.error(f"Failed to list roles: {str(e)}") + return str(e)