three-way-match
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@three-way-matchMatch invoice INV-4471 against its PO and receipts, flag any SKU mismatches"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Three-way supplier invoice matching MCP server
MCP server for three way matching: supplier invoice matching against purchase orders and accepted receipts by SKU. Supplier invoice, purchase order and receipt checks by exact SKU.
Works with Claude Desktop, Claude Code, Cursor and any Model Context Protocol client. Runs on your own machine: this one has no hosted endpoint, so install it from the bundle or from source.
Try the editable matching example in your browser before installing. No account is needed; the example checks run in your browser without uploading field values.
Install
Claude Desktop, one click. Download three-way-match.mcpb from the bundle catalog and double-click it.
From source. The mirror is self-contained: every @theluckystrike/* dependency is vendored, so a fresh clone builds with no extra setup.
git clone https://github.com/theluckystrike/mcp-three-way-match.git
cd mcp-three-way-match
npm install && npm run buildThen point your client at the built entry point:
{
"mcpServers": {
"three-way-match": {
"command": "node",
"args": ["/absolute/path/to/mcp-three-way-match/dist/index.js"]
}
}
}
@theluckystrike/mcp-three-way-matchis not published on npm yet, so annpx -y @theluckystrike/mcp-three-way-matchcommand will fail. The three paths above are the working ones and each is exercised by CI.

Read-only mirror of mcp-servers/servers/three-way-match. See MIRROR.md.
Check a supplier invoice against its purchase order and delivery receipts in Claude or another MCP client. This local server compares each exact SKU, unit price and billed quantity with the PO, cumulative accepted deliveries and quantities you say were already invoiced. It catches offsetting SKU mistakes even when the invoice and PO grand totals agree, and returns the source values behind every exception. Supply structured documents; this server does not extract PDFs, perform OCR, connect to an ERP, post payments or approve an invoice.
Built by theluckystrike. MIT. Support: support@zovo.one.
Related MCP server: caseware-kb
Install
Requires Node.js 18 or newer. Build from the source checkout; the npm package is not published. No API key or account is required to run the free tools.
git clone https://github.com/theluckystrike/mcp-servers.git
cd mcp-servers
npm install
node scripts/bootstrap-timezone.mjs
npm run build --workspace @theluckystrike/mcp-license
npm run build --workspace @theluckystrike/mcp-three-way-matchUse the absolute path to servers/three-way-match/dist/index.js in your checkout. The server speaks stdio; your MCP client starts it. Do not put an HTTP URL in its place.
Claude Desktop: merge this entry into mcpServers in ~/Library/Application Support/Claude/claude_desktop_config.json on macOS (or %APPDATA%\Claude\claude_desktop_config.json on Windows), replacing /absolute/path with your checkout location:
{
"mcpServers": {
"three-way-match": {
"command": "node",
"args": ["/absolute/path/mcp-servers/servers/three-way-match/dist/index.js"]
}
}
}Claude Code:
claude mcp add three-way-match -- node /absolute/path/mcp-servers/servers/three-way-match/dist/index.jsCursor: merge the same JSON into .cursor/mcp.json in your project or ~/.cursor/mcp.json. Restart your client, call license_status, then run the example below. A tools/list result alone does not verify matching.
For Claude Desktop, download three-way-match.mcpb and open it to install. SHA-256: 22a7b3fa21624cacd644ab90d62b42c85b7067960dee26efd185dd751a816012. This is a local stdio server; no hosted endpoint is available.
Tools
Tool | Arguments and result |
| PO, receipts, invoice, required |
| Optional |
|
|
|
|
|
|
|
|
| No arguments; offline free/Pro status and checkout link. |
|
|
Input contract
One PO and one current supplier invoice per call. There is no fuzzy matching: SKU, supplier and PO references are exact, case-sensitive strings, with no surrounding whitespace or control characters. Document references and SKUs are 1–120 characters. PO, invoice and receipt document references must be distinct. Duplicate SKUs within a document or within prior_invoiced, and duplicate receipt references, produce invalid; ambiguous rows are excluded from comparison. Repeated SKUs across different receipt documents are expected and accumulate.
Quantities are whole units from 0 to 1,000,000,000; PO and invoice line quantities must be positive. Fractional quantities are rejected. accepted_quantity and rejected_quantity are disjoint counts, not a gross count and its subset. Rejected units never increase the quantity available to invoice. Receipts must carry valid YYYY-MM-DD dates; include only receipts relevant to this check. Dates are evidence, not an automatic invoice-date cutoff.
Every monetary input is an integer minor-unit amount from 0 to Number.MAX_SAFE_INTEGER (9,007,199,254,740,991). For USD, 100 means $1.00; for a zero-decimal currency use its own minor units. Supply the uppercase three-letter currency code on both PO and invoice. No currency conversion or currency-code catalog lookup occurs. Unit prices must match exactly, with no tolerance. Money products and totals use integer arithmetic; unsafe results produce invalid with unsafe_money_arithmetic, never a rounded amount.
invoice.total_minor is the total of the supplied goods lines. There are no implicit tax, freight, discount, rounding or credit adjustments. Represent agreed charges as explicit priced PO/invoice SKUs and appropriate receipt evidence, or prepare an excluding-adjustments goods total before calling. Do not supply an all-in invoice total while omitting its adjustments.
prior_invoiced is required, even when empty. Supply the complete cumulative quantities previously billed for each SKU against this PO, excluding this current invoice. [] explicitly asserts none. Current plus prior quantities must fit both accepted receipts and the PO. Saving reports does not update this history or detect repeated invoice references across checks; incorrect or omitted history can allow repeat billing to go undetected. Reports are evidence snapshots, not an accounting ledger.
Bounds apply equally to free and Pro: 1–500 PO lines, 1–500 invoice lines, up to 500 prior SKUs, and up to 100 receipts of 1–500 lines each. An empty receipts array is valid and produces missing-receipt exceptions for billed PO SKUs. Empty or malformed references, blank/missing SKUs, decimals, unsafe input numbers and invalid dates are rejected as input errors. Unknown SKUs are explicit unordered_sku exceptions.
Equal totals can hide SKU errors
Call three_way_match with:
{
"po": {
"reference": "PO-1", "supplier": "Supply Co", "currency": "USD",
"lines": [
{"sku": "A", "quantity": 10, "unit_price_minor": 100},
{"sku": "B", "quantity": 10, "unit_price_minor": 100}
]
},
"receipts": [{
"reference": "GR-1", "po_reference": "PO-1", "supplier": "Supply Co", "date": "2026-10-16",
"lines": [
{"sku": "A", "accepted_quantity": 5, "rejected_quantity": 0},
{"sku": "B", "accepted_quantity": 15, "rejected_quantity": 0}
]
}],
"invoice": {
"reference": "INV-1", "po_reference": "PO-1", "supplier": "Supply Co", "currency": "USD",
"lines": [
{"sku": "A", "quantity": 10, "unit_price_minor": 100},
{"sku": "B", "quantity": 10, "unit_price_minor": 100}
],
"total_minor": 2000
},
"prior_invoiced": [],
"save": false
}The report has status: "exceptions", despite equal 2,000-minor-unit PO/invoice totals and equal aggregate quantities. SKU A has invoiced_above_accepted (10 billed, 5 accepted); SKU B has accepted_above_order (15 accepted, 10 ordered). Changing invoice unit prices to 90 for A and 110 for B also preserves the grand total but produces two unit_price_mismatch issues.
Partial deliveries can match
Using the same PO, supply a receipt containing only A with accepted_quantity: 4, rejected_quantity: 2. Invoice only A with quantity: 4, unit_price_minor: 100, total_minor: 400, and keep prior_invoiced: []. This returns matched. A has six units still undelivered; B need not appear on this partial invoice. A second matching receipt adds its accepted quantity; rejected quantities remain separate evidence. After previously billing two A units, supply prior_invoiced: [{"sku":"A","quantity":2}] and bill at most two more against those four accepted units.
Reading the report
matched means the supplied evidence passes these exact checks; it does not authorize payment. exceptions identifies document mismatches, unknown SKUs, missing receipts, excessive accepted/billed quantities, price differences or an inconsistent declared invoice total. invalid identifies ambiguity or unsafe computed money; resolve it before interpreting the comparison. Mismatched receipt PO/supplier references are flagged and those receipts do not support billing.
Every issue has code, severity, source, optional sku, and a concrete message. Each sorted SKU row includes PO/invoice one-based source line numbers; ordered, accepted, rejected, prior and current invoice quantities; both unit prices; cumulative billed quantity; available quantity before this invoice; remaining undelivered quantity; receipt references/line numbers and inclusion flags; and issue codes. The report retains the complete supplied documents, so a duplicate row never disappears from the audit evidence. Partial shortages are shown as remaining quantities and do not themselves fail a supported partial invoice.
Small reports return inline. A report whose escaped MCP response would exceed 8 MiB returns an explicit paginated: true overview with status, totals, counts, source document headers and report_id. All evidence remains free through report_page. Select section from issues, lines, po_lines, invoice_lines, prior_invoiced, receipts, receipt_lines or line_receipts; use offset (default 0) and limit (default 100, maximum 100), following next_offset until null. lines pages contain scalar evidence and receipt_count; get those receipt entries with line_receipts and the exact sku. receipt_lines requires the zero-based receipt_index from the original receipt array. receipts pages contain document headers and line counts. Together these sections preserve every source row and every computed issue.
Saved reports use their persistent UUID for pages, and report_get returns the same bounded overview for large saved reports. Large unsaved reports, including save-cap and storage failures, use preview:<UUID> IDs: the process keeps its last two large previews for 30 minutes. Restart, expiry or a third preview can evict them; resubmit the original diagnostic to recreate the free preview. Preview IDs belong to the current running server process. The underlying SDK also limits incoming stdio messages to 10 MiB; encoded requests must fit that transport limit even when individual row counts fit the schema.
CSV includes one row per SKU, exact minor-unit prices, quantities and line issue codes; document issues remain in the accompanying JSON and full report. CSV is returned as text, not written to an arbitrary caller-supplied path. Formula-like leading characters are escaped for spreadsheet use.
CSV exports that fit the same 8 MiB response budget stay inline. Larger exports return a first chunk of up to 1,000 rows with paginated, offset, returned, total_rows and next_offset. Pass that next_offset as offset in another report_export_csv call; optional limit is 1–1,000. Every chunk repeats the header; retain one header when combining chunks.
Free and Pro
Capability | Free | Pro |
Full diagnostic checks and source evidence | All checks, up to 500 PO/invoice lines | Same |
Receipts and prior invoice checks | Same documented bounds | Same |
Saved reports | 3 at a time | No report-count cap |
List/get/delete and CSV export | Included | Included |
When save: true hits the free cap, the full report is still returned with saved: false, save_error: "free_saved_report_cap" and the checkout link. A storage error likewise preserves the diagnostic report. Delete an old saved report to reuse a free slot. A saved report file is limited to 64 MiB when saved and read; this is a storage integrity guard, not a Pro limit.
Get Pro: $19 one time. All servers: $39 bundle. Activate the key with license_activate or set MCP_LICENSE_KEY. Keys verify offline.
All data stays local. Matching makes no network requests. Saved JSON reports live under ${XDG_DATA_HOME:-~/.local/share}/mcp-servers/three-way-match/; XDG_DATA_HOME must be absolute and the storage directory ancestry must not contain symlinks. Files use atomic rename and mutations share a cross-process lock. Reports include commercial document data: manage local access and backups accordingly. License activation writes the shared local license config.
Development
npm run build --workspace @theluckystrike/mcp-three-way-match
npm test --workspace @theluckystrike/mcp-three-way-matchTests exercise offsetting quantity/price errors, rejected and multiple receipts, partials, explicit prior billing, unknown and duplicate SKUs/references, currency/PO/supplier mismatches, dates, integer boundaries, free/Pro save policy, atomic storage and an MCP stdio initialization/tools/call round trip. Docker builds from the repository root with docker build -f servers/three-way-match/Dockerfile ..
Available Tools
8 toolslicense_activateActivate licenseA
Activate a Pro key (MCPL1.xxx.yyy) from checkout: verified offline against a built-in public key, saved to your config file. A wrong, malformed or expired key is refused, unsaved. license_status reads it back.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | License key from the checkout confirmation page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It discloses that verification happens offline against a built-in public key, that the key is persisted to the config file, and that invalid keys are refused and left unsaved. This is substantial transparency for an activation tool, though it could mention overwriting an existing key or the exact return behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The first sentence front-loads the main action, source, verification method, and persistence. The second sentence efficiently covers error handling and points to the related read-back tool. Every clause adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a single-parameter tool with no output schema and no annotations, the description covers activation behavior, verification mechanism, persistence, error outcomes, and how to read the result later. The only minor gap is an explicit statement of what the function returns upon success or failure, but the phrase 'refused, unsaved' implies a feedback mechanism. Overall, it is sufficiently complete for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents the 'key' parameter at 100% coverage, so the baseline is 3. The description adds meaningful semantics by giving the concrete key format ('MCPL1.xxx.yyy'), confirming the key comes from the checkout page, and explaining that malformed or expired keys will be rejected. This goes beyond the schema's one-line description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Activate a Pro key'), the exact key format ('MCPL1.xxx.yyy'), the source ('from checkout'), and the core mechanism ('verified offline against a built-in public key'). It also differentiates itself from the sibling license_status by noting that license_status reads the activation back, so there is no ambiguity about which tool does what.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: use this when you have a Pro key from checkout that needs to be activated. It also points to license_status as the read-back tool, which implies when to use a related sibling. It does not explicitly spell out 'do not use for checking status' or list other alternatives, but the context is strong enough to avoid misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
license_statusLicense statusA
Report this server's licence state: product, tier free or pro, licence id, expiry, the key source and the upgrade URL. No arguments, no network. Explains a free-tier refusal; license_activate installs a key.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are absent, so the description carries the full burden of behavioral disclosure. It discloses that the call is local ('no network') and argument-free, and it mentions a specific explanatory behavior. The word 'Report' implies read-only, though it does not explicitly state non-destructive or permission requirements; this is adequate for a status command.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The first sentence lists the output fields; the second adds constraints and the sibling pointer. Every clause contributes meaningful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter status tool with no output schema, the description lists the expected output fields, behavioral constraints, and the relevant alternative tool. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has zero parameters and the description reinforces this with 'No arguments'. It adds value by listing the reported fields, helping an agent understand what the empty input will yield. The baseline for zero-parameter tools is high, and the description meets it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Report'), a clear resource ('this server's licence state'), and enumerates the exact fields returned. It also names the sibling 'license_activate' as the tool that does something different, so an agent can distinguish them immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage constraints: no arguments, no network, and explains a free-tier refusal. It also directs the agent to license_activate when the task is to install a key, serving as an explicit pointer to the relevant alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_deleteDelete a saved matching reportADestructive
Delete one saved report by id, freeing a free-tier storage slot. Does not alter source documents or prior invoice history.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Saved UUID from report_list or three_way_match |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false. The description adds real value beyond them by scoping the blast radius: it does not alter source documents or prior invoice history, and it consumes/releases a free-tier storage slot. It still omits whether deletion is reversible and what happens on a repeat delete of the same id.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the core action first and the side-effect negation second. Nothing could be cut without losing signal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive tool with no output schema, the description covers the key non-effects and the quota consequence, which is most of what an agent needs. Minor gaps remain around reversibility and error behavior, but annotations carry the mutation profile.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With a single parameter at 100% schema coverage, the schema already documents the UUID format and points to report_list/three_way_match as sources. The description's 'by id' adds nothing the schema does not, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (delete) and resource (a saved report, by id), which cleanly separates it from siblings like report_list, report_get, and report_export_csv. It does not explicitly name which sibling is the alternative, but the resource scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It hints at why one would call it ('freeing a free-tier storage slot'), which implies the use case, but there is no explicit when-to-use versus when-not, no mention of alternatives (e.g. report_get to inspect before deleting), and no prerequisite or confirmation guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_export_csvExport saved report line evidence as CSVARead-onlyIdempotent
Return CSV of saved SKU quantities, prices and issues. Large CSVs paginate; follow next_offset with offset. Formula-like text is escaped. Full source evidence uses report_get/report_page.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Saved UUID from report_list or three_way_match | |
| limit | No | ||
| offset | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds genuine behavior: large outputs paginate, how to continue via next_offset/offset, and that formula-like text is escaped (CSV-injection handling). It even hints at the return field next_offset despite no output schema, though it does not describe rate limits or the CSV shape further.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short, front-loaded sentences with no filler; the return content comes first, then pagination, then routing. Efficient, though the pagination and escaping details are dense shorthand.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only tool with no output schema, the description covers what is returned (CSV of quantities, prices, issues), pagination mechanics, escaping, and where to go for full evidence. The missing piece is limit semantics, which leaves a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is only 33% (id documented, limit and offset bare). The description clarifies offset usage by tying it to next_offset pagination, adding meaning for one of the undocumented params, but limit's role/bounds are never explained in prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return CSV of saved SKU quantities, prices and issues') and names the alternative path ('Full source evidence uses report_get/report_page'). An agent can distinguish this export tool from report_get/report_page/report_list without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Routes the agent: use this for CSV of SKU quantities/prices/issues, use report_get/report_page when full source evidence is needed. It gives the alternative and condition, but does not state explicit when-not cases or prerequisites for this tool beyond that.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_getGet a saved matching reportARead-onlyIdempotent
Read a saved report with source documents, per-SKU evidence and all exceptions. Free on both tiers.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Saved UUID from report_list or three_way_match |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and a closed world, so the safety profile is covered. The description adds genuinely new behavioral context: the cost model ("Free on both tiers") and the scope of what is returned, which matters because there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with the action and payload scope front-loaded; nothing is buried. The trailing pricing sentence is slightly tangential but is short and still actionable for a cost-aware agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with full annotations and no output schema, the description adequately covers what comes back. The main gap is routing versus sibling report_* tools, which is a usage-guideline concern rather than a completeness failure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single id parameter, including its UUID pattern and provenance ("Saved UUID from report_list or three_way_match"). The description adds nothing beyond that, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (read) and resource (saved report) and enumerates the payload contents: source documents, per-SKU evidence and all exceptions. That is enough for an agent to distinguish it from report_list or report_delete, though it never explicitly contrasts itself with the closer siblings report_page and report_export_csv.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no when-to-use guidance: no conditions selecting it over report_list, report_page, or report_export_csv, and no note that the id must first come from report_list or three_way_match (that hint lives only in the schema). "Free on both tiers" is a cost note, not routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_listList saved matching reportsBRead-onlyIdempotent
List saved report ids, timestamps, document references, status and issue counts. Free on both tiers; paginated, up to 100 reports per call.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| offset | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral context beyond that: it is free on both tiers and is paginated with a 100-report ceiling per call, which matters for call planning.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with no filler, and the return-content information is front-loaded before the pagination caveat. Slightly more could be trimmed, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates the fields returned, and the annotations cover the read-only safety profile. It is missing offset/default-limit semantics and any indication of how total result count is surfaced, but for a simple two-parameter read tool this is largely sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry parameter meaning, and it only partially does. 'Up to 100 reports per call' communicates the limit ceiling, but the offset parameter, the default limit of 20, and the interaction between the two are left entirely to schema inference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (saved reports) and enumerates the returned fields (ids, timestamps, document references, status, issue counts), which tells an agent exactly what comes back. It does not distinguish itself from siblings like report_page or report_export_csv, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance and no mention of alternatives such as report_get, report_page, or report_export_csv. The only contextual hint is the pricing note ('Free on both tiers'), which is not selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_pageRead a page of complete matching evidenceBRead-onlyIdempotent
Read free pages of large report issues, SKU rows or original source rows. Use report_id from the paginated overview. Unsaved previews expire after 30 minutes and keep only the last two large checks.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| sku | No | ||
| limit | No | ||
| offset | No | ||
| section | Yes | ||
| receipt_index | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safe read-only, idempotent profile, so the description earns credit for adding behavior they cannot express: unsaved previews expire after 30 minutes and only the last two large checks are retained. That is real operational context an agent could not infer elsewhere.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the core action and followed by the prerequisite and the retention caveat. Slightly awkward phrasing ("free pages", "last two large checks") costs it the top mark but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description never explains what a page returns or how pagination works (limit caps at 100, offset semantics), which matters for a paging tool. It does cover preview expiry, so it is adequate but leaves notable gaps for a 6-parameter reader.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 6 parameters, so the description carries the full burden. It loosely covers `id` and hints at `section`/`sku` ("report issues, SKU rows or original source rows") but says nothing about limit, offset, or receipt_index, leaving half the parameter surface undocumented in both schema and prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource (read pages of large report issues, SKU rows, or source rows) and roughly maps onto the section enum values. It does not, however, distinguish itself from siblings like report_get or report_list, which is the main gap.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Use report_id from the paginated overview" points the agent at a prerequisite source, which is useful, but it names the field as report_id while the schema parameter is `id`, and it never says when to use report_page versus report_get or report_list. Usage is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
three_way_matchMatch PO, goods receipts and supplier invoiceB
Compare up to 500 PO/invoice lines by exact SKU, accepted receipts and prior billed quantities. Returns source evidence and exceptions, including offsetting errors. All diagnosis is free; save optionally.
| Name | Required | Description | Default |
|---|---|---|---|
| po | Yes | ||
| save | No | ||
| invoice | Yes | ||
| receipts | Yes | ||
| prior_invoiced | Yes | Cumulative previously invoiced whole units, excluding this invoice; [] explicitly asserts none. Caller must supply complete history. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false and idempotentHint=false, so the agent needs to know what the write actually is; the description only offers 'save optionally' without saying what gets persisted or where. It does add genuinely useful behavior beyond annotations — the 500-line comparison cap, the return of source evidence and exceptions, and that offsetting errors are surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences with no filler; the comparison scope is front-loaded, followed by return behavior. Only 'All diagnosis is free' leans toward promotional phrasing rather than operational detail.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a deeply nested, 5-parameter tool with no output schema and 20% schema coverage, the description leaves major questions unanswered: what save=true creates, how currency/supplier/reference mismatches are handled, and what 'offsetting errors' means as a matching rule. It gives a useful sketch of inputs and outputs but is not complete enough for confident invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 20%, so the description must compensate, and it does partially: it names the inputs conceptually (PO lines, accepted receipts, prior billed quantities) and adds the matching rule that comparison is by exact SKU on accepted quantities. It adds no format or structural guidance for po_reference, supplier, currency, totals, or the save flag, leaving significant gaps.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Compare) over specific resources (PO/invoice lines, accepted receipts, prior billed quantities) and names the matching key (exact SKU). An agent knows exactly what the tool computes, though the sibling report_* tools are unrelated so no differentiation is needed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The line 'All diagnosis is free; save optionally' implies a diagnose-then-optionally-persist workflow and nudges the agent toward the default non-saving call, but it never states when saving is appropriate or what conditions warrant it. Usage is implied rather than prescribed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.22.6- First observed
license_activate - First observed
license_status - First observed
report_delete - First observed
report_export_csv - First observed
report_get - First observed
report_list - First observed
report_page - First observed
three_way_match
TDQS
Scored across 8 tools
Most tools have clearly distinct actions (list, get, delete, page, export) and the core three_way_match is unique. However, report_get and report_page both read report content, and report_export_csv partially overlaps with report_get, which could cause mild hesitation.
The set predominantly follows a snake_case noun_verb pattern (report_list, report_get, license_activate). The standalone three_way_match and noun-style license_status are minor deviations from the otherwise consistent prefix-action convention.
Eight tools is well within the ideal 3-15 range and each tool serves a clear purpose: core matching, report lifecycle, pagination/export, and licensing. No tool feels redundant or excessive.
The surface covers the full lifecycle: matching (three_way_match with optional save), report listing/reading/pagination/export/deletion, and license status/activation. No critical gaps for the stated domain.
Maintenance
Related MCP Connectors
Mechanically reconcile supplied purchase-order lines, invoice lines and goods receipts under expl...
Receipt extraction, invoice-to-PO quantity allocation, and free three-document discrepancy checks.
Evidence-backed UBL, PDF, and image invoice checks before approval or payment.
Reconcile business documents, inspect exact differences and evidence, and export reports.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI-powered invoice analysis and reasoning: given invoice fields, it detects missing data, inconsistencies, duplicates, and proposes actions (register, request data, mark duplicate, review) using deterministic rules.-
- FlicenseNot gradedqualityDmaintenanceEnables querying procurement documents (invoices, purchase orders, shipping orders, inventory reports) via semantic search, order ID lookups, gap analysis, and source excerpt retrieval.-
- FlicenseNot gradedqualityDmaintenanceSelf-serve MCPB demo for accounts payable invoice exception review. It performs deterministic matching across invoice, purchase order, goods receipt, vendor master, invoice history, tax code master, and payment rules.-
- FlicenseNot gradedqualityCmaintenanceEnables accounts payable teams to extract invoice data from PDFs and images, detect duplicates, normalize vendor names, calculate payment terms, and validate invoice completeness. Supports local extraction for text PDFs and optional vision providers for scanned documents.-