Skip to main content
Glama
636,625 tools. Updated 2026-10-04 07:14

"Dell" matching MCP tools:

  • 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.
    ConnectorNo auth
  • Finds a store by name and returns its current cashback rates from every cashback portal that lists it — online and in-store, percentage or fixed amount, with 'up to' flags — so the user can compare every portal and see the best. This is the preferred first call for any cashback question that names a store: 'best cashback for Walmart', 'highest Nike cashback', 'cashback at Expedia', 'Walmart cashback today', 'compare Walmart cashback portals', 'Best Buy in-store cashback', 'Dell cashback in Germany'. No prior lookup is needed — do not call get_stores_by_name, get_stores_by_country or get_countries first. Returns every matching store (best match first, one entry per country), each with its 'cashback_rates'; an empty list means no match — retry with a shorter name or without country_code. Use get_cashback_rates_by_store_id only when a store_id is already known, get_gift_cards_by_store_name for gift card discounts, and get_best_deals_by_brand when the user asks where to buy a brand's products rather than about a specific store. Rates reflect GotCashback's current data, refreshed several times a day. Present every returned portal's rate to the user (a table with a link column, not only the best one) and always show each rate's 'url' as a clickable link — cashback is only credited when the user clicks through it.
    ConnectorNo auth
  • Finds a store by name and returns its current cashback rates from every cashback portal that lists it — online and in-store, percentage or fixed amount, with 'up to' flags — so the user can compare every portal and see the best. This is the preferred first call for any cashback question that names a store: 'best cashback for Walmart', 'highest Nike cashback', 'cashback at Expedia', 'Walmart cashback today', 'compare Walmart cashback portals', 'Best Buy in-store cashback', 'Dell cashback in Germany'. No prior lookup is needed — do not call get_stores_by_name, get_stores_by_country or get_countries first. Returns every matching store (best match first, one entry per country), each with its 'cashback_rates'; an empty list means no match — retry with a shorter name or without country_code. Use get_cashback_rates_by_store_id only when a store_id is already known, get_gift_cards_by_store_name for gift card discounts, and get_best_deals_by_brand when the user asks where to buy a brand's products rather than about a specific store. Rates reflect GotCashback's current data, refreshed several times a day. Present every returned portal's rate to the user (a table with a link column, not only the best one) and always show each rate's 'url' as a clickable link — cashback is only credited when the user clicks through it.
    ConnectorNo auth
  • Attach ONE transaction to the ledger account its journal entry should post to — the write that clears a posting gap. REQUIRED: transaction_id, from `well_list_unposted_transactions`. ledger_account_id — an account id from that read's `ledgerCatalog`, or from the row's own `ledger_suggestions`. Pass `null` to DETACH the account rather than to leave it unchanged; omitting the field is not how you clear one, because the field is required here. **Attaching the account does not, on its own, clear the gate.** The worklist selects on posting attempts, not on whether an account is present, so a row you attach and leave will come back on the next read. Posting is what clears it. Set `no_invoice_expected: true` to post the entry in the same call. Send it ONLY for a row whose `expects_supplier_invoice` is false on `well_list_unposted_transactions`, which is the read that carries that field: it asserts that no supplier invoice is coming, which is what makes the transaction bookable on its own. A row still waiting for its invoice must be attached WITHOUT it — the invoice is its blocker, and posting early books an entry the invoice would then contradict. Omit the field and nothing posts: the account is recorded and the row stays on the worklist. Most categories already imply their account — the chart maps each category key to a canonical code — so reach for this for the rows the category alone cannot settle, and for a deliberate override. When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth
  • Put a cash-flow bridge YOU computed onto the cash-flow waterfall card. **This tool measures nothing.** It takes the four terms of a bridge and the gap between them as input, draws the waterfall, and returns them. Call it only after you have read the opening and closing positions and summed the window's flows yourself — never to "get" a bridge. A bridge rests on one law: the opening, plus the inflows, minus the outflows, lands on the closing. The closing is measured on its own rather than summed from the flows, so the law is a check rather than a given. State the gap as `unexplained` and the tool verifies the five figures add up; state figures that do not and it refuses. REQUIRED: - `currency` — every figure below is in it, each converted before you stated it - `period_start`, `period_end` — the inclusive calendar days the flows cover - `opening` — `amount` (SIGNED, a workspace can be overdrawn), `as_of` (the day before `period_start`), and `derived` (true only when you solved it from the law because the reading could not be taken) - `inflows`, `outflows` — gross magnitudes, both positive; the direction lives in which bar they are - `unexplained` — the SIGNED gap `closing - (opening + inflows - outflows)`, computed from the figures as you rounded them; zero when they meet - `closing` — `amount` (SIGNED) and `as_of`, the moment the reading was taken - `reconciles` — true when the gap is inside the tolerance below, false when it is past it - `partial` — true when any term is incomplete: an anchor some accounts had no reading for, flows with rows no owned account could be placed against, rows that could not be read, or a currency with no rate. A cut-short read returns no rows and stops the run before this call The tolerance is the product's own: 1% of the closing position's size, never less than 1 in the base currency. A bridge that does not reconcile draws an Unexplained bar between the outflows and the closing; one that does draws none. REFUSED rather than rendered, each because your own figures disagree: - five figures that do not add up to within a cent - `reconciles: true` with a gap past the tolerance, or `false` with one inside it - a negative `inflows` or `outflows`; each is a magnitude, so a negative one was re-signed - an opening not dated the day before `period_start` - a window ending more than a day from the day the closing was read - a window that starts after it ends, or a date that names no real day - a derived opening with any gap, on a partial read, or over a window with no flows - a closing `as_of` in the future When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth
  • Sum a workspace's billed amounts over a window of whole months, grouped by month, currency and billing context. Arithmetic only — this tool holds no definition of MRR or recurrence, and returns no figure the app renders. Use it when you are computing a figure whose RULES you are stating yourself: recurring revenue over a window you chose, a total restricted to the billing contexts a reader confirmed, a per-month series behind a trend you are about to describe. The server derives no MRR of its own, so an MRR figure starts here: state the rules, sum exactly those rows, then put the result on a card with `well_render_mrr`. **The window is whole months.** `from` and `to` are both the first day of a month, as YYYY-MM-01; `from` is inclusive and `to` is EXCLUSIVE, so June to August is `2026-06-01` to `2026-09-01`. A bound inside a month is refused rather than widened, and so is a window longer than 36 months. **Which rows are billed amounts is decided here, and stated so you can say it.** A canceled invoice is left out. Only billing documents count: invoices, debit notes, credit notes and subscription billing statements, so a proforma and the invoice it precedes are not summed twice, and an order, a quote or a payment advice never is. A row with no document type is read as an invoice. Every amount is NET of tax (`items_total`), because tax collected is owed onward rather than earned. **`party_scope` is required, and it decides whose invoice this is.** `sales` is what the workspace ISSUED — its receivables, and the only side revenue can come from. `purchase` is what it received. The two are the same rows read from opposite ends, so no default is offered: a server choosing a side would answer a different question from the one asked. `intra_self` is an invoice between two companies the workspace owns, and `unattributed` is one Well could place on neither side. **Those four scopes partition every invoice exactly once**, which is what makes an incomplete picture visible rather than silent. `unattributed_count` comes back on every call, whatever scope you asked for: it counts the invoices in the window that landed in that fourth bucket. State it beside any total, because an unattributed invoice may still belong in the figure and nothing here can tell you whether it does. **Every row carries ONE month, ONE currency and ONE billing context.** Currency is always a grouping key, named or not: adding EUR to USD gives a number denominated in nothing, and no field on the result would tell you it happened. Convert the per-currency subtotals yourself, at a rate you can state, before you add them. **`sum` is already net of credit notes.** A credit note subtracts its magnitude from its own month-currency-context bucket, whichever sign it was stored with; `credit_note_sum` and `credit_note_count` report what that removed, so you can say what the figure netted. Do not subtract them a second time. A bucket whose credit notes outweigh its invoices nets negative, and that is a real state rather than an error. **`billing_context` is `null` on rows that name no billing arrangement** — none stored, `unknown`, or a value Well has no label for — and that is a third answer rather than a kind of one-off. The field is filled by extraction, not by a billing system, so a workspace can carry real recurring revenue on rows that say nothing about it. `unclassified_count` totals those rows. The recurring-contexts card offers them as one choice, keyed `"unclassified"`, so apply that key to these rows and only these. Counted or not, report the count rather than letting a reader read the remainder as "everything else". `corrected_or_consolidated_count` counts the corrected and consolidated invoices among the rows. Each replaces invoices Well holds no link to, so when those originals fall in the same window the sum counts that billing twice. The rows keep them, because dropping them would lose the revenue whenever the originals fall outside the window. State the count beside any total whenever it is not zero. `excluded_malformed` counts billing documents in the window with no readable net amount or no currency. They are in none of the rows and none of the sums, so state the count beside any total. It comes back `null` when the count could not be read, which is NOT `0`: zero says every row was readable, null says nobody counted. `partial: true` means the aggregate was cut short and every figure is a FLOOR rather than a measurement. When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth

Matching MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants and automation platforms to interact with Dell PowerStore storage arrays by dynamically generating over 260 tools from OpenAPI specifications. It features a credential-free architecture for secure, multi-host management of storage, networking, and system health.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server for Dell Unity storage arrays that automatically generates tools from OpenAPI specifications, enabling AI assistants like Claude and n8n to interact with Unity storage systems without storing credentials.
    MIT

Matching MCP Connectors

  • Pay-per-call x402 API for AI trading agents: pre-trade security checks, Polymarket & HIP-4 odds.

  • Precios agrarios de España con fuente y fecha: Generalitat, MAPA, gasóleo B y plazos del campo.

  • Upload a document (invoice, receipt, statement) into the workspace by sending its bytes as base64. ⚠️ THIS IS A WIDGET'S WRITE, NOT YOURS. The card's drop zone reads the file the person dropped or chose, encodes it, and calls this tool itself. Do NOT call it: a model holds no file, so a call made from a conversation can only carry bytes nobody supplied. When a person says they have the invoice, point them at the drop zone on the gap card. Send `content_base64` WITHOUT a data-URI prefix — the raw base64 only, no `data:application/pdf;base64,` header. Accepted content: PDF, JPEG, PNG, GIF, HEIC, HEIF, AVIF, WEBP, TIFF, plain text, CSV, XML. The bytes are checked against the declared `mime_type` (file signature, not just the claim), so a PNG announced as a PDF is refused. Size ceiling: 5 MB of file (before base64). A larger file is refused with its actual size — upload it through the web app instead, which accepts up to 15 MB. Pass `source_transaction_id` to anchor the document to the bank transaction it pays. That is what makes a dropped invoice land on the right line instead of in a general inbox. Well extracts the document after upload; the extraction is asynchronous and this call returns as soon as the file is stored. A file already in the workspace is deduplicated by content and returns the existing document rather than a copy.
    ConnectorNo auth
  • Put a cost breakdown YOU computed onto the cost-structure card. **This tool measures nothing.** It takes the slices and the method behind them as input and returns them for rendering. Call it only after you have computed the breakdown yourself and can state every field below from your own work, never to "get" a cost structure. The server derives no breakdown of its own. The chart draws the slices you state here, which is why every field below is required: the policy behind a grouping is the only thing that makes it checkable. **The card draws the ring, the legend and the month.** Everything else you state below is REQUIRED and reaches no pixel. All of it comes back to you in this tool's text result, which is what you write the prose from. The chart is the measure; the explanation is yours. REQUIRED, because a breakdown whose method is not stated cannot be checked: - `entries`: the slices, largest first, each a POSITIVE magnitude in `currency`. Send NO share: this tool derives every share from the amounts and returns them, and an entry carrying `pct` is refused as an unknown field. At most 4 named slices plus one rolled-up `Other`, because the card performs no rollup of its own - `period_start` and `period_end`: the INCLUSIVE bounds of the single calendar month covered. Never a quarter, never a span, never a month still running - `rung`: which grouping produced these categories. State it in prose too, so the reader knows whether they are looking at their own ledger's categories or Well's - `label_provenance`: whether a person owns those labels. A chart of accounts synced from an accounting tool is `machine`, not `curated`: the names came from the provider, not from anyone at the company - `coverage`: the outflow rows the elected grouping could label, against every outflow row the month held. This is the evidence the rung was elected on, and your prose states it - `convention` and `convention_counts`: which sign means money leaving, and the row counts you elected it from - `excluded`: what fell out, in four named groups. `no_asset_movement` is where CARD SPEND lands, because the transfer rule drops a row with no owned asset leg and a card charge moves a liability. It contains `no_owned_leg`, so never add them. Send an unmeasured LEG count as `null` rather than `0`, because zero says the rule removed nothing, and one cancelled leg count nulls all three. `unreadable_rows` is always measured and takes a number REFUSED rather than rendered: - an entry carrying `pct`, or any other field this schema does not name. The shares are DERIVED here from the amounts, so a share you send is a second opinion the card has no way to reconcile - entries out of descending-amount order, more than 4 named slices, or an `Other` slice that is not last - a negative `amount`: a breakdown is made of magnitudes - a `period_start`/`period_end` pair that is not exactly one whole calendar month, or that names a month which has not ended - `category_key` on any rung but `category_key`, or on the rolled-up `Other` slice, which is many categories and is therefore not one of them - any `label_provenance` but `unlabelled` on a rung that carries no category: `curated`, `machine` and `mixed` each claim that someone or something chose labels the chart never shows. The converse is NOT refused, because a rung elects over the month's rows while the provenance describes the ones that survived into the slices, so a labelled rung whose labelled rows all dropped is legitimately `unlabelled` - `rung: "uncategorised"` sent beside named category slices, which is a breakdown claiming to be the absence of one - `convention: "magnitude"`: that feed keeps direction in a field no grouping reaches, so no outflow was measured. `signed` elected from ZERO negative rows is the same finding, demonstrated rather than declared - coverage wider than the month it covers, or a labelled rung that could label no rows at all - one of `excluded.internal_transfers`, `excluded.no_owned_leg` and `excluded.no_asset_movement` `null` while the others are measured: one cancelled count nulls all three, and the refusal is filed against `excluded.no_asset_movement` - a `currency` outside ISO-4217: the code is checked against the catalog, not its shape An EMPTY `entries` array is accepted, and it means nothing is categorized for that month. Say that, rather than reporting zero spend: a month with no outflow at all is a different answer and the card says so differently. When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth
  • Read records from Well's context graph FOR YOUR OWN WORK. This draws nothing on the user's screen. Use it for every read whose answer is yours rather than the reader's: a gate checking whether a window holds transactions, a `totalCount` an answer has to quote, a sync log's latest status, a field a later step needs, the rows behind a figure you are about to compute. ⚠️ TO SHOW THE USER A TABLE, CALL `well_show_records` INSTEAD. Same arguments, same rows, and it renders the root's own table. This tool cannot put one on screen, so a request to "show me my invoices" answered here leaves the user with prose where a table belongs. ⚠️ WORKFLOW: 1. Call well_get_schema(root) FIRST to discover the available fields. 2. Name in `fields` ONLY the extra values you need (5-15 typically). They are ADDED to the root's default projection in the payload you read. 3. Filter with `whereClause` so the read answers the question. A count under a filter beats reading rows and counting them yourself. 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.) CATEGORY CATALOGS: "categories" holds two independent taxonomies, separated by `category_type`. Always filter on it — an unfiltered read mixes them: - `whereClause: { category_type: { _eq: "company" } }` is the COMPANY-CATEGORY catalog: the industry labels a counterparty carries, and the ids `well_update_company({ category_ids })` accepts. There is no curated allowlist — the labels are minted during enrichment — so read them here rather than inventing a taxonomy. - `whereClause: { category_type: { _eq: "transaction" } }` is the management/transaction taxonomy. 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. FILTERING (whereClause): - Uses Hasura-style operators on field names. - Safe operators (work on ALL field types): _eq, _neq, _in, _nin, _is_null - Numeric/date only: _gt, _gte, _lt, _lte - Text only: _like, _ilike - When unsure of a field's type, prefer _eq or _in (they always work). - Combine with _and, _or, _not - For relationship fields, use nested syntax: { "issuer": { "company_id": { "_eq": "<company_id>" } } } - NEVER select the workspace's OWN records by matching a company name. One legal entity appears under several labels — a registered name, a trade name, a bank-issued label — so a name filter silently drops rows and the total reads as complete. On the invoices root, pass `partyScope` instead: it resolves the workspace's own side on the server, so this query needs no id lookup and no extra call. Call well_get_own_company for the id only when a root has no `partyScope` and you must filter on issuer_pk / receiver_pk or the nested company_id yourself. - Match a counterparty by id too whenever you have one. Reach for _ilike on a name only to DISCOVER candidates to show the user, never to compute a figure you will report. Examples: { "status": { "_eq": "unpaid" } } { "grand_total": { "_gt": 1000 } } { "local_currency": { "_eq": "EUR" } } { "_and": [{ "status": { "_eq": "unpaid" } }, { "grand_total": { "_gte": 500 } }] } { "issuer": { "company_id": { "_eq": "<company_id from well_get_own_company>" } } } SORTING (orderBy): - Sort by any field: { field: "grand_total", direction: "desc" } - Default sort is by primary key ascending. ⚠️ RULES: - `fields` is ADDITIVE — it widens the data you receive on top of the root's default projection - Omitting fields (default view) or naming a few extras both beat allFields - Field paths from schema: "invoices.issuer.name" → ["invoices", "issuer", "name"] - NEVER guess a field name. Common misses: a transaction has no `amount` column (read ["transactions", "instructed_amount", "amount"] and its "currency"), an account has no `name` (read ["accounts", "account_name"]). An unknown field fails the call and the error lists the valid fields of the root: retry once with one of them. - Default 50 records per request, max 500. - Reading whether ANYTHING matches is one call at `limit: 1`: read `totalCount`, not the rows. EXAMPLE - does the window hold any transactions at all? well_query_records({ root: "transactions", limit: 1, whereClause: { "executed_at": { "_gte": "2026-06-01", "_lt": "2026-09-01" } } }) // totalCount answers it. One row comes back and you ignore it. 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. ONE CALL IS THE ANSWER — do not walk the root: Every response carries `totalCount` (ALL matches, not just this page) and `records_url` (the full web-app table, with your filter and sort already applied). Hand the link to the user for anything past this page. - 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 match that no aggregate can express, and tell the user the cost before starting. Then: pass the returned `nextCursor` as `cursor`; `nextCursor: null` is the last page. Returns { rows, totalCount, nextCursor, success }.
    ConnectorNo auth
  • 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, establishment_no, locale (ISO 639-1 two-letter language code, e.g. "en", "fr" — not "en_US"). FRENCH IDENTIFIERS go to three different fields — never put one in another's: - SIREN (9 digits, the legal entity): registered_value, with registry_country "FR". - SIRET (14 digits, SIREN + 5-digit establishment number; the billed establishment): establishment_no, digits only, spaces removed. - VAT number (e.g. "FR44732829320"): tax_id_value, with tax_id_type "VAT". CATEGORIES (a counterparty's industry): pass `category_ids` — the COMPLETE set of category ids the company should carry. It REPLACES the current set: ids you leave out are unlinked, and `[]` clears every category. Omit the field to leave the categories untouched. Read the catalog first with well_query_records({ root: "categories", whereClause: { category_type: { _eq: "company" } } }) and pass ids from it — an id that is not a `category_type = "company"` row is refused, and this tool never creates a category. NOT CHANGEABLE via this tool: emails, phones, locations, linked people, media. Those require dedicated tools (not yet available). PROVENANCE: `decision` says HOW the set was chosen. `accepted_suggestion` — the user let a category the classifier had already proposed stand, without touching it. `explicit` — the user chose the labels. **A request the user typed is always an `explicit` choice, so never send `accepted_suggestion` from a conversation.** The affirmation belongs to the categorization card, where a pre-filled picker the reader leaves alone is the only thing that can be let stand; a user who names a category in words has chosen it, even when they say they agree with a suggestion. Omit the field and the write is `explicit`. The server checks an `accepted_suggestion` claim against the company's own pending proposals and returns `explicit` when the written set matches none of them, so the claim can never manufacture classifier provenance. Returns { success: true, company_id, name } on success — plus category_count, the number of categories the company carries afterwards, and decision, the provenance the server settled on, when the call passed `category_ids`. Returns { success: false, error } on failure.
    Connector
    Destructive
    No auth
  • 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.
    ConnectorNo auth
  • 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 (read from the document; leave it out for a draft, Well numbers drafts itself), issue_date (YYYY-MM-DD), due_date? (YYYY-MM-DD; leave it out on a draft the person gave no due date: Well sets the customer's usual terms, else 30 days after the issue date), currency (ISO 4217) - totals: { items_total?, tax_total?, grand_total } (grand_total required) - line_items[]: { name, quantity?, unit_price, currency?, tax_rate? } - payment_means?[]: { type, iban?, bic?, scheme? } - status?: draft | issued | paid | canceled — create an invoice the user is still reviewing as "draft", then issue it with well_issue_invoice once the user confirms; issuing gives it the next invoice number and locks it - document_type_code?: "380" invoice (default) | "381" credit note; corrects_invoice_id? — the issued invoice a credit note corrects, required for a credit note. An issued invoice cannot be edited: correct it with a credit note, then create a new invoice 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. The answer carries the saved invoice's status, customer_name, currency, grand_total, issue_date, design_layout (null until a design is chosen) and lines. The card shows them, so the reply does not list them again.
    ConnectorNo auth
  • 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.
    ConnectorNo auth
  • List the workspace's counterparty companies and how each one is CATEGORIZED — the company-level industry labels a counterparty carries. Use it for "which suppliers have no category?", "what industries are my counterparties in?", and before categorizing a counterparty so you name real ids instead of guessing. Name a scope, and say whether to keep only the ones missing a category: - `periods: [{ calendar_year, calendar_month }, …]` (1-12): the counterparties whose invoices those months are still missing, categorized ones included, each row tagged with its month and carrying `tx_count`, `base_total_amount` in `base_currency`, and `suggested_retrieval`. Every month must have ended. - `periods` PLUS `uncategorized_only: true`: the same months, keeping ONLY the counterparties that carry no category. Use this whenever the question is which of a period's suppliers still need one, and whenever a step asks the user to categorize them: the categorized ones are not the work, and listing them buries it. - `uncategorized_only: true` alone: a WORKSPACE-WIDE sweep for every counterparty that carries no category, no month involved. Returns 50 rows per page plus `total_count`; `tx_count`, `base_total_amount` and `suggested_retrieval` are null because the call names no period. When `next_cursor` is not null the sweep has more counterparties: call again with `cursor` set to it to read them. It is a POSITION, not a row offset, so categorizing the rows of one page never hides the rows of the next. Only this sweep pages: `cursor` is refused beside `periods`. - `missing_ledger_only: true` alone: the LEDGER-ASSIGNMENT worklist — the counterparties that have a bank transaction and still need a ledger account (COA) default set for the direction their transactions take. Its rows ride in `ledger_rows`, not `rows`, each carrying `needs_payable`/`needs_receivable` and the AP/AR default it holds now; a needed slot is empty, assigned from the chart of accounts. When the classifier proposed an account the person has not confirmed, the row carries it in `suggested_payable_default`/`suggested_receivable_default` (`account`, `confidence`, `reasoning`, `memory_informed`): show it, and only after the person agrees, set the slot to `account.id`, which confirms the proposal. This is a DIFFERENT question from categorization: it assigns a ledger account, not an industry label. Set a default with `well_update_company({ account_payable_default_id | account_receivable_default_id })`; read the account ids with `well_list_ledger_accounts`. It returns the first 500 counterparties needing a default, so a worklist that fills 500 (`total_count` equal to `row_count` at 500) is a FLOOR: assign those and read the scope again for the rest. It is its own scope — never combine it with `periods`, `uncategorized_only`, or `cursor`. COST: the period form has no batch endpoint, so each named month is a separate read of that month's spend. Ask for the months the user actually named, not a whole year "to be safe". Every row carries `categories` (`[{ category_id, name }]`) and `is_categorized`. `categorized_count` and `uncategorized_count` count the COUNTERPARTIES OF THE SCOPE, once each however many months they appear in, not the rows returned. Under `uncategorized_only` the result lists the uncategorized ones alone while `categorized_count` still counts the ones it withheld, so the two together are the period's coverage and `uncategorized_count` is the work left. Report both: naming the listed rows as the period's whole counterparty set overstates how much is uncategorized. TO SET a counterparty's categories, call `well_update_company({ company_id, category_ids: [...] })` — that field REPLACES the company's whole set. Read the available labels first with `well_query_records({ root: "categories", whereClause: { category_type: { _eq: "company" } } })`: that is the company-category catalog. It has no curated allowlist — the labels are minted during enrichment — so pass ids from it rather than inventing a taxonomy. `suggested_retrieval` is derived from the PROVIDER match, not from the category. Categorizing a counterparty does not change it; do not tell the user otherwise. This tool only reads. It categorizes nothing, mints no task, connects nothing and fetches no invoice. No workspace read is needed first: the workspace is resolved from the caller's authorized token, same as every other well_* tool. When the user asks to see, list or fix these rows, call this tool directly: its card is the answer. ⚠️ **This tool draws its card on EVERY call, the empty one included.** So when nobody asked for the list and you only need to CHECK whether anything is left (the first pass of a gate, or a re-check after a repair), call `well_get_worklist_status({ worklist: "counterparties_to_categorize", periods })` first, with the same scope you would pass here. It draws nothing. Call this tool after it only when it answers `open: true`.
    ConnectorNo auth
  • Set which company the workspace itself IS — the confirmed own-company anchor. REQUIRED: company_id — a company that ALREADY EXISTS in this workspace. Obtain it with well_query_records (companies) or well_create_company; this tool never creates one. This is a deliberate, accounting-critical write, not a convenience. Anchoring the own company overwrites the workspace's legal identity on its accounting settings (including clearing fields when the anchor moves), records a manual-confirm audit row, and syncs the billing customer name. It never re-posts existing journal entries. Confirm the exact company with the user before calling; never guess one from a name. Only a workspace owner or admin may set the own company. A caller without that role is refused, not silently ignored. well_start_close hard-gates on this anchor: a workspace with no own company cannot start a close.
    Connector
    Destructive
    No auth
  • Sum a workspace's transactions over a date window, grouped how you ask. Arithmetic only — this tool holds no definition of burn, spend, or runway, and returns no figure the app renders. Use it when you are computing a figure whose RULES you are stating yourself: a burn over a window you chose, a total that excludes categories the user named, a per-month series behind a trend you are about to describe. The server derives no burn of its own, so a burn figure starts here: state the rules, sum exactly those rows, then put the result on a card with `well_render_burn`. `from` is inclusive and `to` is EXCLUSIVE, so a window of whole months passes the first instant of the month after the last one you want. Both are required: a window you cannot state is a decision you have not made, and this tool will not pick one for you. `axes` groups the result (any of `month`, `currency`, `category`, `ledger_account`, `category_label`, `transaction_type`, comma-separated) and names what to group in ADDITION to currency. Every axis appears on every row: the ones you did not group by come back `null`, so the row shape never depends on what you asked for. **On an axis you DID name, a `null` is a group, not a gap.** It is the rows whose column is empty, and it carries its own sums and counts like any other group. A group's rows are `count_negative + count_positive`, so the null group's share of that total is the part that axis cannot label. Both counts cover readable, non-zero rows only: a zero amount is in neither branch, and unreadable ones are in `excluded_malformed`. So the share is a share of the rows this tool could sum, not of every row in the window. What that share means, and which grouping is worth using, is yours to decide: this tool holds no view on it. What each labelling axis IS: - `ledger_account`: the name on the workspace's own chart of accounts. It may have been written by an accounting sync rather than chosen by a person, so do not call it the user's own categorization without checking the `ledger_accounts` root for the connector that wrote it. A blank label reads as `null`. A soft-deleted or inactive account still carries its name, because this axis reports what the row was labelled at the time, not what the current chart of accounts holds. It groups on the NAME, and a chart of accounts is unique on the account number rather than the name, so two accounts sharing one name arrive as a single group carrying both their sums. That is one slice per label, which is what a breakdown by label means, but it is not one slice per account: do not read a group here as an account. - `category`: the typed catalog key, and the ONLY value `exempt_categories` accepts. A key the catalog no longer carries is still populated here, so it groups under a key that names nothing a reader would recognise. - `category_label`: the stored display label, which a connector may have written in its own language. Never pass one to `exempt_categories`; it is not a key. - `transaction_type`: the transaction's own type. Each value is a full sentence rather than a code, and almost every row carries one. **At most 500 groups come back, biggest first.** Past that the smallest are dropped and `rows_truncated` is true, which is NOT `partial`: everything here was measured exactly and only the tail is missing. A total over a truncated result is a floor, and an axis's coverage cannot be read off one at all, because the null group may be among the dropped. Group on fewer axes, or over a shorter window, and ask again. **Currency is always grouped, named or not, so a row never mixes two.** Adding EUR to USD gives a number denominated in nothing, and no field on the result would tell you it happened. Omitting `axes` therefore returns one row PER CURRENCY over the window, not one row. Convert the per-currency subtotals yourself, at a rate you can state, before you add them — and if there is more than one row and you report a single total without converting, the total is wrong. **Each row carries BOTH sign branches, and choosing between them is your job.** `sum_negative` is the magnitude of the rows whose amount is negative; `sum_positive` is the magnitude of the rows whose amount is positive; `count_negative` and `count_positive` say how many rows are behind each. Which one is money leaving depends on the FEED, not on the query: most connectors store outflows as negatives, some store them as positive magnitudes. Read the counts to decide, and decide ONCE over the whole window rather than per row or per group: a single category or month can be all-positive on a signed feed, so electing per group flips the convention mid-answer and totals two different things together. A window whose rows are overwhelmingly negative is a signed feed, and outflow is `sum_negative`. Almost no negatives means the feed stores magnitudes and keeps direction in a field this tool does not group on — so it cannot separate outflow from inflow, and `sum_negative + sum_positive` is gross movement, not spend. Say so rather than reporting it as an outflow. **A substantial share of BOTH is a third answer, not a close call between the first two.** A workspace connected to a signed feed and a magnitude feed at once pools them here, and no combination of the two subtotals is its outflow: `sum_negative` misses the magnitude feed's spend entirely, and adding `sum_positive` pulls in the signed feed's income. There is no grouping that separates them, because the axes carry no connector. Report that the window mixes conventions and that a single outflow cannot be derived from it, rather than electing whichever branch is nearer. State which convention you elected and what the counts were, so the reader can check it. **`scope` is required, and it decides which rows are this workspace's.** `own_and_adopted` is the population the burn tile counts: the workspace's own transactions plus any a parent workspace shared with it through an adoption grant, with legs tested against the parent's accounts too. `own` is the workspace's own transactions only, tested against its own accounts — the rows its balances move with. Use `own` when the sum is reconciled against the workspace's own balances, as a cash-flow bridge is, and `own_and_adopted` for a burn. On most workspaces the two agree; on a child workspace they do not, which is why neither is a default. `exclude_internal_transfers: true` keeps only the rows with EXACTLY ONE leg on an account the workspace owns. Two legs is a movement between your own accounts and drops, which is the rule's purpose. **Zero legs also drops**, and that is the part worth knowing: a card purchase sits against a liability account, so on a card-heavy workspace this removes card spend along with the transfers. `excluded_zero_leg` and `excluded_multi_leg` count the two populations separately, so read them before describing what the figure covers. Read `excluded_zero_leg` as "this many rows carried no asset movement" and nothing narrower: a card charge lands there, and so does a row whose payer and payee resolved to no account at all. `excluded_no_owned_leg` is that second part on its own: rows with no leg on ANY owned account, liabilities included, so card spend is never in it. Those rows could not be attributed to an account and may have moved a balance the sums cannot see, so a figure reconciled against balances treats a non-zero count as flows that are incomplete. A large `excluded_zero_leg` is a reason to look, never a spend total to quote. Any of the three counts comes back as `null` when it could not be measured, which is NOT `0`: zero says the rule removed nothing, null says nobody counted. On a null, say the exclusion is unmeasured rather than reporting none — the sums themselves are unaffected, and `partial` is what speaks for those. For reproducing the burn tile that is exactly right — it is the conservation law the cash-flow bridge rests on. For "total spend excluding transfers between our own accounts" it is not what the words promise, so say what fell out or leave the flag off. The rule is structural: it counts legs, so no label, category, or type on the row affects it, and a user recategorizing something does not change it. `exempt_categories` takes category keys that should not count. A transaction with no category at all is never matched by an exemption and always stays in the sum; if you want those excluded too, that is a different question and you must say so. `excluded_malformed` counts rows in the window whose amount could not be read as a number. They are in none of the sums, so state the count beside any total rather than presenting a figure that silently skipped them. `partial: true` means the aggregate measured nothing: it was cut short, or no asset account is in scope. Either way it arrives with an empty `rows`, so there is no figure, and the empty rows are not a zero. Say so and offer to try again, unless the workspace holds no deposit or other asset account, where a retry changes nothing. When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth
  • List the teammates a workspace can invite, exactly as the Well app's invite card shows them. Use it before well_invite_members, and for "who can I invite to this workspace?". Returns `candidates`, each with `person_id`, `name`, `email`, `avatar_url`, a `state` (`active` already has access, `pending` was invited and has not accepted, `not_member` can be invited), and a `source` (`detected` shares the workspace owner's corporate email domain, `provided` was named in `person_ids` or resolved from the assigned gap owners). Never invite a candidate whose state is `active`. Alongside them it returns `targets` — this workspace plus any workspace group you belong to, each an option for where the invite lands — `roles` (`admin` or `member`, with a hint), and `me_person_id` so you never offer to invite the caller. Three ways to source the candidates: - Default: the detected same-domain teammates who hold no membership. - `person_ids`: resolve specific people you already hold the ids for, with their membership state. Set `include_detected` false to return only those. - `from_assigned_gaps: true`: resolve the owners of the settled expense transactions still missing a supplier invoice for the period, server-side, with their membership state — the invite step of a close or fetch flow uses this so it never depends on remembering who was assigned on the owner card. It returns only those owners (the detected teammates are omitted). Name the period ONE way — `{ calendar_year, calendar_month }` or `{ fiscal_year, fiscal_period }` — or name no period to use the months selected on the period card this session. Every month must have ended. ⚠️ **This tool draws its invite card on EVERY call, the empty one included.** When the user asks who they can invite, call it directly: the card, with its contact search, is the answer. But in the invite step of a close or missing-invoice flow, where you read with `from_assigned_gaps: true` only to find out whether an owner of the period's gaps still needs an invitation, call `well_get_worklist_status({ worklist: "gap_owners_to_invite" })` first, with the same period you would pass here or none for this conversation's selected months. It draws nothing, and its `count` is how many of those owners are `pending` or `not_member`. Make the `from_assigned_gaps` call only when that count is above zero. A solo workspace whose owner assigned the gaps to themselves answers 0: nobody is left to invite, so no card is drawn. An ABSENT count is not a zero: `success: false` means the probe could not read the owners. ⚠️ WAIT ON THE CARD IN THE TURN THAT DREW IT. Write your one line for the user FIRST, then call `well_wait_for_selection({ kind: "invite_ack" })`, which this result's `next_step` also states. The card's own footer sends the invitations and writes the acknowledgement, so never call `well_invite_members` yourself after a click. The outcome the click carries says which button it was: "done" sent the invitations, "keep_for_later" set the step aside. Both end the step. When the token authorizes one workspace, call this directly — no other tool call is needed first. When it authorizes several, this read will not guess which one you mean: pass `workspace_id` on the call.
    ConnectorNo auth
  • Invite one or more teammates into a workspace, or into a workspace group. Use it after well_list_member_candidates, on the people the user chose. Pass `invites` — 1 to 20 `{ email, role }`, role `admin` or `member` — and a `target`: `{ kind: "workspace" }` for this workspace, or `{ kind: "group", group_id }` for a group you belong to. Only a workspace owner or admin may invite; a caller without that role is refused. Returns one `results` entry per invite: `status` `sent` (a new invitation), `reissued` (an already-pending address got a fresh link), or `refused` — with `refusal_reason` naming why, ALREADY_WORKSPACE_MEMBER when the address already has access and INSUFFICIENT_PERMISSIONS when the caller may not invite. `invitation_email_sent` is false when the invite persisted but the email did not leave, so offer a resend. Each successful result carries `person_id` for the invited address. Never invite an address already active in the workspace. Pass `notify: false` (workspace target only) to create or reissue the pending membership WITHOUT emailing — for the assign-then-invite flow where an owner is assigned by a typed email now and the invitation is sent later from the invite card. Use the returned `person_id` to assign that person as an owner without a second lookup.
    ConnectorNo auth
  • Set the owner SET of the missing-invoice TRANSACTIONS you name — the only write for missing-invoice ownership. REQUIRED: transaction_ids — the settled lines still missing a supplier invoice, from well_list_missing_invoice_owners. owner_person_ids — the people who together owe those invoices; pass an EMPTY array to clear the owners. Ownership is per TRANSACTION and is a SET, not one owner and not a card rule. The write REPLACES the owner set on every named transaction: the people you send become its owners and anyone not sent is removed. Assigning several people to a (counterparty × month) gap creates ONE proof task per distinct person, and ONE supplier invoice resolves every owner's task for that gap — the fan-out is for accountability, not for N separate collections. Tell the user this plainly. Each person_id must already be a member of the workspace (get them with well_query_records on people). A person outside the workspace is refused (refusal_reason NOT_FOUND), not silently dropped. Closed periods are frozen: a transaction whose fiscal month already closed refuses the whole batch (refusal_reason CLOSE_OWNER_PERIOD_FROZEN) rather than rewriting a committed close. A transaction id the workspace does not own refuses the batch too (refusal_reason NOT_FOUND).
    Connector
    Destructive
    No auth
  • Mint a company candidate from a registry hit, the step between finding the company and creating its workspace. This is the deliberate pick the confirm-your-company card makes. REQUIRED: registry_ref — the `id` of a well_search_company_registry hit. This tool hydrates that hit and mints the company as a primary (own-company) candidate. Then call well_create_company_workspace with the returned `candidate_id` to make it the company workspace. Only a workspace owner or admin may mint a candidate. A caller without that role is refused, not silently ignored. When the picked company already has a confirmed company workspace, the result carries `linked_to_existing_child: true` and its `workspace_id` — switch into it with well_switch_workspace instead of creating another. Confirm the exact company with the user before calling; never pick one from a name alone.
    ConnectorNo auth
  • Show the user the detected COMPANY candidates on a card and let them pick which company is theirs: a tile per detected company candidate with its confidence, and a company-registry search at the top for the case where none was detected. ⚠️ ONLY for the zero-company case — a membership workspace with no own company attached — when the user must choose or find the company to create the workspace from. For the values alone, read `well_get_own_company`, which draws nothing. ⚠️ WAIT ON THE CARD IN THE TURN THAT DREW IT. Write your one line for the user FIRST — the wait holds the turn open for up to a minute, and a user looking at a card with no sentence beside it has been given no reason to click — then call `well_wait_for_selection({ kind: "company_pick" })`, which this result's `next_step` also states. The card's own footer mints the company workspace and switches into it on the click, so never mint it yourself after the pick. ⚠️ NEVER PICK THE COMPANY for the user, and never infer it from the workspace name.
    ConnectorNo auth