Skip to main content

mercury-multiorg-mcp

Unofficial. Not affiliated with or endorsed by Mercury.

Read-only MCP server that exposes several Mercury organizations to one AI session. Mercury's hosted MCP and its API tokens are single-organization per connection; this server holds one read-only token per org and routes every tool call by an explicit entity key.

Version 0.1.4 (see CHANGELOG.md). The maintainer tags releases as vX.Y.Z; find the commit to pin with git ls-remote --tags https://github.com/dkaleganov/mercury-multiorg-mcp 'v0.1.4^{}'. The complete tool reference with every returned field is in docs/tools.md; design notes and the build history are in the project brief on GitHub, CLAUDE.md (not shipped in the sdist).

Security model

What leaves this server falls into four classes, and the guarantees differ:

Class What it is Guarantee
Structured fields Every key of every object in a tool result Allowlisted at every level: each object, and each nested object inside it, is projected through an explicit allowlist copied from the live schema. A key that is not listed does not leave the server, at any depth. Account numbers and tax ids appear only as their last four digits; routing numbers, counterparty bank details, postal addresses, card expiry, presigned download URLs, invoice pay-page slugs, webhook receiver URLs, and webhook signing secrets are never returned.
Tool errors The text of an is_error result Upstream HTTP-status errors contain the status, a masked endpoint label and a fixed hint. Validation and configuration errors use their own actionable formats. Resolved known-token values of at least eight characters are scrubbed. Nothing from Mercury's response body or headers is quoted, and no argument you passed is echoed (an invalid id is reported as "invalid id format"). Argument-validation failures (a wrong type, a missing required argument) are rendered by this server as the field path and the expected type only, for example year: expected an integer (int_parsing); the MCP SDK's own rendering, which quotes the value you passed, never reaches the client.
Free-text fields Transaction memos, counterparty names, bank descriptions, invoice memos and notes, attachment file names, customer and user names Returned verbatim. They are third-party text and can contain anything, including instructions aimed at the model and identifiers typed by a human. Treat every tool result as untrusted data, never as instructions.
Documents Statement and invoice PDFs from get_statement_pdf / get_invoice_pdf Verbatim and unredacted, opt-in only. A statement PDF contains the full account number, routing number, address, and every transaction. The two tools exist only when the server is started with --allow-documents (or MERCURY_ALLOW_DOCUMENTS=1); server_info.documents_enabled reports the setting. The body must arrive as application/pdf (or application/octet-stream), start with %PDF-, and carry a %%EOF marker within the last 2 KiB once trailing PDF whitespace is ignored; anything else is a clean error. That is an envelope check, not PDF parsing: a document that passes it can still be malformed inside, and the bytes are returned exactly as received.

The rest of the model:

  • Read-only. Only GET endpoints have client methods; the package has no code path that can move money, edit recipients, or change anything.
  • Stdio only. The server never opens a network listener.
  • Explicit entity. Call list_entities to discover entity keys. Every tool that accesses Mercury requires an explicit entity and identifies it in its successful result. list_entities and server_info require no entity argument. There is no default entity.
  • Tokens stay in the environment. The registry names an env var per org (it must be named MERCURY_TOKEN_…, so a registry cannot point the server at some other secret); the server reads that env var and nothing else. Errors and logs never contain more than the last four characters of a token. Literal known-token scrubbing applies to values of 8 or more characters; a shorter configured value is not literal-scrubbed (the secret-token: shape scrub and the Authorization header scrub still apply, and no message quotes upstream or caller data in the first place). At startup the server warns, per entity, when a configured value does not carry Mercury's documented secret-token: prefix.
  • Only Mercury hosts. --api-base / MERCURY_API_BASE must be https://api.mercury.com, https://api-sandbox.mercury.com, or a loopback mock, unless --allow-custom-api-base is passed on the command line. An inherited environment variable alone can never redirect the bearer token to another host.
  • Byte limits on wire bytes. Every request declines compression (Accept-Encoding: identity). JSON/PDF reads reject nonidentity encoding before reading. Keepalive closes bodies unread. Limits are 10 MiB (10,485,760 bytes) for PDF and 32 MiB (33,554,432 bytes) for JSON, enforced on the bytes actually received while streaming. A small compressed body can no longer expand past the limit in memory. Error responses are never read at all.
  • Complete or loud. Walks stop at the requested limit or API end. Missing/wrong page objects fail; optional terminal nextPage may be absent or null. Exact duplicate IDs are dropped and counted; conflicting contents fail. A page with no fresh usable rows while more are advertised fails. A walk that needs more than 200 pages fails, and a treasury cursor that is not a non-negative integer fails. Duplicate counts are reported as duplicates_dropped on every paginated result and under reportable_totals.totals, so a total is never built on a stalled, malformed, or double-counted walk.
  • Windowed feeds are walked in full. Mercury documents no sort key for events or treasury transactions, so a client-side window (since on list_events, start/end on list_treasury_transactions) walks the whole bounded feed (90 days of events; the treasury ledger up to 200 pages), filters and sorts newest first here, then applies limit. truncated is exact. The cost is proportional to the feed, not the window.
  • Binary documents stay in memory. PDFs come back as an embedded application/pdf blob (base64), never written to disk.
  • Path ids are validated. Every id that becomes part of a request path must be a single safe segment; nothing can redirect a call to another endpoint.
  • Startup errors are one line, exit 2. A missing or malformed registry (including non-string YAML keys), an unreadable file, a bad --env-file, or a disallowed API host prints one line to stderr and exits with status 2. The redacting exception hooks are installed before anything is loaded, so no startup path can print an unredacted traceback.
  • Never files anything. reportable_totals is a pre-filing cross-check. Mercury has no 1099 filing endpoint; filing happens in each org's dashboard.

Hygiene. This package lives in a public repository. Tracked files, fixtures, and commit messages carry no tokens, account numbers, or financial identifiers, with two deliberate exceptions. First, the maintainer's own name appears in the package authors metadata (approved by the repository owner); business and personal names of anyone else do not appear. Second, a history note: the first Phase 1 commit's fixtures used a real, public ABA routing number as sample data; it was replaced with an obviously fake value in the next commit, so it is absent from every tagged file tree but remains in their ancestry. It identifies a bank, not an account, and the history was deliberately not rewritten. This release passed a full-history gitleaks scan.

Repository history. This package was developed in the personal-ai-systems monorepo through v0.1.3 and moved to this repository at v0.1.4 with its history preserved (the same commits, rewritten to this repository's layout, so their SHAs differ from the monorepo's). Releases up to 0.1.3 were tagged mercury-v0.1.x there and are tagged v0.1.x here; release tags are vX.Y.Z from now on. Both hygiene exceptions above apply to this history unchanged.

Install

From PyPI, running the pinned release with uvx (no clone needed):

uvx mercury-multiorg-mcp@0.1.4 --entities /private/path/entities.yaml

uvx <package>@<version> runs exactly that release in an isolated, cached environment. pip install 'mercury-multiorg-mcp==0.1.4' also works and puts mercury-multiorg-mcp and mercury-multiorg-mcp-keepalive on your PATH.

Requires Python 3.11+ and uv (for uvx).

From source / pinned commit

From a clone:

git clone https://github.com/dkaleganov/mercury-multiorg-mcp.git   # or git@github.com:dkaleganov/mercury-multiorg-mcp.git
cd mercury-multiorg-mcp
uv sync
uv run mercury-multiorg-mcp --entities /private/path/entities.yaml

Or pin a full commit SHA with uvx (pin a SHA, not a tag: a full SHA is immutable and cache-safe, while a tag can be moved):

uvx --from 'git+https://github.com/dkaleganov/mercury-multiorg-mcp@<FULL_COMMIT_SHA>' \
  mercury-multiorg-mcp --entities /private/path/entities.yaml

Configure

  1. In each Mercury org: org switcher → All Settings → Tokens → create a Read Only token (no IP allowlist required).
  2. Copy entities.example.yaml to a private location outside this repo and list your orgs (key, display_name, token_env; the env var name must start with MERCURY_TOKEN_).
  3. Export one env var per org, named as in the registry, in the environment that launches the server (.env.example shows the names). Configuration is read from process environment variables only; no .env file is read unless you pass --env-file <path>, so nothing is picked up by accident from the repo, your home directory, or a uvx cache.
  4. Optional: MERCURY_API_BASE=https://api-sandbox.mercury.com with sandbox-created tokens.
  5. Optional: --allow-documents (or MERCURY_ALLOW_DOCUMENTS=1) to register the two PDF tools. Leave it off unless the session really needs unredacted documents.

Command line

