"""42crunch MCP Server implementation using FastMCP."""
from fastmcp import FastMCP
from typing import Optional
from .client import FortyTwoCrunchClient
from .config import Config
# Initialize FastMCP server
mcp = FastMCP("42crunch")
# Initialize client (will be created on first use)
_client: Optional[FortyTwoCrunchClient] = None
def get_client() -> FortyTwoCrunchClient:
"""Get or create the API client instance."""
global _client
if _client is None:
_client = FortyTwoCrunchClient()
return _client
@mcp.tool()
def list_collections(
page: Optional[int] = 1,
per_page: Optional[int] = 10,
order: Optional[str] = "default",
sort: Optional[str] = "default",
) -> dict:
"""List all API collections from 42crunch.
Args:
page: Page number (default: 1)
per_page: Items per page (default: 10)
order: Sort order (default: "default")
sort: Sort field (default: "default")
Returns:
Dictionary containing collections data with metadata
"""
try:
client = get_client()
result = client.list_collections(
page=page or 1,
per_page=per_page or 10,
order=order or "default",
sort=sort or "default",
)
return {
"success": True,
"data": result,
}
except Exception as e:
return {
"success": False,
"error": str(e),
"error_type": type(e).__name__,
}
@mcp.tool()
def get_collection_apis(
collection_id: str,
with_tags: Optional[bool] = True,
) -> dict:
"""Get all APIs within a specific collection.
Args:
collection_id: Collection UUID (required)
with_tags: Include tags in response (default: True)
Returns:
Dictionary containing list of APIs in the collection
"""
if not collection_id:
return {
"success": False,
"error": "collection_id is required",
}
try:
client = get_client()
result = client.get_collection_apis(
collection_id=collection_id,
with_tags=with_tags if with_tags is not None else True,
)
return {
"success": True,
"data": result,
}
except Exception as e:
return {
"success": False,
"error": str(e),
"error_type": type(e).__name__,
}
@mcp.tool()
def get_api_details(
api_id: str,
branch: Optional[str] = "main",
include_definition: Optional[bool] = True,
include_assessment: Optional[bool] = True,
include_scan: Optional[bool] = True,
) -> dict:
"""Get detailed information about a specific API.
Args:
api_id: API UUID (required)
branch: Branch name (default: "main")
include_definition: Include OpenAPI definition (default: True)
include_assessment: Include assessment data (default: True)
include_scan: Include scan results (default: True)
Returns:
Dictionary containing complete API details
"""
if not api_id:
return {
"success": False,
"error": "api_id is required",
}
try:
client = get_client()
result = client.get_api_details(
api_id=api_id,
branch=branch or "main",
read_openapi_definition=include_definition if include_definition is not None else True,
read_assessment=include_assessment if include_assessment is not None else True,
read_scan=include_scan if include_scan is not None else True,
)
return {
"success": True,
"data": result,
}
except Exception as e:
return {
"success": False,
"error": str(e),
"error_type": type(e).__name__,
}
if __name__ == "__main__":
# Run the MCP server
mcp.run()