mirror of
https://github.com/jlengrand/ghost-mcp.git
synced 2026-03-10 08:21:19 +00:00
Merge pull request #5 from MFYDev/simplify-tools
🎨 Simplify Tools Structure
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -10,4 +10,5 @@ wheels/
|
|||||||
.venv
|
.venv
|
||||||
.vscode
|
.vscode
|
||||||
ghost-admin-api.md
|
ghost-admin-api.md
|
||||||
mcp-python-sdk.md
|
mcp-python-sdk.md
|
||||||
|
.qodo
|
||||||
|
|||||||
@@ -26,12 +26,9 @@ def register_resources(mcp: FastMCP) -> None:
|
|||||||
mcp.resource(uri_template)(handler)
|
mcp.resource(uri_template)(handler)
|
||||||
|
|
||||||
def register_tools(mcp: FastMCP) -> None:
|
def register_tools(mcp: FastMCP) -> None:
|
||||||
"""Register all available tools."""
|
"""Register only the main ghost tool (which provides access to all functionality)."""
|
||||||
# Get all tool functions from __all__
|
# Register only the main ghost tool
|
||||||
for tool_name in tools.__all__:
|
mcp.tool()(tools.ghost)
|
||||||
tool_func = getattr(tools, tool_name)
|
|
||||||
if inspect.isfunction(tool_func):
|
|
||||||
mcp.tool()(tool_func)
|
|
||||||
|
|
||||||
def register_prompts(mcp: FastMCP) -> None:
|
def register_prompts(mcp: FastMCP) -> None:
|
||||||
"""Register all prompt templates."""
|
"""Register all prompt templates."""
|
||||||
@@ -39,9 +36,9 @@ def register_prompts(mcp: FastMCP) -> None:
|
|||||||
def search_blog() -> str:
|
def search_blog() -> str:
|
||||||
"""Prompt template for searching blog posts"""
|
"""Prompt template for searching blog posts"""
|
||||||
return """I want to help you search the blog posts. You can:
|
return """I want to help you search the blog posts. You can:
|
||||||
1. Search by title with: search_posts_by_title("your search term")
|
1. Search by title with: ghost(action="search_posts_by_title", params={"query": "your search term"})
|
||||||
2. List all posts with: list_posts()
|
2. List all posts with: ghost(action="list_posts")
|
||||||
3. Read a specific post with: read_post("post_id")
|
3. Read a specific post with: ghost(action="read_post", params={"post_id": "post_id"})
|
||||||
|
|
||||||
What would you like to search for?"""
|
What would you like to search for?"""
|
||||||
|
|
||||||
@@ -52,7 +49,10 @@ What would you like to search for?"""
|
|||||||
|
|
||||||
Resource: post://{post_id}
|
Resource: post://{post_id}
|
||||||
|
|
||||||
Key points to include:
|
Alternatively, you can also get the post content with:
|
||||||
|
ghost(action="read_post", params={{"post_id": "{post_id}"}})
|
||||||
|
|
||||||
|
Key points to include in your summary:
|
||||||
1. Main topic/theme
|
1. Main topic/theme
|
||||||
2. Key arguments or insights
|
2. Key arguments or insights
|
||||||
3. Important conclusions
|
3. Important conclusions
|
||||||
|
|||||||
@@ -16,29 +16,31 @@ from .tags import browse_tags, read_tag, create_tag, update_tag, delete_tag
|
|||||||
from .tiers import list_tiers, read_tier, create_tier, update_tier
|
from .tiers import list_tiers, read_tier, create_tier, update_tier
|
||||||
from .users import list_users, read_user, delete_user
|
from .users import list_users, read_user, delete_user
|
||||||
from .webhooks import create_webhook, update_webhook, delete_webhook
|
from .webhooks import create_webhook, update_webhook, delete_webhook
|
||||||
|
from .ghost import ghost
|
||||||
|
|
||||||
__all__ = [
|
# Hidden tools - these are accessible through the ghost meta-tool but not exposed directly
|
||||||
|
_all_tools = [
|
||||||
# Invites
|
# Invites
|
||||||
"create_invite",
|
"create_invite",
|
||||||
|
|
||||||
# Members
|
# Members
|
||||||
"list_members",
|
"list_members",
|
||||||
"read_member",
|
"read_member",
|
||||||
"create_member",
|
"create_member",
|
||||||
"update_member",
|
"update_member",
|
||||||
|
|
||||||
# Newsletters
|
# Newsletters
|
||||||
"list_newsletters",
|
"list_newsletters",
|
||||||
"read_newsletter",
|
"read_newsletter",
|
||||||
"create_newsletter",
|
"create_newsletter",
|
||||||
"update_newsletter",
|
"update_newsletter",
|
||||||
|
|
||||||
# Offers
|
# Offers
|
||||||
"list_offers",
|
"list_offers",
|
||||||
"read_offer",
|
"read_offer",
|
||||||
"create_offer",
|
"create_offer",
|
||||||
"update_offer",
|
"update_offer",
|
||||||
|
|
||||||
# Posts
|
# Posts
|
||||||
"list_posts",
|
"list_posts",
|
||||||
"search_posts_by_title",
|
"search_posts_by_title",
|
||||||
@@ -47,30 +49,33 @@ __all__ = [
|
|||||||
"update_post",
|
"update_post",
|
||||||
"delete_post",
|
"delete_post",
|
||||||
"batchly_update_posts",
|
"batchly_update_posts",
|
||||||
|
|
||||||
# Roles
|
# Roles
|
||||||
"list_roles",
|
"list_roles",
|
||||||
|
|
||||||
# Tags
|
# Tags
|
||||||
"browse_tags",
|
"browse_tags",
|
||||||
"read_tag",
|
"read_tag",
|
||||||
"create_tag",
|
"create_tag",
|
||||||
"update_tag",
|
"update_tag",
|
||||||
"delete_tag",
|
"delete_tag",
|
||||||
|
|
||||||
# Tiers
|
# Tiers
|
||||||
"list_tiers",
|
"list_tiers",
|
||||||
"read_tier",
|
"read_tier",
|
||||||
"create_tier",
|
"create_tier",
|
||||||
"update_tier",
|
"update_tier",
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
"list_users",
|
"list_users",
|
||||||
"read_user",
|
"read_user",
|
||||||
"delete_user",
|
"delete_user",
|
||||||
|
|
||||||
# Webhooks
|
# Webhooks
|
||||||
"create_webhook",
|
"create_webhook",
|
||||||
"update_webhook",
|
"update_webhook",
|
||||||
"delete_webhook",
|
"delete_webhook",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Only expose the ghost meta-tool publicly
|
||||||
|
__all__ = ["ghost"]
|
||||||
|
|||||||
91
src/ghost_mcp/tools/ghost.py
Normal file
91
src/ghost_mcp/tools/ghost.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
"""Main Ghost meta-tool that provides access to all Ghost functionality."""
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
from mcp.server.fastmcp import Context
|
||||||
|
from typing import Any, Dict, Optional, List
|
||||||
|
|
||||||
|
from .. import tools
|
||||||
|
from ..exceptions import GhostError
|
||||||
|
|
||||||
|
async def ghost(
|
||||||
|
action: str,
|
||||||
|
params: Optional[Dict[str, Any]] = None,
|
||||||
|
ctx: Optional[Context] = None
|
||||||
|
) -> str:
|
||||||
|
"""Central Ghost tool that provides access to all Ghost CMS functionality.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
action: The specific Ghost action to perform.
|
||||||
|
Available actions:
|
||||||
|
- Posts: list_posts, search_posts_by_title, read_post, create_post, update_post, delete_post, batchly_update_posts
|
||||||
|
- Users: list_users, read_user, delete_user, list_roles
|
||||||
|
- Members: list_members, read_member, create_member, update_member
|
||||||
|
- Tags: browse_tags, read_tag, create_tag, update_tag, delete_tag
|
||||||
|
- Tiers: list_tiers, read_tier, create_tier, update_tier
|
||||||
|
- Offers: list_offers, read_offer, create_offer, update_offer
|
||||||
|
- Newsletters: list_newsletters, read_newsletter, create_newsletter, update_newsletter
|
||||||
|
- Webhooks: create_webhook, update_webhook, delete_webhook
|
||||||
|
- Invites: create_invite
|
||||||
|
|
||||||
|
params: Dictionary of parameters specific to the chosen action.
|
||||||
|
Required parameters vary by action.
|
||||||
|
ctx: Optional context for logging
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Response from the specified Ghost action
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
GhostError: If there is an error processing the request
|
||||||
|
"""
|
||||||
|
if ctx:
|
||||||
|
ctx.info(f"Ghost tool called with action: {action}, params: {params}")
|
||||||
|
|
||||||
|
# Validate action
|
||||||
|
if action not in tools._all_tools:
|
||||||
|
valid_actions = ", ".join(tools._all_tools)
|
||||||
|
return f"Invalid action '{action}'. Valid actions are: {valid_actions}"
|
||||||
|
|
||||||
|
# Get the function for the specified action
|
||||||
|
tool_func = getattr(tools, action)
|
||||||
|
if not inspect.isfunction(tool_func):
|
||||||
|
return f"Invalid action '{action}'. This is not a valid function."
|
||||||
|
|
||||||
|
# Prepare parameters for the function call
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
# Add context to params if the function expects it
|
||||||
|
sig = inspect.signature(tool_func)
|
||||||
|
call_params = params.copy()
|
||||||
|
if 'ctx' in sig.parameters:
|
||||||
|
call_params['ctx'] = ctx
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Call the function with the appropriate parameters
|
||||||
|
result = await tool_func(**call_params)
|
||||||
|
return result
|
||||||
|
except GhostError as e:
|
||||||
|
if ctx:
|
||||||
|
ctx.error(f"Ghost tool error for action '{action}': {str(e)}")
|
||||||
|
return f"Error executing '{action}': {str(e)}"
|
||||||
|
except TypeError as e:
|
||||||
|
# This usually happens when the wrong parameters are provided
|
||||||
|
if ctx:
|
||||||
|
ctx.error(f"Parameter error for action '{action}': {str(e)}")
|
||||||
|
|
||||||
|
# Get the function parameters to provide better error messages
|
||||||
|
params_info = []
|
||||||
|
for name, param in sig.parameters.items():
|
||||||
|
if name == 'ctx':
|
||||||
|
continue
|
||||||
|
|
||||||
|
param_type = param.annotation.__name__ if param.annotation != inspect.Parameter.empty else "any"
|
||||||
|
default = f"(default: {param.default})" if param.default != inspect.Parameter.empty else "(required)"
|
||||||
|
params_info.append(f"- {name}: {param_type} {default}")
|
||||||
|
|
||||||
|
params_help = "\n".join(params_info)
|
||||||
|
return f"Error: {str(e)}\n\nExpected parameters for '{action}':\n{params_help}"
|
||||||
|
except Exception as e:
|
||||||
|
if ctx:
|
||||||
|
ctx.error(f"Unexpected error for action '{action}': {str(e)}")
|
||||||
|
return f"Unexpected error executing '{action}': {str(e)}"
|
||||||
Reference in New Issue
Block a user