Home · Setup · Claude Desktop
Job orders for trades and field work: parts and labour as they happen, a status that moves one dated step at a time, a completion report, and an invoice payload that needs no retyping. You raise a work order against a client, and the client is the one the invoice server already knows, looked up by name in its own records rather than spelled a second way here, so the job and the invoice carry the same customer. It gets a site address, the date it was asked for, what the job is and how urgent, and a WO-YYYY-NNNN number. Then you log what the job actually uses as it goes: labour as hours at an hourly rate, parts as a quantity at a unit cost in minor units with an optional markup percent. The markup goes on the UNIT cost and never on the line total, which sounds like a detail and is the decision the whole server rests on, because the invoice server rounds a unit price into minor units first and computes the line from that stored value: the marked-up unit is the only basis an invoice can reproduce. The status moves one step at a time, draft to scheduled to in progress to done to invoiced, each step stamped with its own date and a note, and a skipped step is refused naming the step that IS next, because a job that went from scheduled straight to invoiced was never marked done, so no completion report was ever produced and nothing in the record says the day the work finished. Backwards is refused too: a job that has to go back is a new work order, and the history of the first one has to stay true. Nothing is stored twice: the value, the hours, the materials and the VAT are derived from the lines on every call, because a stored total is a second copy of what the lines already decide and the copy is the one that gets believed after somebody edits a line. Hours are counted on the LINE date rather than the order date, so a February call worked in March logs its hours in March. When the job is done you hand the customer a completion report with the hours, the materials, the totals and a sign-off block, and take work_order_invoice_payload straight to invoice_create: it posts nothing, marks nothing, and its totals are computed by the invoice server's own function over the very items it is handing you, so there is no second implementation to disagree.
The job notes are usually already in this window, photographed off a paper docket or typed on the way back from the van, so reading three hours and a part number out of a picture and into work_order_add_line is one sentence, and the question that follows it, what does the invoice say, is the next one. Nothing leaves the machine: the server makes no network call on any tool, so a customer's site address and what you charged them stays on the laptop it was typed on.
| You say | Tool |
|---|---|
| Raise a work order for Harbour Cafe, site 12 Quay Street, requested 2026-03-06, urgent: the walk-in is not holding temperature. | work_order_create |
| Three hours labour on 2026-03-08 at 8,500 an hour, and seven thermostats at 1,299 each with 15 percent markup. | work_order_add_line |
| Mark it done on 2026-03-09, then give me the completion report and the invoice payload. | work_order_status |
The markup basis is worth exactly one minor unit at a time, and one minor unit is enough to make an invoice disagree with the job it came from. Measured on this server's own engine: seven parts at a unit cost of 1,299 with 15 percent on top is roundHalfUp(1299 * 1.15) = 1,494 a unit and 10,458 on the line. Marking up the line total instead is roundHalfUp(9093 * 1.15) = 10,457. Both are defensible arithmetic, both reconcile against their own workings, and only one of them is what the customer is billed, because the invoice server stores a rounded unit price and computes the line from it. The unit suite asserts that gap is exactly 1, so a change of basis fails the build rather than quietly re-pricing every job on the board. The worked job then runs the whole way through: the payload's items are handed back to the invoice server's own computeTotals from the test process and come back at net 59,833, VAT 13,762 and total 73,595, with rounding drift of zero.
The file is claude_desktop_config.json, and the key inside it is mcpServers.
| Scope | Path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
{
"mcpServers": {
"work-order": {
"command": "npx",
"args": ["-y", "@theluckystrike/mcp-work-order"]
}
}
}
If node came from nvm, asdf or homebrew, replace "npx" with the absolute path that which npx prints:
"command": "/Users/you/.nvm/versions/node/v22.14.0/bin/npx"
Save, then completely quit Claude Desktop and start it again. A window reload is not enough.
The npm publish of @theluckystrike/mcp-work-order is pending; until then use the .mcpb bundle or a clone and build from the latest release.
The same server runs at https://mcp.zovo.one/mcp/https://mcp.zovo.one/mcp/work-order over MCP streamable HTTP, no install. Mint a free token with curl https://mcp.zovo.one/mcp/token, or use a Pro key. It has no filesystem, so a file comes back as a one-hour download link.
{
"mcpServers": {
"work-order": {
"url": "https://mcp.zovo.one/mcp/https://mcp.zovo.one/mcp/work-order",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
Two documented facts decide whether the entry works: every path in claude_desktop_config.json must be absolute, and a stdio server started here inherits only a limited, platform-dependent subset of environment variables. If node came from nvm or homebrew, paste what `which npx` prints instead of the bare word. The .mcpb route avoids both: Claude Desktop ships a built-in Node.js environment.
Free: Five OPEN work orders, which is a one-van trade, and 200 lines on each of them on every tier. The cap counts open jobs, draft, scheduled and in progress, rather than jobs ever raised, so finishing a job frees its slot: the free tier does not fill up with history. work_order_delete on a draft with no lines is free on every tier as well, because a way back that only a Pro key can reach is not a way back. The text completion report is free too: handing the customer a written record of what was done is the thing the job was for, not an upsell. A byte-identical work order is refused before the cap is even consulted, so a double-typed job names the id already stored rather than being met with an upgrade prompt, and it burns neither a slot nor a WO number. Pro is $19 once, verified offline.
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json. Windows: %APPDATA%\Claude\claude_desktop_config.json. There is no published Linux path. Settings, Developer, Edit Config opens the right copy and creates it if it does not exist.
In order: did you fully quit and restart, not just close the window? Is every path absolute? And is the command resolvable, given the limited environment a stdio server inherits here? If node came from nvm, paste what which npx prints.
Yes. An .mcpb bundle, the format renamed from .dxt, opens with Claude and shows an installation dialog. One you built yourself goes in through Settings, Extensions, Advanced settings, Install Extension.
MCP Work Order in detail · The same server in Claude.ai and Claude Desktop connectors and Claude Code · Every server in Claude Desktop · Guides · Claude Desktop docs · Buy Pro