Skip to main content
Glama
cornelcroi

French Tax MCP Server

by cornelcroi

calculate_income_tax

Calculate French income tax using net taxable income and household composition to determine tax liability based on official government data.

Instructions

Calculate French income tax based on net taxable income and household composition

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
net_taxable_incomeYes
household_partsNo
yearNo
ctxNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Registration of the calculate_income_tax tool using MCP decorator
    @mcp.tool(
        name="calculate_income_tax",
        description="Calculate French income tax based on net taxable income and household composition",
    )
  • MCP tool handler: wrapper function that invokes the analyzer's calculate_income_tax and handles errors/context logging
    async def calculate_income_tax_wrapper(
        net_taxable_income: float,
        household_parts: float = 1.0,
        year: Optional[int] = None,
        ctx: Optional[Context] = None,
    ) -> Optional[Dict]:
        """Calculate income tax based on net taxable income and household composition.
    
        Args:
            net_taxable_income: Net taxable income in euros
            household_parts: Number of household parts (quotient familial)
            year: Tax year (defaults to current year)
            ctx: MCP context for logging
    
        Returns:
            Dict: Dictionary containing tax calculation details
        """
        try:
            if ctx:
                await ctx.info(f"Calculating income tax for {net_taxable_income}€ with {household_parts} parts")
    
            result = await calculate_income_tax(net_taxable_income, household_parts, year)
            return result
        except Exception as e:
            if ctx:
                await ctx.error(f"Failed to calculate income tax: {e}")
            return {
                "status": "error",
                "message": f"Error calculating income tax: {str(e)}",
            }
  • Core logic in IncomeTaxAnalyzer class: fetches tax brackets, applies quotient familial, computes progressive tax
    async def calculate_income_tax(
        self,
        net_taxable_income: float,
        household_parts: float = 1.0,
        year: Optional[int] = None,
    ) -> Dict:
        """Calculate income tax based on net taxable income and household composition.
    
        Args:
            net_taxable_income: Net taxable income in euros
            household_parts: Number of household parts (quotient familial)
            year: Tax year (defaults to current year)
    
        Returns:
            Dictionary containing tax calculation details
        """
        # Set default year to current year if not specified
        current_year = datetime.now().year
        tax_year = year or current_year - 1  # Default to previous year for tax declarations
    
        logger.info(
            f"Calculating income tax for {net_taxable_income}€ with {household_parts} parts for year {tax_year}"
        )
    
        try:
            # Get tax brackets
            brackets_response = await get_tax_brackets(tax_year)
    
            if brackets_response["status"] != "success":
                return {
                    "status": "error",
                    "message": f"Failed to retrieve tax brackets: {brackets_response.get('message', 'Unknown error')}",
                    "year": tax_year,
                }
    
            brackets = brackets_response["data"]["brackets"]
    
            # Calculate income tax
            tax_result = self._calculate_tax(net_taxable_income, household_parts, brackets)
            
            # Log data source
            data_source = brackets_response.get("source", "unknown")
            logger.info(f"Tax calculation completed using data from: {data_source}")
    
            return {
                "status": "success",
                "data": {
                    "year": tax_year,
                    "net_taxable_income": net_taxable_income,
                    "household_parts": household_parts,
                    "income_per_part": tax_result["income_per_part"],
                    "tax_per_part": tax_result["tax_per_part"],
                    "total_tax": tax_result["total_tax"],
                    "average_tax_rate": tax_result["average_tax_rate"],
                    "marginal_tax_rate": tax_result["marginal_tax_rate"],
                    "bracket_details": tax_result["bracket_details"],
                    "brackets_source": data_source,
                },
                "message": f"Successfully calculated income tax for {tax_year} using {data_source}",
            }
    
        except Exception as e:
            logger.error(f"Error calculating income tax: {e}")
            return {
                "status": "error",
                "message": f"Failed to calculate income tax: {str(e)}",
                "year": tax_year,
            }
  • Top-level convenience function delegating to singleton IncomeTaxAnalyzer instance
    async def calculate_income_tax(
        net_taxable_income: float,
        household_parts: float = 1.0,
        year: Optional[int] = None,
    ) -> Dict:
        """Calculate income tax based on net taxable income and household composition.
    
        Args:
            net_taxable_income: Net taxable income in euros
            household_parts: Number of household parts (quotient familial)
            year: Tax year (defaults to current year)
    
        Returns:
            Dictionary containing tax calculation details
        """
        return await income_tax_analyzer.calculate_income_tax(net_taxable_income, household_parts, year)
  • Private method implementing progressive tax bracket calculation with household quotient adjustment
    def _calculate_tax(
        self,
        net_taxable_income: float,
        household_parts: float,
        brackets: List[Dict],
    ) -> Dict:
        """Calculate income tax based on brackets.
    
        Args:
            net_taxable_income: Net taxable income in euros
            household_parts: Number of household parts (quotient familial)
            brackets: List of tax brackets
    
        Returns:
            Dictionary containing tax calculation details
        """
        # Calculate income per part
        income_per_part = net_taxable_income / household_parts
    
        # Calculate tax per part
        tax_per_part = 0
        bracket_details = []
        marginal_tax_rate = 0
    
        for i, bracket in enumerate(brackets):
            min_value = bracket["min"]
            max_value = bracket["max"] if bracket["max"] is not None else float("inf")
            rate = bracket["rate"] / 100  # Convert percentage to decimal
    
            if income_per_part > min_value:
                # Calculate taxable amount in this bracket
                taxable_in_bracket = min(income_per_part, max_value) - min_value
                tax_in_bracket = taxable_in_bracket * rate
    
                tax_per_part += tax_in_bracket
    
                bracket_details.append(
                    {
                        "bracket": i + 1,
                        "min": min_value,
                        "max": max_value if max_value != float("inf") else None,
                        "rate": bracket["rate"],
                        "taxable_amount": taxable_in_bracket,
                        "tax_amount": tax_in_bracket,
                    }
                )
    
                # Update marginal tax rate if this is the highest bracket used
                if income_per_part <= max_value or max_value == float("inf"):
                    marginal_tax_rate = bracket["rate"]
    
        # Calculate total tax
        total_tax = tax_per_part * household_parts
    
        # Calculate average tax rate
        average_tax_rate = (total_tax / net_taxable_income) * 100 if net_taxable_income > 0 else 0
    
        return {
            "income_per_part": income_per_part,
            "tax_per_part": tax_per_part,
            "total_tax": total_tax,
            "average_tax_rate": average_tax_rate,
            "marginal_tax_rate": marginal_tax_rate,
            "bracket_details": bracket_details,
        }
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the calculation purpose but lacks details on permissions, rate limits, error handling, or output format. It doesn't clarify if this is a read-only calculation or if it has side effects like caching results, which is insufficient for a tool with potential financial implications.

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

Conciseness5/5

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

The description is a single, efficient sentence that front-loads the core purpose without unnecessary words. It directly communicates what the tool does without redundancy or fluff, making it easy to parse quickly.

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 complexity (tax calculation with financial implications), no annotations, and 0% schema description coverage, the description is incomplete. It lacks behavioral details and full parameter explanations. However, the presence of an output schema mitigates some gaps by presumably documenting return values, preventing a lower score.

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

Parameters3/5

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

The description mentions 'net taxable income and household composition,' which partially explains two of the four parameters (net_taxable_income and household_parts). However, with 0% schema description coverage, it doesn't address the 'year' parameter's purpose or the 'ctx' parameter's role, leaving significant gaps in parameter understanding.

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's purpose: calculating French income tax based on specific inputs. It specifies the verb ('calculate'), resource ('French income tax'), and key factors ('net taxable income and household composition'). However, it doesn't explicitly differentiate from sibling tools like 'generate_tax_report' or 'get_tax_brackets', which might also involve tax calculations.

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 sibling tools like 'get_tax_brackets' (which might provide rate information) or 'generate_tax_report' (which might produce formatted output), nor does it specify prerequisites or exclusions for usage.

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/cornelcroi/french-tax-mcp'

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