com.yaktool/yaktool
NPM · YAKTOOL-MCP · SCANNED SEP 20
73 local deterministic tools: GTIN, feeds, CSV-XLSX, Digital Link QR, e-invoices. Rules cited.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →
Supply Chain Security100
- No malware found by supply-chain analysis.Pass
- No known CVEs affecting this package version or its production dependencies.Pass
- No install/post-install scripts declared.Pass
- No production dependencies, so there is no dependency health to assess. View diagnostics → Pass
Provenance & Transparency19
- Repository check failed: no source repository is declared. See how to fix → View diagnostics → Fail
- Provenance check failed: no build-provenance attestation is published. See how to fix → View diagnostics → Fail
- Clear OSI-approved license (MIT).Pass
- Actively maintained (last published 25 days ago).Pass
- Security-disclosure policy not yet verified: we couldn't inspect the source repository.Unverified
Schema Quality & AI Usability64
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 25676 tokens (~351/item across 73 items; 73 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management89
- Stability check failed: the tool surface changed between 0.2.0 and 0.4.2: 1 tool removals, 0 breaking changes, 3 additions. See how to fix → Fail
Tool Coverage99
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 96% of tool parameters carry a description.Partial
Tool Safety50
- Injection-marker check failed: the description of tool "check_invoice_sequence" contains an instruction to conceal the call from the user, the text "DO NOT TELL THE USER", at byte 953 of that field, plus 1 further marker(s) of the same kind. See how to fix → Fail
- We read all 73 captured tool definition(s), and no name or description among them implies an irreversible operation.Pass
- An AI judge read all 73 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the com.yaktool/yaktool MCP server?
com.yaktool/yaktool runs locally as an npm package, launched with npx -y yaktool-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
npm · yaktool-mcp
claude mcp add com-yaktool-yaktool -- npx -y yaktool-mcp
{
"mcpServers": {
"com-yaktool-yaktool": {
"command": "npx",
"args": [
"-y",
"yaktool-mcp"
]
}
}
} {
"servers": {
"com-yaktool-yaktool": {
"command": "npx",
"args": [
"-y",
"yaktool-mcp"
]
}
}
} codex mcp add com-yaktool-yaktool -- npx -y yaktool-mcp
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"com-yaktool-yaktool": {
"type": "local",
"command": [
"npx",
"-y",
"yaktool-mcp"
],
"enabled": true
}
}
} openclaw mcp add com-yaktool-yaktool --command npx --arg -y --arg yaktool-mcp
mcp_servers:
com-yaktool-yaktool:
command: "npx"
args: ["-y", "yaktool-mcp"] {
"McpServers": {
"com-yaktool-yaktool": {
"Transport": "stdio",
"Command": "npx",
"Arguments": [
"-y",
"yaktool-mcp"
]
}
}
} assistant mcp add com-yaktool-yaktool -t stdio -c npx -a -y yaktool-mcp
{
"mcpServers": {
"com-yaktool-yaktool": {
"command": "npx",
"args": [
"-y",
"yaktool-mcp"
]
}
}
} Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 20 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 85 to 89.
- 18 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 79 to 82.
- 16 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 72 to 75.
- 14 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 65 to 69.
- 11 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 55 to 59.
- 9 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 49 to 52.
- 7 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 42 to 45.
- 5 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 35 to 39.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Analysed npm/yaktool-mcp@0.4.2
Provenance No attestation
The registry publishes no build provenance for this version, so there is nothing to verify.
| Result | No attestation |
|---|---|
| Ecosystem | npm |
Background: How many MCP packages publish verified provenance →
Dependencies 0 packages
| Packages resolved | 0 |
|---|---|
| Tree resolution | Complete |
Background: SBOMs and build attestations, explained →
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
analyze_amazon_search_terms Analyze Amazon backend search terms (byte budget + rules) ~368
Check Amazon backend search terms against the UTF-8 BYTE limit (under 250 bytes, i.e. 249 max) and 13 documented rules. CRITICAL for listing-generation agents: the limit is bytes, NOT characters — accented Latin costs 2 bytes per character, CJK 3, emoji 4 — and exceeding it can stop Amazon indexing the ENTIRE field, not just the overflow. Also flags wasted budget (duplicate words, commas as separators, singular+plural pairs, words already in the title), disallowed content (ASINs, subjective claims like "best"), and invisible/full-width characters. Optional `title` enables title-overlap detection; optional `competitorBrands` enables branded-term detection (this tool cannot know every trademark — an empty result is not clearance). Returns { bytes, byteLimit, bytesRemaining, characters, tokens[{text,bytes}], normalized, findings[], ok }. Use `normalized` as the cleaned value to submit. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| byteLimit | integer | – | Override the byte limit for a marketplace with different rules (default 249). |
| competitorBrands | array | – | Brand names that must not appear (e.g. competitor brands). |
| searchTerms | string | – | The backend search terms string, exactly as it would be submitted. |
| title | string | – | Product title, to detect keywords that are already indexed. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
audit_column Find duplicate and inconsistently written values in a column ~345
Audit one column (one value per line, or a CSV first column) for values that are the same thing. Answers in THREE degrees, and the distinction is the point: (1) `identical` — the same string on several rows; in a SKU or id column this is a hard error because the second row either overwrites the first or is rejected. (2) `presentation` — differ only in case, whitespace, full-width characters or invisible characters. The merge is unambiguous, and `normalise_column` applies it. Canonical form is the most-used spelling, or the one written first if they tie. (3) `synonym` — L and Large, Grey and Gray. THESE ARE NEVER MERGED AUTOMATICALLY and you must not merge them on the user's behalf either: in some categories the short and long forms genuinely differ, and applying the merge is a merchandising decision. Present them and ask. The synonym table is deliberately conservative — it holds only pairs that are the same word, and specifically does NOT contain Small/XS, which genuinely differ. Google's size and colour values are RECOMMENDATIONS, not requirements, so word synonym findings as observations, never as errors. Returns { total, distinct, groups[{canonical,variants[{value,lines[]}],basis,collapses}], exactDuplicateLines[], findings[] }, groups sorted by how many distinct values merging would remove.
| Name | Type | Req | Description |
|---|---|---|---|
| column | string | yes | One value per line. |
| normalise | boolean | – | Also return the column with the unambiguous presentation merges applied. |
| skipSynonyms | boolean | – | Turn off synonym suggestions — do this for SKU and id columns. |
No output schema declared.
No examples provided.
audit_media_specs Audit a batch of images and videos against marketplace limits ~368
Given file metadata (name, pixel width and height, byte size, format, kind, optional duration and alpha flag), report which files fail on which platform. THE OUTPUT IS A MATRIX and should be relayed as one: the useful answer before a bulk upload is "6 of these 40 fail on eBay only", not a per-file verdict. `summary` gives the failing count per platform. The same file legitimately passes one marketplace and fails another — a 12.5 MB photo is fine for Google Shopping and over eBay’s limit; a WebP is accepted by Google and eBay and not by Amazon. Do not collapse this into a single pass/fail. METADATA ONLY: this does not look at pixels, so it says nothing about background, crop or how much of the frame the product fills — that is a different tool (check_main_image). VIDEO: a browser can read duration and frame size but NOT the codec, and most platform video specs require a particular codec. Every video result carries MED-V02 saying so; repeat that caveat rather than letting a pass read as "ready to upload". Duration limits vary by platform and programme, so `maxVideoSeconds` is an input — ask the user. Amazon’s values are the general marketplace ones (Seller Central is login-gated and requirements vary by category); Google and eBay values come from their published pages. Returns { files[{file,verdicts[{platform,passes,reasons[],notes[]}],passesAll,findings[]}], summary[{platform,failing,total}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| files | array | yes | Metadata for each file. |
| maxVideoSeconds | number | – | Duration limit for the target placement. |
| platforms | array | – | Limit to these platforms; omit for all. |
No output schema declared.
No examples provided.
build_gs1_digital_link Build a conformant GS1 Digital Link URI from a GTIN ~306
Construct a Digital Link URI that is conformant by construction: the GTIN is padded to the 14 digits v1.4.0 requires, and any key qualifiers are emitted in the order the standard mandates (consumer product variant, then batch/lot, then serial number) regardless of the order you pass them in. Data attributes are placed in the query string, which is where the standard requires them. NOTE: this is the quick, unvalidated builder — it does not verify the check digit, does not validate qualifier character sets, and produces no QR. For a validated build with a refuse-on-error gate, print-size advice and the QR image, use generate_digital_link_qr. Returns { uri } — feed it to check_gs1_digital_link if you want the conformance report as well.
| Name | Type | Req | Description |
|---|---|---|---|
| attributes | object | – | Data attributes as AI → value, e.g. { "17": "261001" }. They go in the query string. |
| cpv | string | – | Consumer product variant, AI 22. |
| gtin | string | yes | The GTIN — 8, 12, 13 or 14 digits; it will be padded to 14. |
| lot | string | – | Batch or lot number, AI 10. |
| serial | string | – | Serial number, AI 21. |
| stem | string | – | Resolver origin and optional path prefix (default https://id.gs1.org). |
No output schema declared.
No examples provided.
build_product_jsonld Generate Product JSON-LD that passes validation ~229
Build a Product JSON-LD block. The price is emitted as a bare number string with the currency in priceCurrency (the shape the specification requires), the currency is upper-cased, and availability defaults to the schema.org URL form rather than free text. If no price is given, `offers` is omitted entirely rather than emitted empty — an empty offer is worse than none. Feed the result to check_product_jsonld to see the report as well. Returns { jsonLd }.
| Name | Type | Req | Description |
|---|---|---|---|
| availability | string | – | InStock, OutOfStock, PreOrder or BackOrder (default InStock). |
| brand | string | – | – |
| gtin | string | – | The barcode; it is validated by check_product_jsonld. |
| image | string | – | Absolute URL. |
| name | string | yes | Product name — required. |
| price | string | – | Bare number, e.g. "19.99". No currency symbol, no comma. |
| priceCurrency | string | – | Three-letter ISO 4217 code. |
| sku | string | – | – |
| url | string | – | – |
No output schema declared.
No examples provided.
build_utm_url Build a correctly tagged campaign URL ~175
Construct a campaign URL with the required parameters. Values are lower-cased and spaces become hyphens by default, because parameter values are case sensitive and that is the only habit that keeps one channel from splitting into several rows. Returns { uri } — feed it to check_utm if you also want the report.
| Name | Type | Req | Description |
|---|---|---|---|
| campaign | string | yes | utm_campaign — the campaign name. |
| content | string | – | utm_content — creative variant. |
| id | string | – | utm_id — campaign id. |
| medium | string | yes | utm_medium — the channel type, e.g. cpc, email. |
| source | string | yes | utm_source — where the traffic comes from. |
| term | string | – | utm_term — paid keyword. |
| url | string | yes | The landing page URL. |
No output schema declared.
No examples provided.
calculate_check_digit Calculate / complete a GTIN check digit ~289
Compute the GS1 Mod-10 check digit for a GTIN payload and return the completed code with the full step-by-step working (digits × 3/1 weights → sum → next multiple of ten). Length semantics (ambiguity is made explicit, never guessed): 7/11 digits → completed as GTIN-8/GTIN-12; 12/13 digits → BOTH interpretations returned (payload to complete AND already-complete code to verify), payload first; 8/14 digits → verify-only (the value already contains a check digit — use validate_gtin for full validation). Input cleaning (Excel damage, separators, full-width digits) matches validate_gtin. Returns { input, normalized, findings, interpretations[{kind: "payload"|"complete", ...}] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | – | Digits to complete (7/11/12/13, without check digit) or a complete GTIN to verify — raw, uncleaned. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
calculate_dim_weight Dimensional weight and the break-even box size ~447
Compute dimensional (volumetric) weight across divisors and, more usefully, the BREAK-EVEN box size at which volume stops setting the price. LEAD WITH THE BREAK-EVEN, not the dimensional weight. A carrier calculator already answers "what does this parcel weigh dimensionally"; what a person packing goods needs is "how small does the box have to be" — `breakEvenScale` is the factor on the current linear dimensions, so multiply the longest side by it to get an actionable target. Carriers round EACH SIDE up to a whole unit before multiplying, then round the result up. `dimensionalRounded` does that; `dimensionalPlain` is the multiply-then-round-once figure most online calculators use, and it is smaller. Quote the rounded one. THE DIVISOR IS NOT VERIFIED DATA. It varies by carrier, service, destination and contract, and negotiated accounts often have their own. This project could not verify the published values by automated request on 2026-08-23 (UPS refused the connection, FedEx serves the figure only via JavaScript, DHL returned 403). Present presets as a starting point and ask the user for the divisor on their rate card — pass it as `customDivisor` and only that is used. Never present the output as a shipping quote. Divisors are unit-specific: 139 and 166 are inches/pounds, 5000 and 6000 are centimetres/kilograms. Mismatched presets are SKIPPED rather than computed, because feeding centimetres into 139 gives an answer wrong by an order of magnitude that looks entirely plausible. Returns { readings[{preset,dimensionalRounded,dimensionalPlain,billable,volumetric,breakEvenScale}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| actualWeight | number | yes | – |
| customDivisor | number | – | The divisor from the user’s own rate card; overrides all presets. |
| dimUnit | string | yes | Unit the dimensions are in. |
| height | number | yes | – |
| length | number | yes | – |
| massUnit | string | yes | Unit the weight is in. |
| width | number | yes | – |
No output schema declared.
No examples provided.
check_colour_space Check whether an image is CMYK, RGB, greyscale or indexed ~307
Read the colour space out of a JPEG or PNG header supplied as base64. Only the header is needed, so send the FIRST 64 KB rather than the whole file. THE FINDING THAT MATTERS: a CMYK JPEG. It looks completely normal in every viewer — nothing is visibly wrong — and marketplaces then reject it or display the colours inverted. Files that came from print artwork are the usual source, and converting the file format does not convert the colour model. If `colourSpace` is "CMYK" or "YCCK", tell the user to re-export as RGB before uploading anywhere. Detection is from the JPEG frame header (component count: 1 greyscale, 3 colour, 4 CMYK) and the Adobe APP14 transform byte, or from the PNG IHDR colour-type byte. No pixels are decoded. PNG has no CMYK at all, so never report one for a PNG; PNG problems are different — an indexed palette bands on product photography, and an alpha channel is composited against different backgrounds on different platforms. This says what colour model the file DECLARES, not whether the colours are right, and not whether the background is white — that needs pixel measurement. Returns { format, colourSpace, components?, bitDepth?, hasAlpha, iccProfileBytes?, adobeTransform?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| imageBase64 | string | yes | The first part of the image file as base64. 64 KB is more than enough. |
No output schema declared.
No examples provided.
check_compliance_statement Check Prop 65, allergen and CE/UKCA/FCC statement wording ~433
Check the WORDING of a statement that law prescribes, element by element. Set `kind`. NOT LEGAL ADVICE, and it cannot tell you whether a statement is REQUIRED — that depends on formulation, exposure and jurisdiction, none of which text reveals. Say this when you report results. THE THREE KINDS DIFFER IN HOW CERTAIN THEY ARE, so report them differently: prop65 — the regulation (27 CCR §25603) fixes near-verbatim text, so all four elements (signal word, named chemical, the harm it is listed for, www.P65Warnings.ca.gov) are checked separately. Report WHICH element is missing: dropping the URL and dropping the chemical name are different mistakes. The yellow triangle symbol is a GRAPHIC requirement that no text check can see — mention it, but never fail text for it. allergen — the nine major US allergens are statutory (milk, eggs, fish, Crustacean shellfish, tree nuts, peanuts, wheat, soybeans, sesame), but whether a product must declare one is not checkable here. Watch for ALG-S01: sesame became the ninth allergen after most label templates were written, and those templates still circulate — this is the most common way a careful allergen statement is now out of date. Also: "may contain" is a VOLUNTARY advisory and does not substitute for the Contains declaration. marking — CE, UKCA and FCC are NOT text problems. They are declarations that conformity assessment was completed and a technical file exists. No wording change can create one, and claiming a marking the product does not hold is an offence. Never help a user reword their way into a marking claim; ask for the directive, standard or FCC ID instead. CE does not imply UKCA or the reverse. Returns { kind, elements[{name,present,found?,expected}], complete, findings[] }. `expected` is copy-ready text for a missing element.
| Name | Type | Req | Description |
|---|---|---|---|
| kind | string | yes | Which kind of statement this is. |
| statement | string | yes | The statement text as it appears on the listing or label. |
No output schema declared.
No examples provided.
check_country_code Check or convert an ISO 3166-1 country code ~406
Resolve a country identifier and classify it. THE TRAP: **UK is not a country code.** It is not in the registry at all — ISO 3166-1 assigns GB — and it is the most common reason a country column is rejected. Never emit UK; if a user writes it, correct it to GB. Returns `status` with five distinct values, which need different handling: "assigned" (an ordinary country code, safe for a feed), "special" (registered but not a country — EU, UN, EZ, AC; feeds reject these), "private-use" (AA/ZZ, an escaped internal placeholder), "deprecated" (withdrawn; `suggestion` names the successor when the registry does, and is ABSENT when the territory split into several — do not invent one), and "unknown" (not in the registry). Also converts other forms: alpha-3 (DEU), numeric (276, and 8 for a code whose leading zeros a spreadsheet ate), and country names in either the IANA or UN wording. Data is generated from the IANA Language Subtag Registry joined to the UN M49 list and cross-checked against ICU. Note TW is a valid ISO code but absent from the UN list, so its alpha-3 and numeric fields are empty rather than guessed. Returns { input, normalized, status, entry?, suggestion?{code,reason}, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | – | The country code, alpha-3, numeric code or country name, as written. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
check_creditor_reference Check an ISO 11649 RF creditor reference ~356
Validate an RF creditor reference — the structured payment reference on European invoices — by its ISO 7064 MOD 97-10 check digit, the same checksum IBAN uses. A VALID REFERENCE IS NOT A MATCHED PAYMENT. The check digit proves the reference was copied without a slip; it does not mean the reference exists in a creditor's system or that a payment will reconcile. Never tell a user their payment will be matched — this is a structural check, not a lookup. IT IS NOT AN IBAN. RF references and IBANs share the checksum and both open with two letters plus two check digits, which is exactly why they get confused. An RF reference identifies a payment, starts with the literal letters RF and is at most 25 characters; do not route it to IBAN validation. SOURCING: ISO 11649 is a paid standard and is not reproduced; the checksum is public ISO 7064 MOD 97-10, self-proved against the standard's published example RF18 5390 0754 7034. When the check digits are wrong, `expectedCheckDigits` gives the correct pair — but relay the advice to re-read the source, since the error may be in the reference body, not the check digits. BULK: pass `values` (an array, max 1000) instead of `value` to check a column in one call; the result is then { rows, summary }. Returns { input, normalized?, valid, reference?, expectedCheckDigits?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | – | The RF reference. Spaces and lower case are normalised away. |
| values | array | – | Bulk form: one reference per array element. |
No output schema declared.
No examples provided.
check_date_format Check a date for ambiguity, or decode a spreadsheet serial ~401
Decide what a date value actually says, and whether it says more than one thing. THE TRAP THIS EXISTS FOR: when both components are 12 or lower, "01/02/2026" is 1 February in most of the world and 2 January in the United States — a month apart, and no parser errors on it. When that happens `ambiguous` is true and EVERY reading is returned in `readings` with its weekday; do NOT pick one silently, surface the ambiguity to the user. Also decodes values that are dates in disguise: a bare number in the spreadsheet serial range (45658 is 1 January 2025), where serial 60 is the non-existent 29 February 1900 that spreadsheets deliberately reproduce, and the legacy 1904 Mac epoch puts the same serial 1462 days away; and 10- or 13-digit Unix timestamps. Validates impossible dates against the full Gregorian leap rule, flags two-digit years and separator-less compact dates, checks Merchant Center date ranges (start/end) including ranges that end before they start, and warns when a time carries no zone — Merchant Center does NOT simply assume UTC there, it uses the target country default for text/XML feeds and UTC only for the API. Returns { input, kind, readings[{convention,iso,spelled,weekday}], ambiguous, iso?, time?, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | – | The date as written — any format, including a bare serial number or a start/end range. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
check_description_html Check product description HTML for what a marketplace will strip ~308
Check the HTML of a product description against the things that go wrong on every marketplace. THE TRAP: active content is removed SILENTLY. eBay's wording is that JavaScript, Flash, plug-ins and form actions are "no longer displayed in listings" — not rejected, not reported, just absent, so the seller sees a description with a hole in it and no explanation anywhere. Scripts, iframes, forms, embeds and INLINE EVENT HANDLERS (onclick, onerror) all go. The event handlers matter most because they hide inside otherwise ordinary elements and survive a copy-paste from a site template. SECOND TRAP: an unclosed tag rarely damages the description — it damages the page AROUND it, because the marketplace template inherits the open element, so the symptom appears far from the cause. `sanitised` removes only the active content. Styles, links and tables are REPORTED AND LEFT ALONE: whether to keep them depends on the layout, and deleting a seller's formatting automatically would be its own silent failure. Do not strip those on the user's behalf either. This does NOT know each marketplace's exact allowed-tag list — Amazon's lives behind a Seller Central login. It checks what goes wrong everywhere. Returns { input, tags[], spans[{start,end,tag,ruleId}], textLength, sanitised?, findings[] }. Spans use code-point offsets.
| Name | Type | Req | Description |
|---|---|---|---|
| html | string | yes | The description HTML, exactly as it would be submitted. |
No output schema declared.
No examples provided.
check_email_template Check email merge fields before a send ~307
Find merge fields in an email template and report the three failures that get noticed after the send. TPL-U01 (unclosed field) is the expensive one: the fragment goes out literally to every recipient, and in an editor it looks nearly right. TPL-X01 means two merge syntaxes are present — Mailchimp *|FIELD|* alongside {{field}}, say — which is almost always a block pasted from a template built on another platform, and one of the two will not be replaced. TPL-F01 is NOT a syntax error: "Hi {{first_name}}," is perfectly valid and renders as "Hi ," for every recipient with a blank record, and there are always some. When you report it, show the user what the empty case reads like rather than quoting the rule. Recognises *|FIELD|*, {{ field }}, %%FIELD%%, ${field} and [FIELD], reads fallbacks (*|FNAME:there|*, {{ x | default: "y" }}), and counts delimiter balance PER SYNTAX so one platform’s markers are not mistaken for another’s unclosed field. These are this project’s own engineering rules — no email platform publishes a formal grammar for merge fields. Say so rather than presenting them as a standard. Returns { variables[{raw,name,syntax,start,end,fallback?}], syntaxes[], unclosed[], findings[] }; offsets are code points.
| Name | Type | Req | Description |
|---|---|---|---|
| template | string | yes | The email template text or HTML. |
No output schema declared.
No examples provided.
check_gs1_digital_link Check a GS1 Digital Link URI against the current standard ~336
Parse a GS1 Digital Link URI, report every conformance problem, and return the corrected URI in `corrected`. TWO RECENT CHANGES INVALIDATED MOST EXISTING URIS, and neither makes the URI look wrong — do NOT assume an older URI is fine: (1) convenience alphabetic names such as /gtin/ were deprecated in v1.2 and REMOVED COMPLETELY in v1.3.0, so they are non-conformant, not merely discouraged; (2) as of v1.4.0 the GTIN must be expressed with 14 digits — a GTIN-8/12/13 needs leading-zero padding, even though the code and its check digit are unchanged. Also enforces: the path grammar of all sixteen primary keys (01 GTIN, 00 SSCC, 414 GLN, 8006 ITIP and the rest), key qualifier ORDER (for a GTIN: 22 then 10 then 21 — the standard gives the reversed form as an explicit counter-example), qualifiers that are required rather than optional (415 needs 8020), the GS1 Mod-10 check digit, and the rule that data attributes SHALL live in the query string rather than the path. Compressed URIs are detected but NOT decoded — compression is a separate GS1 standard; the result says so instead of guessing. Returns { input, stem?, primary?, qualifiers[], attributes[], segments[], corrected?, conformant, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| uri | string | yes | The Digital Link URI exactly as it appears, including the scheme if present. |
No output schema declared.
No examples provided.
check_hreflang Check hreflang annotations and produce the block every page must carry ~339
Validate a set of hreflang annotations. THE TRAP: invalid annotations are IGNORED SILENTLY by search engines — no error, no warning, nothing in any report. "en-UK" is the classic case: UK is not an ISO 3166-1 region code (the United Kingdom is GB), so the annotation is thrown away and the targeting simply does not happen. Never emit en-UK. Rules enforced: language must be ISO 639-1 and region ISO 3166-1 alpha-2 (validated against the IANA registry); a country code alone is NOT valid because the language is never inferred from the country; underscores are not hyphens; each set must reference its own page; no value may point at two URLs. THE USEFUL OUTPUT is `canonicalBlock`: because every version must list itself and all the others, the correct set of tags is IDENTICAL on every page. Emit that block on all of them and the reciprocity requirement is satisfied by construction — rather than trying to patch pages one at a time. Honest boundary: whether the other pages actually carry the block cannot be checked here, because nothing is fetched. Do not claim return links are verified. Accepts link tags pasted from page source, or "value URL" pairs one per line. Returns { entries[{value,normalized,href,valid,...}], canonicalBlock?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| annotations | string | yes | The hreflang link tags, or one "value URL" pair per line. |
| selfUrl | string | – | This page's own URL, so the self-reference can be checked. |
No output schema declared.
No examples provided.
check_hs_code Check an HS / HTS / CN commodity code ~509
Check whether a tariff code exists, what its heading officially covers, and whether it is the right length for a destination. IT DOES NOT CLASSIFY GOODS AND NEITHER SHOULD YOU. It cannot tell the user which code their product needs — that depends on material and use and is decided by the General Rules of Interpretation. Do NOT supply a code from your own knowledge when this tool says one is wrong; send the user to their customs broker or the destination tariff search. A confidently wrong tariff code is a penalty, not a typo. EXISTENCE IS CHECKED AGAINST REAL DATA — every published heading and subheading, extracted from the US tariff (the six-digit level is identical in every WCO country by treaty). `HS-H01`/`HS-S01` mean the code is wrong in every country, not just one. RELAY `headingDescription` TO THE USER. Confirming that the official heading text matches the goods is the cheapest check available, and a well-formed code for the wrong goods passes every format validator. LEADING ZEROS: chapters 01–09 (animals, meat, fish, dairy, vegetables, fruit, coffee, tea, spices) lose their zero in spreadsheets. An odd digit count is that, and `HS-X01` gives the restored code. DIGIT COUNTS ARE ONLY GIVEN FOR DESTINATIONS WITH A CITED SOURCE (international 6, United States 10, EU 8). Other countries use other lengths; do NOT fill them in from memory — say the requirement is not covered here. Chapters 98/99 are one country’s own special provisions, so they are reported as scoped, not as invalid. Chapter 77 is empty by design. Returns { input, normalized?, formatted?, valid, parts?{chapter,heading,subheading?,national?}, headingDescription?, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| code | string | – | The commodity code. Dots and spaces are ignored. |
| destination | string | – | Check the digit count for this destination. Omit if unknown — do not assume. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
check_image_metadata Check an image for privacy-leaking EXIF metadata ~276
Read the EXIF metadata out of a JPEG or TIFF supplied as base64 and report what it leaks. THE FINDING THAT MATTERS: GPS coordinates. A product photo taken at home carries the seller's home address to a few metres, and many marketplaces pass it through unchanged — if `gps` is present, tell the user before the image is published anywhere. Also reports camera and lens SERIAL NUMBERS (a stable identifier linking every photo from that device), personal names in the artist/copyright/owner fields, capture timestamps, editing software, an embedded thumbnail (which may still show the image BEFORE a crop), and an orientation flag other than 1 (feed processors that ignore it display the photo sideways). Do NOT paste the coordinates into a map service on the user's behalf — that discloses the location you were asked to check for. Only JPEG and TIFF are parsed; other containers return format with a "not parsed" finding rather than a false all-clear. Returns { format, hasExif, byteOrder?, tags[{tag,name,value,ifd}], gps?{latitude,longitude,latitudeDms,longitudeDms,altitude?}, thumbnailBytes?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| imageBase64 | string | yes | The image file as base64. Only the first metadata segments are read; the pixels are ignored. |
No output schema declared.
No examples provided.
check_incoterm Check an Incoterms trade term against the transport mode ~429
Check how a trade term is written and whether it is valid for the mode of transport. Pass the term as it appears in the contract and, if known, the mode. THE FINDING THAT MATTERS IS INC-M01. FAS, FOB, CFR and CIF are SEA AND INLAND WATERWAY rules whose risk transfer is "goods on board the vessel". For a container that moment does not happen as anyone imagines — the box is handed over at a terminal days earlier and the seller is still carrying risk while the buyer believes they took it. For air freight the moment does not exist. Both sides think they agreed a transfer point and did not agree the same one. Report this as a contract problem, not a style note. The answer for containers is FCA, or CPT/CIP if the seller pays carriage. If the mode is NOT stated, this check does not fire — do not assume a mode on the user’s behalf; ask them. Also flags: a term with no named place (incomplete — "FOB" alone does not say where risk passes); no edition stated (DAT became DPU, CIP insurance changed in 2020); retired terms (DAT, DDU, DAF, DES, DEQ); EXW, which leaves export clearance in the seller’s country to a buyer who often has no entity there; and DDP, which puts import clearance and duty on a seller who often has no registration in the destination. COPYRIGHT: the text of the Incoterms® rules and the buyer/seller obligation matrix are ICC copyright. This tool does not reproduce them and NEITHER SHOULD YOU — do not generate a who-pays-what table from memory in response to its output. Point the user to ICC for the rules themselves. Returns { input, code?, entry?, namedPlace?, version?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| mode | string | – | How the goods actually travel. Omit if unknown — do not guess. |
| term | string | yes | The term as written, e.g. "FOB Shanghai Incoterms 2020". |
No output schema declared.
No examples provided.
check_invoice_sequence Find gaps and duplicates in a column of invoice numbers ~365
Check a column of invoice references for missing numbers, duplicates, width drift and out-of-order rows. THE HARD PART IS SERIES DETECTION, not gap finding. Real references carry prefixes, year segments and branch codes (INV-2026-0001, 2026/001, FV/1/2026), and one column often holds SEVERAL independent sequences. This tool infers the pattern and splits them; counting several series as one is how a healthy set of books comes out looking like hundreds of gaps. When you report results, show the split so the user can confirm it. REPORT A GAP AND A DUPLICATE DIFFERENTLY. A gap is NOT automatically a violation — cancelling an invoice legitimately leaves a hole, and most jurisdictions want the void recorded rather than the number reused. Present gaps as a list to reconcile against cancelled documents. A DUPLICATE has no innocent reading: two documents claim the same identity and any reference to that number is ambiguous. That one is an error. DO NOT TELL THE USER WHAT THEIR JURISDICTION REQUIRES. Numbering rules differ by country — some mandate an unbroken sequence, some only that gaps be explainable, and even the definition of a series varies. This tool reports what is in the column; that is all it can support. Returns { total, unparsed[{raw,line}], series[{key,example,count,min,max,gaps[{from,to}],missing,duplicates[{number,lines[]}],widths[],outOfOrder[]}], findings[] }. Gaps are collapsed into ranges.
| Name | Type | Req | Description |
|---|---|---|---|
| maxGapRanges | integer | – | Cap on gap ranges listed per series (default 20). |
| references | string | yes | One invoice reference per line, or a CSV first column. |
No output schema declared.
No examples provided.
check_lei Check the structure and check digit of an LEI ~446
Check a Legal Entity Identifier (ISO 17442) for length, character set, the reserved pair at positions five and six, and the modulo-97 check digit. WELL FORMED IS NOT REGISTERED, AND YOU MUST SAY SO. A passing check digit means the twenty characters are internally consistent. It does NOT mean the code was ever issued, does not say which entity holds it, and does not say whether the registration lapsed — a dead LEI passes exactly as a live one does. Never tell a user their LEI is "valid" without that qualification, and never name the entity behind an LEI from your own knowledge. Send them to the GLEIF search. THE CHECK DIGIT IS WEAKER THAN IT LOOKS: over seven thousand single-character mutations of real codes, about three in a thousand still passed. CHECK DIGITS RUN 02 TO 98. A code ending 00, 01 or 99 was not produced by the rule at all (`LEI-D01`), which usually means the check digits were never calculated. SOURCING, STATED HONESTLY: ISO 17442 is a paid standard and is not quoted. GLEIF's own code-structure page could not be reached anonymously (two URLs returned an identical generic page). The structure rules here are MEASURED against 800 real codes from GLEIF's public API across 16 countries and 16 issuing organisations. If you relay these rules, relay that basis too rather than implying a specification citation. Returns { input, normalized?, valid, parts?[{label,value,meaning}], expectedCheckDigits?, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| code | string | – | The LEI. Spaces, hyphens and lower case are normalised away. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
check_lithium_battery Calculate lithium battery watt hours and the passenger-carriage band ~469
Work out watt hours and place a battery in the published passenger-carriage bands (up to 100 Wh: no approval; 101-160 Wh: airline approval and at most two spares; above 160 Wh: not permitted in passenger baggage; lithium metal uses grams of lithium at 2 g and 8 g). THE COMMON ERROR IS THE VOLTAGE. A capacity in mAh is rated at the CELL voltage (3.6-3.7 V for lithium-ion), not the 5 V a USB port outputs. A 20 000 mAh pack is 74 Wh at 3.7 V and 100 Wh at 5 V — the difference between "carry it freely" and "ask the airline". If a Wh figure is printed on the battery, use `ratedWattHours` and skip the calculation entirely. If no voltage is given, EVERY common nominal reading is returned in `readings` and the verdict assumes the highest — do not present a single number as the answer in that case, present the range and ask which voltage the battery is marked with. Always mention that spare batteries and power banks travel in the cabin only, never checked. SCOPE: these are the published FAA rules for what a PASSENGER may carry. CARGO shipping is governed by the IATA Dangerous Goods Regulations and its packing instructions (PI 965-970), a paid standard this server does not carry — do NOT reconstruct that classification from memory, it is a safety matter. Refer the user to their carrier or freight forwarder. This is a calculator plus a summary of published rules, not a compliance determination. Returns { chemistry, milliampHours?, lithiumGrams?, readings[{volts,basis,wattHours}], carriage, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| chemistry | string | – | Default lithium-ion. |
| lithiumGrams | number | – | Lithium content in grams, for lithium metal batteries. |
| milliampHours | number | – | Capacity in mAh. |
| ratedWattHours | number | – | The Wh figure printed on the battery — preferred over calculating. |
| spare | boolean | – | Carried as a spare rather than installed in a device (default true). |
| volts | number | – | CELL nominal voltage, not the output voltage. |
No output schema declared.
No examples provided.
check_main_image Check product-image measurements against Amazon main-image rules ~341
Judge a product image against 12 Amazon main-image rules. This tool does NOT decode images — you supply MEASUREMENTS (dimensions, edge pixel samples, transparency, the bounding box of non-white content) and it applies the rules, so it works anywhere without an image pipeline. Key rule: the background must be RGB 255,255,255 exactly. A deviation of 3 or more levels (e.g. 250,250,250 — invisible to the eye) is an ERROR, because the automated scan measures it; 1-2 levels is a warning. Also checks minimum/maximum dimensions, aspect ratio, transparency, frame fill and whether content touches the border. SCOPE LIMIT: text, logos, watermarks, borders and whether the photo shows the right product are NOT checked — that needs vision, not measurement. The frame-fill figure is an estimate from the bounding box, not Amazon's algorithm. A clean result is not a guarantee of approval. Returns { width, height, fillRatio, worstSample?, findings[], ok }.
| Name | Type | Req | Description |
|---|---|---|---|
| contentBounds | – | yes | Bounding box of non-white content in pixel coordinates, or null if the image is blank. |
| edgeSamples | array | yes | Background pixel samples from the image edges — corners and edge midpoints give the most reliable verdict. |
| hasTransparency | boolean | yes | Whether the image contains any pixel with alpha < 255. |
| height | integer | yes | Image height in pixels. |
| name | string | – | File name, for display only. |
| nonWhiteRatio | number | yes | Fraction of pixels that are not background white. |
| width | integer | yes | Image width in pixels. |
No output schema declared.
No examples provided.
check_number_format Check a price or number for ambiguous formatting ~325
Decide whether a numeric value has one reading or several, and validate any currency attached to it. THE TRAP THIS EXISTS FOR: a single separator followed by exactly three digits is genuinely ambiguous — "1,234" is 1234 in English and 1.234 in German, a thousandfold apart, and no parser errors on it. When that happens `ambiguous` is true and EVERY reading is returned in `interpretations`; do NOT pick one silently, surface the ambiguity to the user. Unambiguous values (two decimal places, both separators present, or none at all) return a single `value`. Currency: ISO 4217 codes are validated with their correct minor-unit count — note that JPY and KRW have ZERO decimal places and BHD/KWD have THREE, so "1500.00 JPY" is malformed. A bare symbol is flagged because $ alone is used by more than twenty currencies. Returns { input, currency?, numericPart, interpretations[{convention,value,canonical}], value?, ambiguous, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | – | The price or number as written, including any currency code or symbol. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
check_open_graph Check Open Graph meta tags ~273
Check Open Graph markup pasted as HTML. Reports the four required properties (og:title, og:type, og:image, og:url), the attribute each tag used, and the problems that a browser never reveals. THE FINDING THAT MATTERS MOST IS OG-A01: the protocol requires `property=`, and almost every other meta tag uses `name=`, so `name="og:title"` is the natural thing to write. The page looks identical, naive validators searching for the string "og:title" find it, and the share card comes out blank. This tool therefore counts a name= tag as ABSENT, exactly as a scraper does — report it that way rather than saying the tag is present but wrong. OG-U01 is the other invisible one: a relative og:image resolves fine in a browser (which has the page URL) and not at all for a scraper (which does not). THIS TOOL FETCHES NOTHING. It does not request og:image or og:url, so it cannot say whether the image exists, what size it is, or whether the URL 404s. Do not imply otherwise. Returns { tags[{property,content,attribute}], required[{property,present,content?}], valid, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| html | string | yes | The meta tags, or a whole <head>. |
No output schema declared.
No examples provided.
check_origin_declaration Check a preferential origin declaration against the prescribed wording ~438
Compare the origin declaration on a commercial invoice against the text EU Regulation 2015/2447 prescribes, in every prescribed language version. THE WORDING IS FIXED BY LAW AND THIS CHECK IS LITERAL. A sentence that means the same thing is not the same thing: customs in the importing country can refuse the preference on the wording alone, and the duty then falls on the buyer. Do NOT reassure the user that a reworded declaration is fine because the meaning is clear. THREE DECLARATIONS HAVE NEARLY IDENTICAL OPENINGS and it is the ending that says which arrangement is being claimed: Annex 22-13 (general) stops at "preferential origin"; Annex 22-09 (GSP) continues with the Generalised System of Preferences clause; Annex 22-07 (REX statement on origin) must also state the origin criterion. `ORG-X01` means two of them have been spliced together. DELETING THE BRACKETED AUTHORISATION NUMBER IS CORRECT for an exporter who is not an approved exporter — the regulation requires it. Do not tell the user to put it back. What is wrong is leaving a number copied from someone else’s template (`ORG-A01` reports the number so they can confirm it is theirs). IT DOES NOT DECIDE WHETHER THE GOODS QUALIFY. Preferential origin depends on the rules of origin, the processing done and the materials used. Never answer that question from the wording, and never draft an origin claim for goods you have not been told qualify. SCOPE: only the Union Customs Code declarations. Individual free trade agreements — the EU–UK agreement among them — prescribe their own wording in their own annexes; say so rather than checking those against this text. Returns { input, matched?{annex,label,lang,code,prescribed}, score, diff[{op,text,slot?}], slots[{index,role,content,placeholder}], findings[] }. `diff` is word level: op is same | missing | extra | slot.
| Name | Type | Req | Description |
|---|---|---|---|
| text | string | yes | The declaration text as it appears on the invoice. |
No output schema declared.
No examples provided.
check_peppol_invoice Check a UBL invoice against the published Peppol BIS Billing 3.0 rules ~349
Validate a Peppol BIS Billing 3.0 UBL invoice supplied as XML. FINDINGS CARRY THE OFFICIAL PEPPOL RULE IDENTIFIERS (BR-01, UBL-CR-002). Relay them verbatim — the whole point is that the user can open the Peppol specification and read the rule themselves. Do NOT paraphrase a rule into your own numbering or wording. REPORT THE SCOPE EVERY TIME. Only a subset of the published rules is evaluated (the result gives `evaluated` and `total`); the rest are conditional rules, monetary total calculations and code list checks that need the full semantic model. A clean result is NOT a full Peppol validation and you must say so — money depends on this answer. CHECK THE IDENTITY FIRST. The most common real-world rejection is not a business rule but a wrong cbc:CustomizationID: the document is well formed and declares a specification the receiver is not running. `identity.isPeppolBis3` answers that; lead with it. CII documents are identified and declined rather than checked badly — the rules here are the UBL ones. EN 16931 itself is a paid CEN standard and is not quoted; what is cited is Peppol's public restatement. Do not fill the gap with EN 16931 text from memory. Returns { identity{rootElement,kind,syntax,customizationId?,profileId?,isPeppolBis3}, evaluated, total, violations[{rule,detail}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | integer | – | Cap on violations returned (default 200). |
| xml | string | yes | The invoice XML. |
No output schema declared.
No examples provided.
check_postcode Check postcodes against the format each country uses ~332
Check one postcode per line against the pattern its country normally uses. A line may name its own country ("SW1A 1AA, GB"); otherwise `defaultCountry` applies. READ THIS BEFORE ACTING ON THE RESULT: this checks FORMAT, not existence. The patterns come from the address metadata Chrome and Android use — widely deployed, but NOT the postal authorities, whose own tables sit behind a paid service. A mismatch is therefore a WARNING, never an error, and where the country publishes an official lookup the finding names it. Do not tell a user their address is invalid on this basis; tell them it does not match the usual pattern and point at the lookup. The summary separates two different amounts of work: `formatting` rows are batch-fixable (SW1A1AA vs SW1A 1AA — accepted either way, but they do not match each other when systems compare addresses exactly), while `mismatched` rows need a human with the real lookup. It also knows the countries that have NO postcode system at all — there, a value in the field is itself the bug, usually a checkout form that made the field mandatory everywhere. Returns { rows[{line,input,country,normalized,matches,corrected?,format?,findings[]}], summary{total,matching,formatting,mismatched} }.
| Name | Type | Req | Description |
|---|---|---|---|
| defaultCountry | string | yes | ISO 3166-1 alpha-2 code for rows that do not name a country. |
| postcodes | string | yes | One postcode per line, optionally followed by ", CC" to set that row's country. |
No output schema declared.
No examples provided.
check_product_jsonld Validate Product structured data, values included ~285
Check a Product JSON-LD block. Accepts the bare JSON, a whole page of HTML (the ld+json block is extracted), or an @graph. Beyond the required properties (name; and at least one of offers, review, aggregateRating; and price inside an offer), this VALIDATES THE VALUES using the same engines as the rest of this server: price must be a NUMBER — "19,99" is not 19.99 and is the single most common silent failure, because it reads correctly to a European author; priceCurrency is checked against ISO 4217 including its minor-unit count, so "1500.00 JPY" is flagged (the yen has no decimal places); gtin goes through the full barcode engine, so a wrong check digit, a restricted in-store range or a placeholder code is caught — a Product asserting an identifier that does not exist is worse than one asserting none. GTIN problems keep the barcode engine's own severity rather than being re-graded here. Also: aggregateRating with no review or rating count behind it, which is a documented cause of manual action; availability that is free text rather than a schema.org URL; relative image URLs. Returns { input, data?, type?, valid, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| markup | string | yes | The JSON-LD block, or the page HTML containing it. |
No output schema declared.
No examples provided.
check_supplier_declaration Pick and check an EU supplier's declaration ~494
Choose the right one of the four supplier declarations EU Regulation 2015/2447 prescribes, and check a long-term declaration's validity period. THE FOUR FORMS ARE A 2x2: preferential origin status or not, one-off or long-term. Annex 22-15 / 22-16 / 22-17 / 22-18. Using a preferential form for goods containing non-originating materials is the common and costly error, because the manufacturer downstream builds their own origin claims on it. THE TWO LONG-TERM FORMS ARE WORDED DIFFERENTLY AND YOU MUST NOT FLATTEN THEM. Annex 22-16 says the period "shall not exceed 24 months or 12 months if the declaration was issued retrospectively". Annex 22-18 says only that it "should not exceed 24 months" — softer wording, and NO retrospective rule at all. Never apply the 12-month retrospective limit to 22-18, and never state it as a general rule for long-term supplier declarations; `SUP-R01` reports that silence deliberately. The verbatim footnote comes back in `form.periodNote` — quote that rather than paraphrasing. IT DOES NOT DECIDE WHETHER THE GOODS QUALIFY for preferential origin. That is an input, from the rules of origin for the arrangement. Do not infer origin status from the form choice, and do not tell a user their goods qualify. Dates are YYYY-MM-DD and are validated as real calendar dates, never rounded. Exactly 24 months is allowed — the annex says not to EXCEED it. Returns { form{annex,key,title,body,notes[],periodNote,binding}, period?{from,to,months,limitMonths,fromRetrospective,latestAllowed,withinLimit}, shipmentCovered?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| issuedOn | string | – | YYYY-MM-DD. Earlier than validFrom means the declaration is retrospective. |
| longTerm | boolean | yes | Is this a long-term declaration covering regular supplies? |
| preferential | boolean | yes | Do the goods already have preferential origin status? This is an input, not something the tool determines. |
| shipmentDate | string | – | YYYY-MM-DD. Checks whether that shipment falls inside the validity period. |
| validFrom | string | – | Long-term only. YYYY-MM-DD. |
| validTo | string | – | Long-term only. YYYY-MM-DD. |
No output schema declared.
No examples provided.
check_textile_label Check garment fibre content and care wording ~407
Check a fibre content declaration against 16 CFR 303 and a care instruction against 16 CFR 423. THE RULE MOST TOOLS MISS IS TEX-P02: a fibre under 5 percent of total weight must be disclosed as "other fiber", NOT by name. Adding to 100 is not sufficient — "97% cotton, 3% spandex" totals correctly and is still a violation. There IS an exception: a small fibre may be named if it has a clearly established and definite functional significance at that amount (the regulation's own example is 96% acetate / 4% spandex). That is a fact about the product, not the text, so ASK THE USER and pass `functionalFibres` — never assume it. TEX-N01: fibres must carry the generic name. Lycra is spandex, Tencel is lyocell, viscose is rayon. A trade name beside the generic one is fine; instead of it is a violation. CARE SYMBOLS ARE DELIBERATELY NOT COVERED and you should say so if asked: ISO 3758 is a paid standard and the symbols are GINETEX trade marks in many countries, so this project neither reproduces nor translates them. What is checked is the WORDS 16 CFR 423 requires — cleaning method, water temperature where washing is instructed, drying, bleaching, ironing. Do not fill the gap by reciting a symbol chart from memory. Returns { fibres[{raw,percent,name,generic,other}], total, careCovered[{aspect,present,found?}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| careInstruction | string | yes | The care instruction line; pass an empty string to skip. |
| fibreContent | string | yes | The fibre content line, e.g. "60% cotton, 40% polyester". |
| functionalFibres | array | – | Fibres under 5% that genuinely have a function at that amount — ask the user, do not assume. |
No output schema declared.
No examples provided.
check_utm Check a set of campaign URLs for tagging problems and report fragmentation ~251
Check UTM tagging across a SET of campaign URLs, one per line. Pass them all together — the most damaging problem is invisible in any single URL. THE TRAP: parameter values are CASE SENSITIVE. utm_source=Meta and utm_source=meta are two different sources and become two separate rows in every report, while each URL looks perfectly correct on its own. The same happens with separator style (spring_sale vs spring-sale). This tool reports those collisions and lists every value each parameter took. Also per URL: missing required parameters (utm_source, utm_medium, utm_campaign — a missing one reports as "(not set)", it does not error); misspelled utm_ parameters, which are silently IGNORED so the URL looks tagged and reports nothing; parameters placed after a # fragment, which are never sent anywhere; duplicate parameters; upper case and spaces in values. When emitting UTM values yourself, lower-case them — it is the only habit that prevents the split. Returns { urls[], valuesByParameter[{parameter,values[]}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| urls | string | yes | One campaign URL per line. Pass the whole set, not one at a time. |
No output schema declared.
No examples provided.
check_xrechnung Check a German XRechnung invoice against KoSIT's official BR-DE rules ~447
Check an XRechnung invoice (UBL or CII) against the German CIUS additions to EN 16931. THESE ARE NOT PEPPOL'S RULES. XRechnung (BR-DE-*) and Peppol BIS Billing (BR-*, UBL-CR-*, PEPPOL-*) are siblings, each adding different rules on top of the same EN 16931 core. A document can pass one and fail the other. If unsure which applies, use identify_einvoice first — its `profile.id` tells you. ONLY UNCONDITIONAL RULES ARE EVALUATED: 13 of 56 for UBL, 12 for CII. Most BR-DE rules are conditional on other field values (VAT code branching, payment method, computed amounts) and are NOT evaluated — evaluating them wrong would be worse than not evaluating them, so they are catalogued (id + official German text) but not checked. `evaluated`/`total` says exactly how far this went; a clean result is not a full XRechnung validation. THE OFFICIAL RULE TEXT IS GERMAN ONLY — KoSIT has never published an English translation. Finding messages include an English description written and checked by this project (NOT an official translation), the verbatim German original, and the official EN 16931 English business term embedded in it (e.g. "Seller city" (BT-37) — that quoted term is KoSIT's own citation, not our translation). Do not present the English description as KoSIT's own wording. RULES ARE CONDITIONAL ON OPTIONAL GROUPS WHERE THE GERMAN TEXT SAYS SO (e.g. delivery-address rules only apply if a delivery address is given at all — most domestic invoices have none and that is correct, not a violation). Never tell a user a rule was violated when the underlying business group is simply absent; the checker already accounts for this. Returns { identity{syntax,kind,rootElement,customizationId?}, evaluated, total, violations[{rule,detail}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| xml | string | yes | The invoice XML, UBL or CII. |
No output schema declared.
No examples provided.
convert_csv_to_xlsx Convert a CSV file to .xlsx without destroying identifiers ~379
Convert a local CSV/TSV file to .xlsx the safe way: columns that hold identifiers are auto-detected and written as TEXT cells so nothing gets reinterpreted — leading zeros survive, 12+ digit codes never become 8.71E+12, GTIN columns (recognised by check digit) stay verbatim, phone numbers keep their +, date-like text is not silently committed to one reading, and formula-looking values (=, @) become inert text. The protections are published as 7 rules (PROT-*); the result reports exactly which columns were protected and why, plus per-value fallbacks in unprotected columns. Values that are plain safe numbers (prices, quantities) stay real numbers, so the sheet still calculates. The source is also pre-checked against known Excel damage signatures: cells already mangled by a previous spreadsheet round-trip (scientific notation corpses, suspected lost zeros) are WARNED about, never "repaired" — this tool refuses to invent digits (XLC-W01). Dialect (comma/semicolon/tab/pipe, quoting, embedded newlines) is detected automatically. Encoding: UTF-8, with Windows-1252 fallback (reported when used). GUARANTEES: the input file is never modified; an existing output file is never overwritten. Returns { outcome, path, out?, encoding, report } where report lists protections [{header, ruleId, reason, examples}], cellCounts, damage precheck and findings.
| Name | Type | Req | Description |
|---|---|---|---|
| out | string | – | Absolute output path (.xlsx). Default: alongside the input as <name>.xlsx. Never overwrites. |
| path | string | yes | Absolute path to the CSV/TSV file. |
| sheetName | string | – | Worksheet name (default "Sheet1"; illegal characters are replaced, max 31 chars). |
No output schema declared.
No examples provided.
convert_feed Convert a product feed between Google Shopping and Meta ~397
Convert a tab- or comma-separated feed (first line is the header) between Google Shopping and Meta catalog dialects. THE POINT OF THIS TOOL IS WHAT IT REFUSES TO DO. Google supports four availability values (in_stock, out_of_stock, preorder, backorder); Meta supports two. `preorder` and `backorder` have NO equivalent, and neither substitute is free: "in stock" advertises goods the seller does not have, "out of stock" refuses an order they would have taken. Those cells are left EMPTY and listed in `rows[].undecided`. DO NOT FILL THEM IN. Not in the output, not in your reply, not "reasonably". It is a merchandising decision that belongs to the seller, and a converter that picks one looks more finished while having decided something on their behalf. Present the trade-off and ask. CNV-T01 covers the values that DO map but are spelled differently (in_stock with an underscore on Google, "in stock" with a space on Meta) — that difference is what silently breaks a reused feed. Only Google and Meta are supported, because both publish their value sets openly. Other marketplaces keep theirs behind a seller login or change them per release; converting to those would mean guessing, and a wrong conversion is worse than none because it looks finished. Do not extend this to another platform from memory. This CONVERTS, it does not VALIDATE — run the result through validate_marketplace_feed afterwards. Returns { from, to, header[], rows[{line,values,undecided[{field,from,guidance}]}], needingDecision, findings[] } plus `output` when `render` is set.
| Name | Type | Req | Description |
|---|---|---|---|
| feed | string | yes | The feed with a header row. |
| from | string | yes | Source dialect. |
| render | boolean | – | Also return the converted feed as text. |
| to | string | yes | Target dialect. |
No output schema declared.
No examples provided.
convert_gtin Convert a GTIN between UPC-12, EAN-13 and GTIN-14 ~346
Convert a barcode between formats: GTIN-12 (UPC-A), GTIN-13 (EAN-13) and GTIN-14 (case code). The code is VALIDATED FIRST — an invalid GTIN is refused rather than converted, so a broken number is not propagated across channels. Check digits are recalculated whenever the indicator digit changes (GTIN-14 ⇄ GTIN-13); zero-padding (UPC ⇄ EAN-13) preserves the check digit. Two conversions are impossible by GS1 rules and are refused with an explanation: GTIN-8 → anything (it is an independent number range, NOT a short EAN-13), and GTIN-13 → UPC-12 when the code does not start with 0. Returns { input, normalized, sourceFormat, target, converted?, ok, note?, findings[] }. BULK: pass `values` (an array, max 1000) instead of the single value to check a whole column in one call. The result is then { rows, summary } rather than a single result. Do not loop this tool over a column one value at a time.
| Name | Type | Req | Description |
|---|---|---|---|
| indicator | integer | – | Indicator digit for GTIN-14 targets: 1-8 = packaging level, 9 = variable measure. Default 1. |
| target | string | yes | Target format. GTIN-8 is not a valid target — those codes are allocated by GS1, not constructed. |
| value | string | – | The barcode to convert, raw and uncleaned. |
| values | array | – | Bulk form: one value per array element. Use this instead of looping the single-value form. |
No output schema declared.
No examples provided.
convert_shoe_size Convert shoe sizes from the unit definitions ~334
Convert between EU, UK, US men’s, US women’s and foot length in centimetres. Each reading carries the arithmetic that produced it. LEAD WITH `footLengthCm`, not the converted size. Foot length is the only quantity that does not change between brands, and it is what the user should measure and match against the brand’s own chart. A size number is an inference from it. The unit arithmetic is exact — a Paris point is 2/3 cm, a barleycorn is 1/3 inch — but the last allowance and the US/UK offsets are trade convention, and brands deviate by more than the conversion moves. Always pass on SHO-B01 rather than presenting a converted size as definitive. US men’s and US women’s are DIFFERENT SCALES about a size and a half apart; if the user says only "US 8", ask which. APPAREL SIZES ARE NOT SUPPORTED, deliberately. There is no derivable relationship between S/M/L and any national numeric apparel scale — only each brand’s block. If asked to convert clothing sizes, call `explain_apparel_sizing` or relay the same point: DO NOT produce a conversion chart from memory. Those charts are one or two brands’ tables presented as universal, and the returns land on the seller. Tell them to publish the garment’s actual measurements instead. Returns { input, footLengthCm?, readings[{system,label,value,working}], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| system | string | yes | Which scale the value is in. |
| value | number | yes | The size to convert from. |
No output schema declared.
No examples provided.
convert_units Convert dimensions or weights for a feed, and report what rounding costs ~342
Convert length or mass values, one per line, and report BOTH the exact result and the value rounded to the precision a feed field accepts — plus what that rounding cost as a percentage. THE POINT: the conversion factors are EXACT by definition (an inch is exactly 0.0254 m, a pound exactly 0.453 592 37 kg, since 1959), so any error in a converted value came from rounding, not from the conversion. One pound rounded to two decimals is 0.45 kg — about 0.8 % light, always in the same direction, so it accumulates across a consignment rather than cancelling out. Report the cost to the user rather than only the rounded number. Batch mode also flags a column that MIXES units, which is worse than a wrong one: a feed field carries a single unit for the whole column, so every row that does not match is silently mislabelled while each number remains individually valid. Length and mass only. Volume, area and temperature are absent on purpose rather than approximated. Returns { rows[{line,input,exactValue?,rounded?,roundingErrorPercent?,findings[]}], summary{total,converted,failed,worstErrorPercent,unitsSeen}, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| decimals | integer | – | Decimal places the target field accepts (default 2). |
| to | string | yes | Target unit code: mm, cm, m, in, ft, yd, g, kg, lb, oz. |
| values | string | yes | One value per line, e.g. "1 lb" or "10 in". The unit may be attached or spelled out. |
No output schema declared.
No examples provided.
convert_upc_e Convert UPC-E ⇄ UPC-A (zero suppression) ~244
Expand a UPC-E (8 digits) to its UPC-A (12 digits) form, or compress a UPC-A to UPC-E when the standard allows it. CRITICAL details most implementations get wrong: (1) a UPC-E check digit is computed from the EXPANDED UPC-A, never from the 8 digits themselves; (2) which zeros are suppressed is determined by the LAST DATA DIGIT, and the four compression rules are mutually exclusive — applying them in the wrong order compresses one UPC-A into two different UPC-E values; (3) a UPC-E must start with number system 0 or 1 — an 8-digit code starting with anything else is an EAN-8/GTIN-8, an INDEPENDENT GS1 range that expands to nothing; (4) most UPC-A codes have NO UPC-E form, and this tool says so instead of inventing one. Returns { input, normalized, detected, valid, upcE?, upcA?, rule?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| value | string | yes | A UPC-E (8 digits) or UPC-A (12 digits), with or without hyphens. |
No output schema declared.
No examples provided.
convert_xlsx_to_csv Convert an .xlsx workbook to CSV without silent data changes ~504
Convert a local .xlsx file to CSV, one file per worksheet, with every liberty disclosed instead of taken silently: numbers are NEVER emitted in scientific notation (exponent-stored values are expanded exactly by string arithmetic, not floating point); date cells become unambiguous ISO 8601 text using the epoch the workbook itself declares (including the legacy Mac 1904 system — the same serial is 1,462 days apart between epochs); formulas contribute their last calculated value and are counted (XLC-R03); merged ranges flatten with the value in the top-left cell (XLC-R04); embedded images/charts are counted as not-carried-over (XLC-R06); leading/trailing spaces in cells survive verbatim. Every disclosure is a numbered rule (9 XLC-* rules published). If the output still contains values a spreadsheet would damage on double-click (leading zeros, 12+ digits), that risk is flagged (XLC-W08) — the CSV is correct, the danger is in how it gets opened next. Legacy .xls and password-protected workbooks are refused with a clear explanation (XLC-E07), not mis-parsed. GUARANTEES: the input file is never modified; existing output files are never overwritten (the call fails before writing anything if any target exists). Defaults follow Excel-survival practice: comma, minimal quoting, CRLF, WITH a UTF-8 BOM (double-clicked no-BOM UTF-8 is mojibake in Excel); all four are overridable. Returns { outcome, path, files[{sheet, out, rows, columns}], report } with findings, epoch, counts and any structural problems.
| Name | Type | Req | Description |
|---|---|---|---|
| bom | boolean | – | Write a UTF-8 BOM (default true — Excel double-click reads BOM-less UTF-8 as ANSI and mangles every non-ASCII character; some Unix tools dislike the BOM, hence the switch). |
| delimiter | string | – | Output delimiter, default comma. |
| lineEnding | string | – | Line ending, default CRLF (the Excel-ecosystem default). |
| outDir | string | – | Absolute directory for the CSV output (default: the input's directory). One sheet → <name>.csv; several → <name>-<sheet>.csv each. |
| path | string | yes | Absolute path to the .xlsx file. |
| quoting | string | – | minimal (default) quotes only fields that need it; all quotes every field. |
No output schema declared.
No examples provided.
detect_csv_dialect Detect the delimiter, quoting and encoding traits of a CSV ~229
Work out what dialect a delimited file actually is: delimiter, quoting, line endings, byte-order mark, whether the first row is a header, and which rows are ragged. Detection is by COLUMN-COUNT CONSISTENCY across the whole file with RFC 4180 quoting honoured — not by counting separators in the first line, which picks the wrong delimiter on the most common real file there is (a semicolon-separated European export whose descriptions are full of commas). Each candidate separator is returned with its consistency score, so the verdict can be checked rather than trusted. Use before parsing an unfamiliar feed, or when an import complains about a header column that is visibly present (that symptom is almost always a BOM). Returns { delimiter, delimiterName, candidates[{delimiter,name,consistency,columns}], lineEnding, hasBom, usesQuotes, looksLikeHeader, columns[], rowCount, raggedRows[], findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| text | string | yes | The file contents, or its first few dozen lines. Pass it raw — the BOM and line endings are part of what gets detected. |
No output schema declared.
No examples provided.
detect_invisible_characters Find and explain invisible or look-alike characters in text ~411
Scan text for characters that are invisible or that impersonate ordinary ones, and explain each: Unicode name, where it typically comes from, and what it breaks. Catches zero-width spaces, the BOM (the usual cause of "missing header" import errors), non-breaking and narrow spaces, smart quotes, en/em dashes and minus signs, soft hyphens, exotic line separators, bidirectional overrides, full-width Latin forms, variation selectors and control characters. Use this when two strings that look identical fail to match, when an import complains about a column that is clearly present, or before storing text that came from a spreadsheet, a PDF or a web page. Positions are CODE POINT offsets. `cleaned` applies each character's safe replacement — note that characters whose meaning is contextual (zero-width joiners inside emoji sequences) are deliberately KEPT, so `cleaned` is not a blanket strip. The result also carries `bidi`, the BALANCE of bidirectional controls, and that is the part worth acting on: listing "there is a U+202E here" does not explain anything, but an UNTERMINATED opener does — everything from that point to the end of the string displays differently from how it is stored, which is the mechanism behind Trojan-Source-style text. `bidi.unterminated` and `bidi.strayClosers` give the positions; `bidi.affectedFrom` is where the divergence starts. Note U+202C closes only embeddings and overrides while U+2069 closes only isolates — the wrong closer does not balance. These characters are legitimate in Arabic and Hebrew text, so report the imbalance as a fact, not as intent. Returns { input, characters, findings[{info{code,name,category,severity,origin,consequence,replacement?}, positions[], count}], cleaned, changed, hasErrors }.
| Name | Type | Req | Description |
|---|---|---|---|
| text | string | yes | The text to inspect, exactly as stored — do not pre-clean it. |
No output schema declared.
No examples provided.
detect_mixed_script Find characters that are not what they look like ~262
Detect characters in listing text that render like ordinary Latin text but are not. Two distinct problems: (1) FULL-WIDTH PUNCTUATION — ,。()!? produced by CJK input methods. They look like ordinary punctuation, break search matching, and are a mechanical substitution, so `suggested` carries the corrected text. (2) LOOKALIKE LETTERS — Cyrillic а е о р с and Greek ο are visually IDENTICAL to Latin letters. A word containing one is a different string: search misses it, deduplication misses it, spellcheck stays quiet. This is invisible to any amount of proofreading, so it can only be found mechanically. Leftover words in another script are reported but NOT changed — deciding to translate, transliterate or delete them requires knowing what they say. Do not substitute anything there. Spans use CODE-POINT offsets, not UTF-16 indices, so they stay correct with emoji present. Returns { input, scripts[], spans[{start,end,text,script,ruleId}], suggested?, findings[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| expectedScript | string | – | The script the text should be in (default Latin). Anything outside it is reported as leftover. |
| text | string | yes | The listing text to examine. |
No output schema declared.
No examples provided.
diagnose_excel_damage Diagnose what a spreadsheet broke in a column of data ~420
Take a column of values that came out of a spreadsheet and report, per value, what damage it carries and — the part that matters — WHETHER IT CAN STILL BE REPAIRED. Each row gets `recoverability`: "intact", "recoverable" (a determinate fix exists and is given in `repaired`), or "unrecoverable" (the original data is not in this file and no tool can restore it). Use that field to decide whether to fix in place or tell the user to re-export from the source. THE TRAP THIS EXISTS FOR: expanding scientific notation is NOT the same as repairing it. "8.71E+12" describes a 13-digit number but carries only 3 of its digits; expanding it to 8710000000000 invents the other 10. This tool counts carried vs lost digits and refuses to offer a repair when digits were destroyed — do not expand such values yourself. Also detects: leading zeros stripped (only when the column width makes it detectable — at least three same-length numeric cells), rounding past the 15 significant digits a spreadsheet keeps, codes coerced to dates (MAR1 becomes 1-Mar and CANNOT be reversed — `originalCandidates` lists the possibilities), floating-point tails, spreadsheet error values, display formatting baked into values (accounting brackets mean NEGATIVE), booleans, and invisible whitespace. SECURITY: cells beginning with =, +, -, @, tab, CR, LF or the full-width variants = + - @ are executed as formulas when the file is opened (OWASP CSV Injection). These are reported as errors, not style notes. Returns { rows[{line,input,recoverability,repaired?,originalCandidates?,findings[]}], modalNumericLength?, summary{total,intact,recoverable,unrecoverable,byRule[]} }.
| Name | Type | Req | Description |
|---|---|---|---|
| column | string | yes | The column of values, one per line, exactly as exported — do NOT pre-clean it; the damage is what gets diagnosed. |
No output schema declared.
No examples provided.
diff_product_feeds Compare two product feed versions aligned by SKU ~366
Compare two versions of a product feed (CSV or TSV) ALIGNED BY KEY rather than by line. This matters because product exports do not preserve row order — a re-sorted or partially deleted export makes a line-based diff report that everything changed when nothing did. Rows here are matched on id/sku/handle/gtin (auto-detected, or pass `keyColumn`), so reordering yields zero differences. Returns per-row classification (added / removed / changed / unchanged) and, for changed rows, FIELD-LEVEL before/after pairs with numeric deltas and percentages for price and stock, plus semantic notes (stock hit zero, availability flipped, image replaced, value cleared). WARNINGS matter: duplicate keys make any key-based comparison unreliable and are reported explicitly, as are columns present in only one file (which are excluded from comparison rather than reported as changes). Use `ignoreColumns` for volatile fields such as export timestamps. Returns { keyColumn, keySource, columns{both,onlyBefore,onlyAfter}, rows[], summary{added,removed,changed,unchanged,byField,duplicateKeys*}, warnings[{ruleId,severity,message,fix?}] }. Structural warnings carry stable rule ids (DIFF-K01 no key column, DIFF-K02 key missing on one side, DIFF-K03 duplicate keys, DIFF-C01 different columns) — branch on the id rather than matching the English text.
| Name | Type | Req | Description |
|---|---|---|---|
| after | string | yes | The newer feed export, as text. |
| before | string | yes | The older feed export, as text. |
| ignoreColumns | array | – | Columns whose changes should be ignored (export timestamps and similar). |
| keyColumn | string | – | Column to align rows by. Auto-detected when omitted. |
No output schema declared.
No examples provided.
explain_apparel_sizing Explain why apparel sizes cannot be converted ~123
Returns the reasoned position on cross-brand apparel size conversion, for when a user asks for a clothing size chart. Use this INSTEAD OF generating a conversion table. S/M/L and national numeric apparel scales have no derivable relationship; the universal charts online are individual brands’ tables presented as general truth. Producing one from memory states something uncertain in a confident voice and the returns are paid for by the seller. The constructive answer is in the finding’s `fix`: publish the garment’s actual measurements beside the size label. Returns { findings[] }.
Input schema present but exposes no named parameters.
No output schema declared.
No examples provided.
fix_mojibake Diagnose and repair encoding damage (mojibake) ~244
Repair text mangled by an encoding mix-up — "café" back to "café", "don’t" back to "don't". This does NOT use a substitution table: it infers and executes the actual encoding chain (UTF-8 bytes read as CP1252 or ISO-8859-1), so any character in any script repairs the same way, including ones no lookup table would carry. Every candidate is SELF-VERIFIED — the repaired text is pushed back through the same broken chain and only returned if it reproduces your input exactly. Handles double encoding and reports how many layers were undone. IMPORTANT LIMIT: U+FFFD replacement characters (�) mean a decoder already discarded those bytes. That damage is NOT reversible by any tool — the result will say so rather than guessing. Also worth telling the user: repairing the text fixes today's file, but the import that produced it will corrupt the next one too. Returns { input, detected, candidates[{repaired, chain, misreadAs, layers, score}], findings[], signatures[] }.
| Name | Type | Req | Description |
|---|---|---|---|
| text | string | yes | The mangled text, exactly as stored. |
No output schema declared.
No examples provided.
generate_barcode_modules Generate the module pattern for a barcode symbol ~281
Encode a GTIN as a barcode symbol and return the MODULE PATTERN (a string of 1s and 0s, where 1 is a bar and 0 is a space) plus the layout data needed to render it. Supports EAN-13, UPC-A, EAN-8 and ITF-14; the symbology is detected from the digit count unless you specify it. The check digit is VALIDATED FIRST and generation is REFUSED when it is wrong (with the correct number in `suggestion`) — a barcode encoding a wrong number scans as a different product or not at all, which is worse than having no barcode. Rendering to an image is left to the caller: the response gives `modules`, `moduleCount`, `textGroups` (how the human-readable digits are grouped under the symbol) and `guardRanges` (which modules must be drawn as longer guard bars). The encoding tables are verified in our test suite by an independent decoder over thousands of random round-trips. Returns { symbology, value, modules, moduleCount, textGroups[], guardRanges[] } or { error, suggestion? }.
| Name | Type | Req | Description |
|---|---|---|---|
| symbology | string | – | Force a symbology instead of detecting it from the digit count. |
| value | string | yes | The complete GTIN including its check digit. |
No output schema declared.
No examples provided.
generate_digital_link_qr Generate a Sunrise-2027-ready GS1 Digital Link QR code (validated) ~554
Build a conformant GS1 Digital Link URI for a GTIN (optionally with CPV (22), batch/lot (10) and serial (21) qualifiers) and render it as a QR code — with a hard gate: if the GTIN fails the full validation engine, or a qualifier value falls outside the standard's 82-character set, NOTHING is generated (8 published QRG-* rules explain every refusal). A printed QR cannot be patched, so this tool refuses rather than warns. Conformance details handled for you: GTIN padded to 14 digits (required since URI syntax v1.4.0), qualifiers emitted in the mandatory 22→10→21 order, reserved characters percent-encoded per the standard's own table, verified round-trip against this project's Digital Link parser. The result includes print-size advice for retail POS scanning derived from GS1's published X-dimension range (0.396–0.990 mm) and the (modules + 8) × X formula — the quiet zone is included in the numbers and in the SVG. Error correction level M is this project's default (GS1 mandates none). Sunrise 2027 context, honestly stated: it is an industry capability milestone (retail POS able to scan 2D by end of 2027), not a legal mandate; during the transition GS1 US describes on-pack marking as mandatory 1D plus optional 2D. For a quick unvalidated URI (no QR, no gate) use build_gs1_digital_link instead. Returns { uri?, conformant, gtin14?, checks{gtin,qualifiers,domain}, findings[], qr?{moduleCount, modules[] (rows of 1/0)}, sizeAdvice?{minMm,exampleMm,maxMm}, svg? }.
| Name | Type | Req | Description |
|---|---|---|---|
| cpv | string | – | AI 22 Consumer product variant (max 20 chars from the GS1 82-character set). |
| domain | string | – | Resolver origin, default https://id.gs1.org (canonical). A brand domain is conformant too — the result explains the operational difference. |
| gtin | string | yes | The GTIN (8/12/13/14 digits; spaces and hyphens are cleaned). Refused if the check digit fails. |
| includeSvg | boolean | – | Include the rendered SVG string (default true). The SVG already carries the 4-module quiet zone. |
| lot | string | – | AI 10 batch/lot (max 20 chars from the GS1 82-character set). |
| serial | string | – | AI 21 serial number (max 20 chars from the GS1 82-character set). |
No output schema declared.
No examples provided.
What is the com.yaktool/yaktool MCP server?
com.yaktool/yaktool is an MCP server listed in the public MCP registry as com.yaktool/yaktool. 73 local deterministic tools: GTIN, feeds, CSV-XLSX, Digital Link QR, e-invoices. Rules cited. This page covers its npm package (yaktool-mcp).
Is the com.yaktool/yaktool MCP server safe to use?
com.yaktool/yaktool scores 73 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. It declares no install or post-install scripts. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the com.yaktool/yaktool MCP server expose?
com.yaktool/yaktool exposes 73 tools: validate_gtin, calculate_check_digit, analyze_amazon_search_terms, convert_gtin, validate_google_feed, and 68 more. Their descriptions and schemas cost roughly 25,676 tokens of context every time the server is loaded.
Is the com.yaktool/yaktool MCP server still maintained?
com.yaktool/yaktool is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.
What licence is the com.yaktool/yaktool MCP server under?
com.yaktool/yaktool declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.