Skip to main content

modern-collections

The official Python client, command-line tool and MCP server for the Modern Collections API. With a Modern Collections API key you, a script, or your AI assistant can do what you do in the creditor dashboard: place overdue invoices, find and follow accounts, record payments, work disputes, attach documents, and pull what has been collected.

  • AI assistants (Claude, Cursor, anything that speaks MCP) connect to the hosted server at https://api.moderncollections.io/mcp. No install.
  • Command line: modern-collections.
  • Python: from mc_api import MCClient.

Connect your AI assistant

No install: the hosted server

Claude.ai, Claude Desktop, ChatGPT: add the URL and sign in. Add https://api.moderncollections.io/mcp as a custom connector. The app opens our sign-in page; sign in with your dashboard login and choose what the app may do. Starting, stopping or changing debtor outreach (placing invoices, recording payments, resolving disputes) is off unless you tick it. No API key is involved. A partner user connects the partner once; the app lists the linked creditors with partner_creditor_list and names one on each call. Disconnect any time under Settings → Developer access → Connected apps.

Without a credential, /mcp answers 401 with a WWW-Authenticate challenge that points OAuth clients at /.well-known/oauth-protected-resource/mcp.

Any other MCP client that can send a custom header can use an API key. Point it at:

  • URL: https://api.moderncollections.io/mcp (streamable HTTP)
  • Header: Authorization: Bearer <your API key>
{
  "mcpServers": {
    "modern-collections": {
      "url": "https://api.moderncollections.io/mcp",
      "headers": { "Authorization": "Bearer ca_..." }
    }
  }
}

Then ask your assistant to run account_whoami. It names the account the key reaches and says what, if anything, blocks placing (verification, the agreement, the payout account).

One command: Claude Code, Cursor, Claude Desktop

uv tool install modern-collections      # or: pip install modern-collections
modern-collections mcp install --client claude-code      # or cursor, claude-desktop

It asks for your key without echoing it, checks it, and only then writes the client's configuration:

--client What it writes
claude-code runs claude mcp add --transport http against the hosted server (--scope user by default)
cursor ~/.cursor/mcp.json
claude-desktop Claude Desktop's config file: a local modern-collections-mcp entry, or with --transport remote the hosted server through npx mcp-remote

Other servers already in those files are left alone. Restart Claude Desktop after installing.

Local server

The same tools run as a local stdio server, with the key in its environment:

MC_API_ENV=prod MC_API_KEY=ca_... modern-collections-mcp

modern-collections-mcp --http serves the same thing over streamable HTTP on http://127.0.0.1:8765/mcp; the key then comes from each request's Authorization header.

Getting a key

Dashboard → Settings → API Key. The key is shown once, when it is created or rotated; Modern Collections keeps only a one-way hash, so a lost key is rotated, not recovered. Setup snippets are under Settings → Developer access.

Creditor keys look like ca_<prefix>_<secret>. Partner keys (pa_<prefix>_<secret>) act for every creditor linked to the partner; see Partner keys.

What your assistant can do

A default set of about 25 tools covers everyday work:

Area Tools
Setup account_whoami, guide, partner_creditor_list
Placing and following placement_create, placement_list (search by company or invoice number), placement_status, audit_query, placement_context
Changing a placement placement_amend, placement_update_debtor, placement_set_posture, placement_recall
Payments payment_record, payment_list
Disputes dispute_list, dispute_get, dispute_acknowledge, dispute_resolve
Documents document_upload, document_upload_link, placement_documents, document_status
Reporting analytics_summary, analytics_series, remittance_list, statement_list, statement_download_url

Everything else (settlement floors, contact choices, CSV and file intake, evidence scoring, the recovery workspace, notifications, webhooks, QuickBooks) is in the full set. Turn it on with ?tools=all on the hosted URL (or the header X-MC-Tools: all), MC_API_MCP_TOOLS=all for the local server, or --all-tools on mcp install.

document_upload_link is for files on your computer that a chat assistant cannot read: it returns a link, valid for 30 minutes, that you open in a browser to upload the file onto the placement.

Confirmations

