Skip to main content
Glama

Taokeh MCP server

Search document lines

search_document_lines
Read-only

Read the LINE ITEMS of documents IN BULK — what was actually sold or bought, line by line, across many documents in one call. search_documents answers WHICH documents; this answers WHAT WAS ON THEM. Use it for any question that needs the detail behind the totals: average price per item across a year, how a price moved between two customers, which sizes or grades actually shift, how much of something was supplied. Without it the only way to see lines was to open one PDF per document — 180 documents is 180 round trips and 180 chances to misread a layout. docType is REQUIRED and must be one of: 'invoice', 'credit_note', 'sales_debit_note' (an additional charge this business issued to a customer), 'quote', 'delivery_order', 'bill', 'debit_note' (the BUY-side one, raised against a supplier), 'purchase_order'. Narrow with any combination of number (partial doc number — on invoices this also matches the customer's own Ref No, their DO/PO number), party (partial customer or vendor name), from/to (document date range) and productText — a case-insensitive contains matched against the PRODUCT NAME or the LINE DESCRIPTION, so "chengal" or "2x4" pulls only those lines. docType on its own is a legitimate whole-book pull. Each row: docId, docNumber, docDate, party, lineNo, product {sku, name}, description, quantity, unit, unitStamped, unitPrice, unitCost, discount, lineTotal, taxCode, docStatus, currency, fxRate, isMeasureDrift — verbatim from what was stored, never re-derived. CURRENCY: unitPrice, discount and lineTotal are in the DOCUMENT's own currency exactly as stored, NOT converted to ringgit; fxRate is the rate frozen on that document (1 unit of currency = fxRate MYR; 1 on a ringgit document). Convert with it yourself where you need ringgit, and never average or total rows of different currencies together unconverted. (sales_summary and search_documents report ringgit instead — converted once per document — so a foreign document's figures differ between them and here by exactly that conversion.) ⚠ Sell-side unitCost is ALWAYS ringgit (the stock cost). MARGIN — ONE RULE, in ringgit: sell-side line margin (RM) = lineTotal × fxRate − quantity × unitCost. lineTotal is the line AFTER its discount and BEFORE SST; unitCost is already ringgit; fxRate is 1 on a ringgit document. Never use unitPrice − unitCost: it ignores the discount and, on a foreign-currency line, subtracts ringgit from foreign money. On an isMeasureDrift row count its lineTotal but NO cost (it is a money correction, not a unit of goods — the posted cost of goods leaves it out). On the BUY side (bill, buy-side debit note) unitCost is the supplier's price in the DOCUMENT currency, not ringgit — multiply by fxRate for ringgit. MEASURE ROUNDING ROWS: isMeasureDrift true marks the measure engine's rounding correction — a line of quantity 1 at a small negative price (typically described 'Discount') that brings a measured line back to the true per-foot money. It is a real line and belongs in document totals, but EXCLUDE isMeasureDrift rows when computing an average price or quantity per product, or they drag the average down and add a phantom unit. It is null on bills, buy-side debit notes and purchase orders, which store no such row. ⚠ The flag is only reliable from the date each table started storing it — invoice, credit-note and sell-side debit-note lines from 4 Sep 2026, delivery-order lines from 19 Sep 2026, quote lines from 23 Sep 2026. Older rows all read false, and nothing was backfilled, so a line written before that date CAN be an unmarked rounding row; Taokeh does not guess which (a qty-1 negative line may equally be a real discount or fee). Say so if your answer leans on older lines. ⚠ DIMENSIONS AND SPECIFICATIONS ARE TEXT, NOT FIELDS. Taokeh has no column for a timber size, a grade, a colour or a variant: they live inside the product name and the line description as the business types them ("Chengal 2x4x8"). So this hands you that text as written and YOU do the parsing and the grouping — the server will not invent a dimension it does not store, and two lines for the same real size may be spelled differently. unit is the unit of measure stamped on the line when it was written; where the line stores none it falls back to the product's CURRENT unit, and unitStamped says which: true = the line's own stamp, false = the product stand-in. A false is right for an ordinary unmeasured line, but a MEASURED line (tons, feet) written before its table could store the unit also reads false and may show the product's unit (often 'ea') — invoice/bill lines before 3 Sep 2026, delivery-order lines before 19 Sep 2026, quote lines before 23 Sep 2026, and purchase-order lines written before the deploy that added their unit column (migration 20260923120000, late September 2026). So never assume pieces, and do not treat a false-unitStamped quantity as a measured one without checking the description. Rows come back newest document first, then in the document's own line order, capped at 200 with total, shown and more — when more is true, narrow by date (from/to) and pull the periods in turn rather than accepting a partial answer as the whole. unitCost is the COST BASIS STAMPED ON THE LINE WHEN IT WAS POSTED — like unit and the tax code beside it — so a historical line reports the cost as of THAT SALE, not the product's cost today. That is what makes per-product margin answerable here, line by line — see MARGIN below. On a BILL, a buy-side debit note or a PURCHASE ORDER there is only one price column, so unitCost and unitPrice are the same figure — what the SUPPLIER charged (on a PO: what was ordered at). On a QUOTE unitCost is null (a quote stores no cost). On a DELIVERY ORDER it is the product's moving-average cost captured when the DO was saved — a dispatch-time reference, NOT the cost of goods: the invoice the DO becomes re-reads cost when it posts, and that is the figure on the invoice line. QUOTES AND DELIVERY ORDERS ARE NOT SALES. Voided ones are left out (as voided posted documents are); every other row carries docStatus — quote OPEN or CONVERTED, delivery order OPEN or INVOICED (null on posted types). ⚠ A CONVERTED quote's lines and an INVOICED delivery order's lines ALSO appear as invoice lines (and a quote converted into a delivery order appears on that DO too), so never add a quote or DO pull to an invoice pull — for what was actually sold, use 'invoice'; for what is still only quoted or delivered-not-billed, keep docStatus OPEN. PURCHASE ORDERS ARE NOT PURCHASES either: a CANCELLED one is left out, every other row carries docStatus DRAFT, SENT or CONVERTED, and a CONVERTED order's lines ALSO appear as the bill's lines — for what was actually bought, use 'bill'. Before you propose a correction to an existing quote, delivery order or purchase order (update_quote_draft / update_delivery_order_draft / update_purchase_order_draft), read its lines here first: those tools take the FULL replacement line set, and each row's lineNo is what their keep entries refer to. Header-only search: search_documents. Paid expenses (which have no product lines): search_expenses. The ledger postings behind a document: search_journal. Nothing is written, and no draft is created.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
toNoLatest DOCUMENT date (YYYY-MM-DD).
refNoNOT a filter on this tool. Pass the customer's own Ref No (their DO / PO number) as `number` — that one parameter searches BOTH the invoice's own number and the customer's Ref No, and the row it returns reports each separately as `number` and `refNo`.
skuNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
fromNoEarliest DOCUMENT date (YYYY-MM-DD). The main way to break a >200-line pull into honest slices.
itemNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
sizeNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them). There is no size field to filter on.
textNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
docIdNoNOT a filter on this tool. This tool reads lines across MANY documents — narrow by `number` (the document number), `party` or a date range instead. For one document, pass its number as `number`.
limitNoNOT a filter on this tool. The page size is fixed at 200 lines. Narrow with from/to, party or productText and pull the periods in turn.
partyNoPartial customer or vendor name (case-insensitive contains).
refNoNoNOT a filter on this tool. Pass the customer's own Ref No (their DO / PO number) as `number` — that one parameter searches BOTH the invoice's own number and the customer's Ref No, and the row it returns reports each separately as `number` and `refNo`.
numberNoPartial doc number (case-insensitive). On INVOICES this also matches the customer's own Ref No — their DO or PO number.
vendorNoNOT a filter on this tool. Pass a customer or vendor name as `party`.
docTypeNoREQUIRED. One of: 'invoice', 'credit_note', 'sales_debit_note', 'quote', 'delivery_order', 'bill', 'debit_note', 'purchase_order'. Note the two debit notes: 'sales_debit_note' is one this business ISSUED to a customer; 'debit_note' is the BUY side, against a supplier bill.
productNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
customerNoNOT a filter on this tool. Pass a customer or vendor name as `party`.
supplierNoNOT a filter on this tool. Pass a customer or vendor name as `party`.
docNumberNoNOT a filter on this tool. Pass the document number as `number` (partial matches are fine).
productIdNoNOT a filter on this tool. This search matches product TEXT, not ids — pass the name or size words as `productText`.
referenceNoNOT a filter on this tool. Pass the customer's own Ref No (their DO / PO number) as `number` — that one parameter searches BOTH the invoice's own number and the customer's Ref No, and the row it returns reports each separately as `number` and `refNo`.
descriptionNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
productNameNoNOT a filter on this tool. Pass it as `productText` — one case-insensitive contains matched against BOTH the product name and the line description, which is where sizes, grades and variants live (Taokeh stores no column for them).
productTextNoCase-insensitive text matched against the PRODUCT NAME or the LINE DESCRIPTION — this is where sizes, grades and variants live, because Taokeh stores no column for them. e.g. "chengal", "2x4".

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / docType / description
      Previous value: -"REQUIRED. One of: 'invoice', 'credit_note', 'sales_debit_note', 'quote', 'delivery_order', 'bill', 'debit_note'. Note the two debit notes: 'sales_debit_note' is one this business ISSUED to a customer; 'debit_note' is the BUY side, against a supplier bill."New value: +"REQUIRED. One of: 'invoice', 'credit_note', 'sales_debit_note', 'quote', 'delivery_order', 'bill', 'debit_note', 'purchase_order'. Note the two debit notes: 'sales_debit_note' is one this business ISSUED to a customer; 'debit_note' is the BUY side, against a supplier bill."
  2. Changed1 schema field changed
    • changedInput schema / properties / docType / description
      Previous value: -"REQUIRED. One of: 'invoice', 'credit_note', 'sales_debit_note', 'bill', 'debit_note'. Note the two debit notes: 'sales_debit_note' is one this business ISSUED to a customer; 'debit_note' is the BUY side, against a supplier bill."New value: +"REQUIRED. One of: 'invoice', 'credit_note', 'sales_debit_note', 'quote', 'delivery_order', 'bill', 'debit_note'. Note the two debit notes: 'sales_debit_note' is one this business ISSUED to a customer; 'debit_note' is the BUY side, against a supplier bill."
  3. Added

TDQS

A4.9/5.0
Behavior5/5

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

The description adds substantial behavioral context beyond the readOnlyHint and openWorldHint annotations: fixed 200-row cap with total/shown/more, ordering rules, currency conversion guidance, margin formula, docStatus semantics, isMeasureDrift caveats, unit fallback behavior, and historical cost-basis explanation. It ends with 'Nothing is written, and no draft is created,' reinforcing the read-only annotation without contradiction.

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

Conciseness4/5

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

The description is very long, but appropriately so for a high-stakes tool with many edge cases around currency, margin, measure drift, and document types. It front-loads the core purpose and use cases before diving into caveats, and uses bold labels and clear sectioning to make the length navigable, though a tighter edit would improve readability.

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

Completeness5/5

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

With no output schema present, the description carries the full burden of explaining return rows, ordering, pagination, currency behavior, margin calculation, and per-document-type semantics — and it does so comprehensively. It covers buy-side vs sell-side differences, voided/converted document statuses, and data-reliability cutoffs, leaving no critical gap for an agent deciding whether and how to call this tool.

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?

Though schema coverage is 100%, the description adds meaning the schema alone cannot convey: docType is REQUIRED despite the schema not enforcing it, number also matches the customer's Ref No on invoices, productText matches both product name and line description, and many schema parameters (ref, sku, item, size, docId, limit, etc.) are explicitly marked as NOT filters with instructions on what to use instead. This is far beyond the baseline.

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

Purpose5/5

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

The description opens with a specific verb and resource: 'Read the LINE ITEMS of documents IN BULK' and immediately contrasts with search_documents ('answers WHICH documents; this answers WHAT WAS ON THEM'). This makes the tool's scope unmistakable and distinguishes it from closely named 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?

It explicitly says when to use the tool ('any question that needs the detail behind the totals'), what it replaces (opening one PDF per document), and names concrete alternatives: search_documents for header-only, search_expenses for paid expenses, search_journal for ledger postings. It even warns to read lines here before calling draft-update tools that take full replacement line sets.

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