Skip to main content
Glama
cmendezs

mcp-facture-electronique-fr

submit_lifecycle_status

Emit a lifecycle status (e.g., Refused, Approved, Cashed) for a received invoice. Mandatory statuses are transmitted to the PPF.

Instructions

Emit a processing status on a received invoice: Refused, Approved, PartiallyApproved, Disputed, Suspended, Cashed, PaymentTransmitted, Cancelled. Refused and Cashed are mandatory transmissions to PPF. Reason is mandatory for Refused and Disputed.

HUMAN-IN-THE-LOOP: Requires user confirmation. Call without confirmation_token first, show the summary to the user, then call again with the token.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
referenced_flow_idYesIdentifier of the invoice flow to which this status applies (flowId returned upon receipt, maxLength 36).
status_codeYesLifecycle status code to emit. Values defined in XP Z12-014: Refused (transmitted to PPF), Approved, PartiallyApproved, Disputed, Suspended, Cashed (transmitted to PPF), PaymentTransmitted, Cancelled. Refused and Cashed are mandatory transmissions to PPF.
reasonNoStatus reason, mandatory for Refused and Disputed. Free text describing the reason for refusal or dispute.
payment_dateNoPayment date (ISO 8601 format: YYYY-MM-DD). Provided for Cashed and PaymentTransmitted statuses.
payment_amountNoPayment amount (decimal string, e.g. '1250.00'). Provided for Cashed and PaymentTransmitted statuses.
confirmation_tokenNoConfirmation token from a previous call. Omit on the first call; supply on the second call to execute.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • MCP tool handler for submit_lifecycle_status. Decorated with @mcp.tool() inside register_flow_tools(). Validates read-only mode, checks flow not in terminal state, requires user confirmation via ConfirmationGate, then delegates to FlowClient.submit_lifecycle_status.
    async def submit_lifecycle_status(
        referenced_flow_id: Annotated[
            str,
            Field(
                description=(
                    "Identifier of the invoice flow to which this status applies "
                    "(flowId returned upon receipt, maxLength 36)."
                )
            ),
        ],
        status_code: Annotated[
            LifecycleStatusCode,
            Field(
                description=(
                    "Lifecycle status code to emit. Values defined in XP Z12-014: "
                    "Refused (transmitted to PPF), "
                    "Approved, "
                    "PartiallyApproved, "
                    "Disputed, "
                    "Suspended, "
                    "Cashed (transmitted to PPF), "
                    "PaymentTransmitted, "
                    "Cancelled. "
                    "Refused and Cashed are mandatory transmissions to PPF."
                )
            ),
        ],
        reason: Annotated[
            Optional[str],
            Field(
                default=None,
                description=(
                    "Status reason, mandatory for Refused and Disputed. "
                    "Free text describing the reason for refusal or dispute."
                ),
            ),
        ] = None,
        payment_date: Annotated[
            Optional[str],
            Field(
                default=None,
                description=(
                    "Payment date (ISO 8601 format: YYYY-MM-DD). "
                    "Provided for Cashed and PaymentTransmitted statuses."
                ),
            ),
        ] = None,
        payment_amount: Annotated[
            Optional[str],
            Field(
                default=None,
                description=(
                    "Payment amount (decimal string, e.g. '1250.00'). "
                    "Provided for Cashed and PaymentTransmitted statuses."
                ),
            ),
        ] = None,
        confirmation_token: Annotated[
            Optional[str],
            Field(
                default=None,
                description=(
                    "Confirmation token from a previous call. "
                    "Omit on the first call; supply on the second call to execute."
                ),
            ),
        ] = None,
    ) -> dict:
        """
        Emit a processing status on a received invoice: Refused, Approved,
        PartiallyApproved, Disputed, Suspended, Cashed, PaymentTransmitted,
        Cancelled. Refused and Cashed are mandatory transmissions to PPF.
        Reason is mandatory for Refused and Disputed.
    
        HUMAN-IN-THE-LOOP: Requires user confirmation. Call without confirmation_token
        first, show the summary to the user, then call again with the token.
        """
        assert_not_read_only("FR_READ_ONLY")
        client = get_flow_client()
        try:
            await _check_flow_not_terminal(referenced_flow_id, client)
        except ValueError as exc:
            return {"error": str(exc)}
    
        gate = ConfirmationGate.get_default()
        if not gate.is_confirmed(confirmation_token):
            reason_note = f", reason={reason!r}" if reason else ""
            return gate.pending_response(
                action="submit_lifecycle_status",
                summary=(
                    f"Emit lifecycle status {status_code!r} on flow "
                    f"{referenced_flow_id!r}{reason_note}. "
                    "Refused and Cashed statuses are transmitted to PPF and cannot be retracted."
                ),
                token=confirmation_token,
            )
    
        result = await client.submit_lifecycle_status(
            referenced_flow_id=referenced_flow_id,
            status_code=status_code,
            reason=reason,
            payment_date=payment_date,
            payment_amount=payment_amount,
        )
        gate.consume(confirmation_token)
        return result
  • HTTP client method that builds CDAR lifecycle status XML via _build_lifecycle_status_xml helper and POSTs it as a multipart form (file + flowInfo JSON) to the AP's /v1/flows endpoint.
    async def submit_lifecycle_status(
        self,
        referenced_flow_id: str,
        status_code: LifecycleStatusCode,
        reason: Optional[str] = None,
        payment_date: Optional[str] = None,
        payment_amount: Optional[str] = None,
    ) -> dict[str, Any]:
        """POST /v1/flows — Submit a CDAR lifecycle status."""
        status_xml = _build_lifecycle_status_xml(
            referenced_flow_id=referenced_flow_id,
            status_code=status_code,
            reason=reason,
            payment_date=payment_date,
            payment_amount=payment_amount,
        )
        flow_info: dict[str, Any] = {
            "flowSyntax": "CDAR",
            "processingRule": "NotApplicable",
            "flowType": "SupplierInvoiceLC",
            "name": "lifecycle_status.xml",
        }
        files = {
            "file": ("lifecycle_status.xml", status_xml.encode("utf-8"), "application/xml"),
            "flowInfo": (None, _json.dumps(flow_info), "application/json"),
        }
        response = await self._request("POST", "/v1/flows", files=files)
        return response.json()
  • Helper that builds the CDAR lifecycle status XML payload per XP Z12-014. Includes optional Reason and Payment elements (Date, Amount) in the XML structure.
    def _build_lifecycle_status_xml(
        referenced_flow_id: str,
        status_code: str,
        reason: Optional[str] = None,
        payment_date: Optional[str] = None,
        payment_amount: Optional[str] = None,
    ) -> str:
        """Build a CDAR lifecycle status XML document (XP Z12-014)."""
        reason_el = f"<Reason>{_xml_escape(reason)}</Reason>" if reason else ""
        payment_el = ""
        if payment_date or payment_amount:
            payment_el = (
                "<Payment>"
                + (f"<Date>{_xml_escape(payment_date)}</Date>" if payment_date else "")
                + (f"<Amount>{_xml_escape(payment_amount)}</Amount>" if payment_amount else "")
                + "</Payment>"
            )
        return (
            '<?xml version="1.0" encoding="UTF-8"?>'
            '<LifecycleStatus xmlns="urn:xp-z12-013:lifecycle-status:1.0">'
            f"<ReferencedFlowId>{_xml_escape(referenced_flow_id)}</ReferencedFlowId>"
            f"<StatusCode>{_xml_escape(status_code)}</StatusCode>"
            f"{reason_el}"
            f"{payment_el}"
            "</LifecycleStatus>"
        )
  • LifecycleStatusCode type definition — a Literal union of all valid CDAR status values (Refused, Approved, PartiallyApproved, Disputed, Suspended, Cashed, PaymentTransmitted, Cancelled). Used as the type for the status_code parameter.
    LifecycleStatusCode = Literal[
        "Refused",
        "Approved",
        "PartiallyApproved",
        "Disputed",
        "Suspended",
        "Cashed",
        "PaymentTransmitted",
        "Cancelled",
    ]
  • Registration function that wraps all flow tools. Within this function, submit_lifecycle_status is registered via @mcp.tool() decorator. Called from server.py line 74: register_flow_tools(mcp).
    def register_flow_tools(mcp: FastMCP) -> None:
        """Registers the 5 Flow Service tools on the FastMCP instance."""
Behavior4/5

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

Discloses the two-step confirmation requirement and mandatory transmission obligations. Lacks details on side effects like database updates, but given no annotations, the description adequately covers behavioral traits.

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?

Two concise paragraphs: first lists statuses and constraints, second gives step-by-step human-in-the-loop instructions. Every sentence adds value, no filler.

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

Completeness4/5

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

Covers purpose, status categories, mandatory fields, and the two-step process. Could mention error handling for invalid combinations, but overall complete for a 6-param tool with an output schema.

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 has 100% coverage; description adds value by linking parameters to specific statuses (e.g., reason mandatory for Refused/Disputed) and explaining the confirmation_token flow. Doesn't add new syntax details for payment fields.

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

Purpose5/5

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

The description clearly states it emits a processing status on a received invoice and enumerates all valid statuses. This differentiates it from sibling tools like submit_flow.

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

Usage Guidelines5/5

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

Explicitly describes the two-step human-in-the-loop pattern: call without confirmation_token first, then with token. Also notes mandatory transmissions for Refused and Cashed.

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/cmendezs/mcp-facture-electronique-fr'

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