Skip to main content
Glama
Michaelzag

Migadu MCP Server

by Michaelzag

update_rewrite

Idempotent

Modify email rewrite rules in Migadu to redirect messages based on domain, local part, or destination criteria.

Instructions

Update rewrite rule configuration. List of dicts with: name (required), domain, new_name, local_part_rule, destinations (optional).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
updatesYes

Implementation Reference

  • MCP tool handler for the 'update_rewrite' tool. Decorated with @mcp.tool(), processes bulk updates via the helper function.
    @mcp.tool(
        annotations={
            "readOnlyHint": False,
            "destructiveHint": False,
            "idempotentHint": True,
            "openWorldHint": True,
        },
    )
    async def update_rewrite(
        updates: List[Dict[str, Any]], ctx: Context
    ) -> Dict[str, Any]:
        """Update rewrite rule configuration. List of dicts with: name (required), domain, new_name, local_part_rule, destinations (optional)."""
        count = len(list(ensure_iterable(updates)))
        await log_bulk_operation_start(ctx, "Updating", count, "rewrite rule")
    
        result = await process_update_rewrite(updates, ctx)
        await log_bulk_operation_result(
            ctx, "Rewrite rule update", result, "rewrite rule"
        )
        return result
  • Pydantic schema RewriteUpdateRequest used for input validation in the bulk processor.
    class RewriteUpdateRequest(BaseModel):
        """Request schema for updating a rewrite rule"""
    
        name: str = Field(..., description="Current identifier/slug of the rule")
        domain: Optional[str] = Field(None, description="Domain name")
        new_name: Optional[str] = Field(None, description="New identifier/slug")
        local_part_rule: Optional[str] = Field(None, description="New pattern to match")
        destinations: Optional[Union[List[EmailStr], str]] = Field(
            None, description="New list of destinations or CSV string"
        )
        order_num: Optional[int] = Field(None, description="New processing order")
    
        @field_validator("destinations", mode="before")
        @classmethod
        def normalize_destinations(
            cls, v: Optional[Union[List[str], str]]
        ) -> Optional[List[str]]:
            if v is not None:
                return normalize_destinations(v)
            return v
  • Registration of rewrite tools (including update_rewrite) by calling register_rewrite_tools(mcp).
    register_alias_tools(mcp)
    register_rewrite_tools(mcp)
    register_resources(mcp)
  • Bulk processing helper that validates input with schema and calls the service layer.
    @bulk_processor_with_schema(RewriteUpdateRequest)
    async def process_update_rewrite(
        validated_item: RewriteUpdateRequest, ctx: Context
    ) -> Dict[str, Any]:
        """Process a single rewrite rule update with Pydantic validation"""
        # Use validated Pydantic model directly - all validation already done
        name = validated_item.name
        domain = validated_item.domain
        new_name = validated_item.new_name
        local_part_rule = validated_item.local_part_rule
        destinations = validated_item.destinations
    
        # Get domain if not provided
        if domain is None:
            from migadu_mcp.config import get_config
    
            config = get_config()
            domain = config.get_default_domain()
            if not domain:
                raise ValueError("No domain provided and MIGADU_DOMAIN not configured")
    
        await log_operation_start(ctx, "Updating rewrite rule", f"{name}@{domain}")
    
        service = get_service_factory().rewrite_service()
        # Convert Optional[List[EmailStr]] to Optional[List[str]] for service layer
        destinations_str = None
        if destinations is not None:
            destinations_str = [str(dest) for dest in destinations]
    
        result = await service.update_rewrite(
            domain, name, new_name, local_part_rule, destinations_str
        )
    
        await log_operation_success(ctx, "Updated rewrite rule", f"{name}@{domain}")
        return {"rewrite": result, "name": name, "domain": domain, "success": True}
  • Service layer implementation that makes the actual API PUT request to update the rewrite rule.
    async def update_rewrite(
        self,
        domain: str,
        name: str,
        new_name: Optional[str] = None,
        local_part_rule: Optional[str] = None,
        destinations: Optional[List[str]] = None,
    ) -> Dict[str, Any]:
        """Update rewrite settings"""
        data: Dict[str, Any] = {}
        if new_name is not None:
            data["name"] = new_name
        if local_part_rule is not None:
            data["local_part_rule"] = local_part_rule
        if destinations is not None:
            data["destinations"] = ",".join(destinations)
    
        return await self.client.request(
            "PUT", f"/domains/{domain}/rewrites/{name}", json=data
        )
Behavior3/5

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

Annotations cover key behavioral traits: readOnlyHint=false indicates mutation, openWorldHint=true suggests flexible input, idempotentHint=true means safe to retry, and destructiveHint=false implies no data loss. The description adds minimal context by specifying the structure of updates (list of dicts with fields), but doesn't elaborate on effects like error handling or permissions. No contradiction with annotations.

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 a single, efficient sentence that front-loads the action and key details. It avoids redundancy, though it could be slightly more structured by separating field explanations. Every word contributes value, making it appropriately concise for the tool's complexity.

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 the tool's moderate complexity (1 parameter with nested structure), no output schema, and rich annotations, the description is adequate but has gaps. It explains the parameter semantics well but lacks details on return values, error cases, or integration with sibling tools. For an update operation, more context on outcomes would be beneficial.

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?

With 0% schema description coverage, the description compensates by detailing the 'updates' parameter as a list of dicts with specific fields (name, domain, new_name, local_part_rule, destinations), including which are required or optional. This adds significant meaning beyond the generic schema, though it doesn't cover all potential properties due to additionalProperties: true.

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 verb 'Update' and resource 'rewrite rule configuration', making the purpose evident. It distinguishes from siblings like 'create_rewrite' and 'delete_rewrite' by specifying it's for updates, though it doesn't explicitly contrast with 'update_alias' or 'update_mailbox' which serve similar functions on different resources.

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?

No guidance is provided on when to use this tool versus alternatives. It doesn't mention prerequisites, such as needing existing rewrite rules to update, or differentiate from other update tools like 'update_alias'. The context is implied as part of a rewrite management system, but explicit usage instructions are absent.

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/Michaelzag/migadu-mcp'

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