Flag / env var Meaning
--entities PATH / MERCURY_ENTITIES_FILE Entity registry YAML. Required (flag wins over env var); there is no implicit default.
--env-file PATH Load this dotenv file before resolving tokens. Existing env vars win. Without the flag no dotenv file is read from anywhere.
--api-base URL / MERCURY_API_BASE Mercury API host, default https://api.mercury.com. Allowed: production, https://api-sandbox.mercury.com, or plain http:// on localhost / 127.0.0.1 for mocks.
--allow-custom-api-base Permit any other https:// host. Never set this from an environment variable; it exists so a custom host is always a deliberate command-line choice.
--allow-documents / MERCURY_ALLOW_DOCUMENTS=1 Register get_statement_pdf and get_invoice_pdf (documents are returned unredacted). Off by default: 24 tools without it, 26 with it.
--version Print the package version and exit.

Startup problems (missing or malformed registry, invalid YAML, unreadable file, bad API base) print one line to stderr and exit with status 2. Stdout is reserved for the MCP protocol.

Mercury deletes an API token after 45 days of inactivity (the token inactivity clock) and separately downgrades permissions unused for 45 days. Run mercury-multiorg-mcp-keepalive on a schedule so the inactivity clock never expires; see docs/keepalive.md for cron and launchd snippets.

Works with any MCP client

Compatible with MCP clients that support local stdio servers and the negotiated protocol version. Configure the following command on the client host, with access to the private registry and environment file. Document display and client approval policies vary. This server does not expose HTTP or SSE. The command and arguments are the same in every client:

command: uvx
args:    mercury-multiorg-mcp@0.1.4 --entities /private/path/entities.yaml
optional extra arg: --allow-documents   (registers the two unredacted PDF tools)

To run a pinned commit instead of the PyPI release, replace the first argument with --from, git+https://github.com/dkaleganov/mercury-multiorg-mcp@<FULL_COMMIT_SHA>, mercury-multiorg-mcp (see "From source / pinned commit").

Tokens reach the server as environment variables named in your registry. Two ways to supply them: an env block in the client's config (only where the client expands placeholders such as ${MERCURY_TOKEN_ACME_MAIN} from your shell; a literal token in a config file is a secret on disk), or a private dotenv file. A private dotenv file passed with --env-file /private/path/mercury.env avoids client-specific placeholder expansion. The client host must be able to read it; existing process environment variables win. Keep the registry and the dotenv file outside any repository and readable only by your user.

Claude Code (.mcp.json)

Claude Code expands ${VAR} from its environment. This repository includes an example .mcp.json; clients that discover this format may offer to launch it. It points to the synthetic example registry and contains no credentials (so list_accounts returns a clean per-entity error).

{
  "mcpServers": {
    "mercury-multiorg": {
      "command": "uvx",
      "args": [
        "mercury-multiorg-mcp@0.1.4",
        "--entities",
        "/private/path/entities.yaml"
      ],
      "env": {
        "MERCURY_TOKEN_ACME_MAIN": "${MERCURY_TOKEN_ACME_MAIN}"
      }
    }
  }
}

Claude Desktop (claude_desktop_config.json)

Open Settings → Developer → Edit Config. Use --env-file so this setup does not depend on client-specific placeholder expansion:

{
  "mcpServers": {
    "mercury-multiorg": {
      "command": "uvx",
      "args": [
        "mercury-multiorg-mcp@0.1.4",
        "--entities",
        "/private/path/entities.yaml",
        "--env-file",
        "/private/path/mercury.env"
      ]
    }
  }
}

Codex CLI (~/.codex/config.toml)

[mcp_servers.mercury-multiorg]
command = "uvx"
args = [
  "mercury-multiorg-mcp@0.1.4",
  "--entities", "/private/path/entities.yaml",
  "--env-file", "/private/path/mercury.env",
]
# `env = { MERCURY_TOKEN_ACME_MAIN = "..." }` is also accepted, but values there are
# literal, so prefer --env-file over putting a token in this file.

Cursor / Windsurf legacy Cascade (mcp.json)

Cursor uses .cursor/mcp.json or ~/.cursor/mcp.json. Windsurf legacy Cascade uses ~/.codeium/windsurf/mcp_config.json. The current default Devin Local agent uses its own CLI configuration; this example targets legacy Cascade. Both use an mcpServers map. Use --env-file unless your client's documentation says it expands environment placeholders.

