Skip to main content
Glama

Taokeh MCP server

Stage a historical document

stage_document

Bring ONE already-issued historical document (a sales invoice, or a supplier bill) across from the system this company is migrating FROM. This is the BULK migration door and it is NOT create_invoice_draft: nothing is posted, nothing is drafted for individual approval, and no approval card is raised per document. Staged documents group into monthly batches the owner reviews and approves together at /switch/documents. Use it ONLY for documents that were genuinely issued in the old system (or written in a paper book) — a NEW document belongs in create_invoice_draft / create_bill_draft. The lane must be OPEN (the owner turns it on at /switch → "Bring over your documents") and it can only be open before the books are locked; if it is closed the call is refused with instructions. IDEMPOTENCY IS ON sourceDocId: staging the same sourceDocId again UPDATES that pending row instead of filing a second one. Once the owner has ENTERED it, or deliberately LEFT IT OUT, nothing you send can change it, re-book it or bring it back — only the owner can. So re-running your whole export is always safe. THE CUTOVER: bring over only documents dated AFTER the company's accounting start date. Anything dated on or before it is already carried by the owner's opening balances, and Taokeh will flag it and refuse to enter it — staging those wastes both our time, so filter them out of your export if you can. ORDER MATTERS: stage the SUPPLIER BILLS for a period before the sales invoices for it, because Taokeh works out cost of sales from the stock that was bought. The server re-computes every quantity and the grand total from the lines (with SST); your own printed total goes in sourceTotal and is used ONLY to show the owner a tie against the server's figure. Anything the server cannot settle — a product that does not resolve, a customer name matching several contacts, a printed total that disagrees — is staged anyway, FLAGGED, and held out of bulk approve for the owner to open individually. The document keeps its ORIGINAL number (reference) and its ORIGINAL date, and posts marked as historical so Taokeh never e-invoices or chases it. A MARKETPLACE ORDER (Shopee, TikTok Shop, Shopify) brought over as an invoice: pass marketplaceOrderKey (e.g. SHOPEE-2608246V81G729) so it posts as that channel's sale and a later import of the same order is not booked twice — one order, one invoice; a key already booked or already staged is refused. PAPER: if you read this document off a photo or a scan, ATTACH IT — request_attachment_upload, PUT the bytes, pass attachmentToken here. The owner then reviews your figures beside the actual slip on that document's own screen, edits anything you misread, and approves it there; the original lands on the posted document. Without it they are approving your arithmetic on your word alone. Show your per-line working, and mark any balancing/catch-all line residual:true — a residual line carrying a material share of the total is flagged for the owner, because that is exactly where a misread hides. NOT EVERY LINE IS A CATALOGUED PRODUCT, and an old document is full of the ones that are not: a delivery or transport charge, a labour or installation line, a service fee, a rounding line. Those still go through as ordinary lines — productRef is REQUIRED and must not be blank, so put the line's OWN wording in it ("Delivery charge"), and Taokeh CREATES that wording as a non-stock item (MD, 2026-09-09) so the document derives normally — the row is flagged, the created item is named for the owner, and it carries no stock and no price of its own. That is the designed path: it is not an error, so do not drop the line, do not fold its amount into another line, and do not invent a SKU for it. Omitting productRef altogether is the one thing that fails — the call is refused at the boundary before anything is staged. ⛔ ROW KEYS ARE STRICT (MD, 2026-09-09): a key the schema does not list is REFUSED BY NAME — with the key it probably meant, e.g. sell_price → unitPrice — and NOTHING is staged. Send the contract's apiField, not the spreadsheet header. Unknown keys used to be dropped in silence, so a set could stage "successfully" with its prices missing; that is the bug this refusal closes. NOT IN THE CATALOGUE? IT IS NOW: a line whose productRef matches NOTHING is created as a NON-STOCK item named after the line's own wording (no stock, no price of its own, marked as created by the migration), so the document derives and the owner reviews figures instead of a blocked row. Tell the owner which items were added — the reply names them. A ref that matches SEVERAL products is still flagged rather than duplicated. ⚠ NOT ON A DOCUMENT THE CUTOVER FENCE REFUSES: Taokeh will not grow the catalogue for a document it can never enter, so a pre-cutover row stages with no figures and an unresolved-product note ALONGSIDE its fence. The fence is the blocker; the product note is a consequence of it. Do not call resolve_product for such a row, do not ask the owner to add a catalogue item for it, and never route it to the manual bill form or the expense door — the only answers are to leave it out or to have the owner move the accounting start date.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "docKind": "<docKind>",
      "sourceDocId": "<sourceDocId>",
      "docDate": "<docDate>",
      "lines": "<lines>"
    },
    "name": "stage_document"
  }
}