Tools that contact a debtor, move money, change who is contacted, or make a legal statement are marked destructive (placement_create, payment_record, placement_amend, placement_update_debtor, dispute_resolve, placement_recall, intake commits, and a few more). Your assistant asks before using them, and most MCP clients ask you too. When you want your assistant to act without asking, tell it so, or choose "always allow" for those tools in your MCP client.

placement_create starts real outreach to a real company. There is no sandbox on this API; placement_recall stops a placement that should not have been opened.

Install

uv tool install modern-collections      # CLI + local MCP server
pip install modern-collections          # or as a library

Python 3.11 or later. The PyPI project named mc-api is unrelated.

Configure

Pick an environment and supply a key. There is no default environment, so a forgotten setting can never send a key to the wrong place. The key is read from MC_API_KEY and is never printed or logged.

Variable Values
MC_API_ENV prod
MC_API_BASE_URL an explicit API URL (overrides MC_API_ENV)
MC_API_KEY ca_... (creditor) or pa_... (partner)
MC_API_CREDITOR partner keys only: the default creditor to act for

Command line

export MC_API_ENV=prod MC_API_KEY=ca_...

modern-collections whoami                                  # check your setup
modern-collections placements list --q "Acme"              # find by company or invoice number
modern-collections placements create --company "Acme Freight" --amount 7500.00 --email ap@acme.co \
  --invoice-number INV-4411 --invoice-date 2026-01-01 --due-date 2026-02-01 --state OH
modern-collections placements get <placement_id>
modern-collections placements audit <placement_id>         # what has happened on the account
modern-collections payments record <placement_id> --amount 500.00 --idempotency-key <bank-ref>
modern-collections disputes list --status open
modern-collections documents upload invoice-4411.pdf --placement <placement_id> --type invoice
modern-collections documents upload-link <placement_id> --type invoice
modern-collections analytics summary
modern-collections remittances list

-o json gives machine-readable output. It is a global option, so it goes before the subcommand (modern-collections -o json placements list), as do --env, --base-url, --api-key, --creditor and --timeout. Exit codes: 0 success, 1 API or runtime error, 2 configuration or usage error.

File an invoice, read it back, correct it

P=$(modern-collections -o json placements create --company "Acme Freight" --amount 7500.00 \
      --invoice-number INV-4411 --invoice-date 2026-01-01 --due-date 2026-02-01 \
      | jq -r .placement_id)

modern-collections documents upload invoice-4411.pdf --placement $P --type invoice
modern-collections placements context $P                    # what was read off the invoice
modern-collections placements amend $P --po-number PO-8871 --reason "read off the signed BOL"
modern-collections placements amend $P --amount 7250.00 --reason "credit memo applied"
modern-collections placements debtor $P --email ap@acmefreight.com

Amendments apply while outreach is running: the next call or email uses the corrected placement. Every edit is kept as an append-only, audited record. One amendment kind per call: --amount, --notes/--clear-notes, or any mix of the invoice fields (--invoice-number, --invoice-date, --due-date, --po-number, --service-date, --currency, --written-contract). Status is changed through payments record, disputes resolve or placements recall.

Python

from mc_api import MCClient, NotFoundError

with MCClient(env="prod", api_key="ca_...") as api:
    print(api.whoami()["blocking"])

    placement = api.create_placement(
        {
            "invoice_amount": "7500.00",
            "invoice_number": "INV-4411",
            "invoice_date": "2026-01-01",
            "due_date": "2026-02-01",
            "debtor": {"company_name": "Acme Freight", "primary_email": "ap@acme.co"},
        },
        idempotency_key="INV-4411",
    )

    for row in api.iter_placements(q="Acme", status="in_outreach"):
        print(row["id"], row["invoice_amount"])

    try:
        api.get_placement("00000000-0000-0000-0000-000000000000")
    except NotFoundError:
        pass

