Skip to main content
Glama
jamesbrink

MCP Server for Coroot

update_application_category

Modify application categories in Coroot to adjust monitoring patterns and notification settings for incidents and deployments.

Instructions

Update an existing application category.

Updates specific fields of an application category. Only provided fields are updated.

Args: project_id: Project ID name: Category name to update custom_patterns: New space-separated glob patterns (optional) notify_incidents: Whether to notify about incidents (optional) notify_deployments: Whether to notify about deployments (optional) slack_channel: Slack channel for notifications (optional)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idYes
nameYes
custom_patternsNo
notify_incidentsNo
notify_deploymentsNo
slack_channelNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core handler logic for the MCP tool 'update_application_category'. Fetches current category config, merges updates, and calls Coroot API to persist changes.
    async def update_application_category_impl(
        project_id: str,
        name: str,
        custom_patterns: str | None = None,
        notify_incidents: bool | None = None,
        notify_deployments: bool | None = None,
        slack_channel: str | None = None,
    ) -> dict[str, Any]:
        """Update an existing application category."""
        # First get the existing category
        categories = await get_client().get_application_categories(project_id)
        existing: dict[str, Any] | None = None
        for cat in categories:
            if isinstance(cat, dict) and cat.get("name") == name:
                existing = cat
                break
    
        if not existing:
            raise ValueError(f"Category '{name}' not found")
    
        # Update only specified fields
        if custom_patterns is not None:
            existing["custom_patterns"] = custom_patterns
    
        if notify_incidents is not None:
            existing["notification_settings"]["incidents"]["enabled"] = notify_incidents
    
        if notify_deployments is not None:
            existing["notification_settings"]["deployments"]["enabled"] = notify_deployments
    
        if slack_channel is not None:
            if "slack" not in existing["notification_settings"]["incidents"]:
                existing["notification_settings"]["incidents"]["slack"] = {}
            slack = existing["notification_settings"]["incidents"]["slack"]
            slack["channel"] = slack_channel
            slack["enabled"] = True
    
            if "slack" not in existing["notification_settings"]["deployments"]:
                existing["notification_settings"]["deployments"]["slack"] = {}
            slack = existing["notification_settings"]["deployments"]["slack"]
            slack["channel"] = slack_channel
    
        await get_client().update_application_category(project_id, name, existing)
        return {
            "success": True,
            "message": f"Application category '{name}' updated successfully",
        }
  • MCP tool registration via @mcp.tool() decorator. Defines input parameters and docstring schema for the 'update_application_category' tool.
    @mcp.tool()
    async def update_application_category(
        project_id: str,
        name: str,
        custom_patterns: str | None = None,
        notify_incidents: bool | None = None,
        notify_deployments: bool | None = None,
        slack_channel: str | None = None,
    ) -> dict[str, Any]:
        """Update an existing application category.
    
        Updates specific fields of an application category.
        Only provided fields are updated.
    
        Args:
            project_id: Project ID
            name: Category name to update
            custom_patterns: New space-separated glob patterns (optional)
            notify_incidents: Whether to notify about incidents (optional)
            notify_deployments: Whether to notify about deployments (optional)
            slack_channel: Slack channel for notifications (optional)
        """
        return await update_application_category_impl(  # type: ignore[no-any-return]
            project_id,
            name,
            custom_patterns,
            notify_incidents,
            notify_deployments,
            slack_channel,
        )
  • CorootClient helper method that performs the HTTP POST request to the Coroot API endpoint for updating application categories.
    async def update_application_category(
        self, project_id: str, category_name: str, category: dict[str, Any]
    ) -> dict[str, Any]:
        """Update an existing application category.
    
        Args:
            project_id: Project ID.
            category_name: Name of the category to update.
            category: Updated category object.
    
        Returns:
            Updated category.
        """
        # Set the id field for updates
        category["id"] = category_name
        response = await self._request(
            "POST", f"/api/project/{project_id}/application_categories", json=category
        )
        return self._parse_json_response(response)
  • Shared helper function that provides the authenticated CorootClient instance used by all MCP tools.
    def get_client() -> CorootClient:
        """Get or create the client instance.
    
        Raises:
            ValueError: If no credentials are configured.
        """
        global _client
        if _client is None:
            try:
                _client = CorootClient()
            except ValueError as e:
                # Re-raise with more context
                raise ValueError(
                    "Coroot credentials not configured. "
                    "Please set COROOT_BASE_URL and either:\n"
                    "  - COROOT_USERNAME and COROOT_PASSWORD for automatic login\n"
                    "  - COROOT_SESSION_COOKIE for direct authentication\n"
                    "  - COROOT_API_KEY for data ingestion endpoints"
                ) from e
        return _client
  • Error handling decorator applied to the handler implementation for standardized error responses.
    def handle_errors(func: Callable[..., Any]) -> Callable[..., Any]:
        """Decorator to handle common errors in tool implementations."""
    
        @wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> dict[str, Any]:
            try:
                return await func(*args, **kwargs)  # type: ignore[no-any-return]
            except ValueError as e:
                # Handle missing credentials or other validation errors
                return {
                    "success": False,
                    "error": str(e),
                    "error_type": "validation",
                }
            except CorootError as e:
                # Handle Coroot API errors (including authentication)
                error_msg = str(e)
                if "Authentication failed" in error_msg:
                    return {
                        "success": False,
                        "error": error_msg,
                        "error_type": "authentication",
                    }
                elif "401" in error_msg or "Unauthorized" in error_msg:
                    return {
                        "success": False,
                        "error": "Authentication required. Please check your credentials.",
                        "error_type": "authentication",
                    }
                return {
                    "success": False,
                    "error": error_msg,
                    "error_type": "api_error",
                }
            except Exception as e:
                # Handle unexpected errors
                return {
                    "success": False,
                    "error": f"Unexpected error: {str(e)}",
                    "error_type": "unknown",
                }
    
        return wrapper
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It states 'Only provided fields are updated,' which is useful behavioral context about partial updates. However, it doesn't disclose important traits like required permissions, whether changes are reversible, rate limits, error conditions, or what the response contains. For a mutation tool with zero annotation coverage, this leaves significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a clear opening statement followed by a parameter list. It's appropriately sized for a 6-parameter tool. However, the 'Args:' section could be more integrated, and there's some redundancy ('Update an existing application category.' followed by 'Updates specific fields...'). Every sentence earns its place, but minor tightening is possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 6 parameters with 0% schema coverage and no annotations, the description does a fair job explaining parameters but lacks behavioral context. The presence of an output schema (per context signals) means the description doesn't need to explain return values, which helps. However, for a mutation tool with multiple parameters, more guidance on usage and behavioral traits would improve completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It provides a parameter list with brief explanations for all 6 parameters, adding meaning beyond the schema's titles. For example, it clarifies 'custom_patterns' as 'space-separated glob patterns' and explains the boolean parameters' purposes. However, it doesn't provide format details (e.g., Slack channel format) or constraints, keeping it from a perfect score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool updates an existing application category, specifying the resource (application category) and action (update). It distinguishes from sibling 'create_application_category' by specifying 'existing' and from 'delete_application_category' by being an update rather than deletion. However, it doesn't explicitly differentiate from other update tools like 'update_application_risks' or 'update_project_settings'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an existing category), compare with sibling tools like 'create_application_category' or 'delete_application_category', or indicate appropriate contexts. The only implicit guidance is that it updates existing categories, but this is already covered in purpose clarity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/jamesbrink/mcp-coroot'

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