Input Schema

NameRequiredDescriptionDefault
linesYes
notesNoA SHORT note for the owner about this document — one or two sentences naming anything they should check. Not a place for lengthy reasoning.
partyNoThe customer (sales invoice) or supplier (purchase bill) name as printed. Matched against the existing contacts; a name matching several, or one that looks like shorthand for an existing contact, is flagged for the owner rather than guessed. Omit for a walk-in cash sale with no named customer.
docDateYesThe date the document was ORIGINALLY issued, YYYY-MM-DD. Never today unless it really was today — the whole point is that these documents keep their real dates.
docKindYes'sales_invoice' = an invoice this company ISSUED to a customer. 'purchase_bill' = a bill a supplier issued TO this company (inventory lines only, same rule as create_bill_draft). Other kinds are not supported yet.
partyIdNoThe Taokeh customer/vendor id, when you already resolved it with resolve_customer / resolve_vendor. Wins over `party`.
referenceNoThe document number exactly as printed in the old system (e.g. INV1603). Taokeh keeps it, so the customer's copy and yours still match. It must be unique in this company: a number already on the books is refused by name. Leave it out only if the document genuinely has no number. Before the first such invoice is entered, the owner must confirm where the real invoice series continues; Taokeh never silently starts migrated books at INV1.
needsReviewNoSet true when you want the owner to look at this one specifically. It is then held out of bulk approve and gets its own door.
sourceDocIdYesThe id this document has in the system you are migrating FROM — the primary key, row id or export id. THIS IS THE DEDUPE KEY: staging the same sourceDocId twice updates one row instead of booking the document twice, which is what makes re-running your export a no-op. If the old system has no id, use the document number, but use it consistently across the whole export.
sourceTotalNoThe grand total PRINTED on the source document. Advisory only — Taokeh re-derives its own figure and shows the two side by side, so the owner can see a whole batch tie to the old system's report. Send it whenever the paper states one; it is the single most useful check in the whole migration.
paymentMethodNo'CREDIT' (default) = it was on account, so it carries into receivables/payables. 'CASH' = it was settled at the counter. Get this right: it decides whether the document leaves a balance behind.
attachmentTokenNoThe ORIGINAL this document was read off — the photo of the handwritten cash-sale slip, the scanned invoice page. Call request_attachment_upload FIRST, PUT the raw bytes to its uploadUrl, then pass the token here (there is no inline base64 on this door: a backlog export would blow the context). The file rides the staged row, the owner sees it BESIDE your figures on the document's own review screen, and it lands on the posted invoice or bill automatically when they approve. Re-staging the same sourceDocId WITH a token replaces the file; re-staging without one leaves the file already there untouched, so a bare filing is repairable.
marketplaceOrderKeyNoSALES INVOICES ONLY, and only when the invoice WAS a marketplace order: the channel plus the order's own number, exactly as Taokeh's channel import keys it — 'SHOPEE-<order number>' (e.g. SHOPEE-2608246V81G729), 'TIKTOK-<order ID>' (digits), or 'SHOPIFY-<order ID>' (the numeric id in the Shopify admin address /admin/orders/<id>, NOT the '#1001' order name). It is posted as the sale's order reference and channel, so the invoice counts as a Shopee/TikTok/Shopify sale everywhere and a later live import of the same order is recognised instead of booked twice. A malformed key, a key already on an invoice in the books, or a key another staged document already carries is REFUSED and nothing is staged. A Shopee order number starts with the order's date (YYMMDD); when that is not docDate the document is FLAGGED for the owner (not refused) — check which date is right. Keep `reference` for the invoice's own number.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedInput schema / properties / marketplaceOrderKey
      Added value: +{
      +  "description": "SALES INVOICES ONLY, and only when the invoice WAS a marketplace order: the channel plus the order's own number, exactly as Taokeh's channel import keys it — 'SHOPEE-<order number>' (e.g. SHOPEE-2608246V81G729), 'TIKTOK-<order ID>' (digits), or 'SHOPIFY-<order ID>' (the numeric id in the Shopify admin address /admin/orders/<id>, NOT the '#1001' order name). It is posted as the sale's order reference and channel, so the invoice counts as a Shopee/TikTok/Shopify sale everywhere and a later live import of the same order is recognised instead of booked twice. A malformed key, a key already on an invoice in the books, or a key another staged document already carries is REFUSED and nothing is staged. A Shopee order number starts with the order's date (YYMMDD); when that is not docDate the document is FLAGGED for the owner (not refused) — check which date is right. Keep `reference` for the invoice's own number.",
      +  "type": "string"
      +}
  2. Changed2 schema fields changed
    • removedInput schema / properties / lines / items / properties / discount / anyOf
      Removed value: -[
      -  {
      -    "type": "number"
      -  },
      -  {
      -    "type": "string"
      -  }
      -]
    • addedInput schema / properties / lines / items / properties / discount / type
      Added value: +[
      +  "number",
      +  "string"
      +]
  3. Changed1 schema field changed
    • changedInput schema / properties / lines / items / properties / quantity / description
      Previous value: -"The line quantity as the old document states it. On a measurement-profile company (see intake_contract's `measureProfile`) OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity from those, and a quantity sent alongside a parseable tally is NOT used to compute: it is kept as your advisory figure and shown to the owner beside the server's. On the default passthrough company nothing is derived, so this IS the quantity — send it."New value: +"The line quantity as the old document states it. On a measurement-profile company (see intake_contract's `measureProfile`) OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity from those, and a quantity sent alongside a parseable tally is NOT used to compute: it is kept as your advisory figure and shown to the owner beside the server's. On the default passthrough company nothing is derived, so this IS the quantity — send it. On a timber company, for an item kept in tons, a per-ton quantity MORE than the tons a description's size and total feet give ('2x2 = 400'' is 0.2222 ton) stages the document flagged as not worked out, naming the tons, and it cannot be entered until it is staged again with the tons — send the tons, never the feet."
  4. Changed1 schema field changed
    • changedInput schema / properties / lines / items / properties / unitPrice / description
      Previous value: -"The unit PRICE for a sales invoice, or the unit COST for a purchase bill — one field for both; Taokeh maps it. On a sales invoice: two decimals at most (whole sen, or whole cents in another currency), with any discount or tax in its own field; the same on a purchase bill."New value: +"The unit PRICE for a sales invoice, or the unit COST for a purchase bill — one field for both; Taokeh maps it. On a sales invoice: two decimals at most (whole sen, or whole cents in another currency); on a purchase bill: up to four decimals, exactly as invoiced (a per-foot or per-piece price that Taokeh converts to tons: two decimals). Either way, any discount or tax goes in its own field."
  5. Changed1 schema field changed
    • changedInput schema / properties / lines / items / properties / unitPrice / description
      Previous value: -"The unit PRICE for a sales invoice, or the unit COST for a purchase bill — one field for both; Taokeh maps it."New value: +"The unit PRICE for a sales invoice, or the unit COST for a purchase bill — one field for both; Taokeh maps it. On a sales invoice: two decimals at most (whole sen, or whole cents in another currency), with any discount or tax in its own field; the same on a purchase bill."
  6. Changed2 schema fields changed
    • changedInput schema / properties / lines / items / properties / tally / description
      Previous value: -"The piece tally as pieces/length_ft pairs — '10/10 12/14' is 10 pieces of 10 ft and 12 of 14 ft. With thickness and width this is what the quantity is derived FROM."New value: +"The tally as pieces/length_ft pairs — '10/10 12/14' is 10 pieces of 10 ft and 12 of 14 ft — OR the total running feet like 400' when the paper gives no cut list. Never invent a cut list (no '1/400'). With thickness and width this is what the quantity is derived FROM. Every token must be a pieces/length pair — a tally with anything else in it (a grade word, a stray number, '=') is refused; put grade words in the description. A total-feet tally needs thickness and width (or a named size) to work out the tons, and has no pieces, so it cannot carry a per-piece price — both are refused."
    • addedInput schema / properties / lines / items / properties / unit / description
      Added value: +"The unit the PRICE is quoted in. On a timber company: 'feet' = per running foot, 'pcs' = per piece, 'ton' or omitted = per ton. A per-foot/per-piece price is converted to the per-ton rate from thickness/width/tally, or from a cut list in the description ('2x2 = 10/10 12/14'); a description cut list the server cannot read cleanly is refused — send thickness/width/tally instead."
  7. Changed2 schema fields changed
    • addedInput schema / properties / lines / items / additionalProperties
      Added value: +false
    • addedInput schema / properties / lines / items / properties / description / description
      Added value: +"The line text as PRINTED on the historical document, when it says more than the product name does — a size, a grade, a job reference. It rides onto the posted line and is what the owner reads beside the original. THIS IS ALSO WHERE A NON-STOCK LINE LIVES: a delivery charge, a transport fee or a labour line has no catalogued product, so put its own wording in `productRef` (it is required and must not be blank) and any extra detail here — the line stages, is flagged as unresolved, and the owner picks or creates the item on the review screen. Do NOT drop the line and do not fold it into another one."
  8. Changed2 schema fields changed
    • changedInput schema / properties / lines / items / properties / quantity / description
      Previous value: -"The line quantity as the old document states it. On a measurement-profile workspace (see intake_contract's `measureProfile`) OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity from those, and a quantity sent alongside a parseable tally is NOT used to compute: it is kept as your advisory figure and shown to the owner beside the server's. On the default passthrough workspace nothing is derived, so this IS the quantity — send it."New value: +"The line quantity as the old document states it. On a measurement-profile company (see intake_contract's `measureProfile`) OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity from those, and a quantity sent alongside a parseable tally is NOT used to compute: it is kept as your advisory figure and shown to the owner beside the server's. On the default passthrough company nothing is derived, so this IS the quantity — send it."
    • changedInput schema / properties / lines / items / properties / thickness / description
      Previous value: -"Thickness in inches on a dimensional line — measurement-profile workspaces only (intake_contract shows this workspace's `measureProfile`). Give thickness + width + tally INSTEAD of a quantity and the server computes the authoritative quantity from them."New value: +"Thickness in inches on a dimensional line — measurement-profile companies only (intake_contract shows this company's `measureProfile`). Give thickness + width + tally INSTEAD of a quantity and the server computes the authoritative quantity from them."
  9. Changed4 schema fields changed
    • addedInput schema / properties / lines / items / properties / quantity / description
      Added value: +"The line quantity as the old document states it. On a measurement-profile workspace (see intake_contract's `measureProfile`) OMIT it whenever you give thickness/width/tally, or write the measure detail into the description ('2x2 = 10/10 12/14') — the server derives the authoritative quantity from those, and a quantity sent alongside a parseable tally is NOT used to compute: it is kept as your advisory figure and shown to the owner beside the server's. On the default passthrough workspace nothing is derived, so this IS the quantity — send it."
    • addedInput schema / properties / lines / items / properties / tally / description
      Added value: +"The piece tally as pieces/length_ft pairs — '10/10 12/14' is 10 pieces of 10 ft and 12 of 14 ft. With thickness and width this is what the quantity is derived FROM."
    • addedInput schema / properties / lines / items / properties / thickness / description
      Added value: +"Thickness in inches on a dimensional line — measurement-profile workspaces only (intake_contract shows this workspace's `measureProfile`). Give thickness + width + tally INSTEAD of a quantity and the server computes the authoritative quantity from them."
    • addedInput schema / properties / lines / items / properties / width / description
      Added value: +"Width in inches on a dimensional line. Goes with thickness and tally."
  10. Changed2 schema fields changed
    • changedInput schema / properties / docKind / description
      Previous value: -"'sales_invoice' = an invoice this workspace ISSUED to a customer. 'purchase_bill' = a bill a supplier issued TO this workspace (inventory lines only, same rule as create_bill_draft). Other kinds are not supported yet."New value: +"'sales_invoice' = an invoice this company ISSUED to a customer. 'purchase_bill' = a bill a supplier issued TO this company (inventory lines only, same rule as create_bill_draft). Other kinds are not supported yet."
    • changedInput schema / properties / reference / description
      Previous value: -"The document number exactly as printed in the old system (e.g. INV1603). Taokeh keeps it, so the customer's copy and yours still match. It must be unique in this workspace: a number already on the books is refused by name. Leave it out only if the document genuinely has no number. Before the first such invoice is entered, the owner must confirm where the real invoice series continues; Taokeh never silently starts migrated books at INV1."New value: +"The document number exactly as printed in the old system (e.g. INV1603). Taokeh keeps it, so the customer's copy and yours still match. It must be unique in this company: a number already on the books is refused by name. Leave it out only if the document genuinely has no number. Before the first such invoice is entered, the owner must confirm where the real invoice series continues; Taokeh never silently starts migrated books at INV1."
  11. Changed1 schema field changed
    • changedInput schema / properties / reference / description
      Previous value: -"The document number exactly as printed in the old system (e.g. INV1603). Taokeh keeps it, so the customer's copy and yours still match. It must be unique in this workspace: a number already on the books is refused by name. Leave it out only if the document genuinely has no number, and Taokeh will mint one."New value: +"The document number exactly as printed in the old system (e.g. INV1603). Taokeh keeps it, so the customer's copy and yours still match. It must be unique in this workspace: a number already on the books is refused by name. Leave it out only if the document genuinely has no number. Before the first such invoice is entered, the owner must confirm where the real invoice series continues; Taokeh never silently starts migrated books at INV1."
  12. Changed3 schema fields changed
    • addedInput schema / properties / attachmentToken
      Added value: +{
      +  "description": "The ORIGINAL this document was read off — the photo of the handwritten cash-sale slip, the scanned invoice page. Call request_attachment_upload FIRST, PUT the raw bytes to its uploadUrl, then pass the token here (there is no inline base64 on this door: a backlog export would blow the context). The file rides the staged row, the owner sees it BESIDE your figures on the document's own review screen, and it lands on the posted invoice or bill automatically when they approve. Re-staging the same sourceDocId WITH a token replaces the file; re-staging without one leaves the file already there untouched, so a bare filing is repairable.",
      +  "type": "string"
      +}
    • addedInput schema / properties / lines / items / properties / residual
      Added value: +{
      +  "description": "TRUE if this line is a balancing / catch-all figure rather than a real item — rounding, an adjustment, 'misc'. Say so honestly: Taokeh flags a residual line that carries a material share of the document, because that is where a misread hides. Never use a residual line to force a total to tie — report the gap instead.",
      +  "type": "boolean"
      +}
    • changedInput schema / properties / lines / items / properties / working / description
      Previous value: -"Your own arithmetic, kept for the owner to read. Never used to compute."New value: +"Your own arithmetic, kept for the owner to read. Never used to compute. On a handwritten slip this is what the owner checks you against — show the tally, the multiplication, the subtotal, in the order you did them."
  13. Added