{
  "mcpServers": {
    "mercury-multiorg": {
      "command": "uvx",
      "args": [
        "mercury-multiorg-mcp@0.1.4",
        "--entities",
        "/private/path/entities.yaml",
        "--env-file",
        "/private/path/mercury.env"
      ]
    }
  }
}

VS Code (.vscode/mcp.json)

VS Code uses a servers map (not mcpServers) and an explicit "type": "stdio":

{
  "servers": {
    "mercury-multiorg": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "mercury-multiorg-mcp@0.1.4",
        "--entities", "/private/path/entities.yaml",
        "--env-file", "/private/path/mercury.env"
      ]
    }
  }
}

Gemini CLI (~/.gemini/settings.json or .gemini/settings.json)

{
  "mcpServers": {
    "mercury-multiorg": {
      "command": "uvx",
      "args": [
        "mercury-multiorg-mcp@0.1.4",
        "--entities",
        "/private/path/entities.yaml",
        "--env-file",
        "/private/path/mercury.env"
      ]
    }
  }
}

Any other client

Any client that supports local stdio servers and the negotiated protocol version, running on a host that can read the private registry and environment file: point it at the same uvx command and arguments. The server never opens a network listener, so an HTTP or SSE transport is not offered.

Tools

Every tool that accesses Mercury requires an explicit entity and identifies it in its successful result; list_entities and server_info require no entity argument. The seven tools with a limit argument return count and truncated. Full-list tools have no public limit. Paginated results also expose duplicate diagnostics (duplicates_dropped: identical rows the walk dropped). Full field-by-field reference: docs/tools.md.

Tool Arguments Returns
list_entities entity keys, display names, whether each token env var is set
server_info package version, API base, entity count, documents_enabled (no secrets)
list_accounts entity accounts with balances, accountNumberLast4
list_transactions entity, account_id?, start?, end?, search?, limit=100 transactions in Mercury API desc order, truncated flag
reportable_totals entity, year, threshold? (default 600 through 2025, 2000 from 2026, for nonemployee services and certain MISC payments; finite, at most 1,000,000,000) per-recipient 1099 cross-check totals; needs_review buckets, unclassified, excluded_summary
list_recipients entity recipients: id, name, nickname, status, default payment method, date last paid, emails, isBusiness
list_tax_docs entity tax-form attachments per recipient, plus recipients_without_docs
get_org entity id, legal name, DBAs, kind, subscription tier, billing cadence, einLast4
list_statements entity, account_id, start?, end?, limit=100 statement metadata in Mercury API desc order (masked account number and EIN, transactionCount)
get_statement_pdf (opt-in) entity, statement_id the statement PDF as an embedded blob (≤ 10 MB), unredacted; only with --allow-documents
list_treasury entity treasury accounts with balances and monthly net returns
list_treasury_transactions entity, treasury_id, start?, end?, limit=100 treasury ledger rows in Mercury API desc order; with a date window the whole ledger is walked, filtered, and sorted by canonicalDay newest first
list_treasury_statements entity, treasury_id, document_type? treasury statements and tax documents (metadata)
list_credit_accounts entity credit accounts with balances
list_cards entity, account_id?, status?, limit=100 cards: last four, name, nickname, kind, type, status, limits, budgets, locks
get_card entity, card_id one card, same fields
list_categories entity custom expense categories
list_merchants entity, search?, limit=100 priority merchants (id, name)
list_customers entity AR customers: id, name, email, deletedAt
list_invoices entity, status?, start?, end?, limit=100 AR invoices (filters applied client-side after a full walk)
get_invoice entity, invoice_id one invoice with service period and line items
get_invoice_pdf (opt-in) entity, invoice_id the invoice PDF as an embedded blob (≤ 10 MB), unredacted; only with --allow-documents
list_invoice_attachments entity, invoice_id attachment ids and file names (no URLs)
list_users entity users: id, first and last name, email, role
list_events entity, since?, resource_type?, limit=100 change events in Mercury API desc order; with since the whole 90-day feed is walked, filtered, and sorted by occurredAt newest first; patches re-projected per resource allowlist
list_webhooks entity webhook endpoints: id, url_fingerprint, status, enabled, event types, filter paths (never the secret or any part of the receiver URL)

start / end on list_transactions filter on createdAt (YYYY-MM-DD or ISO 8601). The Mercury dashboard displays postedAt, so a date range may differ slightly from the UI.

