> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thredfi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server

> Connect Claude, ChatGPT, and other AI assistants directly to the Thred Partner API via the Model Context Protocol

The **Thred MCP server** exposes the Thred Partner API as a set of [Model Context Protocol](https://modelcontextprotocol.io) tools, so AI assistants like **Claude** and **ChatGPT** can read and write a business's accounting data in plain language — no custom integration code required.

It is published on npm as [`thred-mcp`](https://www.npmjs.com/package/thred-mcp) and runs locally over stdio.

<CardGroup cols={3}>
  <Card title="Ask" icon="magnifying-glass">
    Read-only questions about the business — overview, cash flow, AR/AP, reports.
  </Card>

  <Card title="Do" icon="bolt">
    Write actions — create invoices, record payments, manage customers, vendors & bills.
  </Card>

  <Card title="Watch" icon="bell">
    Proactive alerts (overdue, cash-low, unusual transactions). *Roadmap — not yet shipped.*
  </Card>
</CardGroup>

## How it works

The MCP server is a thin, stateless adapter. It does not store data — every tool call is translated into a single authenticated request against the Partner API (`https://api.thredfi.com`).

```
AI assistant (Claude / ChatGPT)
      │  MCP (stdio, JSON-RPC)
      ▼
thred-mcp  ──►  POST /v1/platform/oauth2/token/   (client_credentials, cached)
      │
      └──────►  https://api.thredfi.com/v1/platform/...   (Bearer token)
```

1. The AI client launches `thred-mcp` as a subprocess and speaks MCP over stdio.
2. On the first tool call, the server exchanges your **Partner UUID + API Key** for an OAuth2 access token.
3. The token is cached in memory and reused until \~5 minutes before expiry, then refreshed automatically.
4. Each tool maps to one Partner API endpoint; the JSON response is returned to the model.

<Note>
  The MCP server is **channel-agnostic** and runs entirely on the user's machine. Your Partner credentials never leave the local process, and no Thred data is persisted by the server.
</Note>

## Installation

Requires **Node.js 18+**. No global install needed — clients run it via `npx`.

```bash theme={null}
npx thred-mcp
```

### Authentication

The server reads two environment variables and performs the OAuth2 `client_credentials` flow for you:

| Variable             | Required | Description                                                                                      |
| -------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `THRED_PARTNER_UUID` | Yes      | Your Partner UUID from the Partner Portal                                                        |
| `THRED_API_KEY`      | Yes      | Your Partner API Key                                                                             |
| `THRED_ENV`          | No       | `production` (default) or `sandbox` — selects the API environment                                |
| `THRED_BASE_URL`     | No       | Explicit origin override (e.g. `https://sandbox.thredfi.com`); takes precedence over `THRED_ENV` |

Credentials are sent as HTTP Basic auth to `POST /v1/platform/oauth2/token/`; the returned `access_token` is then used as a `Bearer` token on every API call. See [Authentication](/implementation/authentication) for the underlying token model.

<Warning>
  The MCP server connects to **production** (`api.thredfi.com`) unless `THRED_ENV=sandbox` or `THRED_BASE_URL` is set. Write tools mutate data in the selected environment. Keep sandbox credentials separate from production credentials and do not point one environment's credentials at the other environment's URL.
</Warning>

## Connecting an AI client

<Tabs>
  <Tab title="Claude Desktop">
    Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (create it if missing), then fully restart Claude (Cmd+Q and reopen):

    ```json theme={null}
    {
      "mcpServers": {
        "thred": {
          "command": "npx",
          "args": ["-y", "thred-mcp"],
          "env": {
            "THRED_PARTNER_UUID": "your-partner-uuid",
            "THRED_API_KEY": "your-api-key",
            "THRED_ENV": "sandbox"
          }
        }
      }
    }
    ```

    A hammer icon appears in the composer — click it to see the Thred tools.
  </Tab>

  <Tab title="Cursor / VS Code">
    Add the same block to your client's MCP settings (e.g. `~/.cursor/mcp.json` or the workspace `.vscode/mcp.json`):

    ```json theme={null}
    {
      "mcpServers": {
        "thred": {
          "command": "npx",
          "args": ["-y", "thred-mcp"],
          "env": {
            "THRED_PARTNER_UUID": "your-partner-uuid",
            "THRED_API_KEY": "your-api-key",
            "THRED_ENV": "sandbox"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Manual / debugging">
    Run the server directly to verify credentials and inspect stdio:

    ```bash theme={null}
    THRED_PARTNER_UUID=your-uuid \
    THRED_API_KEY=your-key \
    THRED_ENV=sandbox \
    npx thred-mcp
    ```

    On success it logs `Thred MCP server running on stdio` to stderr. You can also point the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) at this command.
  </Tab>
</Tabs>

## Tool catalog

The server exposes **50 tools** across 9 categories. Every tool requires a `business_id` (resolve it first with `list_businesses`). Tools are tagged **R** (read) or **W** (write); write tools should be confirmed with the user before execution.

<AccordionGroup>
  <Accordion title="Businesses (5)" icon="building">
    | Tool               | Type | Purpose                                                                                                                  |
    | ------------------ | ---- | ------------------------------------------------------------------------------------------------------------------------ |
    | `list_businesses`  | R    | List all businesses under the partner — the entry point for resolving `business_id`                                      |
    | `get_business`     | R    | Fetch a single business                                                                                                  |
    | `create_business`  | W    | Onboard a new business with Friday fields: `external_id`, `legal_name`, `entity_type`, `email`, optional `base_currency` |
    | `update_business`  | W    | Update mutable details only; no-op updates are rejected before calling the API                                           |
    | `archive_business` | W    | Archive a business                                                                                                       |
  </Accordion>

  <Accordion title="Customers (6)" icon="user">
    | Tool                 | Type | Purpose                                                                         |
    | -------------------- | ---- | ------------------------------------------------------------------------------- |
    | `list_customers`     | R    | List / search customers — used to match a name to a `customer_id`               |
    | `get_customer`       | R    | Fetch a single customer                                                         |
    | `create_customer`    | W    | Create a customer (`company_name` for businesses, `individual_name` for people) |
    | `update_customer`    | W    | Update a customer                                                               |
    | `archive_customer`   | W    | Archive a customer                                                              |
    | `unarchive_customer` | W    | Restore an archived customer                                                    |
  </Accordion>

  <Accordion title="Invoices (6)" icon="file-invoice">
    | Tool             | Type | Purpose                                                                          |
    | ---------------- | ---- | -------------------------------------------------------------------------------- |
    | `list_invoices`  | R    | List invoices, filterable by status (`draft`, `sent`, `paid`, `overdue`, `void`) |
    | `list_tax_codes` | R    | List valid tax/VAT codes for invoice line items                                  |
    | `get_invoice`    | R    | Fetch a single invoice                                                           |
    | `create_invoice` | W    | Create an invoice for a customer; line items may include `tax_code`              |
    | `update_invoice` | W    | Update an invoice; line items may include `tax_code`                             |
    | `void_invoice`   | W    | Void an invoice (irreversible)                                                   |
  </Accordion>

  <Accordion title="Invoice Payments (5)" icon="money-bill">
    | Tool                     | Type | Purpose                                      |
    | ------------------------ | ---- | -------------------------------------------- |
    | `list_invoice_payments`  | R    | List payments recorded against invoices      |
    | `get_invoice_payment`    | R    | Fetch a single payment                       |
    | `create_invoice_payment` | W    | Record a payment against an invoice          |
    | `update_invoice_payment` | W    | Update a recorded payment                    |
    | `delete_invoice_payment` | W    | Delete a payment (reverts invoice to unpaid) |
  </Accordion>

  <Accordion title="Vendors (6)" icon="truck">
    | Tool               | Type | Purpose                                                       |
    | ------------------ | ---- | ------------------------------------------------------------- |
    | `list_vendors`     | R    | List / search vendors — used to match a name to a `vendor_id` |
    | `get_vendor`       | R    | Fetch a single vendor                                         |
    | `create_vendor`    | W    | Create a vendor                                               |
    | `update_vendor`    | W    | Update a vendor                                               |
    | `archive_vendor`   | W    | Archive a vendor                                              |
    | `unarchive_vendor` | W    | Restore an archived vendor                                    |
  </Accordion>

  <Accordion title="Bills & Bill Payments (10)" icon="receipt">
    | Tool                  | Type | Purpose                                      |
    | --------------------- | ---- | -------------------------------------------- |
    | `list_bills`          | R    | List bills (accounts payable / vendor spend) |
    | `get_bill`            | R    | Fetch a single bill                          |
    | `create_bill`         | W    | Record a bill from a vendor                  |
    | `update_bill`         | W    | Update a bill                                |
    | `void_bill`           | W    | Void a bill                                  |
    | `list_bill_payments`  | R    | List payments made against bills             |
    | `get_bill_payment`    | R    | Fetch a single bill payment                  |
    | `create_bill_payment` | W    | Record a payment against a bill              |
    | `update_bill_payment` | W    | Update a bill payment                        |
    | `delete_bill_payment` | W    | Delete a bill payment                        |
  </Accordion>

  <Accordion title="Chart of Accounts (6)" icon="sitemap">
    | Tool                              | Type | Purpose                                             |
    | --------------------------------- | ---- | --------------------------------------------------- |
    | `list_chart_of_accounts`          | R    | List all ledger accounts                            |
    | `get_chart_of_accounts_hierarchy` | R    | Get the account tree (preferred for categorization) |
    | `get_account`                     | R    | Fetch a single account                              |
    | `create_account`                  | W    | Create a ledger account                             |
    | `update_account`                  | W    | Update an account                                   |
    | `archive_account`                 | W    | Archive an account                                  |
  </Accordion>

  <Accordion title="Financial Reports (6)" icon="chart-line">
    | Tool                    | Type | Purpose                                                                        |
    | ----------------------- | ---- | ------------------------------------------------------------------------------ |
    | `get_profit_and_loss`   | R    | P\&L over a date range (`start_date`, `end_date`)                              |
    | `get_balance_sheet`     | R    | Balance sheet as of a date (`as_of_date`)                                      |
    | `get_cash_flow`         | R    | Cash flow statement over a date range                                          |
    | `get_ar_aging`          | R    | Accounts receivable aging                                                      |
    | `get_ap_aging`          | R    | Accounts payable aging                                                         |
    | `get_financial_summary` | R    | High-level financial insights over an explicit `start_date` / `end_date` range |
  </Accordion>
</AccordionGroup>

## Tested Payloads

These payloads match the current MCP contract tests and Friday Partner API behavior.

### Create business

```json theme={null}
{
  "external_id": "partner-biz-001",
  "legal_name": "Acme Solutions B.V.",
  "entity_type": "bv",
  "email": "finance@acme.example",
  "country": "NL",
  "base_currency": "EUR",
  "accounting_method": "accrual",
  "vat_number": "NL123456789B01",
  "company_number": "12345678",
  "metadata": {
    "source": "mcp"
  },
  "coa_language": "en"
}
```

### Update business

`update_business` sends only mutable Friday fields. `country`, `external_id`, and `base_currency` are not sent by this tool.

```json theme={null}
{
  "business_id": "business-id",
  "legal_name": "Acme Solutions Updated B.V.",
  "vat_number": "NL987654321B01",
  "email": "ops@acme.example",
  "metadata": {
    "reviewed": true
  }
}
```

### Create invoice with tax code

```json theme={null}
{
  "business_id": "business-id",
  "external_id": "invoice-ext-001",
  "customer_id": "customer-id",
  "invoice_number": "INV-2026-001",
  "sent_at": "2026-06-11T10:00:00Z",
  "due_at": "2026-07-11T10:00:00Z",
  "line_items": [
    {
      "external_id": "line-ext-001",
      "description": "Consulting services",
      "quantity": 1,
      "unit_price": 10000,
      "tax_code": "BTW_21"
    }
  ]
}
```

### Financial summary

`get_financial_summary` requires explicit dates; missing `start_date` or `end_date` is rejected before the API call.

```json theme={null}
{
  "business_id": "business-id",
  "start_date": "2026-01-01",
  "end_date": "2026-06-30"
}
```

## Composed capabilities

Several product experiences are **not** single endpoints — the AI assistant orchestrates multiple atomic tools and composes the narrative, emails, or layout around the returned data:

| Capability                     | How it's composed                                                                                                                          |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **Board pack**                 | `get_profit_and_loss` (current + prior period) + `get_cash_flow` + `get_balance_sheet`, synthesized into a summary with runway             |
| **Natural-language dashboard** | Report tools called with date ranges derived from the user's phrasing ("last 6 months"), optionally across multiple periods for comparison |
| **Payment reminders**          | `list_invoices` (status `overdue`) → match customer → AI-composed reminder email                                                           |
| **Vendor outreach**            | `list_vendors` / `list_bills` → identify missing document → AI-composed request                                                            |

## Behavioral model

Tool descriptions are written to steer the model toward safe, useful behavior:

<Steps>
  <Step title="Confirmation">
    High-risk writes (`create_*`, `void_*`, `delete_*`) prompt for explicit user confirmation before executing.
  </Step>

  <Step title="Slot-filling">
    Missing required fields (amount, due date, line items) trigger follow-up questions rather than guesses.
  </Step>

  <Step title="Name matching">
    Customer/vendor names are resolved to IDs via the `list_*` tools — the model never fabricates an ID.
  </Step>

  <Step title="Action chaining">
    After an action, the next logical step is offered (e.g. invoice created → "send it?").
  </Step>
</Steps>

## Request lifecycle & errors

* **Transport:** JSON-RPC over stdio (`@modelcontextprotocol/sdk`).
* **Auth caching:** one token per process, refreshed \~5 minutes before `expires_in`.
* **Methods:** tools map to `GET` / `POST` / `PATCH` / `PUT` / `DELETE` on `/v1/platform/...`.
* **Errors:** non-2xx responses are returned to the model as `Error: API error <status> on <method> <path>: <body>` with `isError: true`, so the assistant can explain or retry. A `204 No Content` resolves to an empty result.

See [Error Handling](/implementation/error-handling), [Pagination](/implementation/pagination), and [Idempotency](/implementation/idempotency) for API-level behavior that applies to every tool call.

## Example prompts

```text theme={null}
"List the businesses in my Thred account."
"How is Acme Ltd doing this month?"
"Who is more than 30 days overdue, and send them a reminder."
"Create an invoice for Acme — €5,000, net 30."
"What did we spend per vendor last quarter?"
"Reconcile the €2,400 that just came in from Acme."
"Build my Q1 board pack — P&L vs. prior quarter, cash position, and runway."
```

<Card title="Source & package" icon="github" href="https://www.npmjs.com/package/thred-mcp">
  `thred-mcp` on npm · `npx thred-mcp`
</Card>
