koble-mcp
OfficialConnect Claude to Koble/EBMS ERP to query data, make guarded verified writes, run MRP planning, and follow built-in procedures.
List reachable companies/datasets, with IDs, names, versions, and write permission.
Read EBMS OData collections or single records using select, filter, expand, orderby, top, skip, and count.
Create, update, or delete records with safety guards and read-back verification; reports mismatches, problems, notes, and uncertainty.
Run only allow-listed bound actions, avoiding posts, payments, processing, or sending.
Run read-only MRP plans for a time frame and scope, returning buy/make recommendations and a worksheet.
View everything needed to build a finished good down its BOM against availability.
Turn approved MRP worksheets into purchase-order or manufacturing-batch drafts without creating anything.
Retrieve EBMS workflow skills and reference procedures via ebms_guide.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@koble-mcporder 10 tubes from Bike Parts Co"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
koble-mcp
EBMS (Koble Systems ERP) for Claude. Ask Claude to enter a sales order, raise or receive a purchase order, set up a product, manage a task, or plan what to buy and make — and it does it in EBMS, confirming each change with you and checking afterwards that EBMS stored what was sent.
It is two things in one install:
A small MCP server that owns the EBMS connection: your credentials, which companies it may touch, and a few hard guards (nothing is ever posted, paid or sent; every write is verified).
Skills — the procedures, written down: how to build an order in chunks, what to confirm, which EBMS quirks to avoid. They live in
skills/, and the server also serves them to Claude apps that cannot install skills themselves.
Install
One command downloads the koble program (checked against the release's checksums), then
koble setup asks for your EBMS serial number, lists the companies it reaches and has you choose
which ones the agent may use, asks for a test company, then a username and password for each
company. It checks each login works, stores the passwords in your system's credential store, and
connects the AI apps you choose from the ones it finds. Later, koble companies shows and changes
which companies are enabled, and koble login <company> signs in to one again:
App | What koble sets up |
Claude Desktop | the server, in the config Desktop actually reads (including the Windows Store build's own folder) |
Claude Code, and Claude Desktop's Code tab | the server, plus the skills as |
Codex (OpenAI) | the server, in |
Cursor, VS Code (Copilot), Gemini CLI, Windsurf | the server, in each app's MCP config |
Every app also gets the procedures through the server itself (ebms_guide), so none of them needs
anything uploaded. Run koble doctor any time to check everything, and koble connect --apps … to
add an app later.
ChatGPT. The ChatGPT app can only connect to servers on the internet, not to a program on your computer, so it needs a hosted version of koble that doesn't exist yet. OpenAI's Codex works today.
Windows
In PowerShell (Start menu → PowerShell):
irm https://github.com/koblesystems/koble-mcp/releases/latest/download/install.ps1 | iexIt installs koble.exe to %LOCALAPPDATA%\Programs\koble and adds that folder to your PATH.
The password goes to Windows Credential Manager.
If Windows blocks
koble.exe. Releases are not code-signed yet, so SmartScreen may show "Windows protected your PC" — choose More info → Run anyway. On Windows 11 with Smart App Control turned on, unsigned programs are blocked outright; until signed builds are published, use a machine or VM without Smart App Control. Please don't turn it off just for this.
macOS
In Terminal:
curl -fsSL https://github.com/koblesystems/koble-mcp/releases/latest/download/install.sh | bashIt installs koble to ~/.local/bin (Apple silicon). The password goes to the macOS Keychain.
Intel Macs are not built yet.
Linux
curl -fsSL https://github.com/koblesystems/koble-mcp/releases/latest/download/install.sh | bashx64 and arm64. The password goes to the Secret Service keyring when secret-tool is available,
otherwise to a file in ~/.config/koble that only you can read. Claude Desktop does not run on
Linux; use Claude Code.
Checking a download. The installers and
koble updatecheck each file against the release'schecksums.txt. Every release file also carries a build provenance attestation, so with the GitHub CLI you can confirm it was built by this repository's release workflow:gh attestation verify koble-darwin-arm64 --repo koblesystems/koble-mcp.
Claude Code
The installer above connects Claude Code and copies the skills into its skills folder, so they are
/ commands straight away: /ebms-mrp, /ebms-purchase-orders, /koble-setup and the rest.
If you'd rather start from inside Claude Code, add the plugin:
claude plugin marketplace add koblesystems/koble-mcp
claude plugin install koble-mcp@koblesystemsand ask Claude to "set up Koble" (or run /koble-mcp:koble-setup): it installs the program,
saves your settings, and has you type each company's password into koble login yourself — a
password never goes through the chat.
Let an AI agent install it
Point any coding agent at install.md. It is written to be followed step by step.
After installing
Claude Desktop: quit and reopen it.
Claude Code: start a new session (or run
/mcp).Ask: "Which EBMS companies can you see?" — Claude should name them.
Settings live in ~/.config/koble (%APPDATA%\koble on Windows). koble update installs the
newest release; koble setup again changes any answer.
/ commands in Claude Desktop's chat
Claude Code and Desktop's Code tab get the skills as / commands automatically. Desktop's regular
chat shows skills from plugins on your Claude account, and this repository is a plugin marketplace:
Claude Desktop → Settings → Customize → Plugins → Add marketplace → Add from a repository
Enter
koblesystems/koble-mcpand install Koble.
The skills then appear under / as Koble in every Claude chat on your account, and update
themselves from this repository. (They follow the repository, so they can be a little newer than
your koble; they only use its tools, so that is fine — koble update keeps the two close.)
koble doctor says whether the plugin is on your account. Desktop's Code tab shows it too, so
once it is there koble connect stops copying the skills into Claude Code's folder (and removes the
copies it made) — otherwise every skill would appear twice. The claude command in a terminal
does not see account plugins; used on its own, it keeps koble's copies.
If your account cannot add a marketplace from GitHub, koble plugin saves the same skills as a
koble.plugin file to upload there instead — one or the other, not both.
Uninstall
koble uninstallThe same on every system. It lists everything koble added — its entry in each AI app's config,
the skills it put in Claude Code, the stored password, its settings, and the program itself (and,
on Windows, its folder on your PATH) — asks once, then removes exactly those. Each app config is
backed up first, a config it cannot read safely is left alone with a note, and a skill of your own
with the same name is never touched. Your MRP worksheets and the config backups stay. Quit Claude
Desktop first, or it may write koble back into its config. --yes skips the question.
Related MCP server: PrintSmith MCP Server
Using it
Ask in your own words — "order 10 tubes from Bike Parts Co", "what's open for the bike shop?", "run MRP for the next 60 days" — or start a named workflow:
Workflow | Claude Code (and Desktop's Code tab) | Claude Desktop chat (+ menu; or |
Plan what to buy and make |
| + menu → koble-mcp → mrp-plan |
Create the POs / batches an MRP worksheet approved |
| + → mrp-purchase-orders, mrp-batches |
Sales orders |
| + → sales-order |
Purchase orders, receiving, what's on order |
| + → purchase-order, receive, on-order |
Products, tasks |
| + → product, task |
Reschedule a week's tasks so nobody overlaps |
| + → task-reflow |
Customers and vendors |
| + → customer, vendor |
Import a CSV or Excel file (review first, then one yes) |
| + → import, import-products, import-customers, import-vendors, review-spreadsheet |
Set up a new, empty company from scratch |
| + → new-company |
Check or repair the install |
| run |
The server's named workflows also appear in Claude Code as /mcp__koble-mcp__mrp-plan and so on,
and in other apps wherever they list an MCP server's prompts.
What is safe. Planning and import review are read-only: mrp_plan, mrp_item_view,
po_from_csv, batches_from_csv and import_from_csv never write to EBMS. Purchase orders and
batches are only created by the second and third skills, one at a time, after you say yes to
each; an import's records only by the ebms-import skill, after one yes for the file. With EBMS_SANDBOX set, writes can only go to that company: the company is part of a URL
this server builds itself, and a request that would land anywhere else is refused before it is
sent. Leave it set while testing. The PROCESS field is refused in every request body, and
ebms_command runs only a short list of actions, none of which posts, pays or sends.
Testing it? TESTING.md has a checklist and what to send back.
Tools
Tool | What it does | Refuses |
| Lists the companies the serial reaches — ID, name, version, and whether writes are allowed. Needs no credentials. | — |
| One GET: a collection or a record, with | anything but |
| Pages a whole collection to a CSV, Excel or JSONL file in | the same path rules, and a keyed path; a |
| One POST, PATCH or DELETE with a JSON body. | a company that is not configured (or not the sandbox, while testing); |
| One bound action: | a company that is not configured (or not the sandbox, while testing); any action that is not on the allow-list ( |
| Serves the skills: the list, one skill, or one reference file. Lets Claude Desktop use them without uploading anything. | — (read-only; only the files it shipped with) |
| Planning and worksheet reading (see Planning). | — (read-only) |
| Reviews a CSV or Excel file of one entity against EBMS and drafts the writes (see Importing). | — (read-only) |
Every result names the company it ran against. Every failure carries uncertain and says
what it means:
uncertain: falsewithrefused: true— this server stopped it, a check before the write failed, or it could not sign in. Nothing was sent.uncertain: falsewith anerror.status— EBMS answered and said no. Nothing was saved.uncertain: true— a timeout, a dropped connection, a response that broke off part-way, a 5xx, a 2xx carrying an error message, or a fault inside this server after the request had gone out. The write may or may not have happened, so read the record back before sending it again. A resent create or add duplicates.
Paths are parsed and rebuilt, not passed through. The entity name is validated; each key
value may not contain / \ ? %, .. or control characters, and is percent-encoded (so a #
in a PO number is data, not a URL fragment). As a second check the client refuses any finished
URL that is not inside the company's own OData root. That is what makes the company boundary
hold even against text a model was tricked into using.
Actions are allowed by name, not refused by name. EBMS has many bound actions that post,
process, pay or send (ProcessScanner, Post, Unpost, RecordPayment, Send, …); a list of
those could never be complete, so ebms_command runs only EBMS_ALLOWED_COMMANDS — by default MarkAllAsShipped, RecalculateAllPrices, CalculateFreight, ChangeCustomer and LinkInvoice.
Every write is verified
A 2xx is not proof. EBMS answers 200 to writes it only partly applies: an unknown @id is
ignored, an unwritable field is dropped, an over-long value is cut, a quantity can come back
as 0. So after each write the server reads back exactly the fields that were sent and
compares them in code — numbers within half a cent, strings ignoring padding and line-ending
style — instead of leaving the arithmetic to a model:
"verification": {
"ok": false,
"checked": 6,
"mismatches": [{ "where": "Details[1] › Materials[2] TEAMJERSEY", "field": "M_QUAN_VIS", "sent": 1, "stored": 0 }],
"problems": [],
"notes": [],
"rows": [ … the stored values of every row the write touched or created … ]
}mismatches— a field stored differently from what was sent.problems— a row that never appeared, an@idEBMS ignored, a removal that didn't happen.notes— rows EBMS added on its own, such as an assembly kit's default components. Not a failure. PassreadBack.children: "Materials"to have new rows checked for them.rows— what EBMS stored, including anything asked for inreadBack.lines(UNIT_MEAS,UNIT_VIS,SO_AMOUNT) orreadBack.record. Report these, not what was sent.
It is generic: it understands OData's shapes (top-level fields, Nav@delta arrays, nested
arrays on a create) and knows nothing about any one entity. New rows are told apart from old
by a light read of row IDs before a PATCH; children are read only for the parent rows the
write touched, because an unfiltered nested expand costs EBMS tens of seconds on a large
document. If the write succeeds and only the read-back fails, the result says exactly that
and tells the caller not to resend. verify: false switches it off.
The write result no longer echoes EBMS's whole record (about a hundred fields); it returns
the record's AUTOID, INVOICE and ID plus the verification.
Importing
import_from_csv reads a CSV or Excel file of products, units, vendor records, bills of
materials, customers, vendors, workers, folders, tax rates or configuration records. It maps the
columns to fields using EBMS's live metadata, checks every row (blanks, types, lengths,
duplicates, and every folder, vendor, product and unit a row names), skips rows already in EBMS
or created by an earlier run of the same import, and returns the exact ebms_write call for each
remaining row. Problems come back grouped by kind with counts, and the rows that need a person
are saved to an exceptions workbook beside the file (<name>.exceptions.xlsx) with a Problem
and a Fix column. That workbook can be corrected and handed straight back.
It writes nothing. The ebms-import skill shows the mapping, the problems and a few drafts, asks
once for the file, and writes the drafts in order; every create carries an EXTERNALID
(claude-import-<importId>-r<row>), so a rerun skips what exists and a resend is refused. A row
is only skipped when the record found is the row's own (same key, or same name for a customer EBMS
numbered); a marker on a different record (a row deleted, or another file under the same name) is
reported, never skipped.
ebms-new-company puts the files in the order they depend on each other. The shaping the tool
does (units and vendor records grouped per product, at most 50 to a PATCH; a folder drafted only
once its parent exists, since EBMS numbers new folders itself) never decides anything: it is
deterministic and documented in src/import/drafts.ts and src/import/lookups.ts.
Some records cannot be created through the EBMS API (1.8.184): customer and vendor folders, workers, warehouses and price levels. Those are set up in EBMS; a worker file can still be reviewed. Verified on a live company, with what was not, in the two skills.
Planning (MRP)
Two read-only tools sit beside the proxy, for the same reason write verification does: it is arithmetic over hundreds of rows that has to be exact.
Tool | What it answers |
| What to buy and make, by when, and why — for a time frame and a scope (everything, particular vendors, or particular products) that the user gives. It will not assume either. The worksheet comes back attached to the result, so it can be handed to the user in the conversation. |
| Everything needed to build N of one finished good, down every BOM level, against what is available. |
| Reads the planner's approved worksheet and drafts one purchase order per vendor. Creates nothing; the drafts go through |
| Reads the approved |
What is read, and how it is netted (worked out against SBX with someone who knows the database):
Demand — open sales (
S) and job (J) lines fromARINVDET,QUAN − SHIPin base units, dated by the line'sSHIP_DATE. A line with a materials list underneath is skipped in favour of its children. Open batches' consumables (INMFG→ARINVDETs) are demand too.Supply — open purchase lines through
APINV→Details(O_QUAN_VIS − SHIP_VIS), and open batches' finished goods (INMFG→FinishedDetails, whereSHIP_VISis the quantity made so far). These are in the line's unit and are converted to base units fromINVENUNT.Parameters —
T_ON_HAND,MIN_INVEN(floor),MAX_INVEN(order up to),ORDER_AMT(reorder increment),PRI_VENDOR,PURC_METHfromINVENTRY. Only stocked products and stocked lines are pooled; drop-ship, sync and associated lines belong to their own orders.Made or bought — an item is manufactured if it has ever been a batch's finished good;
alsoMadeandbuyInsteadoverride that for a run. Made items explode throughINVENDET, level by level, so a made component of a made item is planned too.Two rules for shortage — a projected stock-out pulls in a later receipt (an expedite message) or plans a dated order; being under the minimum only matters if it is still under at the end of the time frame. (
QUAN2ORDERon the product is not a formula to match: it is whatever EBMS's own purchasing screen last saved. The worksheet shows it as a reference.)A receipt with no expected date is counted on the last day of the time frame — late enough that it cannot quietly cover a shortage it may not arrive for, early enough to count toward the minimum. Where it is needed sooner, the plan asks the buyer to confirm it by that date.
What is already on order just after the time frame is not netted, but it is shown: on the worksheet, and beside any item the plan says to buy.
Lead time — the product's record for its primary vendor (
INVENDOR.LEAD_DAYS), else the vendor's (APVENDOR.LEAD_DAYS); 0 means not set. A purchase with a lead time gets an order-by date; without one it carries only a needed-by date.leadTimes(per product) overrides EBMS,leadTimeDaysfills in where EBMS has none. On an EBMS too old to publishLEAD_DAYS, the plan runs without and says so. Demand just after the time frame that a long lead time pulls inside it is listed, not netted.
Manufacturing batches. What creating test batches in EBMS showed, and the drafts are built on:
the finished good must be a Track Count product (anything else is refused); EBMS does not add
consumed materials itself when a batch arrives through the API, as its own screens do, so every
component is sent from INVENDET; and a consumed line's M_QUAN_VIS is the amount for one
finished good, which EBMS multiplies by the batch size. Drafts mark nothing as made or consumed,
state each line's unit, take the warehouse the planner gives or the one the product was last made
in, and carry an EXTERNALID of the run plus the worksheet line so a batch cannot be created
twice (INMFG is covered by the duplicate guard alongside ARINV, APINV and TASK).
The worksheet. mrp_plan writes an Excel workbook (to KOBLE_OUTPUT_DIR, or
Documents/Koble MRP) that opens in Excel and Google Sheets:
Summary — what to do, orders by vendor with live totals of what has been approved, and the plan's caveats.
To order — purchases grouped by vendor (one group, one purchase order), most urgent first: quantity in the vendor's purchase unit, part number, order-by and needed-by dates, lead time, cost from
INVENDOR(the product's own stock unit when the vendor has none, stated on the order so EBMS cannot default to a case), and a short reason. Late order-by dates are red.To make — batches. Follow up — receipts to chase and orders nothing needs, with the document named ("PO#185", "Batch 178"). All items — every planned item and its figures.
The planner edits only the shaded columns — Approve (a Yes/No list), Qty, Vendor and Notes — and
saves the file. The columns that tie a row to its run are hidden, and columns empty on every row
are hidden too. po_from_csv and batches_from_csv take the workbook's path, or a CSV as before.
Spreadsheets reformat dates, turn long numeric product IDs into 3.94E+13 and drop leading
zeros, so the file is not trusted for anything the planner was not meant to edit: mrp_plan
also saves a small run record (runs/<run>.json beside the worksheet), and po_from_csv
takes the item, unit, cost and date from it, keyed by the row's Line. Each row also carries a
Check code over its run, line and product, so a Run cell changed on every row, a worksheet
re-pointed at another run, or a row typed in by hand is refused with or without the record.
A line the planner moves to another vendor has its quantity converted through stock units into
that vendor's unit (2 cases of 24 become 48 each), and says so. Rows added by hand,
duplicated rows, a changed Run cell, unrecognised Approve text and ambiguous quantities
(1,5, 1e3) are named as problems, and each draft lists what the planner changed. If the
record cannot be found (the file moved to another computer) the file is read strictly and the
result says so. Drafts do not send an expected date: on the purchase orders created so far, EBMS stored its own
ETA_DATE (apparently from the vendor's lead time) and ignored the one sent, so the read-back reports it and the skill compares it with the day
the stock is needed. po_from_csv checks each approved row against EBMS, names
any it cannot order (no vendor, zero quantity, inactive product), and drafts one purchase order per
vendor whose EXTERNALID is the run plus the vendor, so the same worksheet cannot order twice.
The file is written and read by code so the numbers a person approves are the numbers ordered.
The engine (src/mrp/engine.ts), the finished-good view (src/mrp/tree.ts) and unit conversion
(src/mrp/units.ts) are pure and unit-tested; src/mrp/snapshot.ts does the reads. A 60-day
plan of SBX takes about 30 s, nearly all of it EBMS answering six reads one after another.
Companies
One server can serve several companies on the same serial number.
EBMS_SERIAL_NUMBER=...
EBMS_USERNAME=...
EBMS_PASSWORD=...
EBMS_COMPANIES=sbx,live # optional: narrow to these IDs; unset = every company the serial reaches
EBMS_SANDBOX=sbx # optional, while testing: writes go only here
EBMS_COF_USERNAME=... # optional per-company credentials
EBMS_COF_PASSWORD=...
EBMS_ALLOWED_COMMANDS=MarkAllAsShipped,RecalculateAllPrices,CalculateFreight,ChangeCustomer # optional; this is the default
EBMS_LOG_FILE=./logs/requests.jsonl # optional; method, path, company, status, ms — never bodiesUsers rarely know a company's internal ID, so the server discovers the companies itself: at
startup it asks the serial's unauthenticated company-list endpoint, and ebms_companies
shows the result with names. Every company argument accepts the ID or the name
("Sample Coffee Co"). EBMS_COMPANIES is only needed to narrow that list.
Every available company may be read and written. EBMS_SANDBOX is for testing:
when set, writes go only to that one company, which is readable by implication and need not
be repeated in the list. With one company configured, company may be omitted on reads; on
writes and commands it is always required, and with several companies it is required
everywhere. EBMS_COMPANY_ID (the variable ebms-mcp used) is still honoured.
Nothing in EBMS marks a dataset as live or a copy. Listing a live company means a model can write to it, so the skills' rule of showing the exact request and getting a yes before every write is what protects it — together with the guards below, which are the mistakes a confirmation step does not catch.
Developing
Needs Node 22.
git clone https://github.com/koblesystems/koble-mcp.git
cd koble-mcp
npm install
npm run check # builds, then runs the tests; none of them touch the network
node cli.js setup # the same setup, run from source
node scripts/build-single.mjs # the single-file koble for this platform, in dist/The Claude Code plugin brings only the skills. koble connect registers the server itself, by its full path, so it never depends on PATH.
The server reads EBMS_* settings from its environment when they are set (see .env.example),
and otherwise from what koble setup stored — so an existing configuration that passes them in
an MCP client's env block keeps working. A release is cut by pushing a tag vX.Y.Z that matches
package.json; the release workflow builds koble for Windows, macOS and Linux and publishes it
with checksums.txt.
Design rules
The server never decides. No chunking, no resume logic, no planning. Those were the parts that went wrong in the previous design, and they are the parts a skill can fix without a rebuild and a restart. What it does do in code is arithmetic nobody should trust a model with: comparing what was stored against what was sent.
The guards are the ones a model skips under pressure, and only those: an unconfigured company,
PROCESS, duplicateEXTERNALID, actions off the allow-list, and anything in a path that could leave the company.Uncertainty is explicit. Timeouts, network failures and 5xx responses are labelled so a skill can tell "EBMS said no" from "nobody knows".
Credentials stay in the process. They are read once, per company, and never enter a result, an error or the log.
stdout belongs to JSON-RPC. Log with
console.erroronly.
License
MIT — see LICENSE. Security reports: see SECURITY.md.
Available Tools
11 toolsbatches_from_csvA
Turn approved MAKE rows of an MRP worksheet into manufacturing-batch drafts, read-only. For each it checks EBMS will accept the product as a finished good (it must be classified Track Count), lists every component from the bill of materials with its quantity per one finished good (EBMS does NOT add consumed materials itself when a batch arrives through the API), picks the warehouse (the one given, else where the product was last made), and returns the exact body to POST to INMFG with ebms_write. It creates nothing. Drafts mark nothing as made or consumed and never carry PROCESS: finishing and processing a batch is done by a person in EBMS. Show each draft and get a clear yes before writing it.
| Name | Required | Description | Default |
|---|---|---|---|
| csv | No | The worksheet's CSV text, exactly as the user attached or pasted it. | |
| path | No | Path of the worksheet on this computer: the .xlsx workbook mrp_plan saved (after the user approved rows in it), or a CSV. Give this or csv. | |
| company | Yes | Required. Company, by ID or name. Must match the worksheet's company. | |
| warehouse | No | Warehouse ID for every batch. ASK the user if they have more than one; when omitted, each product's batch goes where it was last made. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the whole burden and does so well: it declares read-only behavior ('It creates nothing'), that drafts mark nothing made or consumed, that PROCESS is never carried and must be finished by a person in EBMS, and that EBMS does NOT auto-add consumed materials via the API. It also discloses the Track Count acceptance check and the warehouse fallback rule.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a precise statement of what it does, and every clause is substantive (the Track Count check, the BOM quantity caveat, the draft-is-not-a-write warning). It is a dense single paragraph with a couple of long parentheticals that would read better as a short list, but little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description explains what comes back (the exact POST body per draft) and how to use it (show each draft, get a clear yes). It does not describe the shape of the returned draft list beyond that, a minor gap for a tool with this much behavior to convey.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all four parameters. The description restates the warehouse defaulting rule ('the one given, else where the product was last made') and the company-match requirement, both of which already appear in the schema, so it adds little beyond the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: turn approved MAKE rows of an MRP worksheet into manufacturing-batch drafts, read-only. That is clearly distinct from mrp_plan (which produces the worksheet) and ebms_write (which performs the POST), so an agent can separate it from siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives the precondition (rows approved in the mrp_plan worksheet), names the follow-on tool ('returns the exact body to POST to INMFG with ebms_write'), and rules out human-only steps. It does not state explicit when-not conditions or contrast against import_from_csv/po_from_csv, so it falls just short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_commandA
Run a bound action on one record: POST /ENTITY('')/Model.Entities.. Omit body for a command with no dialog (MarkAllAsShipped, RecalculateAllPrices) — EBMS rejects even {}. Pass the dialog's fields for one that has a dialog (ChangeCustomer). Refused for a company that is not configured (or not the sandbox, while testing), and for any action that is not on the server's short allow-list — nothing that posts, processes, pays or sends. Commands return little; read the record back afterwards.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Required. AUTOID of the record. | |
| body | No | Dialog fields, only for commands that have a dialog. | |
| entity | Yes | Required. The entity, e.g. ARINV | |
| command | Yes | Required. The action name, e.g. MarkAllAsShipped, RecalculateAllPrices, ChangeCustomer | |
| company | Yes | Company, by ID or name as ebms_companies lists them. Required on every write. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and delivers strong transparency: it discloses the HTTP POST method, the fact that EBMS rejects even an empty {} for no-dialog commands, server-side allow-list restrictions (nothing that posts, processes, pays or sends), and that commands return little data. This gives an agent a clear behavioral profile before invoking.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: purpose, endpoint, body rules, restrictions, and return behavior are packed into a compact, front-loaded description with no redundancy. The critical nuance about omitting the body is stated early, and the allow-list restriction is explained clearly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has 5 parameters, a nested body, and no output schema, but the description covers all tricky invocation details: body omission, allow-list restrictions, and the fact that commands return little, directing the agent to read the record back. This compensates for the missing output schema and leaves the agent well-equipped to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaningful nuance: it explicitly says to omit the body for no-dialog commands and that EBMS rejects even {}, which goes beyond the schema's generic 'Dialog fields, only for commands that have a dialog.' It also adds the configured-company/sandbox restriction and gives concrete command values for the command parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair, 'Run a bound action on one record,' and gives the exact endpoint pattern, POST /ENTITY('<AUTOID>')/Model.Entities.<Command>. Concrete examples like MarkAllAsShipped and ChangeCustomer differentiate this from sibling tools such as ebms_write or ebms_get, so an agent can identify its purpose without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when the command will be refused (unconfigured company, non-sandbox during testing, actions not on the allow-list) and advises reading the record back afterwards, implying a follow-up read via another tool. However, it never explicitly names sibling tools or states when to choose this over ebms_write/ebms_get; the alternative usage is implied rather than spelled out.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_companiesA
List the companies (datasets) this server can reach on its EBMS serial number, with name, ID, version and whether writes are allowed. Needs no credentials. Call it when the user names a company you haven't seen, or before the first write of a session, so the company is confirmed by name. Nothing marks a company as live or a test copy; ask if unsure.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does well: it discloses that no credentials are needed, and it surfaces the key limitation that nothing marks a company as live or test. The 'list' verb implies read-only and the output fields are enumerated. It stops short of explicitly stating a lack of side effects, but coverage is strong for a listing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: what it lists, when to call it, and the live/test caveat. The most important scoping information is front-loaded and there is no filler or repetition of schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with no output schema and no annotations, the description is complete. It enumerates the returned fields in prose, covers authentication requirements, gives trigger conditions, and flags ambiguity about live vs. test copies. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is empty, so there is nothing to elaborate. Per the baseline for 0-parameter tools, a 4 is appropriate; the description correctly avoids inventing input details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('List the companies (datasets) this server can reach') plus the exact fields returned (name, ID, version, write permission). The specifics of a company catalog listing clearly set it apart from siblings like ebms_get, ebms_write, and ebms_command, so an agent can distinguish it without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit, actionable when-to-call guidance: 'Call it when the user names a company you haven't seen, or before the first write of a session.' It also warns that no marker distinguishes live vs. test copies and to ask when unsure. It does not name alternatives or when-not conditions, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_exportA
Read a whole EBMS collection to a file (CSV, Excel or JSONL) instead of into the conversation, for anything more than a few hundred rows: sales history, every product, all open lines. The server pages through it itself and returns only the file's path, the row count, the columns, five sample rows and min/max/sum of each numeric column — never the rows. Analyse the file with a script (pandas, duckdb) and read back only the aggregates; never write a script that calls EBMS. Count first with ebms_get (top 1). Select only the fields you need. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Required. An entity set, e.g. ARINVDET, INVENTRY. Not a keyed path. | |
| expand | No | $expand, with a select inside, e.g. Details($select=INVEN,O_QUAN_VIS). Line _VIS fields read 0 unless read through the parent like this. | |
| filter | No | $filter, unencoded. | |
| folder | No | Only a folder the user named: an existing one, not hidden and not koble's settings. Default: KOBLE_EXPORT_DIR, or 'Koble Exports' in the user's Documents (created if missing). | |
| format | No | Default csv. | |
| select | Yes | Required. $select, comma-separated. AUTOID is added if missing. | |
| company | No | Company, by ID or name as ebms_companies lists them. May be omitted only when one company is available. | |
| explode | No | An expanded collection, e.g. Details: one row per child, with the parent's fields repeated and the child's as Details.<FIELD>. Without it an expanded collection is JSON text in one cell. | |
| maxRows | No | Refuse an export larger than this. Default 250000. | |
| orderby | No | Default AUTOID, so pages do not shift while being read; where EBMS refuses that sort, the server's own order is used and repeats are still removed by AUTOID (the result says ordered: false). | |
| filename | No | File name only. Default <company>-<entity>-<timestamp>. An existing file is never overwritten. | |
| pageSize | No | Rows per request. Default 500, or 25 with an expand. Lower it if a page times out. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses that the server pages internally, that it returns only path, row count, columns, five sample rows and numeric aggregates 'never the rows', that existing files are never overwritten, that ordering may fall back ('ordered: false'), and that it is read-only. That is substantive behavioral context beyond a bare verb.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and the file-vs-conversation distinction before the mechanics. Dense but nearly every clause carries information; the dash-heavy style is slightly compressed but not padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must explain the return shape — and it does precisely (path, row count, columns, five samples, per-numeric min/max/sum). For a 12-parameter export tool this covers everything an agent needs to call it and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the param descriptions already explain expand/explode examples, defaults and maxRows behavior, so the schema does the heavy lifting. The description reinforces field selection ('Select only the fields you need') but adds little parameter-level meaning beyond what the schema states. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read a whole EBMS collection') plus the destination ('to a file (CSV, Excel or JSONL)') and explicitly contrasts with the alternative of reading into the conversation. An agent can distinguish this from ebms_get without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit selection criteria ('anything more than a few hundred rows'), names the prerequisite/alternative ('Count first with ebms_get (top 1)'), and describes the downstream workflow ('Analyse the file with a script... never write a script that calls EBMS'). When-to-use and when-not-to-use are both present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_getA
Read from EBMS OData: a collection (path 'ARINV') or one record (path "ARINV('')"). Always pass select — an unselected read returns every field, many computed, and large ones hit the 2-minute limit. For a collection, count is on by default and the result says whether rows were truncated. For more than a few hundred rows use ebms_export instead: without top only 200 rows are shown, and never more than about 150 KB. Query syntax and the install's quirks are in the ebms-api skill.
| Name | Required | Description | Default |
|---|---|---|---|
| top | No | ||
| path | Yes | Required. Entity path only, e.g. ARINV, ARINV('7XQPR42LM8W91000'), EntityMetaData('ARINV'), $metadata. No query string. | |
| skip | No | ||
| count | No | Ask for @odata.count. Default true for collections. | |
| expand | No | ||
| filter | No | $filter, unencoded. | |
| select | No | $select, comma-separated. Include one inside expand too: Details($select=AUTOID,INVEN). | |
| company | No | Company, by ID or name as ebms_companies lists them. May be omitted only when one company is available. | |
| orderby | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so well: it discloses the 2-minute timeout risk from unselected reads, that count defaults to true for collections, that truncation is reported, that without top only 200 rows are shown, and that responses never exceed ~150 KB. These are exactly the behavioral traits an agent needs before invoking.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: what the tool reads, the mandatory select warning, the count/truncation default, the size-based alternative to ebms_export, and where to find query syntax. The critical constraints are front-loaded and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter read tool with no annotations and no output schema, the description covers the operational essentials (path forms, select requirement, row/size limits, truncation signaling, alternative tool). It stops short of describing the response shape or auth/company requirements, which are partly left to the schema and the ebms-api skill.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 56%, and the description adds crucial meaning for select (must always be passed) and top (default 200 rows, 150 KB cap) that the schema alone does not convey. It leaves filter, expand, orderby, skip, and company to the schema and defers query syntax to the ebms-api skill, so it does not fully compensate for every gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read from EBMS OData') and covers both modes (a collection or one record) with concrete path examples ('ARINV', "ARINV('<AUTOID>')"). An agent can immediately tell this apart from ebms_write (writes) and ebms_export (bulk).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the alternative and the condition that selects it: 'For more than a few hundred rows use ebms_export instead.' It also mandates 'Always pass select' and explains the consequence of not doing so, so the when-to-use and how-to-call guidance is complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_guideA
The procedures for working with EBMS through this server: how to build and change sales orders and purchase orders, receive stock, manage products, customers, vendors and tasks, run MRP, import files and set up a new company. Call it before any task beyond a single read, unless the matching skill is already loaded in this app. With no arguments it lists the skills; with skill it returns that skill; with file it returns one of the skill's reference files. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| file | No | A file a skill refers to, as listed, e.g. ebms-purchase-orders/references/receive.md. | |
| skill | No | A skill name from the list, e.g. ebms-purchase-orders. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full safety burden, and it discharges the most important part by declaring 'Read-only' and spelling out all three invocation modes (no args lists skills, skill returns one skill, file returns a reference file). It stops short of noting output size or pagination for the listing mode, which is a minor residual gap for a doc-fetch tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core instruction and read-only declaration come early and the mode behavior is packed into one sentence. The domain enumeration is slightly long but earns its place by telling the agent what procedures are available before it calls.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no annotations, the description fully covers what the agent needs: when to call, what each argument mode returns, and that the operation is read-only. Nothing required for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description earns above that by explaining the dispatch semantics between the two optional parameters and by describing the no-argument default behavior, which the schema cannot express. The example formats themselves live in the schema, not the description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource precisely — the procedural/skill documentation for EBMS through this server — and enumerates the covered domains (sales orders, purchase orders, receiving, products, customers, vendors, MRP, imports, company setup). This makes it unmistakable against action siblings such as ebms_get, ebms_write, and mrp_plan.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit call condition — 'before any task beyond a single read' — plus the exception ('unless the matching skill is already loaded in this app'). That is a concrete when-to-use rule an agent can apply without inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ebms_writeA
Write to EBMS: POST creates a record (documents take their lines nested as Details), PATCH updates one by quoted AUTOID (lines via a Details@delta array), DELETE removes one. Refused for a company that is not configured (or not the sandbox, while testing), and refused if the body carries PROCESS anywhere, a POST's EXTERNALID already exists (orders, POs, batches, tasks, customers, vendors, products, workers), or a vendor (APVENDOR) POST has no ID. A 2xx is not proof — EBMS silently ignores unknown @ids and unwritable fields — so the server reads back the fields you sent and returns a verification: ok, mismatches (sent vs stored), problems (a row that never appeared or was not removed), notes (rows EBMS added itself) and the stored rows. Treat ok:false as a partly failed write and tell the user. If the result says uncertain, read back before resending — a resent create or add duplicates; a create resent by EXTERNALID is refused until a read finds it or confirms it is absent.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | JSON body for POST and PATCH. Omit for DELETE. | |
| path | Yes | Required. ARINV for a POST; ARINV('<AUTOID>') for PATCH or DELETE. | |
| method | Yes | ||
| verify | No | Default true: after the write the server reads back exactly the fields you sent and reports each mismatch. Set false only for a write whose result you will read yourself. | |
| company | Yes | Company, by ID or name as ebms_companies lists them. Required on every write. | |
| readBack | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden and does so thoroughly: it discloses refusal conditions, that a 2xx is not proof, that EBMS silently ignores unknown @ids and unwritable fields, the exact verification payload shape (ok, mismatches, problems, notes), and the duplicate risk on resend. This is precisely the behavioral context an agent needs before a mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation-to-method mapping, then refusal rules, then verification and resend guidance in a logical progression. It is dense and reads as a long block, but nearly every clause carries actionable information, so waste is minimal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and a mutation surface, the description fully specifies the return contract (verification object with ok/mismatches/problems/notes plus stored rows) and the correct reaction to ok:false and uncertain. Nothing essential for calling this correctly is left unexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67%, and the description compensates by explaining nested line semantics (Details for POST, Details@delta array for PATCH), path quoting by AUTOID, and the PROCESS-in-body rejection, none of which appear in the schema. It stops short of detailing every readBack subfield, but adds substantial meaning beyond the structured fields.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (write to EBMS) and immediately enumerates the three operations with their targets: POST creates, PATCH updates by quoted AUTOID, DELETE removes one. This clearly separates it from the read-oriented sibling ebms_get without the agent needing to open a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not conditions (company not configured, sandbox mismatch, PROCESS in body, duplicate EXTERNALID, APVENDOR POST missing ID) and routes the agent on what to do when the result is 'uncertain' (read back before resending). It also states the verify default and when to set false, so method selection and follow-up behavior are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
import_from_csvA
Review a CSV or Excel (.xlsx) file of records for one EBMS entity — products, units, vendor records, bills of materials, customers, vendors, workers, folders, tax rates or other configuration — and draft the writes, read-only. Maps each column to a field (from EBMS's live metadata), checks every row (blanks, types, lengths, duplicates, folders, vendors, products and units that do not exist), skips rows already in EBMS or already created by an earlier run of the same import, writes an exceptions workbook holding only the rows that need fixing, and returns the exact ebms_write call for each remaining row. It writes nothing to EBMS. Follow the ebms-import skill: show the mapping, problems and a few drafts, get one clear yes for the file, then call ebms_write for each draft in order. Run it again on the same file (or the corrected exceptions file) to continue: what was created is skipped.
| Name | Required | Description | Default |
|---|---|---|---|
| csv | No | The file's CSV text, as the user attached or pasted it. | |
| path | No | Path of the file on this computer: .csv, .tsv, .txt or .xlsx (also an exceptions workbook this tool wrote), up to 20 MB. Hidden files and settings folders are refused. Give this or csv. | |
| sheet | No | For a workbook with several sheets: the one to read. Default: the first. | |
| entity | Yes | What the file holds: INVENTRY products; INVENUNT units, INVENDOR vendor records, INVENDET bill-of-materials lines (each row names its product in ID); ARCUST customers; APVENDOR vendors; PYEMP workers; INVENTRE / ARCUSTRE / APVENTRE / PYEMPTRE / PYWORKTRE folders; ARTAX tax rates; or a configuration set. | |
| rowsTo | No | ||
| company | Yes | Required. Company, by ID or name. | |
| mapping | No | Header -> field, overriding the automatic match. Map a header to "" to leave the column out. | |
| defaults | No | Field -> value for every row whose cell is blank or whose column is missing, e.g. {"TREE_ID": "26", "C_TYPE": 2}. Only what the user chose: never a guessed folder or classification. | |
| importId | No | Continue an earlier import of the same records from a renamed file: the importId an earlier result gave. Or, when a result reports rows where an earlier run created a different record and the user confirms this is a new file, the newImportId that result offered. | |
| rowsFrom | No | First row number to draft (validation always covers the whole file). | |
| maxDrafts | No | At most this many drafts in one result. Default 200. | |
| failedRows | No | Rows whose ebms_write failed in this import, with what EBMS said: they go to the exceptions workbook instead of being drafted again. | |
| exceptionsTo | No | Only a path the user named: an .xlsx file to save the exceptions workbook as. Default: beside the file as <name>.exceptions.xlsx. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it discloses that nothing is written to EBMS, that it writes an exceptions .xlsx beside the file, that existing/earlier-created rows are skipped (idempotent continuation), and that it reads EBMS's live metadata for mapping. It even names the downstream contract — a returned ebms_write call per remaining row.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and every clause carries information — no filler. However, the first sentence is a very long run-on stacking validation steps, skipping rules, workbook writing and return values; bullets or shorter sentences would make the same content far more scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter, nested-object tool with no annotations and no output schema, the description covers the full lifecycle: mapping, validation checks, dedupe, exceptions output, draft return, and resumption. An agent can execute the correct sequence without opening any other documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 92%, so the schema already does most of the work and 3 is the baseline. The prose still adds real semantics the schema lacks: the importId continuation story (renamed file, newImportId after confirmation), the exceptions workbook destination, and the draft-per-row output loop — enough to lift it above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: review a CSV/.xlsx file of records for one EBMS entity, validate it, and draft (not perform) writes. The scope is unambiguous, but it never distinguishes itself from sibling importers like po_from_csv or batches_from_csv, so an agent must infer which CSV importer applies to purchase orders or batches.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit about the workflow: follow the ebms-import skill, get one clear yes, then call ebms_write per draft; nothing is written here. It also explains the re-run/continuation case (same file or corrected exceptions file) and which record types it covers. The missing piece is routing guidance against the other *_from_csv siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mrp_item_viewA
The total view of one finished good, read-only: everything needed to build a quantity of it, down every level of its bill of materials, against what is available (on hand + incoming − on order). Stock of a sub-assembly covers its branch before anything is exploded further, and a part used in two branches is only counted once. Returns an indented tree, what to make, what to buy, and canBuildWithoutBuying: true when every purchased part is available, even if sub-assemblies still have to be made from them.
| Name | Required | Description | Default |
|---|---|---|---|
| qty | Yes | Required. How many to build. | |
| item | Yes | Required. Product ID of the finished good. | |
| company | No | Company, by ID or name. May be omitted only when one company is available. | |
| alsoMade | No | Product IDs to treat as manufactured although they have never been on a batch. | |
| buyInstead | No | Made products to plan as purchased for this run (not exploded into components). | |
| availability | No | 'available' (default) = on hand + incoming − on order; 'onHand' = what is on the shelf now. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It clearly discloses read-only behavior, the netting formula (on hand + incoming − on order), the branch-stopping rule for sub-assemblies, the once-only counting of parts used in two branches, and the canBuildWithoutBuying flag. This is rich behavioral context beyond a simple 'view' label.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single dense paragraph that front-loads the core purpose and read-only nature, then explains key behaviors. It is efficient and every sentence adds value, though it is slightly long and could be broken into two sentences for readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only view tool with no output schema, the description explains the return shape (indented tree, what to make/buy, canBuildWithoutBuying) and the key calculation rules. It does not detail pagination or exact output fields, but the core semantics an agent needs to invoke and interpret the tool are present. The absence of annotations raises the burden, and the description mostly meets it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all six parameters. The description adds context for the overall semantics (e.g., how availability is calculated, how alsoMade/buyInstead affect the explosion) but does not add per-parameter details beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('view'), a resource ('one finished good'), and a precise scope: everything needed to build a quantity down every BOM level, against availability. It clearly distinguishes itself from siblings like mrp_plan by focusing on a read-only total view of one finished good.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it: when you need a complete indented tree of what to make/buy for a single finished good and whether it can be built without buying. It does not explicitly name alternatives or exclusions, but the read-only framing and single-finished-good scope provide clear context. Sibling names like mrp_plan suggest a broader planning tool, but the description doesn't explicitly contrast them.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mrp_planA
Material requirements plan for one company, read-only: nets open sales and job demand, open manufacturing batches and open purchase orders against stock, day by day, through the bill of materials, and returns what to buy and make, by when, and why. ALWAYS ask the user two things first and never assume either: the time frame (through, or days) — 'buy and make what is needed to cover everything due by this date' — and the scope: everything, particular vendors, or particular products. Lead times come from EBMS: the product's vendor record (INVENDOR.LEAD_DAYS), else the vendor's (APVENDOR.LEAD_DAYS); 0 means not set. A purchase with a lead time gets an order-by date; one without carries only its needed-by date. Pass leadTimes or leadTimeDays only for figures the user gives. Only stocked products and stocked lines are planned; drop-ship, associated and sync lines belong to their own orders. The planner's worksheet is an Excel workbook saved on this computer (worksheet.savedAt): give the user that path; they approve rows in it. A CSV copy of its rows is attached for reading only.
| Name | Required | Description | Default |
|---|---|---|---|
| days | No | Time frame as days from today. Give this or through. | |
| items | No | With scope 'products': the product IDs to report. | |
| scope | No | Required. ASK the user: everything, particular vendors, or particular products? Buyers often work one vendor at a time. The whole company is always planned; the scope decides what is reported. | |
| inChat | No | Default true: attach a CSV copy of the worksheet's rows to this result, for reading. | |
| saveTo | No | Folder for the worksheet. Default: KOBLE_OUTPUT_DIR, or 'Koble MRP' in the user's Documents. | |
| company | No | Company, by ID or name. May be omitted only when one company is available. | |
| maxRows | No | Rows per section in this result, default 25. The worksheet always has every row. | |
| through | No | Last date to cover, yyyy-mm-dd. Give this or days. | |
| vendors | No | With scope 'vendors': vendor IDs or names. A product belongs to its primary vendor. | |
| alsoMade | No | Product IDs to treat as manufactured although they have never been on a batch. | |
| leadTimes | No | Lead time in days per product ID, from the user; overrides EBMS's figure for that product. | |
| worksheet | No | Default true: write the planner's worksheet (an Excel workbook). | |
| buyInstead | No | Made products to plan as purchased for this run (not exploded into components). | |
| includeJobs | No | Count job transfers as demand. Default true. | |
| minimumRule | No | How an item that ends the time frame under its minimum is restored. when-crossed (default): the minimum is a reorder point, so the order is dated the day the item went under and can replace an expedite. by-end: the minimum is a level to be back at by the end of the time frame, so the order is dated its last day. It is a company policy; ask once. | |
| leadTimeDays | No | A lead time for items EBMS has none for (and for made items), only if the user states one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so: it declares the operation read-only, explains that only stocked products/lines are planned and that drop-ship, associated and sync lines are excluded, and documents the side effects — an Excel worksheet written to disk whose path must be given to the user, plus an attached read-only CSV copy. It also discloses where lead times come from (INVENDOR then APVENDOR, 0 means unset) and the resulting order-by vs needed-by distinction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The critical constraint — ask for time frame and scope first — is front-loaded, and nearly every sentence carries operational weight. It is a dense single block with no line breaks, though, which makes the lead-time sourcing and exclusion rules harder to scan than they need to be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 16-parameter planning tool with no annotations and no output schema, the description supplies what an agent needs: output shape in prose (buy/make, by when, why), the worksheet-first approval workflow, defaults, and the demand/exclusion rules. Nothing essential to calling it correctly is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond it: the lead-time precedence chain that leadTimes/leadTimeDays override, the rule that lead-time parameters are passed only when the user supplies figures, and that scope governs reporting while the whole company is always planned. It does not add anything for the remaining 13 parameters, which is acceptable given the schema already documents them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ('Material requirements plan for one company'), states the read-only scope, and specifies the mechanism (nets sales/job demand, batches and POs against stock through the BOM) and the return ('what to buy and make, by when, and why'). That is enough to separate it from mrp_item_view and the CSV import/export siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit precondition — ALWAYS ask for the time frame and the scope first, never assume — and spells out the three scope choices. It also tells the agent which inputs are user-supplied only ('Pass leadTimes or leadTimeDays only for figures the user gives') and that minimumRule is a policy to ask once.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
po_from_csvA
Turn an approved MRP worksheet into purchase-order drafts, read-only. Reads the worksheet mrp_plan produced (its Excel workbook, or a CSV), after the planner approved BUY rows on its To order tab (and perhaps changed Qty or Vendor); checks every vendor and product against EBMS; and returns one draft per vendor with the exact body to POST to APINV with ebms_write. It creates nothing. A worksheet handed in twice cannot order twice: ebms_write refuses the duplicate EXTERNALID. Show the drafts and get a clear yes per purchase order before writing.
| Name | Required | Description | Default |
|---|---|---|---|
| csv | No | The worksheet's CSV text, exactly as the user attached or pasted it. | |
| path | No | Path of the worksheet on this computer: the .xlsx workbook mrp_plan saved (after the user approved rows in it), or a CSV. Give this or csv. | |
| company | Yes | Required. Company, by ID or name. Must match the worksheet's company. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: read-only ('It creates nothing'), validation of every vendor and product against EBMS, and idempotency guaranteed by ebms_write refusing duplicate EXTERNALID. It does not say what a draft looks like when a vendor or product fails validation, which is the one behavioral gap for a tool whose whole job is validation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences, front-loaded with the core action and read-only guarantee, then workflow, then safety rule. Slightly run-on with the exclamation-free but long third clause, yet each sentence contributes distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must describe returns and it does: one draft per vendor with the exact body to POST to APINV. Combined with the idempotency note and approval gate, an agent has enough to act; only error/partial-failure behavior is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains csv, path and company, including the either/or between csv and path and the company-match requirement. The description adds only indirect meaning (the worksheet may have edited Qty/Vendor) and does not clarify formats or precedence beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific transformation (worksheet -> purchase-order drafts) plus the read-only constraint in the first clause. It also implicitly separates its role from mrp_plan (which produces the worksheet) and ebms_write (which posts the drafts), so an agent can place it in the pipeline without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit precondition (planner approved BUY rows on the To order tab, possibly editing Qty or Vendor) and names the downstream step (POST drafts via ebms_write). It also states a procedural rule: show the drafts and get a clear yes per purchase order before writing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- Changed
batches_from_csv1 field changed- changed
Input schema / properties / path / descriptionPrevious value: -"Path of the worksheet CSV on this computer. Give this or csv."New value: +"Path of the worksheet on this computer: the .xlsx workbook mrp_plan saved (after the user approved rows in it), or a CSV. Give this or csv."
- Added
ebms_export - Added
import_from_csv - Changed
mrp_plan4 fields changed- changed
Input schema / properties / inChat / descriptionPrevious value: -"Default true: attach the worksheet's CSV to this result."New value: +"Default true: attach a CSV copy of the worksheet's rows to this result, for reading." - changed
Input schema / properties / leadTimeDays / descriptionPrevious value: -"A lead time to assume for every item, only if the user states one."New value: +"A lead time for items EBMS has none for (and for made items), only if the user states one." - changed
Input schema / properties / leadTimes / descriptionPrevious value: -"Lead time in days per product ID, overriding leadTimeDays."New value: +"Lead time in days per product ID, from the user; overrides EBMS's figure for that product." - changed
Input schema / properties / worksheet / descriptionPrevious value: -"Default true: write the planner's worksheet (CSV)."New value: +"Default true: write the planner's worksheet (an Excel workbook)."
- Changed
po_from_csv1 field changed- changed
Input schema / properties / path / descriptionPrevious value: -"Path of the worksheet CSV on this computer. Give this or csv."New value: +"Path of the worksheet on this computer: the .xlsx workbook mrp_plan saved (after the user approved rows in it), or a CSV. Give this or csv."
9 tool updates
v0.1.0-rc.1- First observed
batches_from_csv - First observed
ebms_command - First observed
ebms_companies - First observed
ebms_get - First observed
ebms_guide - First observed
ebms_write - First observed
mrp_item_view - First observed
mrp_plan - First observed
po_from_csv
TDQS
Scored across 11 tools
Most tools occupy clearly separated niches: ebms_get vs ebms_export is explicitly split by size/side-effects, ebms_write is the sole mutator while po_from_csv/batches_from_csv/import_from_csv are read-only drafters, and mrp_plan vs mrp_item_view split company-wide planning from a single BOM tree. The remaining fuzziness is among the three '*_from_csv' drafters (worksheet BUY rows, MAKE rows, arbitrary entity files), which an agent must read carefully to pick correctly, and ebms_get vs ebms_export overlap in a grey zone of 'a few hundred rows'.
All names are lower snake_case and cluster into readable prefixes (ebms_*, mrp_*, *_from_csv), so the set is predictable. It is not a single uniform verb_noun pattern though: ebms_get/ebms_write/ebms_export are prefix+verb, while po_from_csv/batches_from_csv/import_from_csv use a source-oriented noun_from_source form, and mrp_item_view adds a third shape.
Eleven tools is well inside the healthy range and each one earns its place: read, write, bulk export, plan, per-item view, three drafters for distinct sources, command, guide and company listing. No obvious filler or overlapping convenience wrappers.
The surface covers the full lifecycle: discovery (ebms_companies, ebms_guide), read/aggregate (ebms_get, ebms_export), mutation (ebms_write, ebms_command), planning (mrp_plan, mrp_item_view) and bulk intake (three drafters). The main gap is introspection — there is no tool to list entity metadata/fields or allowed commands directly, so an agent must go through ebms_guide's reference files to learn valid paths and the command allow-list.
Maintenance
Related MCP Connectors
Claude, connected to your own Oracle EPM. Each person as themselves, every call checked and logged.
Create contacts, move deals, send proposals and invoices, read your inbox, from Claude or ChatGPT.
Connect Claude to Dutch accounting software: e-Boekhouden invoices, contacts and ledgers.
Connect Claude or Cursor to books, invoices, bills, payroll, and sealed closes.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Odoo ERP systems through 17+ business tools covering sales, purchasing, inventory, and accounting operations. Supports both Claude Desktop integration and web deployment with dual transport modes.MIT
- AlicenseNot gradedqualityNot gradedmaintenanceConnects Claude to PrintSmith Vision for read-only AI-assisted print shop management. It enables users to query customer data, production job statuses, and financial summaries through natural language.-
- AlicenseNot gradedqualityCmaintenanceEnables Claude to securely interact with Acumatica ERP 2025 R2 via per-user OAuth, role-based access, and sensitive field redaction, providing 48 tools for data lookup, utility, and schema discovery.Apache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables Claude to read and write data in an Odoo instance, including stock, invoices, clients, and reminders, through a secure MCP connector.-