TDQS

A4.4/5.0
Behavior4/5

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

Annotations only cover the coarse safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=false), so the description carries real weight here and delivers: the open-lane gate, the cutover fence, per-line residual flagging, strict row-key refusal by name, marketplace-order dedupe, and the attachment review flow. The only blemish is that 'IDEMPOTENCY IS ON sourceDocId ... staging the same sourceDocId again UPDATES that pending row' sits uneasily with idempotentHint=false; the two are reconcilable (the row is mutated, not a no-op) but the tension is never acknowledged.

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

Conciseness2/5

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

Purpose and the sibling exclusion are front-loaded, but the body is roughly 900 words in a near-unbroken block, dense with ALL-CAPS and emoji markers. Guidance is materially repeated: the non-catalogued-product path is explained once under 'NOT EVERY LINE IS A CATALOGUED PRODUCT' and again under 'NOT IN THE CATALOGUE? IT IS NOW', and the pre-cutover rule recurs in two places. An agent has to read the whole thing to be sure nothing unique is buried in the second telling.

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

Completeness4/5

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

For a 13-parameter, no-output-schema mutation tool that gates a financial migration, the description closes nearly every operational gap: lane state, cutover, ordering, error/refusal modes, attachment workflow, and what happens to flagged rows. The one thing left thin, given there is no output schema, is what a successful response returns — it is only glimpsed in passing ('the reply names them', staged-with-a-note), which an agent needs to report results back to the owner.

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

