https://api.trycactus.com/mcp. Point an MCP-capable agent at it
with your API key and the agent can upload documents, run extractions, start
underwritings, and check usage — the same operations as the REST API, with
the same authentication, billing, and rate limits.
Use a sandbox key (ck_sandbox_...) while building: every tool works
identically, results are instant fixtures, and nothing is billed. See
Sandbox.
Connection details — URL
https://api.trycactus.com/mcp, transport
streamable HTTP, auth header Authorization: Bearer ck_.... There is no
package to install and nothing to run locally; it’s a remote server.Install
- Claude Code
- Claude Desktop / claude.ai
- Cursor
- Other clients
--scope project to write the server into the repo’s .mcp.json and
share it with your team — keep the key out of a committed file by passing
--header "Authorization: Bearer ${CACTUS_API_KEY}", which Claude Code
expands from your environment.Verify with claude mcp list, or run /mcp inside Claude Code: cactus
should show as connected with 13 tools.Your first extraction
With a sandbox key connected, no file upload is needed — the example documents are extractable by filename alone. Ask the agent:
Using the Cactus tools, register example-rent-roll-1.xlsx as a rent roll,
extract it, and summarize the unit mix.
It will call upload_document → create_extraction → get_extraction →
get_extraction_result on its own. The server describes those flows to the
client on connect, so you don’t have to spell out the sequence.
Moving to a live key changes two things: the agent must PUT the real file
bytes to the presigned URL from upload_document before starting a job, and
extractions take minutes instead of returning instantly.
Tools
Every tool maps onto a documented REST endpoint and returns the same JSON.
Two ergonomic differences from the raw API:
create_extractiontakes the three bundle document ids as flat parameters (offering_memorandum_document_id,rent_roll_document_id,t12_document_id) instead of a nestedbundleobject. Itsasset_classparameter is required, exactly as on the endpoint - the tool description tells the agent to ask you rather than guess.create_underwritingtakes the property address as flat parameters (address_line1,city,state,postal_code, …).
idempotency_key, with the same
semantics as the Idempotency-Key header on the REST endpoints.
get_extraction and get_underwriting also take wait — see below.
With a live key, upload_document returns a presigned upload.url; the
agent (or you) must HTTP PUT the raw file bytes to it before starting a
job — the MCP server never handles file contents itself. Sandbox documents
skip the upload entirely.
Waiting for results
With a live key, extraction and underwriting tools return immediately withstatus: processing — the job runs in the background. Getting the waiting
part right is the main thing that separates a smooth agent run from a noisy
one, so the server does most of it for you.
Use wait instead of sleeping. get_extraction and get_underwriting
accept wait (0-45 seconds). The API holds the request open and answers the
moment the job reaches a terminal state, so a typical extraction takes a
couple of tool calls and no timer:
processing
back dozens of times. wait removes that failure mode entirely.
A wait that elapses is not a timeout. You get a normal response with
the job still in flight. Call again; nothing is lost and nothing is
double-billed.
In-flight responses tell you when to come back. While a job is running
the body carries poll_after_seconds (the recommended interval, mirrored in
the Retry-After header) and elapsed_seconds (how long it has been
running). Prefer those to a hard-coded interval — status changes no faster
than poll_after_seconds, so polling harder just burns rate limit.
Expected durations and hard ceilings:
Past the ceiling the job fails, and any billed lines are refunded in full. A
job still reporting
processing has not silently died.
Rent rolls run in two phases, which is why they are the slow path. They
extract, then consolidate into the typed rent_roll.v1 output, and both
phases report status: processing. documents[].phase distinguishes them
(extracting → consolidating), so a job moving between phases is visibly
progressing rather than stuck. An agent that gives up after a few minutes
will abandon rent rolls that were going to succeed.
Sandbox keys complete everything instantly, so none of this applies there —
which is also why an agent flow that looks instant in sandbox needs testing
against a live key before you trust its waiting behaviour.
Billing and limits
Tool calls are ordinary API calls. Live extractions debit your usage pool at acceptance and refund automatically on failure; underwriting runs are not metered. The same rate limits apply either way. Ask the agent to callget_usage for the current balance.
Underwritings are the long path and run for ~20-30 minutes. Keep unattended
agents on a sandbox key.
Troubleshooting
Tools fail with 'No API key'
Tools fail with 'No API key'
The client connected but isn’t sending the header. Check that the value
includes the
Bearer prefix and that it’s configured as a header —
not a URL query parameter or an OAuth setting.401 or 403 on every tool
401 or 403 on every tool
The key itself was rejected.
401 means it’s unknown or revoked; 403
means it lacks the scope for that operation. See
Authentication.The client can't connect at all
The client can't connect at all
Use the exact URL
https://api.trycactus.com/mcp — no trailing slash —
with streamable HTTP transport (not SSE, not stdio). A plain browser
GET of that URL returning 405 is expected; it’s a POST endpoint.A tool call times out
A tool call times out
Requests are capped at 60 seconds. Extractions and underwritings are
asynchronous by design:
create_* returns immediately and the agent
polls get_*. Retry a timed-out poll — no work is lost. wait is
capped at 45 seconds so a long poll always answers inside the cap.The agent polls in a tight loop, or waits far too long
The agent polls in a tight loop, or waits far too long
It’s guessing an interval. Have it pass
wait to get_extraction /
get_underwriting and follow poll_after_seconds from the response
rather than sleeping on its own schedule — see
Waiting for results.A job sits at 'processing' and looks stuck
A job sits at 'processing' and looks stuck
Check
elapsed_seconds against the ceilings above, and
documents[].phase for rent rolls — consolidating means the second
phase is running normally. Jobs cannot exceed their ceiling; past it
they fail and refund in full, so processing always means still
working.Docs search
This documentation site also exposes its own MCP server athttps://docs.trycactus.com/mcp (search and read the docs — no API access).
Connect both to give an agent the reference material and the ability to act
on it.