Returns for the Phase 1 and 2 tools

list_entities               entities[] {entity, display_name, token_configured}
server_info                 name, version, api_base, entity_count, entities_with_token, transport, read_only,
                            documents_enabled
list_accounts               entity, duplicates_dropped, accounts[] {id, name, nickname, legalBusinessName, kind, type,
                            status, availableBalance, currentBalance, createdAt, canReceiveTransactions,
                            dashboardLink, accountNumberLast4}
list_transactions           entity, filters, count, truncated, duplicates_dropped, transactions[] {id, accountId,
                            amount, status, kind, createdAt, postedAt, estimatedDeliveryDate, failedAt,
                            reasonForFailure, counterpartyId, counterpartyName, counterpartyNickname,
                            bankDescription, externalMemo, note, mercuryCategory,
                            categoryData {id, name, visibleForCardSpend, visibleForOther, visibleForReimbursements},
                            merchant {id, category, categoryCode, currency, amount}, checkNumber, cardId,
                            currencyExchangeInfo {convertedFromAmount, convertedFromCurrency, convertedToAmount,
                            convertedToCurrency, exchangeRate, feeAmount, feePercentage, feeTransactionId},
                            dashboardLink}
list_recipients             entity, count, duplicates_dropped, recipients[] {id, name, nickname, status,
                            defaultPaymentMethod, dateLastPaid, emails [strings], contactEmail, isBusiness}
list_tax_docs               see the `list_tax_docs` section below (documents[] {id, recipientId, recipientName,
                            fileName, formType, uploadedAt})
reportable_totals           see the `reportable_totals` section below

Returns for the Phase 3 tools

get_org                     entity, organization {id, legalBusinessName, dbas [{dbaName, dbaIsDefault}], kind,
                            subscriptionTier, billingCadence, einLast4}
list_statements             entity, account_id, filters, count, truncated, duplicates_dropped,
                            statements[] {id, startDate, endDate, endingBalance, companyLegalName,
                            accountNumberLast4, einLast4, transactionCount}
get_statement_pdf           content[0] text {entity, statement_id, mimeType, bytes, encoding, redacted: false};
                            content[1] embedded resource {uri, mimeType: application/pdf, blob (base64)}
list_treasury               entity, count, duplicates_dropped, treasury_accounts[] {id, status, availableBalance, currentBalance,
                            createdAt, netReturns[] {month, netAmount, treasuryFee, status,
                            dividends[] {id, type, securityName, amount}}}
list_treasury_transactions  entity, treasury_id, filters, count, truncated, duplicates_dropped, transactions[] {id, accountId, type,
                            amount, balance, canonicalDay, description, additionalDetails, security,
                            details {creditDescription, depositCounterpartyId, feeDescription,
                            manualAmendmentDescription, security, sweepDirection, tradeAction,
                            withdrawalCounterpartyId}}
list_treasury_statements    entity, treasury_id, filters, count, duplicates_dropped, statements[] {id, accountId, documentType,
                            description, periodStart, periodEnd, creationDate, createdAt, updatedAt}
list_credit_accounts        entity, count, credit_accounts[] {id, status, availableBalance, currentBalance, createdAt}
list_cards                  entity, filters, count, truncated, duplicates_dropped, cards[] {id, accountId, userId, nameOnCard, nickname,
                            lastFour, kind, type, status, physicalCardStatus, isAgentCard, spendLimitType,
                            spendLimit {amountCents, atmAmountCents, interval},
                            budgets[] {id, name, amountCents, remainingAmountCents}, merchantLock {id, name},
                            categoryLocks [strings], createdAt, updatedAt}
get_card                    entity, card {same fields as one list_cards row}
list_categories             entity, count, duplicates_dropped, categories[] {id, name, visibleForCardSpend, visibleForOther,
                            visibleForReimbursements}
list_merchants              entity, filters, count, truncated, duplicates_dropped, merchants[] {id, name}
list_customers              entity, count, duplicates_dropped, customers[] {id, name, email, deletedAt}
list_invoices               entity, filters, count, truncated, duplicates_dropped, invoices[] {id, invoiceNumber, status, amount,
                            currencyCode, customerId, destinationAccountId, invoiceDate, dueDate, createdAt,
                            updatedAt, canceledAt, poNumber, payerMemo, internalNote, ccEmails, achDebitEnabled,
                            creditCardEnabled, useRealAccountNumber}