Parameters5/5

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

With 92% schema coverage the baseline would be 3, but the description adds adjudication the schema cannot: productRef is REQUIRED and must carry the line's own wording for non-stock lines so Taokeh creates an MD item, strict row keys are refused by name with a suggested correction ('sell_price' → 'unitPrice'), and sourceTotal is advisory-only tie-out against the server's re-derived figure. It also explains the marketplaceOrderKey grammar and the paymentMethod consequence ('it decides whether the document leaves a balance behind') in terms of outcome rather than field definition.

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

Purpose5/5

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

States a concrete verb and resource ('Bring ONE already-issued historical document ... across from the system this company is migrating FROM') and immediately draws the boundary against the sibling an agent would most plausibly confuse it with ('it is NOT create_invoice_draft: nothing is posted, nothing is drafted'). The sales-invoice vs supplier-bill scope, the monthly-batch grouping, and the /switch/documents review surface make it unmistakable among the ~70 siblings.

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

Usage Guidelines5/5

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

Gives explicit when-to-use ('documents that were genuinely issued in the old system'), when-not ('a NEW document belongs in create_invoice_draft / create_bill_draft'), and preconditions (the lane must be OPEN and pre-lock, otherwise 'the call is refused with instructions'). It goes further with process-level guidance an agent would otherwise get wrong: filter to post-cutover dates, stage supplier bills before sales invoices for a period, and do not route pre-cutover rows to resolve_product or the expense door.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources