# MCP tools (/docs/agents/tools)

Tools run as the signed-in member, in the team chosen when the client
connected, with that member's role. Each tool does the same as the matching
[REST API](/docs/api) endpoint and returns the same data, as both text and
structured content.

Tools that read data need the `read` scope and are marked read-only. Tools that
create or change data need the `write` scope. Data follows the
[API conventions](/docs/api#conventions): IDs are strings, amounts are decimal
strings, and absent values are `null`. List tools return
`{ "data": [...], "nextCursor": ... }`; pass `nextCursor` back as `cursor` for
the next page.

| Tool | Scope | REST equivalent |
| --- | --- | --- |
| [`get_team`](#get_team) | `read` | `GET /v1/team` |
| [`list_contacts`](#list_contacts) | `read` | `GET /v1/contacts` |
| [`get_contact`](#get_contact) | `read` | `GET /v1/contacts/{contactId}` |
| [`create_contact`](#create_contact) | `write` | `POST /v1/contacts` |
| [`update_contact`](#update_contact) | `write` | `PATCH /v1/contacts/{contactId}` |
| [`list_categories`](#list_categories) | `read` | `GET /v1/categories` |
| [`create_category`](#create_category) | `write` | `POST /v1/categories` |
| [`list_bank_accounts`](#list_bank_accounts) | `read` | `GET /v1/bank-accounts` |
| [`list_transactions`](#list_transactions) | `read` | `GET /v1/transactions` |
| [`get_transaction`](#get_transaction) | `read` | `GET /v1/transactions/{transactionId}` |
| [`update_transaction`](#update_transaction) | `write` | `PATCH /v1/transactions/{transactionId}` |
| [`list_invoices`](#list_invoices) | `read` | `GET /v1/invoices` |
| [`get_invoice`](#get_invoice) | `read` | `GET /v1/invoices/{invoiceId}` |
| [`create_invoice_draft`](#create_invoice_draft) | `write` | `POST /v1/invoices` |
| [`update_invoice_draft`](#update_invoice_draft) | `write` | `PATCH /v1/invoices/{invoiceId}` |
| [`delete_invoice_draft`](#delete_invoice_draft) | `write` | `DELETE /v1/invoices/{invoiceId}` |
| [`get_invoice_settings`](#get_invoice_settings) | `read` | `GET /v1/invoice-settings` |
| [`list_expenses`](#list_expenses) | `read` | `GET /v1/expenses` |
| [`get_expense`](#get_expense) | `read` | `GET /v1/expenses/{expenseId}` |
| [`update_expense`](#update_expense) | `write` | `PATCH /v1/expenses/{expenseId}` |
| [`list_projects`](#list_projects) | `read` | `GET /v1/projects` |
| [`get_project`](#get_project) | `read` | `GET /v1/projects/{projectId}` |
| [`create_project`](#create_project) | `write` | `POST /v1/projects` |
| [`update_project`](#update_project) | `write` | `PATCH /v1/projects/{projectId}` |
| [`list_time_tasks`](#list_time_tasks) | `read` | `GET /v1/projects/{projectId}/tasks` |
| [`create_time_task`](#create_time_task) | `write` | `POST /v1/projects/{projectId}/tasks` |
| [`list_time_entries`](#list_time_entries) | `read` | `GET /v1/time-entries` |
| [`create_time_entry`](#create_time_entry) | `write` | `POST /v1/time-entries` |
| [`update_time_entry`](#update_time_entry) | `write` | `PATCH /v1/time-entries/{entryId}` |
| [`delete_time_entry`](#delete_time_entry) | `write` | `DELETE /v1/time-entries/{entryId}` |
| [`get_timer`](#get_timer) | `read` | `GET /v1/timer` |
| [`start_timer`](#start_timer) | `write` | `POST /v1/timer/start` |
| [`stop_timer`](#stop_timer) | `write` | `POST /v1/timer/stop` |

## Team [#team]

### `get_team` [#get_team]

Returns the team (workspace) the connection acts in.

| Property | Value |
| --- | --- |
| Arguments | None |
| Scope | `read` |
| REST equivalent | `GET /v1/team` |

### Team [#team-1]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Team ID |
| `name` | string | Team name |
| `email` | string or null | Contact email |
| `taxId` | string or null | Tax identification number |
| `address` | string or null | Street address |
| `zipCode` | string or null | Postal code |
| `city` | string or null | City |
| `state` | string or null | State or region |
| `country` | string | ISO 3166-1 alpha-2 country code, such as `PT` |
| `timeZone` | string | IANA time zone, such as `Europe/Lisbon` |
| `website` | string or null | Website URL |
| `logoUrl` | string or null | URL of the team logo |
| `role` | `owner`, `admin`, or `member` | Your role in the team |

## Contacts [#contacts]

Contacts are the people and organizations the team pays (payees) or bills
(clients).

### `list_contacts` [#list_contacts]

Lists contacts by name, or by relevance when `search` is set.

| Property | Value |
| --- | --- |
| Arguments | `search`, `role` (`client` or `payee`), `limit`, `cursor` |
| Scope | `read` |
| REST equivalent | `GET /v1/contacts` |

### `get_contact` [#get_contact]

Returns one contact.

| Property | Value |
| --- | --- |
| Arguments | `contactId` |
| Scope | `read` |
| REST equivalent | `GET /v1/contacts/{contactId}` |

### `create_contact` [#create_contact]

Creates a contact. If the team already has a contact with the same tax ID and
country, email, or legal name, that contact is returned instead.

| Property | Value |
| --- | --- |
| Arguments | `name` (required), `entityType`, `industry`, `isClient`, `isPayee`, and any [contact field](#contact) below |
| Scope | `write` |
| REST equivalent | `POST /v1/contacts` |

### `update_contact` [#update_contact]

Changes the fields sent. `null` clears an optional field; `bankAccount` and
`billing` replace the whole object.

| Property | Value |
| --- | --- |
| Arguments | `contactId` and any field to change |
| Scope | `write` |
| REST equivalent | `PATCH /v1/contacts/{contactId}` |

### Contact [#contact]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Contact ID |
| `name` | string | Display name |
| `legalName` | string | Registered name |
| `entityType` | string | `organization`, `individual`, `government`, `nonprofit`, or `other` |
| `industry` | string | Industry, such as `software_and_cloud` |
| `isClient` | boolean | Whether the team bills this contact |
| `isPayee` | boolean | Whether the team pays this contact |
| `email`, `phone`, `website` | string or null | Contact details |
| `address`, `city`, `state`, `zipCode` | string or null | Postal address |
| `country` | string or null | ISO 3166-1 alpha-2 country code |
| `taxId` | string or null | Tax identification number |
| `note` | string or null | Internal note |
| `categoryId` | string or null | Default category for the contact's transactions |
| `bankAccount` | object or null | `bankName`, `country`, `currency`, `accountNumber`, `accountNumberType` (`iban` or `local`), `bic` |
| `billing` | object or null | For clients: `email`, `bccEmails`, `address`, `city`, `state`, `zipCode`, `country`, `defaultCurrency`, `paymentTermsDays`, `reference`, `portalEnabled` |
| `createdAt` | string | ISO 8601 timestamp |

## Categories [#categories]

Accounting categories classify transactions, contacts and invoices. Only team
owners and admins can create them.

### `list_categories` [#list_categories]

Lists the team's categories, grouped by type and sorted by name. A team has at
most 100 categories, so `nextCursor` is always `null`.

| Property | Value |
| --- | --- |
| Arguments | `includeArchived` (boolean, default `false`): also return archived categories |
| Scope | `read` |
| REST equivalent | `GET /v1/categories` |

### `create_category` [#create_category]

Creates a custom category and returns it. Fails with
`CATEGORY_MANAGEMENT_FORBIDDEN` for members and `CATEGORY_LIMIT_REACHED` when
the team already has 100 categories.

| Property | Value |
| --- | --- |
| Arguments | `name` (required, up to 100 characters), `description` (required, up to 240 characters), `type` (required: `income`, `expense`, `asset`, `tax`, `financing`, `owner`, `transfer` or `other`), `accountingCode` (up to 32 characters) |
| Scope | `write` |
| REST equivalent | `POST /v1/categories` |

### Category [#category]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Category ID |
| `name` | string | Category name |
| `description` | string or null | What belongs in the category |
| `type` | `income`, `expense`, `asset`, `tax`, `financing`, `owner`, `transfer`, or `other` | Accounting type |
| `accountingCode` | string or null | Code in the accountant's chart of accounts |
| `archived` | boolean | Whether the category is archived |
| `systemRole` | `internal_transfer` or null | Workflow role of a required category; `null` for ordinary categories |

## Bank accounts [#bank-accounts]

### `list_bank_accounts` [#list_bank_accounts]

Lists the team's bank accounts with their account number, currency and last
reported balance. All accounts come back in one page, so `nextCursor` is always
`null`.

| Property | Value |
| --- | --- |
| Arguments | None |
| Scope | `read` |
| REST equivalent | `GET /v1/bank-accounts` |

### Bank account [#bank-account]

Each item in `data`:

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Bank account ID; use it as `bankAccountId` to filter transactions |
| `displayName` | string or null | Name the team gave the account |
| `accountHolderName` | string or null | Account holder |
| `bankName` | string or null | Bank name |
| `accountType` | string or null | Account nature, such as `current`, `savings` or `card` |
| `accountNumber` | string or null | Account number, such as an IBAN |
| `accountNumberType` | string or null | `iban`, `bban`, `sort-code-account-number`, `us-routing-account-number`, `pan`, `masked-pan`, `msisdn` or `other` |
| `bic` | string or null | Swift/BIC code |
| `currency` | string or null | ISO 4217 currency code |
| `balance` | string or null | Last balance the bank reported, as a decimal string in `currency` |

## Transactions [#transactions]

### `list_transactions` [#list_transactions]

Lists the team's booked bank transactions, newest first. Archived transactions
are left out unless `archived` is `true`. A page can hold fewer items than
`limit` before the last one, so keep following `nextCursor` until it is `null`.

| Property | Value |
| --- | --- |
| Arguments | `search`, `bankAccountId`, `categoryId` (an ID or `uncategorized`), `projectId`, `dateFrom`, `dateTo` (`YYYY-MM-DD`), `direction` (`credit` or `debit`), `status`, `archived`, `limit` (1–100, default 25), `cursor`; all optional |
| Scope | `read` |
| REST equivalent | `GET /v1/transactions` |

### `get_transaction` [#get_transaction]

Returns one transaction with its category, contact, project, note and
bookkeeping status.

| Property | Value |
| --- | --- |
| Arguments | `transactionId` |
| Scope | `read` |
| REST equivalent | `GET /v1/transactions/{transactionId}` |

### `update_transaction` [#update_transaction]

Sets the category, contact, project, note or archive flag of a transaction and
keeps the fields not sent; `null` clears one. A category on one side of a linked
transfer applies to both sides, debits cannot take income categories, and
transfer categories cannot be combined with a project. Setting or clearing
`projectId` needs the owner or admin role.

| Property | Value |
| --- | --- |
| Arguments | `transactionId`; optional `categoryId`, `note` (up to 500 characters), `contactId`, `projectId`, `archived` |
| Scope | `write` |
| REST equivalent | `PATCH /v1/transactions/{transactionId}` |

### Transaction [#transaction]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Transaction ID |
| `date` | string | Booking date, `YYYY-MM-DD` |
| `direction` | `credit`, `debit`, or `unknown` | Whether money came in or went out |
| `amount` | string | Absolute amount as a decimal string in `currency` |
| `currency` | string | Account currency |
| `instructedAmount` | string or null | Original amount when paid in another currency |
| `instructedCurrency` | string or null | Currency of `instructedAmount` |
| `title` | string or null | Display title, usually the counterparty |
| `subtitle` | string or null | Secondary description |
| `bankAccountId` | string | Bank account ID |
| `categoryId` | string or null | Category ID |
| `contactId` | string or null | Counterparty contact ID |
| `contactName` | string or null | Counterparty contact name |
| `projectId` | string or null | Project ID |
| `note` | string or null | Team note |
| `status` | `uncategorized`, `in_progress`, `complete`, `needs_review`, or `no_impact` | Bookkeeping status |
| `reconciliationStatus` | string or null | `unmatched`, `partial`, `matched`, `difference_accepted` or `review` |
| `internal` | boolean | A transfer between the team's own accounts |
| `archived` | boolean | Hidden from default lists |
| `createdAt` | string | ISO 8601 time Osorik first imported it |

## Invoices [#invoices]

Outgoing invoices the team bills its clients. Agents can read every invoice
and create, change and delete drafts. Issuing, voiding and sending invoices
stays in Osorik. Amounts are decimal strings in the invoice currency, such as
`1250.00`.

### `list_invoices` [#list_invoices]

Lists invoices without their lines, newest first or by relevance when `search` is set.

| Property | Value |
| --- | --- |
| Arguments | `status` (optional array of `draft`, `issuing`, `issue_failed`, `issued`, `void`), `clientId` (optional), `search` (optional), `limit` (1 to 100, default 25), `cursor` (optional) |
| Scope | `read` |
| REST equivalent | `GET /v1/invoices` |

Returns `{ data, nextCursor }`, where `data` is a list of
[invoices](#invoice) and `nextCursor` is `null` on the last page.

### `get_invoice` [#get_invoice]

Returns one invoice with its lines and, once it is issued, a PDF download URL.

| Property | Value |
| --- | --- |
| Arguments | `invoiceId` |
| Scope | `read` |
| REST equivalent | `GET /v1/invoices/{invoiceId}` |

Returns an [invoice with lines](#invoice-with-lines).

### `create_invoice_draft` [#create_invoice_draft]

Creates an unnumbered invoice draft for a client, filling left-out fields from the client's billing defaults and the team's invoice settings.

| Property | Value |
| --- | --- |
| Arguments | `title`, `clientId`, `lines` (1 to 200 of `{ description, quantity, unitPrice }`), `issueDate`, and optional `categoryId`, `bankAccountId`, `currency`, `dueDate`, `discountPercentage` (0 to 100), `note` |
| Scope | `write` |
| REST equivalent | `POST /v1/invoices` |

`quantity` and `unitPrice` are decimal strings with up to 6 decimals.
Left-out fields default as in the invoice editor:

- `currency`: the client's currency, then the bank account's currency, then
  the team currency.
- `dueDate`: `issueDate` plus the client's payment terms, then the settings'
  payment terms (30 days unless changed).
- `categoryId`: the settings' category. It must be an active income category.
- `bankAccountId`: the settings' account, then the first account with payment
  instructions.
- `note`: the settings' note.

Returns the new [invoice with lines](#invoice-with-lines).

### `update_invoice_draft` [#update_invoice_draft]

Changes the fields sent on a draft and keeps the rest; `lines` replaces every line.

| Property | Value |
| --- | --- |
| Arguments | `invoiceId`, and any of `title`, `clientId`, `lines`, `issueDate`, `dueDate`, `categoryId`, `bankAccountId`, `currency`, `discountPercentage`, `note` |
| Scope | `write` |
| REST equivalent | `PATCH /v1/invoices/{invoiceId}` |

`null` clears `discountPercentage` or `note`. Invoices that are no longer
drafts fail with `INVOICE_IMMUTABLE`. Returns the updated
[invoice with lines](#invoice-with-lines).

### `delete_invoice_draft` [#delete_invoice_draft]

Permanently deletes a draft that was never numbered, with its lines.

| Property | Value |
| --- | --- |
| Arguments | `invoiceId` |
| Scope | `write` |
| REST equivalent | `DELETE /v1/invoices/{invoiceId}` |

Returns `{ id, deleted: true }`. Issued, voided and numbered invoices fail with
`INVOICE_IMMUTABLE`.

### `get_invoice_settings` [#get_invoice_settings]

Returns the team's invoice number prefix and the defaults new drafts use.

| Property | Value |
| --- | --- |
| Arguments | None |
| Scope | `read` |
| REST equivalent | `GET /v1/invoice-settings` |

### Invoice [#invoice]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Invoice ID |
| `number` | string or null | Invoice number, such as `INV-2026-0001`; `null` for drafts |
| `title` | string | Invoice title |
| `status` | `draft`, `issuing`, `issue_failed`, `issued`, or `void` | Lifecycle state; only drafts can be changed or deleted |
| `deliveryStatus` | `not_sent`, `queued`, `sent`, or `failed` | Email delivery state |
| `paymentStatus` | `unmatched`, `partial`, `matched`, `difference_accepted`, or `review` | How far bank payments cover the total |
| `clientId` | string | Contact the invoice bills |
| `clientName` | string | Client name, frozen when the invoice is issued |
| `categoryId` | string | Income category ID |
| `bankAccountId` | string | ID of the bank account the client pays into |
| `currency` | string | ISO 4217 currency code, such as `EUR` |
| `issueDate` | string | Issue date as `YYYY-MM-DD` |
| `dueDate` | string | Due date as `YYYY-MM-DD` |
| `discountPercentage` | number or null | Discount on the line subtotal, from 0 to 100 |
| `discountAmount` | string or null | Discount amount; `null` without a discount |
| `totalAmount` | string | Total after discount |
| `paidAmount` | string | Amount matched to bank payments so far |
| `note` | string or null | Note printed on the invoice |
| `issuedAt` | string or null | When the invoice was issued, ISO 8601 |
| `voidedAt` | string or null | When the invoice was voided, ISO 8601 |
| `createdAt` | string | When the invoice was created, ISO 8601 |
| `updatedAt` | string | When the invoice last changed, ISO 8601 |

### Invoice with lines [#invoice-with-lines]

Every [invoice](#invoice) field, plus:

| Field | Type | Description |
| --- | --- | --- |
| `lines` | array | Invoice lines in order, each with the fields below |
| `lines[].description` | string | Line description |
| `lines[].quantity` | string | Decimal quantity |
| `lines[].unitPrice` | string | Decimal unit price |
| `lines[].lineTotal` | string | Quantity times unit price, rounded to the currency |
| `pdfUrl` | string or null | Temporary download URL of the issued PDF; `null` until it is rendered |

### Invoice settings [#invoice-settings]

| Field | Type | Description |
| --- | --- | --- |
| `prefix` | string | Prefix of invoice numbers, such as `INV` |
| `defaultPaymentTermsDays` | number | Days from issue date to due date for new drafts |
| `defaultCategoryId` | string or null | Income category for new drafts |
| `defaultBankAccountId` | string or null | Bank account for new drafts |
| `defaultNote` | string or null | Note for new drafts |

## Expenses [#expenses]

### `list_expenses` [#list_expenses]

Lists the team's expenses, the bills and receipts it uploaded, newest first.
Archived expenses are left out unless `archived` is `true`. A page can hold
fewer items than `limit` before the last one, so keep following `nextCursor`
until it is `null`.

| Property | Value |
| --- | --- |
| Arguments | `status` (list of statuses), `archived`, `search`, `payeeId`, `limit` (1–100, default 25), `cursor`; all optional |
| Scope | `read` |
| REST equivalent | `GET /v1/expenses` |

### `get_expense` [#get_expense]

Returns one expense with its extracted details and a short-lived `documentUrl`
to download the uploaded document.

| Property | Value |
| --- | --- |
| Arguments | `expenseId` |
| Scope | `read` |
| REST equivalent | `GET /v1/expenses/{expenseId}` |

### `update_expense` [#update_expense]

Changes the fields sent and keeps the rest; `null` clears an optional field.
Details can change only while the expense is `unmatched` (otherwise
`EXPENSE_NOT_EDITABLE`); `archived` can change in any status.

| Property | Value |
| --- | --- |
| Arguments | `expenseId`; optional `payeeId`, `reference`, `date`, `dueDate`, `currency`, `amount`, `taxType`, `taxAmount`, `archived` |
| Scope | `write` |
| REST equivalent | `PATCH /v1/expenses/{expenseId}` |

### Expense [#expense]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Expense ID |
| `status` | `processing`, `failed`, `unmatched`, `partial`, `matched`, or `difference_accepted` | Document reading and matching state |
| `payeeId` | string or null | Payee contact ID |
| `payeeName` | string or null | Payee name |
| `reference` | string or null | Invoice or receipt number |
| `date` | string or null | Issue date, `YYYY-MM-DD` |
| `dueDate` | string or null | Due date, `YYYY-MM-DD` |
| `currency` | string or null | ISO 4217 currency code |
| `amount` | string or null | Total including tax, as a decimal string |
| `taxType` | string or null | Tax kind, such as `vat` |
| `taxAmount` | string or null | Tax amount, as a decimal string |
| `reconciledAmount` | string | Part of `amount` matched to bank transactions |
| `archived` | boolean | Hidden from default lists |
| `documentId` | string | ID of the uploaded document |
| `extractionError` | string or null | Why reading the document failed |
| `createdAt` | string | ISO 8601 upload time |
| `documentUrl` | string or null | `get_expense` only: short-lived link to the document |

## Projects [#projects]

Projects group client or internal work for time tracking and cash flow. Every
member can read them; only team owners and admins can create or change them.

### `list_projects` [#list_projects]

Lists the team's projects, most recently updated first, or by relevance when
`search` is set.

| Property | Value |
| --- | --- |
| Arguments | `status` (`planned`, `active`, `on_hold`, `completed` or `cancelled`), `clientId`, `search`, `limit` (1 to 100, default 25), `cursor` |
| Scope | `read` |
| REST equivalent | `GET /v1/projects` |

### `get_project` [#get_project]

Returns one project with its assigned team members. Members' hourly rates are
shown only to owners and admins.

| Property | Value |
| --- | --- |
| Arguments | `projectId` (required) |
| Scope | `read` |
| REST equivalent | `GET /v1/projects/{projectId}` |

### `create_project` [#create_project]

Creates a project in the `planned` state, assigns you to it at `billableRate`
and returns it with its members. `clientId` must be a contact marked as a
client.

| Property | Value |
| --- | --- |
| Arguments | `name` (required, up to 120 characters), `currency` (required, ISO 4217), `billableRate` (required decimal string, `0` when not charged), `description`, `clientId`, `startDate`, `targetEndDate` (on or after `startDate`), `timeRoundingMinutes` (`0`, `5`, `10`, `15` or `30`, default `15`) |
| Scope | `write` |
| REST equivalent | `POST /v1/projects` |

### `update_project` [#update_project]

Changes the fields sent and keeps the rest; `null` clears `description`,
`clientId`, `startDate` or `targetEndDate`. `completed` and `cancelled` close
the project. A closed project must be reopened before its other fields change,
which can happen in the same call. The client and currency cannot change once
time is tracked (`PROJECT_TIME_IDENTITY_LOCKED`).

| Property | Value |
| --- | --- |
| Arguments | `projectId` (required), `name`, `description`, `clientId`, `currency`, `startDate`, `targetEndDate`, `timeRoundingMinutes`, `status` |
| Scope | `write` |
| REST equivalent | `PATCH /v1/projects/{projectId}` |

### Project [#project]

`list_projects` returns these fields; `get_project`, `create_project` and
`update_project` add `members`.

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Project ID |
| `name` | string | Project name |
| `description` | string or null | Project description |
| `status` | `planned`, `active`, `on_hold`, `completed`, or `cancelled` | Lifecycle state |
| `clientId` | string or null | Client contact ID; `null` for internal work |
| `currency` | string | ISO 4217 currency code |
| `startDate` | string or null | Start date, `YYYY-MM-DD` |
| `targetEndDate` | string or null | Planned end date, `YYYY-MM-DD` |
| `timeRoundingMinutes` | `0`, `5`, `10`, `15`, `30`, or null | Rounding applied to billable time entries |
| `closedAt` | string or null | When the project was completed or cancelled (ISO 8601) |
| `createdAt` | string | Creation time (ISO 8601) |
| `updatedAt` | string | Last change (ISO 8601) |
| `members` | array of ProjectMember | Assigned team members (single-project tools only) |

### Project member [#project-member]

| Field | Type | Description |
| --- | --- | --- |
| `userId` | string | User ID of the member |
| `name` | string or null | Member's name |
| `billableRate` | string or null | Hourly rate as a decimal string in the project currency; `null` unless you are an owner or admin |

## Time [#time]

Time is tracked against reusable tasks on projects. Members log time only on
projects they are assigned to, and see and change only their own entries;
owners and admins see everyone's entries and billable rates.

### `list_time_tasks` [#list_time_tasks]

Lists a project's tasks, up to 200, on a single page (`nextCursor` is always
`null`). Archived tasks are left out unless `includeArchived` is `true`.

| Property | Value |
| --- | --- |
| Arguments | `projectId` (required), `includeArchived` |
| Scope | `read` |
| REST equivalent | `GET /v1/projects/{projectId}/tasks` |

### `create_time_task` [#create_time_task]

Adds a task to an open project. Task names are unique within a project,
ignoring case and spacing, and a project holds at most 200 tasks.

| Property | Value |
| --- | --- |
| Arguments | `projectId`, `name` (required); `description` |
| Scope | `write` |
| REST equivalent | `POST /v1/projects/{projectId}/tasks` |

### `list_time_entries` [#list_time_entries]

Lists entries that start between `from` and `to`, which can be at most 62 days
apart. Returns up to 1000 entries; `truncated` is `true` when more matched, so
narrow the range or add filters. Members always get only their own entries.

| Property | Value |
| --- | --- |
| Arguments | `from`, `to` (required, ISO 8601 date-times); `projectId`, `clientId`, `memberId` (owners and admins), `taskId`, `billable` |
| Scope | `read` |
| REST equivalent | `GET /v1/time-entries` |

### `create_time_entry` [#create_time_entry]

Records completed time for you on an active task of a project you are assigned
to. Billable minutes follow the project's rounding, and billable time takes
your project rate, which must be set.

| Property | Value |
| --- | --- |
| Arguments | `projectId`, `taskId`, `startAt`, `endAt` (ISO 8601 date-times), `billable`, all required |
| Scope | `write` |
| REST equivalent | `POST /v1/time-entries` |

### `update_time_entry` [#update_time_entry]

Changes the fields sent on a completed entry and recalculates its minutes and
rate. Owners and admins can move an entry to another assigned member with
`memberId`. Stop a running timer before editing it.

| Property | Value |
| --- | --- |
| Arguments | `entryId` and any of `projectId`, `taskId`, `startAt`, `endAt`, `billable`, `memberId` |
| Scope | `write` |
| REST equivalent | `PATCH /v1/time-entries/{entryId}` |

### `delete_time_entry` [#delete_time_entry]

Permanently deletes a time entry and returns `{ id, deleted: true }`.

| Property | Value |
| --- | --- |
| Arguments | `entryId` |
| Scope | `write` |
| REST equivalent | `DELETE /v1/time-entries/{entryId}` |

### `get_timer` [#get_timer]

Returns your running timer as `{ entry }`, with `entry: null` when none is
running. Each member has at most one timer.

| Property | Value |
| --- | --- |
| Arguments | None |
| Scope | `read` |
| REST equivalent | `GET /v1/timer` |

### `start_timer` [#start_timer]

Starts a timer for you now and returns the running entry. Fails with
`TIME_TIMER_RUNNING` when one is already running.

| Property | Value |
| --- | --- |
| Arguments | `projectId`, `taskId`, `billable`, all required |
| Scope | `write` |
| REST equivalent | `POST /v1/timer/start` |

### `stop_timer` [#stop_timer]

Stops your running timer now and returns the completed entry. Fails with
`TIME_TIMER_NOT_FOUND` when no timer is running.

| Property | Value |
| --- | --- |
| Arguments | None |
| Scope | `write` |
| REST equivalent | `POST /v1/timer/stop` |

### Time task [#time-task]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Task ID |
| `projectId` | string | Project the task belongs to |
| `name` | string | Task name |
| `description` | string or null | Description |
| `archived` | boolean | Archived tasks keep their history but take no new time |

### Time entry [#time-entry]

| Field | Type | Description |
| --- | --- | --- |
| `id` | string | Entry ID |
| `projectId` | string | Project ID |
| `projectName` | string or null | Project name |
| `taskId` | string | Task ID |
| `taskName` | string or null | Task name |
| `clientId`, `clientName` | string or null | Client of the project; `null` for internal projects |
| `member` | object | `id` and `name` of the member the time belongs to |
| `status` | string | `running` or `completed` |
| `startAt` | string | ISO 8601 timestamp |
| `endAt` | string or null | ISO 8601 timestamp; `null` while running |
| `actualMinutes` | number or null | Tracked minutes; `null` while running |
| `billableMinutes` | number or null | Minutes after the project's rounding; `null` while running |
| `billable` | boolean | Whether the time is billable |
| `billableRate` | string or null | Hourly rate as a decimal string, such as `100.00`; `null` for non-billable time and for members |
| `currency` | string | ISO 4217 currency code of the rate |

## Errors [#errors]

When a tool fails, the result has `isError: true` and a text message in the
form `CODE: message`, such as
`INSUFFICIENT_SCOPE: This requires the "write" scope.` or
`PROJECT_MANAGEMENT_FORBIDDEN: Only owners and admins can manage projects.`
See the [error codes](/docs/api#errors).
