The Contractor Codex ships its own Model Context Protocol server. Point Claude Desktop, Claude Code, or any MCP-compatible client at it, hand it an API key, and the model can run your portal — clock in and out, send invoices, draft quotes and contracts, mark payments paid, refund mistakes, post updates to your clients — without you opening the admin UI.
It sits on the same backend the admin and client portals use. No separate database, no separate auth. Every agent call lands an audit-log row, so you can see exactly what the model did and when.
Endpoint/api/mcp
AuthBearer ctsp_live_…
TransportStreamable HTTP
Tools82
Money actions2-step confirm
★Quick start — 3 steps
Enable MCP. Open /admin/settings/mcp and flip Enable MCP Server on the Setup tab.
Create a key. Same screen → Create API Key for MCP. Pick the write groups to grant. The full key shows once, so copy it now. (Key management lives in API keys.)
Wire it into your client. Drop this into your MCP client config:
Once connected, the client lists all 82 tools automatically and the agent can start working. (Strictly, tools/list shows 81: get_openapi is HTTP-only, so it doesn't appear on the MCP surface.)
⚠The endpoint is locked until you do both
Until MCP is enabled and a valid key authenticates, every request is rejected — 401 without a valid key, 403 for your org until the toggle is on. A leaked key alone can't do anything if MCP is off.
How it works
Claude (or any MCP client)
↓ JSON-RPC over HTTPS, Bearer-token auth
https://contractorcodex.com/api/mcp
↓ validates token, checks your org's mcp_enabled flag
runAgentTool() dispatcher
↓ same handler as the /api/agent/<tool> HTTP route
your data
The MCP transport and the HTTP /api/agent/* routes call the same handler functions. Adding a tool exposes it on both surfaces at once — they never drift apart.
Every write tool that takes a "which one?" parameter returns a structured needs_input response when called without it — instead of erroring. The response carries questions (what to ask), inventory (the real options — recent clients, draft invoices, available templates…), and next_step. The agent grounds in your actual data instead of inventing an ID.
ℹExample — “mark the Henderson invoice paid”
AGENT → mark_paid() (no args)
← needs_input · inventory.open_invoices: [Henderson $2,400, Mosi LLC $800, …]
AGENT "I see two open invoices for Henderson — $2,400 and $1,100. Which one?"
USER "The 2400."
AGENT → mark_paid(snapshotId="…", method="check")
← confirmation_required · preview + confirmation_token
AGENT "Mark the $2,400 Henderson invoice paid via check?"
USER "Yes."
AGENT → mark_paid(snapshotId="…", method="check", confirmation_token="ct_…")
← marked_paid
Two structured round-trips before anything changes. No hallucinated IDs, no guessed amounts.
The two-step confirmation rule
Every tool that sends an email, moves money, or destructively changes state goes through a mandatory two-step confirm, regardless of dollar amount:
First call returns confirmation_required + a confirmation_token + a preview the agent reads aloud.
Second call repeats the params plus the token. The tool executes.
Tokens expire after 60 seconds and are bound to (keyId, action, paramsHash) — they can't be replayed or reused for a different action.
send_client_message follows the same two-step confirm — it puts a real email in a client's inbox, so a human approval sits between the agent and the send.
Auth model
Concept
Detail
Scope
admin (any client in your org) or client (bound to one client). Keys minted in this screen are admin-scoped.
Storage
Stored as SHA-256 hashes. The full key shows once at creation.
Expiry
Set per key via expiresAt. No auto-rotation — revoke and reissue.
Org gate
The endpoint returns 403 for your org until mcp_enabled is on (and 401 for any request without a valid key).
Audit
Every call writes an audit-log row (key, tool, status, IP, duration).
Rate limit
30 calls/min per admin key, 60/min per client key (per-tool overrides available). String numeric params are accepted everywhere.
For a read-only key, untick every write group at creation — read tools require no write permission.
The tool catalog
82 tools, grouped by what they touch. Expand a group to see its tools.
Context & identityany5
Tool
Purpose
get_context
The boot call. Org name, your scope, system instructions, workflows, an inventory snapshot, and the endpoint catalog. Call this first.
whoami
The key's scope + bound client, if any. Lightweight identity check.
get_help
Keyword search across this docs site.
get_branding
Business name, support email, portal greeting, portal theme, accent color (the effective one: custom or the selected theme's own), logo, default currency.
get_openapi
The full machine-readable OpenAPI 3 spec for every endpoint — params, schemas, and required flags. For codegen or deep introspection.
Admin overview — readadmin9
Tool
Purpose
admin_get_clients
All active clients with health scores and project counts.
admin_get_insights
Revenue (net of refunds), overdue counts, dunning stats, health distribution.
admin_get_activity
Org-wide activity log.
daily_briefing
"What needs my attention today?" — pending approvals, drafts, overdue invoices, payments collected (net of refunds).
overdue_ar
Overdue invoices with aging buckets.
quote_status_check
Quote pipeline: open, signed, expiring.
get_advisor_briefing
The Advisor's cached daily briefing: AI headline, narrative, and open recommendations with their computed evidence. Never triggers an AI call.
codex_money_summary
This month's money from Codex: collected, spent, net, transactions awaiting review, connected banks. Same math as the Codex Overview page.
get_action_center
The org's open Action Center items (failed/overdue invoices, new and stale leads, unviewed or expiring quotes, pending cancellations, countersigns, calendar sync errors), each with severity, title, and a link. Optional severity filter. Read-only.
Website leadsadmin3
Tool
Purpose
list_website_leads
Quote requests submitted through your own website (the Leads inbox).
accept_website_lead
Turn a lead into a client (links by email or creates a new record). Two-step confirm.
dismiss_website_lead
Dismiss a new or spam lead. Reversible from the UI.
Advisor actionsadmin1
Tool
Purpose
set_advisor_item_state
Check off an Advisor recommendation: done, dismissed, or snoozed for 7 days.
Search & lookup4
Tool
Purpose
find_client
Resolve a natural-language name into a customerId. (admin)
find_project
Resolve a project name into a projectId.
find_recent
Last N quotes / contracts / invoices / clients / projects, newest first. Optional customerId narrows any kind to one client. (admin)
find_active_session
The work session currently running, if any.
Client data — readclient4
Tool
Purpose
get_projects
A client's projects with session status, hours, billing profile, and start/end dates.
get_billing
A client's invoices plus a canonical summary (owed, net paid, invoiced, refunded) and retainer usage.
get_notifications
A client's recent notifications.
get_activity
A client's own activity log.
Settings & status — readadmin4
Tool
Purpose
get_settings
Full admin-settings map (timezone, invoice defaults, payment methods, dunning, late fees, quote defaults).
get_billing_profile
Legal name, DBA, entity type, EIN last-4, address, tax status, plus a complete boolean.
get_stripe_connect_status
DB flags plus a live Stripe diagnostics call (charges / details enabled). Handles webhook lag.
list_imports
The 20 most recent CSV import batches from the import wizard: kind, file name, status, and per-row tallies. Optional status filter. Read-only; starting or committing an import stays in the wizard UI.
Catalogadmin7
Tool
Purpose
list_quote_templates
Saved whole-quote templates.
list_line_item_templates
The line-item library (built-in starter items + your own).
list_surcharges
Surcharge templates.
list_contract_templates
The contract-template library. Built-in starter templates auto-seed the first time it's called.
save_to_catalog
Promote freeform line items / surcharges from a quote into reusable templates.
list_pricing_rates
The pricing rate card — retainer tiers, hourly rates, block packages, and fixed-fee rows, with their codes and included hours.
create_service_plan
Guided. Build a reusable Service Plan — net days, deposit, after-hours/weekend multipliers, min increment, auto-approve ceiling, tax behavior, schedule template. Only name required; the rest inherit org defaults.
Service plans, scheduling, costs & configadmin7
Tool
Purpose
attach_service_plan
Guided. Apply a Service Plan to a project — locks its billing terms and regenerates the client's Billing Terms document.
add_project_discount
Guided. Add a standing discount to a project (percentage / fixed / per-hour) that recurs into billing as a negative line item.
add_project_expense
Guided. Record a recurring product cost — a third-party cost the client pays the vendor directly (a disclosure, never invoiced).
create_calendar_event
Guided. Add a calendar event (UTC times; optional client/project link and client visibility). Pushes to Google when the key creator's calendar is connected.
create_delivery_request
Guided. Open a work request on the Request-to-Delivery board for a client.
update_delivery_request
Move a delivery request across the board — status / priority / due date / project.
update_setting
Change one org setting from a curated safe set; money/tax keys require a two-step confirmation.
Clients — writeadmin4
Tool
Purpose
create_client
Find-or-create by (org, email). Readies a portal-signup invite.
update_client
Patch name, phone, company, subscription, industry, timezone. Elicits a recent-clients list if customerId is missing.
archive_client
Soft-archive. Two-step confirm. Elicits if customerId missing.
restore_client
Clears archive/delete flags. Lists archived clients if customerId missing.
Projects — writeadmin5
Tool
Purpose
create_project
Locks a pricing snapshot. Optional start and end dates (the end date drives the calendar milestone). Elicits clients + billing profiles if anything's missing.
update_project
Patch name, description, billing profile, budget, start and end dates. Changing the end date keeps the calendar milestone in step.
complete_project
Marks done + completion note. Refuses if a session is still running.
reopen_project
Clears the completion state so new work and billing can resume. Completed projects stay browsable without reopening; reopen only to log new work or billing.
add_project_surcharge
Mid-job surcharge. Auto-approved when pre-disclosed, otherwise emails the client for approval. Confirm.
Sessionsadmin5
Tool
Purpose
start_work_session
Clock in. Elicits active projects if projectId missing; returns a conflict if already running elsewhere.
stop_work_session
Clock out. Auto-resolves the active session if sessionId omitted.
add_session_note
Append a note to a session.
set_session_billable
Flip a session's billable flag. Refuses if the session is already on a sent invoice — void and re-issue first.
correct_session
Adjust a session's start / end times. Same invoiced-session guard.
Project updates & notes3
Tool
Purpose
list_project_updates
Newest-first thread with replies.
post_project_update
Admin status note — emails the client and shows on their dashboard. Two-step confirm. (admin)
reply_to_project_update
Threaded reply. Notifies admins for client replies; no email.
Quotes & contractsadmin7
Tool
Purpose
draft_quote_from_description
Price a whole job from plain English using the same AI drafter as the New Quote screen (catalog matches, price anchors, live material lookups). Returns a priced preview, a draft_token for create_quote, and a preview_pdf_url so the admin can see the exact client PDF before anything is saved.
modify_quote_draft
Edit a drafted quote from a plain-English instruction ("make the water heater $700", "drop the cleanup line") without re-drafting. Untouched lines carry through unchanged; returns a fresh token and preview.
create_quote
The marquee tool. Cold-call mode: tell it the client wants a quote and it asks every question (recipient, line items, billing mode, deposit %, expiry) with tailored catalog suggestions. Also persists AI drafts via draftToken. Returns a preview_pdf_url for the saved draft.
send_quote
Email the signing link, pre-signed with the key-owner's saved signature. Two-step confirm. Elicits draft quotes.
create_contract
Draft an agreement or change order from a template. Elicits a template picker (built-ins included) when templateId is missing; find-or-creates the client.
send_contract
Same as send_quote for agreements / change orders. Two-step confirm.
request_approval
Client approval flow for budget overruns or undisclosed surcharges. Two-step confirm.
Out-of-band payment (check, wire, cash). Supports partial amounts (amount_paid_cents) — adds to prior payments and flips to paid only when fully covered. Two-step confirm.
list_invoice_drafts
Snapshots with no Stripe invoice or draft status. Filterable by client.
void_invoice
Void an open invoice in Stripe. Two-step confirm. (Refuses a paid invoice — refund instead.)
Write off an open invoice as bad debt. Two-step confirm.
Client commsadmin4
Tool
Purpose
send_client_message
Free-form email to a client. Two-step confirm (token) — the first call returns the message preview to read back. Elicits recipient + subject + body when missing. Your saved email signature is appended automatically. Replies land in the Email tab inbox with a copy forwarded to your own mailbox, and repeat sends to the same client continue the same thread.
list_client_replies
Client replies from the Email tab inbox, unread first, with the reply text so the agent can read it out. Never marks anything read.
list_client_emails
Everything the platform has emailed a client (composed messages, invoices, notifications), newest first. Outbound only. Read-only.
list_client_contacts
People saved for a client (or the whole directory): name, role, email, phone, primary flag. Read-only.
Team managementadmin4
Tool
Purpose
list_team_members
Your org's admin staff — roles, status, owner count. Read-only.
invite_team_member
Owner-only. Invite an admin (admin or viewer, never owner). Two-step confirmation with an email + role read-back before it sends.
list_client_teammates
A specific client's portal teammates. Read-only.
invite_client_teammate
Invite a teammate to a client's portal (joins as a member). Two-step confirmation with an email read-back.
ℹAuto pre-sign on send_quote / send_contract
Both look up the saved signature of the admin who minted the key and stamp it before the client email goes out — matching the human composer flow. The signer of record is whoever owns the key, so multi-admin teams get correct attribution. No saved signature → the send still goes through unsigned and the response returns a warning the agent should read back. Save one at Settings → Signatures and every future send is pre-signed. (Change orders skip pre-sign — they amend an already-signed parent.)
Not on the agent surface yet
Kept out of the agent surface on purpose: removing or re-roling team members — inviting admins and client teammates is now invite_team_member / invite_client_teammate, but removals and role changes stay in the admin UI, since revoking the wrong person's access is the kind of mistake a confirmation prompt can't fully undo. Two more are intentionally not agent actions: approval decisions are client-side by design — the admin opens a request with request_approval, but accepting it is the client's consent to give, never the admin's (or an agent's) to make on their behalf; and the platform-fee / subscription / API-key / MCP-toggle settings are excluded from update_setting on purpose. Need a tool we don't have? Contact support — we ship new tools fast.
Troubleshooting
⚠Stale tool list after a deploy
If your client cached the tool list before a platform update, restart the MCP connection — the next initialize refreshes everything.
Confirmation token expired — tokens TTL at 60s. Re-call the same tool without the token; the response carries a fresh preview.
Insufficient permissions — the key lacks the right write group. Edit it under Settings → API Keys.
Customer not found in this organization — an admin key passed a customerId from a different org. Keys never see across orgs.
Stripe Connect is not configured — the org hasn't finished Connect onboarding. Call get_stripe_connect_status to see where they are; you can't send or collect invoices without it.
Best practices for client developers
Call get_context first. It returns the workflows map, inventory snapshot, system instructions, and endpoint catalog — the whole session leans on it.
Never pre-fill IDs from training data. When a tool returns needs_input with an inventory, use those IDs verbatim. Hallucinated IDs are the #1 failure mode.
Read previews back to the user word-for-word before the second (committing) call.
On second thoughts, start fresh. If the user changes their mind between calls, re-ask the params and issue a new token.
Use dry_run="true" on send_invoice / mark_paid to preview the dollar amount without locking a confirmation token.
Audit & observability
Every call lands an AgentAuditLog row — tool name, status, IP + user agent, duration, and the linked key. View recent calls under Settings → API Keys → Activity. The same data feeds daily_briefing's activity rollup (calls per day, error rate, top tools).