get_invoice                 entity, invoice {list fields + servicePeriodStartDate, servicePeriodEndDate,
                            lineItems[] {name, quantity, unitPrice, salesTaxRate}}
get_invoice_pdf             same two blocks as get_statement_pdf, keyed by invoice_id
list_invoice_attachments    entity, invoice_id, count, attachments[] {id, fileName}
list_users                  entity, count, duplicates_dropped, users[] {userId, firstName, lastName, email, organizationRole}
list_events                 entity, filters, count, truncated, duplicates_dropped, events[] {id, resourceType,
                            resourceId, operationType, resourceVersion, occurredAt, changedPaths, mergePatch,
                            previousValues, patchOmitted?}
list_webhooks               entity, count, duplicates_dropped, webhooks[] {id, url_fingerprint (first 8 hex chars of sha256 of the
                            receiver URL), status, enabled, eventTypes, filterPaths, createdAt, updatedAt}

Every nested object above has its own allowlist; a key Mercury adds tomorrow at any depth is dropped, not passed through.

Lists keep the API's default order (ascending by an undocumented sort key) except transactions, statements, treasury transactions, and events, which are requested in Mercury API desc order. Mercury documents no sort key, so chronological (newest-first) order is guaranteed only for windowed calls: windowed treasury calls sort by canonicalDay, and events with since sort by occurredAt, before limit applies. An unwindowed call returns Mercury API desc order as is. When truncated is true, the rows kept are the head of whichever order applies.

Where the Mercury API has no server-side filter for a documented argument (since on events, start/end on treasury transactions and invoices, status on invoices) the tool walks the whole feed, applies the filter here, and says so in docs/tools.md.

reportable_totals

Counts only completed money movement (status sent) with an outgoing amount, attributed to the calendar year by postedAt in UTC (the date the dashboard shows). The API is queried with postedStart / postedEnd padded by one day on each side; rows outside the year are dropped client-side and counted under excluded_summary.outside_year. Every page of the year is walked; a walk that cannot complete is an error, never a partial total. The live docs define no semantics for transaction kind, so the table only asserts what the kind name supports; real-organization acceptance (September 2026) showed that negative externalTransfer rows were the organization's own linked external accounts and cross-org transfers, while genuine vendor-initiated ACH debits arrived as kind other. Those two kinds are therefore set aside for a human rather than counted.

Decision Kinds Notes
include outgoingPayment method from the payment details: ach, domesticWire, internationalWire, check, or unknown
include exogenousWireDrawdown (negative amount) wire drawdown, presumed counterparty-initiated; undocumented (wireDrawdown)
needs review externalTransfer (negative amount) linked_account_transfers: usually your own linked/external accounts or cross-org transfers; a vendor-initiated ACH debit could also appear
needs review other (negative amount) unlabeled_debits: no method signal; typically vendor-initiated ACH debits or Mercury product payments
exclude internalTransfer, treasuryTransfer the org's own accounts
exclude creditCardTransaction, debitCardTransaction, creditCardCredit, debitCardCredit the card processor files 1099-K
exclude wireFee, personalBankingSubscriptionFee, billingEngineSubscriptionFee, cardInternationalTransactionFee* bank fees and rebates
exclude incomingDomesticWire, incomingInternationalWire, checkDeposit, interestPayment money received
exclude currencyCloudReturn an international wire returned; the original may already be counted, net it by hand
exclude expenseReimbursement employee reimbursements
exclude any includable, needs-review, or unclassified kind not sent, or with a non-negative amount not_settled:<status> / incoming
unclassified any kind not in the table, or a missing amount listed one by one with a reason

Recipients group by counterpartyId (confidence high when it matches a recipient from GET /recipients, else medium) or, failing that, by counterparty name (low). Id-groups that share a normalised name are cross-referenced so a payee split across two ids is visible. The default threshold is year-aware: 600 through tax year 2025, 2000 from 2026 (inflation-indexed from 2027). It is the default for nonemployee services and certain MISC payments; supply the applicable category/year threshold (see the IRS instructions for Forms 1099-MISC and 1099-NEC). The resolved value is echoed. A threshold must be a finite number between 0 and 1,000,000,000; anything else is an error (never silently zero). Real-time payments appear under ach or unknown depending on whether the API returns routing details for them.

Returns:

