AccuLynx MCP Server & CLI
npm:
acculynx-mcp(MCP server) ·@opsrev/acculynx-cli(CLI + MCP)
An MCP server for the AccuLynx roofing CRM — bring jobs, contacts, and estimates into Claude Desktop, Cursor, or any MCP client. Every tool is exposed with an enforced JSON Schema, so an AI agent can't invent a parameter or call a command that doesn't exist.
- 30 tools across jobs, contacts, estimates, and users.
acculynx-mcp— the MCP server, for Claude Desktop / Cursor / any MCP client.@opsrev/acculynx-cli— the same data as a JSON CLI (and it also ships theacculynx-mcpserver bin).
Use in Claude Desktop
- Get an AccuLynx API key (your AccuLynx account administrator creates it under Account Settings → API).
- Open your Claude Desktop config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
- Add the server (zero-install via
npx):
{
"mcpServers": {
"acculynx": {
"command": "npx",
"args": ["-y", "acculynx-mcp"],
"env": { "ACCULYNX_API_KEY": "your-api-key" }
}
}
}
Prefer a global install? Run npm i -g acculynx-mcp, then use
"command": "acculynx-mcp" with no args.
- Restart Claude Desktop. Open a new chat and ask "List my 5 most recent
AccuLynx jobs" — you should see the
acculynx_*tools available.
Use in Cursor / other MCP clients
Any client that speaks MCP over stdio works. Point it at npx -y acculynx-mcp
(or a global acculynx-mcp) and set ACCULYNX_API_KEY in the environment.
Example (Cursor ~/.cursor/mcp.json):
{
"mcpServers": {
"acculynx": {
"command": "npx",
"args": ["-y", "acculynx-mcp"],
"env": { "ACCULYNX_API_KEY": "your-api-key" }
}
}
}
MCP tools
All tools are prefixed acculynx_ and return JSON.
Configuration
Also a CLI
@opsrev/acculynx-cli exposes the same data as a JSON CLI (and bundles the
acculynx-mcp server bin). All output is JSON to stdout; errors are
{"error": "..."} to stderr with exit code 1.
npm install -g @opsrev/acculynx-cli
acculynx ping # verify API key
acculynx jobs list --limit 5 # 25 results by default; --all to fetch everything
acculynx jobs get <jobId>
acculynx jobs search --query "smith"
acculynx jobs scan --milestones Approved # scan all jobs → digest + coverage receipt
acculynx contacts list --limit 10
acculynx estimates get <estimateId>
List commands default to 25 results; use --limit <n> or --all. Commands
that create resources read a JSON body from stdin:
echo '{"name": "New Job"}' | acculynx jobs create
Pipe to jq for scripting:
JOB_ID=$(acculynx jobs list --limit 1 | jq -r '.[0].id')
acculynx jobs get "$JOB_ID" | jq .
Prospect aging with complete readable rows
acculynx jobs scan --report prospect-aging --as-of 2026-10-20 --exclude-trade-type "Maintenance Program"
This bounded GET-only report ages current Prospect inventory by its full milestone date in America/New_York, with inclusive 0–30, 31–60, 61–90 and 91+ calendar-day buckets. It is not a historical inventory snapshot. Exclusions use exact case-insensitive trade-type names; missing classification stays unknown. Every eligible row includes its full ID, date, age and separate approved/worksheet values in exact cents. Missing values remain unavailable rather than zero.
Enumeration is strict and capped at 5,000 jobs before per-job financial reads. Reports above 180,000 characters return partial with no detailed list, keeping output below the retained process-log limit. No history, payment, message or write requests are made. Invalid/incomplete inventory withholds totals and rows; missing dates or financial evidence make the result partial (exit 3). Incompatible filters and output modes fail before provider access (exit 2). Read long stdout through bounded process-log pages.
Monitoring scans: payments with strict coverage
Scan every job in a set of milestones and fetch each one's received payments in one process, with a coverage line a script can check:
acculynx jobs scan --milestones Approved,Completed,Invoiced \
--enrich payments --strict --format jsonl --out payments.jsonl
Each job line carries payments: the job's full received-payment objects
(id, from, amount, paymentDate, checkNumber, notes, …). The last
line is the coverage receipt:
{"type":"coverage","scanned":299,"serverCount":299,"complete":true,"pageError":null,"enrichErrors":0}
--strict(implied by--enrich payments) treats any pagination anomaly (changing total, duplicate job IDs, overfull or malformed pages) as a partial scan. Partial scans exit 3 and reportcomplete: false. Never treat them as a full inventory.- A per-job payments failure doesn't abort the scan. It appears in that job's
errors({"jobId", "source": "payments", "message"}) and counts towardenrichErrors, so retry just those jobs withacculynx jobs payments <id>. - Without
--strictand withoutpayments,jsonloutput is unchanged: job lines only.
Development
cp .env.example .env # fill in your credentials
npm install
npm test # run unit tests (mocked fetch)
npm run dev -- --help # run the CLI in dev mode (auto-loads .env)
npm run build # build both bins to dist/
npm run dev auto-loads .env via Node's --env-file:
npm run dev -- jobs list --limit 5
License
MIT
Private marketing evidence from a native scan
Operators preparing approval-date reconciliation can preserve exact source fields without parsing the rounded human digest:
acculynx jobs scan --start-date 2026-07-01 --end-date 2026-09-04 --date-filter-type ModifiedDate --enrich dates,financials --format marketing-evidence
This emits one acculynx-marketing-evidence/v1 JSON object. It is private
operator evidence containing full job IDs and individual values; do not post
it in a vendor/customer channel. It excludes contacts, addresses, names,
notes, documents, unrelated financials and raw provider error bodies.
--out and other enrichers are rejected before reading. Redirect stdout only
into an appropriately protected operator workspace if retaining the artifact.
This format does not alter downstream agents' command allowlists or authorize
them to export records.
The receipt distinguishes query completeness from enrichment completeness. Strict pagination requires a numeric stable total, advancing offsets and unique job IDs. Exit 3 means partial evidence; never publish it as a complete result. Full source dates are preserved without timezone conversion, repeated approval milestones remain separate, and current approved value is represented in exact cents. Missing/invalid values and dates remain null with issue codes.
This is not an approval cohort, an original-acquisition attribution, a complete lead-delivery inventory or historical revenue. ModifiedDate is a candidate filter; confirm historical and unassigned/dead-lead coverage separately. Review source date semantics, repeated approvals, transfers and current-versus-original contract value before producing normalized results. A large historical scan reads history and financials for each candidate; bootstrap it separately from short daily marketing jobs, then validate an incremental refresh strategy.