MCP server for Singapore electronic invoicing (InvoiceNow), vendor-neutral Peppol transport
Four tools with domain-specific, detailed descriptions (194 - 350 chars, above baseline 194). All tools have input schemas with type declarations. However, parameter descriptions are sparse or missing entirely: generate_invoice_sg has only one param with a generic description; validate_invoice_sg, get_gst_category_codes_sg, and get_profile_urn_sg lack per-parameter descriptions. Output schemas are not documented. Error handling guidance is absent. Tool names follow verb_noun convention (generate_, validate_, get_) and are clear, but lack actionable recovery hints in descriptions.
Build an SGInvoice from structured data and serialize it to UBL 2.1 XML. `invoice_data['profile']` (CustomizationID) and `invoice_data['business_process']` (ProfileID) select PINT-SG or SG Peppol BIS Billing 3.0, and must be a matched pair (TX2_Annex Annex B) — use get_profile_urn_sg to look up both values together rather than setting them independently. Returns the UBL XML (as a string) plus the customization_id/profile_id that were applied. Does not validate against Schematron — call validate_invoice_sg on the returned XML for that.
Return the IRAS GST category codes accepted on Singapore invoices. Source: IRAS e-Tax Guide Annex E (supply/output-tax side only — the purchase-side codes are out of scope for sent invoices). `rate` is null for categories with no fixed rate ("NA" in the source table).
Return the CustomizationID (BT-24) and ProfileID (BT-23) for a Singapore profile. CustomizationID comes from mcp_einvoicing_core.profile_registry (registered at import time in models/invoice.py); ProfileID is a shared Peppol process identifier, not per-country, so it is returned from a local constant rather than the registry. PINT_SG is the recommended profile for new senders — SG Peppol BIS Billing 3.0 (BIS3) predates the PINT programme and is positioned as legacy (per the package's own compliance reference, "Supported wire formats and profile URNs" — user-supplied guidance, not independently verified against an IRAS/IMDA notice). Not enforced as a hard default here; callers choose explicitly.
Validate a UBL 2.1 XML invoice against IRAS's C5 acceptance-layer Schematron. Runs IRAS's own C5 acceptance layer (checks documents that IRAS itself would still reject, e.g. a missing buyer/seller UEN). The CEN EN16931 base ruleset, PINT-SG's own jurisdiction overlay, and SG Peppol BIS Billing 3.0 are NOT checked — see `scope` and the `EN16931-BASE-UNAVAILABLE` warning in the result, and validators/schematron.py's module docstring for why (SGInvoice's GST category codes have no sourced crosswalk to the UNCL5305 code list the base ruleset requires; tracked as [CORE-EN16931-BASE-SG-CROSSWALK-1]). Requires the optional `xslt2` extra (`pip install mcp-invoicenow-sg[xslt2]`) — the bundled stylesheet needs XSLT 2.0. If missing, returns `level="unavailable"`.
Parameter descriptions missing or minimal. generate_invoice_sg's 'invoice_data' param has only 'Invoice fields matching the SGInvoice schema', no guidance on required fields, structure, or constraints. get_gst_category_codes_sg and get_profile_urn_sg have no per-parameter descriptions at all.
Output schemas not documented. No tool description states what fields are returned, their types, or how to chain results to downstream tools. LLMs cannot plan multi-step workflows without knowing what data is available.
No error recovery guidance. Descriptions mention constraints (e.g. 'profile must be PINT_SG or BIS3', 'xslt2 extra required') but do not tell LLMs what to do if validation fails or a dependency is missing. Error responses should guide next steps.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 53 | 2026-07-28+ | v2 |
Parameter 'profile' in get_profile_urn_sg lacks enum constraint in visible schema. Description mentions 'PINT_SG' or 'BIS3' but schema does not enforce this, inviting hallucinated values.
Tool descriptions reference external documentation (TX2_Annex, IRAS C5, CORE-EN16931-BASE-SG-CROSSWALK-1) without explaining what they mean in chat context. LLMs cannot act on opaque references; descriptions should be self-contained.