Skip to main content
Glama

Clappia MCP

by clappia-dev
clappia-mcp.py13.1 kB
from mcp.server.fastmcp import FastMCP import logging import sys import os import re from datetime import datetime from typing import Dict, Any, Optional, List from tools.get_submissions_aggregation import get_app_submissions_aggregation from tools.get_submissions import get_app_submissions from utils.constants import CLAPPIA_EXTERNAL_API_BASE_URL from clappia_tools import SubmissionClient, AppManagementClient, AppDefinitionClient def setup_logging(): """Configure file-only logging to avoid JSON-RPC interference.""" log_dir = "logs" os.makedirs(log_dir, exist_ok=True) log_filename = f'{log_dir}/mcp_logs_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log' logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[logging.FileHandler(log_filename)] ) return logging.getLogger('clappia-mcp') def get_submission_client(): return SubmissionClient( api_key=os.getenv("CLAPPIA_API_KEY"), base_url=CLAPPIA_EXTERNAL_API_BASE_URL, workplace_id=os.getenv("CLAPPIA_WORKPLACE_ID") ) def get_app_definition_client(): return AppDefinitionClient( api_key=os.getenv("CLAPPIA_API_KEY"), base_url=CLAPPIA_EXTERNAL_API_BASE_URL , workplace_id=os.getenv("CLAPPIA_WORKPLACE_ID") ) def get_app_management_client(): return AppManagementClient( api_key=os.getenv("CLAPPIA_API_KEY"), base_url=CLAPPIA_EXTERNAL_API_BASE_URL, workplace_id=os.getenv("CLAPPIA_WORKPLACE_ID") ) logger = setup_logging() mcp = FastMCP() def validate_required_params(email: str) -> tuple[bool, str]: """ Validate required email parameter. Args: email: Email address to validate Returns: tuple[bool, str]: (is_valid, error_message) """ if not email or not email.strip(): return False, "Email address is required. Please provide a valid email address." if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email.strip()): return False, "Invalid email format. Please provide a valid email address." return True, "" @mcp.tool() def get_clappia_submissions(app_id: str, requesting_user_email_address: str, page_size: int = 10, filters: Optional[dict] = None) -> str: """ Retrieve Clappia form submissions with optional filtering. Required Parameters: requesting_user_email_address (str): Email address of the requesting user. Must be a valid email format. app_id (str): Application identifier (e.g., "ODT537440"). Must be uppercase letters and numbers. Optional Parameters: page_size (int): Number of results to retrieve (1-1000, default: 10). filters (dict): Filter conditions. Returns: str: JSON string with submission records and metadata, or error message if the request fails. Notes: - Requires CLAPPIA_API_KEY and CLAPPIA_WORKPLACE_ID environment variables. """ # Validate required parameters is_valid, error_msg = validate_required_params(requesting_user_email_address) if not is_valid: return f"Error: {error_msg}" logger.info(f"Getting submissions for app: {app_id}") return get_app_submissions(app_id, requesting_user_email_address, page_size, filters) @mcp.tool() def get_clappia_submissions_aggregation(app_id: str, requesting_user_email_address: str, dimensions: Optional[List[dict]] = None, aggregation_dimensions: Optional[List[dict]] = None, x_axis_labels: Optional[List[str]] = None, forward: bool = True, page_size: int = 1000, filters: Optional[dict] = None) -> str: """ Aggregate Clappia submission data for analytics. Required Parameters: requesting_user_email_address (str): Email address of the requesting user. Must be a valid email format. app_id (str): Application ID (e.g., "ODT537440"). Must be uppercase letters and numbers. Optional Parameters: dimensions (List[dict]): Fields to group by. aggregation_dimensions (List[dict]): Calculations. x_axis_labels (List[str]): Output column labels. forward (bool): Pagination direction. page_size (int): Max results (1-1000). filters (dict): Filter conditions. Returns: str: JSON string with tabular data or error message. Notes: - Requires CLAPPIA_API_KEY and CLAPPIA_WORKPLACE_ID environment variables. """ # Validate required parameters is_valid, error_msg = validate_required_params(requesting_user_email_address) if not is_valid: return f"Error: {error_msg}" logger.info(f"Getting submissions aggregation for app: {app_id}") return get_app_submissions_aggregation( app_id=app_id, dimensions=dimensions or [], aggregation_dimensions=aggregation_dimensions or [], x_axis_labels=x_axis_labels or [], requesting_user_email_address=requesting_user_email_address, forward=forward, page_size=page_size, filters=filters ) @mcp.tool() def get_clappia_app_definition(app_id: str, requesting_user_email_address: str, language: str = "en", strip_html: bool = True, include_tags: bool = True) -> str: client = get_app_definition_client() return client.get_definition(app_id, language, strip_html, include_tags) @mcp.tool() def create_clappia_app_submission(app_id: str, data: Dict[str, Any], requesting_user_email_address: str) -> str: client = get_submission_client() return client.create_submission(app_id, data, requesting_user_email_address) @mcp.tool() def edit_clappia_submission(app_id: str, submission_id: str, data: Dict[str, Any], requesting_user_email_address: str) -> str: client = get_submission_client() return client.edit_submission(app_id, submission_id, data, requesting_user_email_address) @mcp.tool() def update_clappia_submission_status(app_id: str, submission_id: str, status_name: str, requesting_user_email_address: str, comments: Optional[str] = None) -> str: client = get_submission_client() return client.update_status(app_id,submission_id,requesting_user_email_address,status_name,comments) @mcp.tool() def update_clappia_submission_owners(app_id: str, submission_id: str, email_ids: List[str], requesting_user_email_address: str) -> str: client = get_submission_client() return client.update_owners(app_id, submission_id, requesting_user_email_address,email_ids) @mcp.tool() def create_clappia_app(app_name: str, requesting_user_email_address: str, sections: List[Dict[str, Any]]) -> str: client = get_app_management_client() return client.create_app(app_name, requesting_user_email_address, sections) @mcp.tool() def add_field_to_clappia_app(app_id: str, requesting_user_email_address: str, section_index: int, field_index: int, field_type: str, label: Optional[str] = None, description: Optional[str] = None, required: Optional[bool] = None, block_width_percentage_desktop: Optional[int] = None, block_width_percentage_mobile: Optional[int] = None, display_condition: Optional[str] = None, retain_values: Optional[bool] = None, is_editable: Optional[bool] = None, editability_condition: Optional[str] = None, validation: Optional[str] = None, default_value: Optional[str] = None, options: Optional[List[str]] = None, style: Optional[str] = None, number_of_cols: Optional[int] = None, allowed_file_types: Optional[List[str]] = None, max_file_allowed: Optional[int] = None, image_quality: Optional[str] = None, image_text: Optional[str] = None, file_name_prefix: Optional[str] = None, formula: Optional[str] = None, hidden: Optional[bool] = None) -> str: client = get_app_management_client() return client.add_field(app_id=app_id, requesting_user_email_address=requesting_user_email_address, section_index=section_index, field_index=field_index, field_type=field_type, label=label, description=description, required=required, block_width_percentage_desktop=block_width_percentage_desktop, block_width_percentage_mobile=block_width_percentage_mobile, display_condition=display_condition, retain_values=retain_values, is_editable=is_editable, editability_condition=editability_condition, validation=validation, default_value=default_value, options=options, style=style, number_of_cols=number_of_cols, allowed_file_types=allowed_file_types, max_file_allowed=max_file_allowed, image_quality=image_quality, image_text=image_text, file_name_prefix=file_name_prefix, formula=formula, hidden=hidden) @mcp.tool() def update_field_in_clappia_app(app_id: str, requesting_user_email_address: str, field_name: str, label: Optional[str] = None, description: Optional[str] = None, required: Optional[bool] = None, block_width_percentage_desktop: Optional[int] = None, block_width_percentage_mobile: Optional[int] = None, display_condition: Optional[str] = None, retain_values: Optional[bool] = None, is_editable: Optional[bool] = None, editability_condition: Optional[str] = None, validation: Optional[str] = None, default_value: Optional[str] = None, options: Optional[List[str]] = None, style: Optional[str] = None, number_of_cols: Optional[int] = None, allowed_file_types: Optional[List[str]] = None, max_file_allowed: Optional[int] = None, image_quality: Optional[str] = None, image_text: Optional[str] = None, file_name_prefix: Optional[str] = None, formula: Optional[str] = None, hidden: Optional[bool] = None) -> str: client = get_app_management_client() return client.update_field(app_id=app_id, requesting_user_email_address=requesting_user_email_address, field_name=field_name, label=label, description=description, required=required, block_width_percentage_desktop=block_width_percentage_desktop, block_width_percentage_mobile=block_width_percentage_mobile, display_condition=display_condition, retain_values=retain_values, is_editable=is_editable, editability_condition=editability_condition, validation=validation, default_value=default_value, options=options, style=style, number_of_cols=number_of_cols, allowed_file_types=allowed_file_types, max_file_allowed=max_file_allowed, image_quality=image_quality, image_text=image_text, file_name_prefix=file_name_prefix, formula=formula, hidden=hidden) def main(): """Start Clappia MCP server with error handling.""" try: logger.info("Starting Clappia MCP server") logger.info("IMPORTANT: All tools require requesting_user_email_address to be explicitly provided") logger.info("Do not use default values for this parameter") logger.info("requesting_user_email_address must be a valid email format") logger.info("CLAPPIA_API_KEY and CLAPPIA_WORKPLACE_ID must be set as environment variables") mcp.run(transport='stdio') except KeyboardInterrupt: logger.info("Server shutdown requested by user") except Exception as e: logger.error(f"Server startup failed: {str(e)}") sys.exit(1) finally: logger.info("MCP server shutdown complete") if __name__ == "__main__": main()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clappia-dev/clappia-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server