Errors are ApiError subclasses: AuthError (401/403), NotFoundError, ValidationError (400/422, with field errors flattened to one line) and RateLimitedError (429, with retry_after). iter_placements, iter_documents, iter_payments, iter_remittances, iter_statements, iter_exports, iter_audit and iter_partner_creditors walk every page lazily. To catch up after a missed webhook, pass updated_since= (a timezone-aware timestamp) to list_placements / iter_placements, or --updated-since on the CLI; rows come back oldest change first. Webhook settings accept webhook_events to subscribe to a subset of event types (unset means all). The package ships type hints (py.typed).

Partner keys

A partner key reaches every creditor linked to the partner through one connection, one creditor per call:

  • MCP: run partner_creditor_list, then pass creditor= on each call (the creditor's id, its external reference, or its exact name).
  • CLI: modern-collections partner creditors, then --creditor <id or ref>, or set MC_API_CREDITOR.
  • Python: MCClient(api_key="pa_...", creditor="<id or ref>").

Two calls cover the whole partner at once, no creditor needed: remittances across every linked creditor (partner_remittance_list, modern-collections partner remittances, list_partner_remittances) and statements (partner_statement_list, modern-collections partner statements, list_partner_statements), each row carrying the creditor it belongs to plus totals for the filtered set. Partner onboarding is scriptable too: create a creditor, submit KYB, invite a user, update a link, fulfil an evidence request, and read webhook events.

A call without a creditor gets a 400 from the API; the client never guesses. With a creditor key the creditor argument is ignored.

Agent skills

Two skills teach an assistant how to work the account: modern-collections (everyday operations) and collections-ar-triage (turn an AR aging export into a reviewed batch of placements). They ship in this package:

modern-collections skills install              # into ~/.claude/skills
modern-collections skills install --dir <project>/.claude/skills

Over MCP the same text is available as prompts, as resources (modern-collections://skills/<name>), and through the guide tool.

Kept out of reach on purpose

  • Accepting the master service agreement is a person's click in the dashboard. The API refuses it from an API key, and no tool or command offers it.
  • Rotating the API key and setting the webhook URL need a signed-in dashboard session, so a leaked key cannot replace itself or redirect events.
  • Signing secrets stay out of the model. The intake webhook secret can be rotated and used from the CLI and the Python client, not through MCP.

Safety properties

  • The API key lives only in the request Authorization header. It is kept out of repr(), exceptions and logs, and so is the creditor scope; neither is sent on the unauthenticated health() check.
  • Explicit connect, read and write timeouts.
  • Reads are retried on 429 (honouring Retry-After), 502, 503 and 504. A write is retried only when it carries an idempotency key, which the server replays; other writes are sent once, so a create or a payment is never silently duplicated. The MCP server derives a key for placement_create and payment_record when none is given, so a retried tool call replays instead of acting twice.
  • Client-side checks on amendment fields and enum-like arguments, so a typo fails locally.
  • Signed structured intake is HMAC'd over the exact bytes sent.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for modern-collections 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for modern-collections 0.3.0
File Size Uploaded Provenance Actions
modern_collections-0.3.0.tar.gz 94.8 kB Without provenance Details for modern_collections-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for modern-collections 0.3.0
File Interpreter ABI Platform Actions
modern_collections-0.3.0-py3-none-any.whl Python 3 none any Details for modern_collections-0.3.0-py3-none-any.whl

Total release size: 196.5 kB

Release files / modern_collections-0.3.0.tar.gz

Download URL modern_collections-0.3.0.tar.gz
Size 94.8 kB
Tags Source
SHA-256 checksum
How to use checksums
fa0edad33d34b915743ecddecf0918ae73c08908f0df565845d3be740bfbba3f
BLAKE2b-256 checksum
How to use checksums
a336235969bba6013a5074994cd47acae81e530413c35a20faa55188250d6867
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / modern_collections-0.3.0-py3-none-any.whl

Download URL modern_collections-0.3.0-py3-none-any.whl
Size 101.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
26f5ead0b8a2bd0940d342d952188742ab03141773a5c283cd21d45a10991aa3
BLAKE2b-256 checksum
How to use checksums
cee9c9eba3fdf72b580825eaec83cbca5b914e381dd99148f5ab7f42fa1e41e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for modern-collections 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page