Well
About
One MCP server that unifies your business tools into a single context graph your AI can query
Explore
{
"mcpServers": {
"well": {
"type": "http",
"url": "https://api.wellapp.ai/v1/mcp"
}
}
}
well_get_schema
Discover available data types and fields. USAGE: - well_get_schema() → List ALL available roots, including the accounting graph (ledger_accounts, journals, journal_entries) plus account_balances, tax_rates, exchange_rates — query these for real financial statements (compte de résultat / balance sheet) instead of reconstructing them from raw invoices - well_get_schema({ root: "invoices" }) → List all available fields for invoices WORKFLOW: 1. Call well_get_schema(root) to see available fields 2. Pick the fields you need for your task (typically 5-15) 3. Call well_query_records with those specific fields Returns fields with path, type, and (when documented) semantic context: - { path: "invoices.grand_total", type: "numeric", context: "Total invoice amount incl. tax in the document currency...", enrichment: "AI extraction" } → use _eq, _gt, _lt, etc. - { path: "invoices.local_currency", type: "enum" } → use ONLY _eq, _neq, _in, _nin, _is_null - { path: "invoices.issuer.name", type: "text" } → use _eq, _like, _ilike, etc. - "context" (when present) explains what the field MEANS in the domain and how it's used — read it to pick the right field and write correct filters. - "enrichment" (when present) is the value's provenance (e.g. "Bank sync", "AI extraction", "System generated", "Derived", "Manual"). Use the type to choose the right whereClause operators in well_query_records. To use in well_query_records, convert path to array: "invoices.issuer.name" → ["invoices", "issuer", "name"]
well_query_records
Query records from Well's database. ⚠️ WORKFLOW: 1. To SHOW the user a table of a record type, just omit `fields`. You never choose columns for presentation: the table the user sees is ALWAYS the root's display view in the Well web app's column order, trimmed on the widest roots to what fits a chat-width table. 2. To answer a targeted question, call well_get_schema(root) FIRST to discover available fields, then name in `fields` ONLY the extra values you need (5-15 typically). They are ADDED to the display view in the payload you read — they do not replace, reorder, or trim the columns the user sees. ROOTS (read-only — all 33): companies, people, connectors, invoices, documents, transactions, accounts, payment_means, workspace_connectors, memberships, cards, checks, ledger_accounts, journals, journal_entries, tax_rates, exchange_rates, invoice_transactions, categories, account_balances, tasks, workspaces, invoice_payment_means, chat_conversations, blueprint_runs, workspace_connector_sync_logs, media, emails, phones, web_links, locations, invoice_items, billing_events (The accounting graph — ledger_accounts, journals, journal_entries — and balances/rates are read-only projections owned by the sync/posting pipelines; query them for financial context, you cannot create/update them here. Sub-resources like emails/phones/locations are usually richer when read via their parent company/person.) CONNECTED TOOLS: do NOT use this tool to show the user what they have connected — call well_list_connectors instead. It owns that job: connection status, and an install link for anything not connected yet. Query root "workspace_connectors" here only for genuine RECORD-level needs — reading sync timestamps, filtering connections, joining them with other roots. ("connectors" is the installable catalog; "workspace_connector_sync_logs" is per-sync history.) Well already syncs the providers' data into the roots above — invoices, transactions, accounts, the accounting graph. ALWAYS read it from here. well_invoke_connector_tool and a provider's own tools are for an ACTION the user explicitly asked to take on that provider (e.g. "create this record in Attio"), never a way to fetch data Well already holds. EXAMPLE - show the user their invoices (no `fields`, ever): well_query_records({ root: "invoices", limit: 50 }) EXAMPLE - answer "how much is still owed on the unpaid invoices?": well_query_records({ root: "invoices", fields: [["invoices", "balance_due"]], whereClause: { "payment_status": { "_in": ["unpaid", "partial"] } } }) // balance_due arrives in the rows for you to total up; the user still sees the // standard invoices table, with its identity, counterparty and status columns. ⚠️ RULES: - `fields` is ADDITIVE — it widens the data you receive, never the table the user sees - Omitting fields (default view) or naming a few extras both beat allFields - Field paths from schema: "invoices.issuer.name" → ["invoices", "issuer", "name"] - Default 50 records per request, max 500. ONE CALL IS THE ANSWER — do not walk the root: Every response already carries `totalCount` (ALL matches, not just this page) and `records_url` (the full web-app table, with your filter and sort already applied). So a request to see a record type is ONE call: the user gets a table of the first page, the count tells them how many there are, and the link takes them to the rest. "Show me all my invoices" is answered by one call + the link — NOT by fetching 483 rows into this conversation. - A non-null `nextCursor` is NOT a to-do. It means more rows exist, which `totalCount` already told you and the link already covers. - Never paginate to compute a total, count, average or breakdown: aggregate over the filtered set instead. Summing a paginated sample produces a wrong number. - Never paginate to "be thorough". Large roots will exhaust the output limit mid-walk, and the user ends up with nothing legible. - Paginate ONLY for per-row work over every …
well_create_company
Create a new company in the current workspace. Use this tool when the user asks to create, add, or register a new company. REQUIRED: name OPTIONAL: description After creation, enrichment (logo, domain, industry, tax ID, description fill-in) runs asynchronously in the background. The new company is available immediately for follow-up actions, but enriched fields may take a few seconds to populate — re-query after a brief delay to see them. Returns { success: true, company_id, name } on success, or { success: false, error } on failure.
well_create_person
Create a new person (contact) in the current workspace. Use this tool when the user asks to add, create, or register a new contact, employee, or person. REQUIRED: first_name OPTIONAL: last_name, job_title After creation, enrichment runs asynchronously in the background. Returns { success: true, person_id, full_name } on success, or { success: false, error } on failure.
well_update_company
Update an existing company in the current workspace. Use this tool when the user asks to change, fix, rename, or edit a company's fields. REQUIRED: company_id OPTIONAL (only include fields the user wants changed): name, description, domain, registered_name, trade_name, tax_id_value, tax_id_type, registry_country (ISO 3166-1 alpha-2, e.g. "FR"), business_type, registered_value, registry_name, locale (ISO 639-1 two-letter language code, e.g. "en", "fr" — not "en_US"). NOT CHANGEABLE via this tool: emails, phones, locations, linked people, media. Those require dedicated tools (not yet available). Returns { success: true, company_id, name } on success, or { success: false, error } on failure.
well_update_person
Update an existing person (contact) in the current workspace. Use this tool when the user asks to change, fix, rename, or edit a person's fields. REQUIRED: person_id OPTIONAL (only include fields the user wants changed): first_name, last_name, job_title. NOT CHANGEABLE via this tool: emails, phones, locations, linked companies, media. Those require dedicated tools (not yet available). Returns { success: true, person_id, full_name } on success, or { success: false, error } on failure.
well_delete_company
Delete a company from the current workspace (soft delete). Use this tool when the user asks to delete, remove, or archive a company. REQUIRED: company_id This soft-deletes the company and its company_person relationships. Linked people records themselves are NOT deleted. Invoices and documents referencing the company are preserved. Returns { success: true, company_id } on success, or { success: false, error } on failure.
well_delete_person
Delete a person (contact) from the current workspace (soft delete). Use this tool when the user asks to delete, remove, or archive a contact. REQUIRED: person_id This soft-deletes the person and its company_person relationships. Linked companies themselves are NOT deleted. The authenticated user cannot delete their own person record. Returns { success: true, person_id } on success, or { success: false, error } on failure.
well_update_invoice
Update an existing invoice in Well. Call well_get_schema("invoices") to discover all available fields. REQUIRED: invoice_id OPTIONAL (only pass fields you want changed): - reference_number, issue_date (ISO date), due_date (ISO date) - status (draft | issued | paid | canceled) - terms, description - grand_total, items_total, tax_total (numbers) - local_currency (ISO 4217 three-letter code, e.g. "EUR", "USD") - document_type_code (UN/CEFACT 1001 code, e.g. "380") - billing_context (e.g. subscription, one_time, project, ...) - issuer_company_id / receiver_company_id (uuid to set, null to clear, omit to leave unchanged) Cannot change line items, payment_means, or document attachment via this tool.
well_delete_invoice
Delete an invoice from Well (soft delete). REQUIRED: invoice_id Soft-deletes the invoice. Linked line items and payment_means rows are NOT cascade-deleted — they remain in the database, orphaned. The delete is reversible only at the database level.
well_add_contact_channel
Add a contact channel to a company or person. Wraps the resource-scoped REST endpoints (POST /v1/{companies,people}/:id/{emails,phones,web-links,locations}). channel + the matching value field: - email → value.email - phone → value.e164_number (E.164; a leading "+" is added if missing) - web_link → value.url (+ optional value.platform, default "website") - location → value.city, value.country (+ optional address_line1/2, region, postal_code) value.label is optional (defaults to "work"). NOTE: adding a phone is supported on a PERSON but NOT on a company (no endpoint) — that combination returns a clear error. To READ existing channels, use well_query_records on the parent (companies/people) or the channel root.
well_remove_contact_channel
Remove a contact channel from a company or person. Wraps the resource-scoped DELETE endpoints (DELETE /v1/{companies,people}/:id/{emails,phones,web-links,locations}/:channelId). Pass channel_id = the UUID of the specific channel row to remove (NOT the parent). Find it by reading the parent with well_query_records and selecting the channel's id field.
well_get_entity
Read ONE entity with its sub-resources nested in a single call. Convenience over well_get_schema + well_query_records: resolves the field paths for you and returns the single record with its related data expanded. depth (relation-nesting BOUNDARY, 1-3, default 1): 1 = the entity + its direct sub-resources (emails, phones, locations, …) 2 = + the sub-resources' related scalars 3 = the full level-3 graph (LARGER payload — use when you need the whole picture) Stops at depth 3. Aggregates are excluded. Each child collection is capped at 50 rows; for a full list or to page a large child collection, use well_query_records on that child root instead.
well_list_connector_tools
Discover the actions a connected provider exposes (e.g. "what can I do with Attio?"). WORKFLOW: 1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row. 2. well_list_connector_tools({ workspace_connector_id }) → the actions that provider offers (name + description + input schema). 3. well_invoke_connector_tool({ workspace_connector_id, tool, args }) → run one, shaping args from the input schema returned here. Use this whenever you don't already know a connector's tool names — never guess them. Every response also carries reconnect_url: a deep link to the connector's setup page in the web app. When success is false or status is "need_reconnect" (the provider's token is stale/revoked, so no tools come back), give the user reconnect_url so they can re-authenticate the connector. Surface it as a clickable link; never invent connector URLs.
well_invoke_connector_tool
Run one tool on a connected provider's own MCP server (e.g. create a record in Attio), on behalf of this workspace's connection. Use this ONLY for an action the user explicitly asked to take on that provider. It is NOT a way to read financial data: Well already syncs invoices, transactions, accounts and the accounting graph from every connected provider — read those with well_query_records instead of calling a provider's own list/read tools. WORKFLOW: 1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row. 2. well_list_connector_tools({ workspace_connector_id }) → the live tool names + input schemas that connection actually exposes right now. 3. well_invoke_connector_tool({ workspace_connector_id, tool: "<one of the names from step 2>", args: { ... } }). Only works on connectors that expose an MCP server (e.g. Attio, Notion, Linear) and whose connection is enabled. Returns the provider's tool result, or { success: false, error } if the tool failed / is not granted.
well_create_invoice_from_data
Create an invoice in Well from data you extracted by reading an invoice (your own OCR) — you send the structured fields, not the file. Well persists the invoice + its line items + payment means using the same pipeline as uploaded documents. Fill every field you can read from the document: - issuer / receiver: { name (required), company_id?, domain?, tax_id? } - reference_number, issue_date (YYYY-MM-DD), due_date? (YYYY-MM-DD), currency (ISO 4217) - totals?: { items_total?, tax_total?, grand_total } - line_items[]: { name, quantity?, unit_price, currency?, tax_rate? } - payment_means?[]: { type, iban?, bic?, scheme? } - status?: draft | issued | paid | canceled ONE CALL IS THE WHOLE WRITE. This tool takes the invoice's status and both parties' company ids, so a create never needs a well_update_invoice after it: - The user asked to DRAFT an invoice → pass status: "draft" here. - You already found the company (well_query_records, well_get_entity) → pass its company_id on that party. Naming the party without its id re-resolves it, which can attach the invoice to the wrong company or create a duplicate one. Creating and then patching the same invoice writes twice and shows the user two confirmations for one action. Put the intent in this call.
well_list_workspaces
List the workspaces this connection is authorized to access. Use this FIRST when a single token may cover more than one workspace. Each entry has: - workspace_id: pass this as the workspace_id argument on other tools to target one workspace. - workspace_name: human-readable name (null if it can't be resolved). - is_primary: true for the token's default workspace (used when you omit workspace_id on a write). - identity: the company behind the workspace (registered name, trade name, registry number, country, website, currency, fiscal year start), so two similarly-named workspaces can be told apart. Every field is null when the workspace has no accounting settings yet. Tax identifiers are deliberately not included. When the token authorizes a single workspace you can omit workspace_id everywhere; when it authorizes several, read tools fan out across all of them unless you pass a workspace_id, and write tools require one.
well_list_connectors
List the connectors a workspace can install, each with a one-click install deep link. Use this to answer "what can I connect to Well?" or "how do I connect <provider>?". Each entry has: - service_id: the connector's stable catalog id (e.g. "stripe"), used in the install link. - name, category_id, direction: what the connector is. - status: "available" connectors are connectable now; "coming_soon"/"unavailable"/"maintenance" are not. - is_matched / is_selected: whether this workspace's detected tools matched this connector / already picked it. - match_score: 0..1 confidence of that match; null when unmatched. A high score is a tool Well is confident the workspace already uses. - is_connected: this workspace already holds a live connection for the connector — offer a reconnect, not a first install. - connection_status: that live connection's state, or null when not connected. "enabled" is connected and syncing; "processing" means the grant is in and the FIRST sync is still running (connected — do not ask the user to connect it again); "error" is authenticated but its last real sync failed, which warrants a reconnect. - workspace_connector_id: the connected instance's id, or null when not connected. This is the id well_invoke_connector_tool and well_list_connector_tools need — resolve it HERE, never via well_query_records on workspace_connectors. - is_preselected: Well recommends connecting this one now (a high-confidence match that is not yet connected). The interactive picker pre-checks exactly these. - install_url: a one-click link that STARTS the connection in Well. It works from any state — it signs the user in if needed, creates their workspace if they have none, then runs the connector's own auth flow — and it covers banks too (a bank opens its bank-login flow pre-selected). Null only when the connector is not "available". Hand this to the user to get started in one click. The default view returns the curated, matched-first connectors; pass q to name-search the full catalog (e.g. a specific bank). This is ALSO the tool that answers "what have I connected?" — read is_connected / connection_status / workspace_connector_id here rather than querying workspace_connectors records. Use well_list_connector_tools for a live connection's actions.
well_run_register_diff
Diff a workspace's bank transactions against its accounting-register transactions (e.g. QuickBooks), and persist the result. - Every match — hard evidence (structured reference, IBAN, tax ID) or inference-only (memo/payee reading) — is raised as a review task with the candidate already attached (raised_for_review). Nothing links automatically; resolve with well_resolve_reconciliation_task once a human decides. - Bank transactions with no register counterpart come back as missing_in_register_ids, each also minted as a gap review task (gaps_proposed) — resolve one with well_resolve_register_diff_gap once a human names the two ledger accounts. gaps_already_proposed counts gaps re-surfaced from an earlier run that already have an open, unresolved proposal. - Bank transactions NOT confirmed absent from the register come back as contended_in_register_ids — never minted as a gap. Two cases land here: (1) a plausible match lost to a higher-confidence sibling transaction this run, so the register-side movement is already accounted for by the winner; (2) the matcher couldn't produce a trustworthy answer (an invalid model response or a provider failure), so absence was never confirmed. Re-run the diff later; a genuine gap or duplicate should resolve itself once the winner's review task is handled or the matcher succeeds. - Register entries no bank transaction explains come back as unexplained_in_register_ids. Returns { enabled: false, ... } with all counts 0 if the workspace's register-diff feature is off.
well_resolve_reconciliation_task
Approve or reject one or more reconciliation review tasks (from well_run_register_diff or the in-app review queue). - approve: confirms the match — the link is flipped to active. - reject: dismisses the match — the candidate does not silently re-surface. Each task_id resolves independently; a failure on one (already resolved, not found) is returned in errors and does not block the rest of the batch.
well_resolve_register_diff_gap
Post a well_run_register_diff gap (one of missing_in_register_ids' review tasks) into QuickBooks as a Purchase or Deposit. Requires the exact ledger_account_id (a UUID, not a name) for both: - bank_ledger_account_id: the bank/cash account the money moved through (e.g. Checking). - category_ledger_account_id: the expense or income category the gap books against. Look these up first with well_query_records({ root: "ledger_accounts", filters: [...] }) scoped to the register connector — never guess an id or match an account by substring/fuzzy name. Fails with an error (not a silent no-op) if gap posting is disabled for this workspace, if either account doesn't belong to this gap's register connector, or if either account no longer resolves in QuickBooks.
well_get_investment_holdings
Get the live holdings/positions (what's currently held and its value) for a connected Plaid investment account — brokerage, IRA, 401k, etc. WORKFLOW: 1. well_list_connectors() → pick the ENABLED Plaid connector (connection_status: "enabled") and read its workspace_connector_id directly off the row. 2. well_get_investment_holdings({ workspace_connector_id }) → the current holdings, fetched fresh from Plaid on every call (never stored/stale data). Only works on Plaid connectors that support the investments product — not the MCP-transport connector-tool-passthrough tools (well_list_connector_tools / well_invoke_connector_tool), and not for investment transactions (buy/sell/dividend/fee), which are queryable as ordinary rows via well_query_records on the transactions root instead.
well_get_runway
Get the workspace's current cash runway — cash on hand, trailing-3-month average burn, and months of cash left — the exact same computation and numbers the Well app's canvas KPI cards show. Use this instead of computing runway yourself from raw account/transaction reads. Returns `cash` (amount + currency), `avg_burn` (amount + currency + trailing_months), `months`, and a `status` discriminator: - "ok" — a finite months figure. - "capped" — runway exceeds 36 months; report as ">36 months", not the raw number. - "infinite" — cash is positive and the workspace isn't burning (net inflow); there is no meaningful "months" figure. - "insufficient_data" — not enough connected cash/transaction data to compute; tell the user to connect a bank/accounting connector (well_list_connectors) instead of guessing. `partial: true` means some accounts or transactions were excluded from the computation (e.g. missing FX rate) — mention the exclusion counts and any `hints` if present rather than presenting the number as unconditionally complete. Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).
well_get_cash_position
Get the workspace's current cash position: total cash on hand right now, converted to the workspace base currency, plus a per-account breakdown — the exact same computation and numbers the Well app's canvas KPI card shows. Use this instead of summing account balances yourself. Returns `amount`/`currency` (the converted total), `accounts` (per-account contributions: native amount/currency, converted amount, the FX rate applied), and `as_of` (the FX-rate anchor date this snapshot is valid for). `unavailable: true` means `amount` is a placeholder, not a real measurement (e.g. no accounts connected yet) — say so plainly rather than presenting it as a real €0 balance. `partial: true` means one or more accounts were excluded from an otherwise real total (e.g. missing FX rate) — mention the exclusion count and any `hints` rather than presenting the number as unconditionally complete. This is a snapshot only — no burn rate or runway is implied. Call `well_get_runway` instead for a forward-looking figure. Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).
well_get_cost_structure
Get the workspace's cost structure: outflow for the latest closed month, broken down by category — the exact same computation and numbers the Well app's canvas cost-structure donut chart shows. Use this instead of summing/grouping transactions yourself. Returns `entries` (an array of `{ category, amount, pct }`, sorted by amount descending) and `currency` (the workspace base currency). `amount` is a magnitude (outflow), not signed. `rung` names which grouping actually produced these categories — "ledger_account" (the workspace's own chart of accounts), "category_normalized" (Well's auto-categorization), "transaction_type" (a technical fallback bucket), or "uncategorised" (no rung qualified — either nothing covered the month, or a rung had the coverage but too few labelled rows). State it when you present the breakdown so the user knows whether they're looking at their own ledger's categories or Well's. If `hints` are present (e.g. a coverage caveat about uncategorized spend), disclose them rather than presenting the breakdown as unconditionally complete. Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).
well_create_invoice_document
Render an existing invoice as a print-ready PDF and attach it as the invoice's source document. The letterhead carries the issuing company's own mark when Well has one on file, and otherwise sets the issuer's name as text. Never promise a logo. Use this tool when the user asks to generate, render, or attach a PDF for an invoice that already exists in the workspace. This does NOT email or send the invoice anywhere — it only creates and attaches the file. REQUIRED: invoice_id (the invoice must already exist) Refused if the invoice is already linked to a REAL ingested document (an upload, a connector import, or a provider-issued PDF) — that source of truth is never overwritten. Returns { success: true, invoice_id, document_id, reference_number, file } on success, or { success: false, error } on failure. `file` carries the rendered PDF's name and size plus the links to fetch it: `download_url` (saves the file), `signed_url` (opens it), and `app_url` (the document in Well). Hand the user `download_url` when they ask for the PDF itself. Both signed links stop working at `expires_at`; `app_url` does not.
well_get_own_company
Get which company the workspace itself is: the confirmed own-company anchor (`anchor`) and any detected companies not yet confirmed as it (`candidates`). Use this whenever a question turns on "mine" versus "theirs" — my payables, my receivables, invoices I owe, what we billed — and then filter by the `company_id` this returns. Never decide which records are the workspace's own by comparing a company NAME: the same legal entity appears under several labels (a registered name, a trade name, a bank-issued label), so a name filter silently drops rows. Returns `anchor` (`company_id`, `registered_name`, `trade_name`) or null when the workspace has not resolved one yet, and `candidates` (each with `company_id`, names, `role`, `confidence_score`, `state`). `anchor: null` means the workspace has no confirmed own company. Say so plainly and do not promote a candidate to the anchor yourself — a candidate is a detection, not a decision, and confirming one is a user action. Registry tax ids and registered addresses are deliberately not returned. Call this directly — no other tool call is needed first. Both the anchor and the candidates are read from the same workspace this call is scoped to.
- well_get_schema: Discover available data types and fields.
USAGE:
- well_get_schema() → List ALL available roots, including the accounting graph (ledger_accounts, journals, journal_entries) plus account_balances, tax_rates, exchange_rates — query these for real financial statements (compte de résultat / balance sheet) instead of reconstructing them from raw invoices
- well_get_schema({ root: "invoices" }) → List all available fields for invoices
WORKFLOW:
1. Call well_get_schema(root) to see available fields
2. Pick the fields you need for your task (typically 5-15)
3. Call well_query_records with those specific fields
Returns fields with path, type, and (when documented) semantic context:
- { path: "invoices.grand_total", type: "numeric", context: "Total invoice amount incl. tax in the document currency...", enrichment: "AI extraction" } → use _eq, _gt, _lt, etc.
- { path: "invoices.local_currency", type: "enum" } → use ONLY _eq, _neq, _in, _nin, _is_null
- { path: "invoices.issuer.name", type: "text" } → use _eq, _like, _ilike, etc.
- "context" (when present) explains what the field MEANS in the domain and how it's used — read it to pick the right field and write correct filters.
- "enrichment" (when present) is the value's provenance (e.g. "Bank sync", "AI extraction", "System generated", "Derived", "Manual").
Use the type to choose the right whereClause operators in well_query_records.
To use in well_query_records, convert path to array:
"invoices.issuer.name" → ["invoices", "issuer", "name"]
- well_query_records: Query records from Well's database.
⚠️ WORKFLOW:
1. To SHOW the user a table of a record type, just omit fields. You never choose
columns for presentation: the table the user sees is ALWAYS the root's display
view in the Well web app's column order, trimmed on the widest roots to what fits
a chat-width table.
2. To answer a targeted question, call well_get_schema(root) FIRST to discover
available fields, then name in fields ONLY the extra values you need (5-15
typically). They are ADDED to the display view in the payload you read — they do
not replace, reorder, or trim the columns the user sees.
ROOTS (read-only — all 33): companies, people, connectors, invoices, documents, transactions, accounts, payment_means, workspace_connectors, memberships, cards, checks, ledger_accounts, journals, journal_entries, tax_rates, exchange_rates, invoice_transactions, categories, account_balances, tasks, workspaces, invoice_payment_means, chat_conversations, blueprint_runs, workspace_connector_sync_logs, media, emails, phones, web_links, locations, invoice_items, billing_events
(The accounting graph — ledger_accounts, journals, journal_entries — and balances/rates are read-only projections owned by the sync/posting pipelines; query them for financial context, you cannot create/update them here. Sub-resources like emails/phones/locations are usually richer when read via their parent company/person.)
CONNECTED TOOLS: do NOT use this tool to show the user what they have connected — call well_list_connectors instead. It owns that job: connection status, and an install link for anything not connected yet. Query root "workspace_connectors" here only for genuine RECORD-level needs — reading sync timestamps, filtering connections, joining them with other roots. ("connectors" is the installable catalog; "workspace_connector_sync_logs" is per-sync history.)
Well already syncs the providers' data into the roots above — invoices, transactions, accounts, the accounting graph. ALWAYS read it from here. well_invoke_connector_tool and a provider's own tools are for an ACTION the user explicitly asked to take on that provider (e.g. "create this record in Attio"), never a way to fetch data Well already holds.
EXAMPLE - show the user their invoices (no fields, ever):
well_query_records({ root: "invoices", limit: 50 })
EXAMPLE - answer "how much is still owed on the unpaid invoices?":
well_query_records({
root: "invoices",
fields: [["invoices", "balance_due"]],
whereClause: { "payment_status": { "_in": ["unpaid", "partial"] } }
})
// balance_due arrives in the rows for you to total up; the user still sees the
// standard invoices table, with its identity, counterparty and status columns.
⚠️ RULES:
- fields is ADDITIVE — it widens the data you receive, never the table the user sees
- Omitting fields (default view) or naming a few extras both beat allFields
- Field paths from schema: "invoices.issuer.name" → ["invoices", "issuer", "name"]
- Default 50 records per request, max 500.
ONE CALL IS THE ANSWER — do not walk the root:
Every response already carries totalCount (ALL matches, not just this page) and
records_url (the full web-app table, with your filter and sort already applied).
So a request to see a record type is ONE call: the user gets a table of the first
page, the count tells them how many there are, and the link takes them to the rest.
"Show me all my invoices" is answered by one call + the link — NOT by fetching 483
rows into this conversation.
- A non-null nextCursor is NOT a to-do. It means more rows exist, which
totalCount already told you and the link already covers.
- Never paginate to compute a total, count, average or breakdown: aggregate over
the filtered set instead. Summing a paginated sample produces a wrong number.
- Never paginate to "be thorough". Large roots will exhaust the output limit
mid-walk, and the user ends up with nothing legible.
- Paginate ONLY for per-row work over every …
- well_create_company: Create a new company in the current workspace.
Use this tool when the user asks to create, add, or register a new company.
REQUIRED: name
OPTIONAL: description
After creation, enrichment (logo, domain, industry, tax ID, description fill-in)
runs asynchronously in the background. The new company is available immediately
for follow-up actions, but enriched fields may take a few seconds to populate —
re-query after a brief delay to see them.
Returns { success: true, company_id, name } on success, or { success: false, error } on failure.
- well_create_person: Create a new person (contact) in the current workspace.
Use this tool when the user asks to add, create, or register a new contact,
employee, or person.
REQUIRED: first_name
OPTIONAL: last_name, job_title
After creation, enrichment runs asynchronously in the background.
Returns { success: true, person_id, full_name } on success, or
{ success: false, error } on failure.
- well_update_company: Update an existing company in the current workspace.
Use this tool when the user asks to change, fix, rename, or edit a company's
fields.
REQUIRED: company_id
OPTIONAL (only include fields the user wants changed): name, description,
domain, registered_name, trade_name, tax_id_value, tax_id_type,
registry_country (ISO 3166-1 alpha-2, e.g. "FR"), business_type,
registered_value, registry_name, locale (ISO 639-1 two-letter language
code, e.g. "en", "fr" — not "en_US").
NOT CHANGEABLE via this tool: emails, phones, locations, linked people, media.
Those require dedicated tools (not yet available).
Returns { success: true, company_id, name } on success, or
{ success: false, error } on failure.
- well_update_person: Update an existing person (contact) in the current workspace.
Use this tool when the user asks to change, fix, rename, or edit a person's
fields.
REQUIRED: person_id
OPTIONAL (only include fields the user wants changed): first_name, last_name,
job_title.
NOT CHANGEABLE via this tool: emails, phones, locations, linked companies,
media. Those require dedicated tools (not yet available).
Returns { success: true, person_id, full_name } on success, or
{ success: false, error } on failure.
- well_delete_company: Delete a company from the current workspace (soft delete).
Use this tool when the user asks to delete, remove, or archive a company.
REQUIRED: company_id
This soft-deletes the company and its company_person relationships.
Linked people records themselves are NOT deleted. Invoices and documents
referencing the company are preserved.
Returns { success: true, company_id } on success, or
{ success: false, error } on failure.
- well_delete_person: Delete a person (contact) from the current workspace (soft delete).
Use this tool when the user asks to delete, remove, or archive a contact.
REQUIRED: person_id
This soft-deletes the person and its company_person relationships.
Linked companies themselves are NOT deleted. The authenticated user cannot
delete their own person record.
Returns { success: true, person_id } on success, or
{ success: false, error } on failure.
- well_update_invoice: Update an existing invoice in Well.
Call well_get_schema("invoices") to discover all available fields.
REQUIRED: invoice_id
OPTIONAL (only pass fields you want changed):
- reference_number, issue_date (ISO date), due_date (ISO date)
- status (draft | issued | paid | canceled)
- terms, description
- grand_total, items_total, tax_total (numbers)
- local_currency (ISO 4217 three-letter code, e.g. "EUR", "USD")
- document_type_code (UN/CEFACT 1001 code, e.g. "380")
- billing_context (e.g. subscription, one_time, project, ...)
- issuer_company_id / receiver_company_id (uuid to set, null to clear,
omit to leave unchanged)
Cannot change line items, payment_means, or document attachment via this tool.
- well_delete_invoice: Delete an invoice from Well (soft delete).
REQUIRED: invoice_id
Soft-deletes the invoice. Linked line items and payment_means rows are NOT
cascade-deleted — they remain in the database, orphaned. The delete is
reversible only at the database level.
- well_add_contact_channel: Add a contact channel to a company or person.
Wraps the resource-scoped REST endpoints (POST /v1/{companies,people}/:id/{emails,phones,web-links,locations}).
channel + the matching value field:
- email → value.email
- phone → value.e164_number (E.164; a leading "+" is added if missing)
- web_link → value.url (+ optional value.platform, default "website")
- location → value.city, value.country (+ optional address_line1/2, region, postal_code)
value.label is optional (defaults to "work").
NOTE: adding a phone is supported on a PERSON but NOT on a company (no endpoint) —
that combination returns a clear error. To READ existing channels, use
well_query_records on the parent (companies/people) or the channel root.
- well_remove_contact_channel: Remove a contact channel from a company or person.
Wraps the resource-scoped DELETE endpoints (DELETE /v1/{companies,people}/:id/{emails,phones,web-links,locations}/:channelId).
Pass channel_id = the UUID of the specific channel row to remove (NOT the parent).
Find it by reading the parent with well_query_records and selecting the channel's id field.
- well_get_entity: Read ONE entity with its sub-resources nested in a single call.
Convenience over well_get_schema + well_query_records: resolves the field paths
for you and returns the single record with its related data expanded.
depth (relation-nesting BOUNDARY, 1-3, default 1):
1 = the entity + its direct sub-resources (emails, phones, locations, …)
2 = + the sub-resources' related scalars
3 = the full level-3 graph (LARGER payload — use when you need the whole picture)
Stops at depth 3. Aggregates are excluded. Each child collection is
capped at 50 rows; for a full list or to page a large child
collection, use well_query_records on that child root instead.
- well_list_connector_tools: Discover the actions a connected provider exposes (e.g. "what can I do with Attio?").
WORKFLOW:
1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row.
2. well_list_connector_tools({ workspace_connector_id }) → the actions that provider offers (name + description + input schema).
3. well_invoke_connector_tool({ workspace_connector_id, tool, args }) → run one, shaping args from the input schema returned here.
Use this whenever you don't already know a connector's tool names — never guess them.
Every response also carries reconnect_url: a deep link to the connector's setup page in the web app. When success is false or status is "need_reconnect" (the provider's token is stale/revoked, so no tools come back), give the user reconnect_url so they can re-authenticate the connector. Surface it as a clickable link; never invent connector URLs.
- well_invoke_connector_tool: Run one tool on a connected provider's own MCP server (e.g. create a record in Attio), on behalf of this workspace's connection.
Use this ONLY for an action the user explicitly asked to take on that provider. It is NOT a way to read financial data: Well already syncs invoices, transactions, accounts and the accounting graph from every connected provider — read those with well_query_records instead of calling a provider's own list/read tools.
WORKFLOW:
1. well_list_connectors() → pick the ENABLED provider (connection_status: "enabled") and read its workspace_connector_id directly off the row.
2. well_list_connector_tools({ workspace_connector_id }) → the live tool names + input schemas that connection actually exposes right now.
3. well_invoke_connector_tool({ workspace_connector_id, tool: "<one of the names from step 2>", args: { ... } }).
Only works on connectors that expose an MCP server (e.g. Attio, Notion, Linear) and whose connection is enabled. Returns the provider's tool result, or { success: false, error } if the tool failed / is not granted.
- well_create_invoice_from_data: Create an invoice in Well from data you extracted by reading an invoice (your own OCR) — you send the structured fields, not the file.
Well persists the invoice + its line items + payment means using the same pipeline as uploaded documents. Fill every field you can read from the document:
- issuer / receiver: { name (required), company_id?, domain?, tax_id? }
- reference_number, issue_date (YYYY-MM-DD), due_date? (YYYY-MM-DD), currency (ISO 4217)
- totals?: { items_total?, tax_total?, grand_total }
- line_items[]: { name, quantity?, unit_price, currency?, tax_rate? }
- payment_means?[]: { type, iban?, bic?, scheme? }
- status?: draft | issued | paid | canceled
ONE CALL IS THE WHOLE WRITE. This tool takes the invoice's status and both
parties' company ids, so a create never needs a well_update_invoice after it:
- The user asked to DRAFT an invoice → pass status: "draft" here.
- You already found the company (well_query_records, well_get_entity) → pass its
company_id on that party. Naming the party without its id re-resolves it, which
can attach the invoice to the wrong company or create a duplicate one.
Creating and then patching the same invoice writes twice and shows the user two
confirmations for one action. Put the intent in this call.
- well_list_workspaces: List the workspaces this connection is authorized to access.
Use this FIRST when a single token may cover more than one workspace. Each entry has:
- workspace_id: pass this as the workspace_id argument on other tools to target one workspace.
- workspace_name: human-readable name (null if it can't be resolved).
- is_primary: true for the token's default workspace (used when you omit workspace_id on a write).
- identity: the company behind the workspace (registered name, trade name, registry number, country, website, currency, fiscal year start), so two similarly-named workspaces can be told apart. Every field is null when the workspace has no accounting settings yet. Tax identifiers are deliberately not included.
When the token authorizes a single workspace you can omit workspace_id everywhere; when it authorizes several, read tools fan out across all of them unless you pass a workspace_id, and write tools require one.
- well_list_connectors: List the connectors a workspace can install, each with a one-click install deep link.
Use this to answer "what can I connect to Well?" or "how do I connect <provider>?". Each entry has:
- service_id: the connector's stable catalog id (e.g. "stripe"), used in the install link.
- name, category_id, direction: what the connector is.
- status: "available" connectors are connectable now; "coming_soon"/"unavailable"/"maintenance" are not.
- is_matched / is_selected: whether this workspace's detected tools matched this connector / already picked it.
- match_score: 0..1 confidence of that match; null when unmatched. A high score is a tool Well is confident the workspace already uses.
- is_connected: this workspace already holds a live connection for the connector — offer a reconnect, not a first install.
- connection_status: that live connection's state, or null when not connected. "enabled" is connected and syncing; "processing" means the grant is in and the FIRST sync is still running (connected — do not ask the user to connect it again); "error" is authenticated but its last real sync failed, which warrants a reconnect.
- workspace_connector_id: the connected instance's id, or null when not connected. This is the id well_invoke_connector_tool and well_list_connector_tools need — resolve it HERE, never via well_query_records on workspace_connectors.
- is_preselected: Well recommends connecting this one now (a high-confidence match that is not yet connected). The interactive picker pre-checks exactly these.
- install_url: a one-click link that STARTS the connection in Well. It works from any state — it signs the user in if needed, creates their workspace if they have none, then runs the connector's own auth flow — and it covers banks too (a bank opens its bank-login flow pre-selected). Null only when the connector is not "available". Hand this to the user to get started in one click.
The default view returns the curated, matched-first connectors; pass q to name-search the full catalog (e.g. a specific bank). This is ALSO the tool that answers "what have I connected?" — read is_connected / connection_status / workspace_connector_id here rather than querying workspace_connectors records. Use well_list_connector_tools for a live connection's actions.
- well_run_register_diff: Diff a workspace's bank transactions against its accounting-register transactions (e.g. QuickBooks), and persist the result.
- Every match — hard evidence (structured reference, IBAN, tax ID) or inference-only (memo/payee reading) — is raised as a review task with the candidate already attached (raised_for_review). Nothing links automatically; resolve with well_resolve_reconciliation_task once a human decides.
- Bank transactions with no register counterpart come back as missing_in_register_ids, each also minted as a gap review task (gaps_proposed) — resolve one with well_resolve_register_diff_gap once a human names the two ledger accounts. gaps_already_proposed counts gaps re-surfaced from an earlier run that already have an open, unresolved proposal.
- Bank transactions NOT confirmed absent from the register come back as contended_in_register_ids — never minted as a gap. Two cases land here: (1) a plausible match lost to a higher-confidence sibling transaction this run, so the register-side movement is already accounted for by the winner; (2) the matcher couldn't produce a trustworthy answer (an invalid model response or a provider failure), so absence was never confirmed. Re-run the diff later; a genuine gap or duplicate should resolve itself once the winner's review task is handled or the matcher succeeds.
- Register entries no bank transaction explains come back as unexplained_in_register_ids.
Returns { enabled: false, ... } with all counts 0 if the workspace's register-diff feature is off.
- well_resolve_reconciliation_task: Approve or reject one or more reconciliation review tasks (from well_run_register_diff or the in-app review queue).
- approve: confirms the match — the link is flipped to active.
- reject: dismisses the match — the candidate does not silently re-surface.
Each task_id resolves independently; a failure on one (already resolved, not found) is returned in errors and does not block the rest of the batch.
- well_resolve_register_diff_gap: Post a well_run_register_diff gap (one of missing_in_register_ids' review tasks) into QuickBooks as a Purchase or Deposit.
Requires the exact ledger_account_id (a UUID, not a name) for both:
- bank_ledger_account_id: the bank/cash account the money moved through (e.g. Checking).
- category_ledger_account_id: the expense or income category the gap books against.
Look these up first with well_query_records({ root: "ledger_accounts", filters: [...] }) scoped to the register connector — never guess an id or match an account by substring/fuzzy name.
Fails with an error (not a silent no-op) if gap posting is disabled for this workspace, if either account doesn't belong to this gap's register connector, or if either account no longer resolves in QuickBooks.
- well_get_investment_holdings: Get the live holdings/positions (what's currently held and its value) for a connected Plaid investment account — brokerage, IRA, 401k, etc.
WORKFLOW:
1. well_list_connectors() → pick the ENABLED Plaid connector (connection_status: "enabled") and read its workspace_connector_id directly off the row.
2. well_get_investment_holdings({ workspace_connector_id }) → the current holdings, fetched fresh from Plaid on every call (never stored/stale data).
Only works on Plaid connectors that support the investments product — not the MCP-transport connector-tool-passthrough tools (well_list_connector_tools / well_invoke_connector_tool), and not for investment transactions (buy/sell/dividend/fee), which are queryable as ordinary rows via well_query_records on the transactions root instead.
- well_get_runway: Get the workspace's current cash runway — cash on hand, trailing-3-month average burn, and months of cash left — the exact same computation and numbers the Well app's canvas KPI cards show. Use this instead of computing runway yourself from raw account/transaction reads.
Returns cash (amount + currency), avg_burn (amount + currency + trailing_months), months, and a status discriminator:
- "ok" — a finite months figure.
- "capped" — runway exceeds 36 months; report as ">36 months", not the raw number.
- "infinite" — cash is positive and the workspace isn't burning (net inflow); there is no meaningful "months" figure.
- "insufficient_data" — not enough connected cash/transaction data to compute; tell the user to connect a bank/accounting connector (well_list_connectors) instead of guessing.
partial: true means some accounts or transactions were excluded from the computation (e.g. missing FX rate) — mention the exclusion counts and any hints if present rather than presenting the number as unconditionally complete.
Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_ tool).
- well_get_cash_position: Get the workspace's current cash position: total cash on hand right now, converted to the workspace base currency, plus a per-account breakdown — the exact same computation and numbers the Well app's canvas KPI card shows. Use this instead of summing account balances yourself.
Returns amount/currency (the converted total), accounts (per-account contributions: native amount/currency, converted amount, the FX rate applied), and as_of (the FX-rate anchor date this snapshot is valid for).
unavailable: true means amount is a placeholder, not a real measurement (e.g. no accounts connected yet) — say so plainly rather than presenting it as a real €0 balance. partial: true means one or more accounts were excluded from an otherwise real total (e.g. missing FX rate) — mention the exclusion count and any hints rather than presenting the number as unconditionally complete.
This is a snapshot only — no burn rate or runway is implied. Call well_get_runway instead for a forward-looking figure.
Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_ tool).
- well_get_cost_structure: Get the workspace's cost structure: outflow for the latest closed month, broken down by category — the exact same computation and numbers the Well app's canvas cost-structure donut chart shows. Use this instead of summing/grouping transactions yourself.
Returns entries (an array of { category, amount, pct }, sorted by amount descending) and currency (the workspace base currency). amount is a magnitude (outflow), not signed.
rung names which grouping actually produced these categories — "ledger_account" (the workspace's own chart of accounts), "category_normalized" (Well's auto-categorization), "transaction_type" (a technical fallback bucket), or "uncategorised" (no rung qualified — either nothing covered the month, or a rung had the coverage but too few labelled rows). State it when you present the breakdown so the user knows whether they're looking at their own ledger's categories or Well's.
If hints are present (e.g. a coverage caveat about uncategorized spend), disclose them rather than presenting the breakdown as unconditionally complete.
Call this directly — no other tool call is needed first (workspace is resolved from the caller's authorized token, same as every other well_* tool).
- well_create_invoice_document: Render an existing invoice as a print-ready PDF and attach it as the invoice's source document.
The letterhead carries the issuing company's own mark when Well has one on
file, and otherwise sets the issuer's name as text. Never promise a logo.
Use this tool when the user asks to generate, render, or attach a PDF for an
invoice that already exists in the workspace. This does NOT email or send the
invoice anywhere — it only creates and attaches the file.
REQUIRED: invoice_id (the invoice must already exist)
Refused if the invoice is already linked to a REAL ingested document (an
upload, a connector import, or a provider-issued PDF) — that source of truth
is never overwritten.
Returns { success: true, invoice_id, document_id, reference_number, file } on
success, or { success: false, error } on failure.
file carries the rendered PDF's name and size plus the links to fetch it:
download_url (saves the file), signed_url (opens it), and app_url (the
document in Well). Hand the user download_url when they ask for the PDF
itself. Both signed links stop working at expires_at; app_url does not.
- well_get_own_company: Get which company the workspace itself is: the confirmed own-company anchor (anchor) and any detected companies not yet confirmed as it (candidates).
Use this whenever a question turns on "mine" versus "theirs" — my payables, my receivables, invoices I owe, what we billed — and then filter by the company_id this returns. Never decide which records are the workspace's own by comparing a company NAME: the same legal entity appears under several labels (a registered name, a trade name, a bank-issued label), so a name filter silently drops rows.
Returns anchor (company_id, registered_name, trade_name) or null when the workspace has not resolved one yet, and candidates (each with company_id, names, role, confidence_score, state).
anchor: null means the workspace has no confirmed own company. Say so plainly and do not promote a candidate to the anchor yourself — a candidate is a detection, not a decision, and confirming one is a user action.
Registry tax ids and registered addresses are deliberately not returned.
Call this directly — no other tool call is needed first. Both the anchor and the candidates are read from the same workspace this call is scoped to.
You don't have to waste time retrieving invoices. AI can.
- Overview
- Features & Benefits
- Use Cases
- How It Works
- Installation
- MCP Integration
- Contributing
- License
- Acknowledgments
- Roadmap
- FAQ
Well is the Chrome extension that becomes every founder's best friend when accounting season hits.
It automates supplier invoice retrieval and pipes the data directly into your accounting tools, ERP, or dashboards — with zero effort.
Built for founders, solo operators, and lean teams, Well replaces hours of repetitive clicking, dragging, chasing, and copy-pasting. What used to eat up days across tax seasons now takes one click.
At its core, Well is aChrome extensionthat automates browser workflows on your behalf — boosting productivity when batch-retrieving invoices. You can also use it on the go: as you browse, Well catches invoices for you.
- WhatsApp and email ingestion
- Google Drive and Slack integrations
- AI-generated workflow blueprints
- Self-healing automations that adapt to changes
- Multi-format export support (JSON, CSV, XML, UBL, QuickBooks, Xero)
- Built-in validation for invoice data integrity
- Extensible plugin system for custom formats
- Compatibility with e-invoicing standards including Factur-X and UBL 2.1
We believe invoice exchange should follow a universal protocol: instant, standardized, and automated. You shouldn't have to think about it. With Well, you won't.
-
100,000+ web portals covered
From the most-used SaaS, utilities, and e-commerce platforms to long-tail portals you thought no one could automate.
Omnichannel capture
Collect invoices from Gmail, WhatsApp, PDFs, and more — in real time.
Works with your stack
Seamlessly connects to your accounting tools, ERP, CRM, and spreadsheets — no extra setup.
Self-healing workflows
Well adapts on the fly when supplier interfaces change.
Privacy-first by design
No passwords stored. Fully compliant with GDPR and CCPA.
Export FormatsWell supports exporting invoice data to multiple formats:
- Automatic validation of required fields
- Type checking for amounts and dates
- Extensible validation rules
- Clear error messages for data issues
-
Founder on the move
One click, zero effort — Well retrieves invoices from emails, browsers, or WhatsApp.
Operator prepping for month-end
Pull 50+ invoices from 15+ portals in under 5 minutes — no mental load.
Finance lead applying the 5S mindset
Enforce structure at the source: sort, shine, sustain — and automate.
Manager tracking team budgets
Monitor vendor spend in real time, catch budget drift, and uncover savings.
Accountant building a clean audit trail
Substantiate expenses for tax time with complete, standardized records.
from exporters import get_exporter # Get an exporter instance exporter = get_exporter('json') # or 'csv', 'xml', 'ubl', 'quickbooks', 'xero' # Export data data = { 'invoice_number': 'INV-1234', 'date': '2025-07-29', 'amount': 199.99, 'customer': 'Acme Corp', # ... other fields } exporter.export(data, 'invoice.json')
All invoices must include these required fields:
- invoice_number(str): Unique identifier for the invoice
- date(str): Invoice date in YYYY-MM-DD format
- amount(float): Total invoice amount (must be positive)
- customer(str): Name of the customer
-
Browse our provider gallery
Visitwellapp.ai/providersto explore thousands of supported portals.
Launch the Chrome extension
Install and pin the extension. One click to launch invoice retrieval.
Auto-detect invoices as you browse
Well's AI suggests retrieval when it sees a paid invoice.
Batch-retrieve during tax season
Run large-scale retrievals in a few clicks.
Generate new blueprints with AI
Use Contributor Mode to teach Well new workflows without code.
Let it self-heal
When a portal changes, Well adapts — no manual fixes needed.
- Install from theChrome Web Store.
- Pin the extension to your toolbar.
- Log in to start syncing with your accounting tools.
Connect your AI assistant to Well using theModel Context Protocol (MCP).
Query your invoices, companies, and contacts directly from Claude, Cursor, Windsurf, or ChatGPT.
The fastest way to use Well inClaude Code— bundles the MCPandfinance skills (build a compte de résultat, balance sheet, reconcile transactions), no API key:
/plugin marketplace add WellApp-ai/Well /plugin install well@well
Then run/mcp, selectwell, andAuthenticate(browser sign-in). Run each command on its own line.
Add this URL to your MCP client and authenticate with your Well account. InClaude Desktop / web: Settings → Connectors → Add custom connector. InCodex: add it to~/.codex/config.tomlviamcp-remote.
- MCP Overview
- Quickstart Guide
- Client Setup- Claude, Cursor, Windsurf, VS Code
- Tools Reference
- Troubleshooting
For full documentation, visitdocs.wellapp.ai/mcp
- Create a new Python file in theexportersdirectory
- Create a class that inherits fromBaseExporter
- Implement the_exportmethod
- Add the@ExporterFactory.register()decorator
from .base_exporter import BaseExporter from .exporter_factory import ExporterFactory @ExporterFactory.register("myformat") class MyFormatExporter(BaseExporter): """Exports invoice data to MyFormat.""" def _export(self, data: dict, output_path: str) -> None: with open(output_path, 'w') as f: f.write(f"MyFormat: {data['invoice_number']}")
We welcome contributions from the community. To propose a fix, feature, or improvement:
- Open a pull request
- Submit an issue
- Or contribute a new blueprint via Contributor Mode
Please review ourCONTRIBUTING.mdandCode of Conduct.
Distributed under the MIT License. SeeLICENSEfor more information.
Thanks to all contributors and early users who helped shape Well. Special thanks to the open source libraries and protocols that made this possible.
- Launch public beta
- Expand support to 200K+ portals
- Add mobile retrieval assistant
- Enable Zapier and Make integrations
- Build a contributor leaderboard
Q: Is my data safe with Well?
A: Yes. We store no passwords, follow strict encryption standards, and comply with GDPR and CCPA.
Q: Can I use Well outside Chrome?
A: Currently, Well is available as a Chrome extension. Other browsers may be supported in the future.
Q: How do I add a new portal?
A: Use Contributor Mode to guide the AI through your workflow. A blueprint is generated instantly.
Bridge Town is an MCP-native, git-versioned financial modeling platform for FP&A teams and finance leaders. AI agents use Bridge Town tools to create projects, write Python model files, run models in isolated cloud sandboxes, query data, write outputs to Google Sheets, create dashboards, branch scenarios, and collaborate with teammates.
The Capital.com MCP Server lets your AI assistant talk to your trading account directly. Market data, position checks, trade previews – all in plain language, without leaving your AI tool.
Coinrule Agentic Trading MCP enables investors to create, backtest, execute, and manage trading agents through natural language across stocks, crypto and ETFs
Invest with Claude and other AI assistants
Australian Consumer Data Right Product Data
Remote MCP server for historical crypto & prediction-market data: search ~500K instruments, live market stats (OHLC, turnover, spreads, depth, slippage) and tick-data purchase. Keyless for catalog & stats; optional OAuth for account tools. Endpoint: https://cryptostruct.com/mcp
Cross-border debt collection from your AI assistant: check cases, get pricing, submit new cases.
Read-only MCP server for your Evibe investment portfolio + live market data (holdings, performance, dividends, benchmarks, screeners). Works with Claude & ChatGPT.
Financial and quantitative modeling engine for AI agents. Typed, named, deterministic.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.



