CTDS Contractor Suite
The arithmetic behind Contractor Suite, offered to AI assistants as 5 tools over the Model Context Protocol.
The Contractor Suite's workbook math: job cost (estimate vs actual, over-budget flag), equipment service status and cost per hour, and bid prices, follow-ups and win rate. Money is integer cents, hours and quantities have two decimals, rates and markups are fractions (0.07 = 7%), dates are yyyy-mm-dd; tools that take today default to the current UTC date, so pass it to pin a run. Results are arithmetic on the records given, not accounting, tax or engineering advice; the server has none of the user's stored jobs, machines or bids.
Connect
The server is at https://contractor.chimneytopdigital.com/api/mcp. It is free, asks for no sign-in and keeps nothing between calls. Rate limits apply per address.
| Client | How |
|---|---|
| Claude Code | One command in a terminal: |
| Claude (web and desktop apps) | Settings → Connectors → Add custom connector, with the URL https://contractor.chimneytopdigital.com/api/mcp. No sign-in is asked for. |
| Codex CLI | One command in a terminal: |
| Any other MCP client | Use the Streamable HTTP transport with the URL https://contractor.chimneytopdigital.com/api/mcp: one JSON-RPC message per POST, JSON answers, no session and no authentication. |
To see the raw protocol, list the tools and call one from a terminal:
curl -s https://contractor.chimneytopdigital.com/api/mcp -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -s https://contractor.chimneytopdigital.com/api/mcp -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_modules","arguments":{}}}'Tools
Every tool is read-only and idempotent, so a client may run it without asking you first. Arguments are checked before a tool runs; a wrong one comes back as a message naming the field.
list_modulesThe suite's modules, defaults and purchasesThe three modules of the Contractor Suite with their workbook defaults (rates, intervals, markup), the fixed lists the tools accept (cost categories, job statuses, machine and service types, bid statuses) and the one-time purchases that unlock each module with their prices in cents.
module(job-cost | equipment | bid-tracker): Only this module
job_cost_resultEstimate vs actual for one jobThe Job-Cost Tracker's figures for one job: estimate and actual by category (labor, fuel, materials with tax, equipment) and in total, hours, the variance in cents and as a share of the estimate, and the Budget flag (Not started, Over budget, On track). Rates come from the settings unless a line overrides them. Totals are rounded from exact sums, as the workbook does.
job(object, required)entries(array, default []): The job's cost-log lineslabor_rate_cents(integer, default 4500): Labor rate, cents per hourfuel_price_cents(integer, default 400): Fuel price, cents per gallonequipment_rate_cents(integer, default 8500): Equipment rate, cents per machine hourtax_rate(number, default 0.07): Sales tax applied to materials, as a fraction (0.07 = 7%)variance_alert(number, default 0.1): Share over the estimate that flags a job Over budget (0.1 = 10%)
job_cost_dashboardJob-cost dashboard across jobsThe Job-Cost Tracker's Dashboard: jobs, active jobs, jobs over budget, estimate and actual totals and variance, estimate vs actual by category, and each job's result. Every entry must name a job in the list.
jobs(array, required)entries(array, default []): Cost-log lines of every job, each with its job_idlabor_rate_cents(integer, default 4500): Labor rate, cents per hourfuel_price_cents(integer, default 400): Fuel price, cents per gallonequipment_rate_cents(integer, default 8500): Equipment rate, cents per machine hourtax_rate(number, default 0.07): Sales tax applied to materials, as a fraction (0.07 = 7%)variance_alert(number, default 0.1): Share over the estimate that flags a job Over budget (0.1 = 10%)
equipment_dashboardService status and cost per hour for a fleetThe Equipment Hours & Service Log's figures on a day: for each machine the current hours (highest of start hours and every meter), last scheduled service, next due by hours and by date, hours and days remaining, status (OK, Due soon, Overdue) and which limit comes first, fuel and service cost, hours used and cost per hour; plus the fleet dashboard and the machines a reminder would list.
machines(array, required)hours(array, default []): Hours Log rowsservices(array, default []): Service Log rowstoday(string): The day to compute status for; defaults to todayfuel_price_cents(integer, default 400): Fuel price, cents per gallontax_rate(number, default 0.07): Tax on parts, as a fractiondefault_interval_hours(number, default 250): Service interval in hours for machines without onedefault_interval_days(integer, default 180): Service interval in days for machines without onedue_soon_hours(number, default 25): Hours left at or under which a machine is Due soondue_soon_days(integer, default 14): Days left at or under which a machine is Due soon
bid_dashboardBid prices, follow-ups and win rateThe Bid Tracker's figures on a day: for each bid the price (cost times 1 plus markup, rounded once to the cent), margin in cents and as a share of the price, days out for Sent bids and the Follow up flag; plus the dashboard (bids, open, won, lost, win rate, open pipeline, won value, margin on won work, follow-ups needed, bids by status). Bids come back in the app's list order: follow-ups first.
bids(array, required)default_markup(number, default 0.15): Markup on cost as a fraction for bids without their ownfollow_up_days(integer, default 7): Sent bids this many days old or older are flagged Follow uptoday(string): The day to count days out from; defaults to today
Limits
- The tools compute from the values the assistant passes in. They cannot read or change anything in your Contractor Suite account; for that, use the app.
- Results carry the same notices the app shows. They are estimates and working aids, not professional advice; ask your assistant to show the notice with the figure.
- Rate limits apply per address. A request over the limit gets a plain error the assistant can read.
- The tool list may grow. This page is generated from the running server, so it shows the tools as they are today.
If something fails
- "Couldn't reach the MCP server", or a 404
- Check the address character by character: the server answers only at
https://contractor.chimneytopdigital.com/api/mcp, over HTTPS. Nothing else on this host speaks MCP. - 405 Method Not Allowed
- The client sent a GET. The server speaks the Streamable HTTP transport without an event stream: one JSON-RPC message per POST, a JSON answer, no session. A notification gets an empty 202.
- 429 Too Many Requests
- Your address passed the fair-use limit. The
Retry-Afterheader says how many seconds to wait; the limit resets on its own. - 413 Payload Too Large
- One request may carry 256 KiB. Send fewer rows per call, or summarize before you send.
- A tool answers with an error naming a field
- The argument did not match the tool's schema above: money is integer cents (or plain dollars where the tool says so), dates are
YYYY-MM-DD, and lists are JSON arrays. Fix the named field and call again; nothing was stored. - Still stuck
- Write to support@chimneytopdigital.com with the tool name, the arguments you sent (with nothing personal in them), the time in UTC and the exact message. We keep no record of calls, so what you send us is all we can look at.
How we built the servers, and the rules every one follows: our guide. Questions: hello@chimneytopdigital.com.