entity, year, threshold            resolved threshold (default depends on year)
date_basis                         {field: "postedAt", timezone: "UTC",
                                    fallback_to_createdAt_count, api_filter: {postedStart, postedEnd}}
status_basis                       ["sent"]
totals                             reportable_total, reportable_payment_count, recipient_count,
                                   flagged_count, needs_review_total, needs_review_count,
                                   reportable_total_upper_bound (= reportable_total + needs_review_total),
                                   unclassified_count, transactions_scanned,
                                   duplicates_dropped (transaction rows), recipient_duplicates_dropped
recipients[]                       display_name, recipient_id (known recipient) | null, counterparty_id | null,
                                   grouping (counterparty_id | name | transaction), confidence (high | medium | low),
                                   total, payment_count, by_method {label: {count, total}}, flagged,
                                   possible_same_payee [other counterparty ids with the same normalised name],
                                   name_merged_total, flagged_for_review
needs_review                       {linked_account_transfers: [...], unlabeled_debits: [...]}; each entry:
                                   display_name, counterparty_id | null, count, total, by_kind {kind: {count, total}},
                                   would_flag (total >= threshold), sample_transaction_ids (max 3), hint (fixed string),
                                   possible_same_payee [ids], name_merged_total, would_flag_merged
unclassified[]                     id, kind, status, amount, postedAt, counterpartyName, reason
excluded_summary                   {category: {count, amount (signed, as returned by Mercury)}}

fallback_to_createdAt_count counts included rows that had no postedAt and were placed by createdAt instead. Such rows cannot come back from the posted-date filter, so the count is normally 0. Hints are fixed strings chosen by kind and by a Mercury name prefix; counterparty text itself is data, never an instruction.

list_tax_docs

Returns:

entity
document_count, recipient_count, recipients_with_docs
duplicates_dropped                 {attachments, recipients}
documents[]                        id, recipientId, recipientName | null, fileName (verbatim third-party text),
                                   formType (w9 | w8BEN | w8BENE | unknown | null), uploadedAt
recipients_without_docs[]          id, name | null, status | null   (every recipient of any status with no attachment)

Download URLs are never returned.

Keepalive

uvx --from 'mercury-multiorg-mcp==0.1.4' mercury-multiorg-mcp-keepalive --entities /private/path/entities.yaml

The keepalive executable is not named after the package, so uvx needs --from; from a clone, uv run mercury-multiorg-mcp-keepalive runs the same command.

One authenticated GET /accounts per configured entity, one line each (<timestamp> OK|FAIL <entity> HTTP <status>), exit 1 if any entity fails or no entity has a token, exit 2 on a configuration error. Same host rules as the server (--allow-custom-api-base for anything but production, sandbox, or loopback). Details, cadence, and cron / launchd snippets in docs/keepalive.md.

Develop

uv sync
uv run pytest

Tests use synthetic JSON fixtures and a mock HTTP transport only. Nothing in this package, its tests, or its history may contain real names, tokens, or account identifiers (see the history note above for the one historical exception, a public bank routing number).

License

MIT; see LICENSE, which also ships in the package.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mercury_multiorg_mcp-0.1.4.tar.gz (160.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mercury_multiorg_mcp-0.1.4-py3-none-any.whl (65.6 kB view details)

Uploaded Python 3

File details

Details for the file mercury_multiorg_mcp-0.1.4.tar.gz.

File metadata

  • Download URL: mercury_multiorg_mcp-0.1.4.tar.gz
  • Upload date:
  • Size: 160.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mercury_multiorg_mcp-0.1.4.tar.gz
Algorithm Hash digest
SHA256 b0f3344348bb6d760f56f29a9f227e2f7d0444b24657cf28fe865d4b56e1425f
MD5 a60b04bb4bce3512a032926f87489ed6
BLAKE2b-256 b161c620d3c48ed0853db4f6d6173058e0c991d5df0319e6ed6284a8f077fb1a

See more details on using hashes here.

File details

Details for the file mercury_multiorg_mcp-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: mercury_multiorg_mcp-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 65.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for mercury_multiorg_mcp-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 a740cf8e71772f6f6f10486238a35fc325d5c9efb8ba6b796d0d3dd4bc149931
MD5 9581397febbfa0679670dea83058e69c
BLAKE2b-256 c91bb876ced65b5a8bfe46f612a7dc97011567884a8dbf6e47f7afcbf9458de7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 files

0.1.3

2 files

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