Read time entries, projects, clients, tasks and invoices; log and update tracked time.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Create a time entry. Requires project_id, task_id and spent_date. Provide `hours` to log a specific duration; OR provide `started_time` (+ optional `ended_time`) for a timestamped entry; OR omit both to start a running timer (on a timestamp-tracking account). Use harvest_list_project_assignments to find valid project_id + task_id. Harvest REST: POST /time_entries. WRITE — creates data.
The task id within the project (required).
The project id to log time against (required).
The date the time was spent, yyyy-mm-dd (required).
Duration in decimal hours, e.g. 1.5. Omit to start a running timer.
Notes for the time entry.
Log on behalf of another user (defaults to the authenticated user; requires permission).
End time for a timestamped entry, e.g. '9:30am'.
Start time for a timestamped entry, e.g. '8:00am'.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
Create a time entry. Requires project_id, task_id and spent_date. Provide `hours` to log a specific duration; OR provide `started_time` (+ optional `ended_time`) for a timestamped entry; OR omit both to start a running timer (on a timestamp-tracking account). Use harvest_list_project_assignments to find valid project_id + task_id. Harvest REST: POST /time_entries. WRITE — creates data.
| Argument | Type | Description |
|---|---|---|
| hours | number | Duration in decimal hours, e.g. 1.5. Omit to start a running timer. |
| notes | string | Notes for the time entry. |
| task_id* | integer | The task id within the project (required). |
| user_id | integer | Log on behalf of another user (defaults to the authenticated user; requires permission). |
| ended_time | string | End time for a timestamped entry, e.g. '9:30am'. |
| project_id* | integer | The project id to log time against (required). |
| spent_date* | string | The date the time was spent, yyyy-mm-dd (required). |
| started_time | string | Start time for a timestamped entry, e.g. '8:00am'. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"project_id",
"task_id",
"spent_date"
],
"properties": {
"hours": {
"type": "number",
"minimum": 0,
"description": "Duration in decimal hours, e.g. 1.5. Omit to start a running timer."
},
"notes": {
"type": "string",
"description": "Notes for the time entry."
},
"task_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The task id within the project (required).",
"exclusiveMinimum": 0
},
"user_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Log on behalf of another user (defaults to the authenticated user; requires permission).",
"exclusiveMinimum": 0
},
"ended_time": {
"type": "string",
"description": "End time for a timestamped entry, e.g. '9:30am'."
},
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The project id to log time against (required).",
"exclusiveMinimum": 0
},
"spent_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "The date the time was spent, yyyy-mm-dd (required)."
},
"started_time": {
"type": "string",
"description": "Start time for a timestamped entry, e.g. '8:00am'."
}
}
}Permanently delete a time entry by id. This cannot be undone. Harvest REST: DELETE /time_entries/{id}. WRITE — destroys data.
| Argument | Type | Description |
|---|---|---|
| time_entry_id* | integer | The time entry id to delete (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"time_entry_id"
],
"properties": {
"time_entry_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The time entry id to delete (required).",
"exclusiveMinimum": 0
}
}
}Retrieve a single client by id. Harvest REST: GET /clients/{id}.
| Argument | Type | Description |
|---|---|---|
| client_id* | integer | The client id (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"client_id"
],
"properties": {
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The client id (required).",
"exclusiveMinimum": 0
}
}
}Retrieve the company/account settings for the authenticated account (name, currency, time/date formats, week start, feature flags). Harvest REST: GET /company.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}Retrieve the currently authenticated user (whom the access token belongs to). Harvest REST: GET /users/me.
No arguments.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {}
}Retrieve a single invoice by id, including its line items. Harvest REST: GET /invoices/{id}.
| Argument | Type | Description |
|---|---|---|
| invoice_id* | integer | The invoice id (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"invoice_id"
],
"properties": {
"invoice_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The invoice id (required).",
"exclusiveMinimum": 0
}
}
}Retrieve a single project by id. Harvest REST: GET /projects/{id}.
| Argument | Type | Description |
|---|---|---|
| project_id* | integer | The project id (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"project_id"
],
"properties": {
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The project id (required).",
"exclusiveMinimum": 0
}
}
}Retrieve a single time entry by id. Harvest REST: GET /time_entries/{id}.
| Argument | Type | Description |
|---|---|---|
| time_entry_id* | integer | The time entry id (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"time_entry_id"
],
"properties": {
"time_entry_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The time entry id (required).",
"exclusiveMinimum": 0
}
}
}List clients, optionally filtered by active status or updated-since. Paginated. Harvest REST: GET /clients.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number (1-based) for pagination. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| is_active | boolean | Only active (true) or archived (false) clients. |
| updated_since | string | Only clients updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"is_active": {
"type": "boolean",
"description": "Only active (true) or archived (false) clients."
},
"updated_since": {
"type": "string",
"description": "Only clients updated since this ISO-8601 datetime."
}
}
}List estimates, optionally filtered by client, state, date range, or updated-since. Paginated. Harvest REST: GET /estimates.
| Argument | Type | Description |
|---|---|---|
| to | string | Only estimates issued on/before this date, yyyy-mm-dd. |
| from | string | Only estimates issued on/after this date, yyyy-mm-dd. |
| page | integer | Page number (1-based) for pagination. |
| state | string | Filter by estimate state: draft, sent, accepted or declined. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| client_id | integer | Filter to a single client id. |
| updated_since | string | Only estimates updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"to": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only estimates issued on/before this date, yyyy-mm-dd."
},
"from": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only estimates issued on/after this date, yyyy-mm-dd."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"state": {
"enum": [
"draft",
"sent",
"accepted",
"declined"
],
"type": "string",
"description": "Filter by estimate state: draft, sent, accepted or declined."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single client id.",
"exclusiveMinimum": 0
},
"updated_since": {
"type": "string",
"description": "Only estimates updated since this ISO-8601 datetime."
}
}
}List expenses, optionally filtered by user, client, project, date range, billed status, or updated-since. Paginated. Harvest REST: GET /expenses.
| Argument | Type | Description |
|---|---|---|
| to | string | Only expenses on/before this date, yyyy-mm-dd. |
| from | string | Only expenses on/after this date, yyyy-mm-dd. |
| page | integer | Page number (1-based) for pagination. |
| user_id | integer | Filter to a single user id. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| client_id | integer | Filter to a single client id. |
| is_billed | boolean | Only billed (true) or unbilled (false) expenses. |
| project_id | integer | Filter to a single project id. |
| updated_since | string | Only expenses updated since this ISO-8601 datetime. |
List invoices, optionally filtered by client, project, state, date range, or updated-since. Paginated. Harvest REST: GET /invoices.
| Argument | Type | Description |
|---|---|---|
| to | string | Only invoices issued on/before this date, yyyy-mm-dd. |
| from | string | Only invoices issued on/after this date, yyyy-mm-dd. |
| page | integer | Page number (1-based) for pagination. |
| state | string | Filter by invoice state: draft, open, paid or closed. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| client_id | integer | Filter to a single client id. |
| project_id | integer | Filter to a single project id. |
| updated_since | string | Only invoices updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"to": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only invoices issued on/before this date, yyyy-mm-dd."
},
"from": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only invoices issued on/after this date, yyyy-mm-dd."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"state": {
"enum": [
"draft",
"open",
"paid",
"closed"
],
"type": "string",
"description": "Filter by invoice state: draft, open, paid or closed."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single client id.",
"exclusiveMinimum": 0
},
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single project id.",
"exclusiveMinimum": 0
},
"updated_since": {
"type": "string",
"description": "Only invoices updated since this ISO-8601 datetime."
}
}
}List the authenticated user's active project assignments — the projects and their assignable tasks the current user can log time against (use this to find the project_id + task_id for harvest_create_time_entry). Paginated. Harvest REST: GET /users/me/project_assignments.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number (1-based) for pagination. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
}
}
}List projects, optionally filtered by active status or client, or updated-since. Paginated. Harvest REST: GET /projects.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number (1-based) for pagination. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| client_id | integer | Filter to a single client id. |
| is_active | boolean | Only active (true) or archived (false) projects. |
| updated_since | string | Only projects updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single client id.",
"exclusiveMinimum": 0
},
"is_active": {
"type": "boolean",
"description": "Only active (true) or archived (false) projects."
},
"updated_since": {
"type": "string",
"description": "Only projects updated since this ISO-8601 datetime."
}
}
}List tasks (the billable/non-billable work categories that can be assigned to projects), optionally filtered by active status or updated-since. Paginated. Harvest REST: GET /tasks.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number (1-based) for pagination. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| is_active | boolean | Only active (true) or archived (false) tasks. |
| updated_since | string | Only tasks updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"is_active": {
"type": "boolean",
"description": "Only active (true) or archived (false) tasks."
},
"updated_since": {
"type": "string",
"description": "Only tasks updated since this ISO-8601 datetime."
}
}
}List time entries, optionally filtered by user, project, client, task, date range, running/billed status, or updated-since. Paginated. Harvest REST: GET /time_entries.
| Argument | Type | Description |
|---|---|---|
| to | string | Only entries on/before this date, yyyy-mm-dd. |
| from | string | Only entries on/after this date, yyyy-mm-dd. |
| page | integer | Page number (1-based) for pagination. |
| task_id | integer | Filter to a single task id. |
| user_id | integer | Filter to a single user id. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| client_id | integer | Filter to a single client id. |
| is_billed | boolean | Only billed (true) or unbilled (false) entries. |
| is_running | boolean | Only running (true) or only stopped (false) entries. |
List users in the account, optionally filtered by active status or updated-since. Paginated. Harvest REST: GET /users.
| Argument | Type | Description |
|---|---|---|
| page | integer | Page number (1-based) for pagination. |
| per_page | integer | Results per page (1–2000, Harvest default 2000). |
| is_active | boolean | Only active (true) or archived (false) users. |
| updated_since | string | Only users updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"is_active": {
"type": "boolean",
"description": "Only active (true) or archived (false) users."
},
"updated_since": {
"type": "string",
"description": "Only users updated since this ISO-8601 datetime."
}
}
}Restart a previously stopped time entry, resuming its timer (error if it is already running). Harvest REST: PATCH /time_entries/{id}/restart. WRITE — modifies data.
| Argument | Type | Description |
|---|---|---|
| time_entry_id* | integer | The stopped time entry id to restart (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"time_entry_id"
],
"properties": {
"time_entry_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The stopped time entry id to restart (required).",
"exclusiveMinimum": 0
}
}
}Stop a currently running time entry (no-op error if it is already stopped). Harvest REST: PATCH /time_entries/{id}/stop. WRITE — modifies data.
| Argument | Type | Description |
|---|---|---|
| time_entry_id* | integer | The running time entry id to stop (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"time_entry_id"
],
"properties": {
"time_entry_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The running time entry id to stop (required).",
"exclusiveMinimum": 0
}
}
}Update an existing time entry's hours, notes, spent date, or project/task. Only the fields you provide are changed. Harvest REST: PATCH /time_entries/{id}. WRITE — modifies data.
| Argument | Type | Description |
|---|---|---|
| hours | number | Change the duration in decimal hours, e.g. 2.25. |
| notes | string | Change the notes. |
| task_id | integer | Reassign to a different task id. |
| ended_time | string | Change the end time, e.g. '9:30am'. |
| project_id | integer | Reassign to a different project id. |
| spent_date | string | Change the date, yyyy-mm-dd. |
| started_time | string | Change the start time, e.g. '8:00am'. |
| time_entry_id* | integer | The time entry id to update (required). |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"time_entry_id"
],
"properties": {
"hours": {
"type": "number",
"minimum": 0,
"description": "Change the duration in decimal hours, e.g. 2.25."
},
"notes": {
"type": "string",
"description": "Change the notes."
},
"task_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Reassign to a different task id.",
"exclusiveMinimum": 0
},
"ended_time": {
"type": "string",
"description": "Change the end time, e.g. '9:30am'."
},
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Reassign to a different project id.",
"exclusiveMinimum": 0
},
"spent_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Change the date, yyyy-mm-dd."
},
"started_time": {
"type": "string",
"description": "Change the start time, e.g. '8:00am'."
},
"time_entry_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "The time entry id to update (required).",
"exclusiveMinimum": 0
}
}
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"to": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only expenses on/before this date, yyyy-mm-dd."
},
"from": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only expenses on/after this date, yyyy-mm-dd."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"user_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single user id.",
"exclusiveMinimum": 0
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single client id.",
"exclusiveMinimum": 0
},
"is_billed": {
"type": "boolean",
"description": "Only billed (true) or unbilled (false) expenses."
},
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single project id.",
"exclusiveMinimum": 0
},
"updated_since": {
"type": "string",
"description": "Only expenses updated since this ISO-8601 datetime."
}
}
}| project_id |
| integer |
| Filter to a single project id. |
| updated_since | string | Only entries updated since this ISO-8601 datetime. |
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"to": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only entries on/before this date, yyyy-mm-dd."
},
"from": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
"description": "Only entries on/after this date, yyyy-mm-dd."
},
"page": {
"type": "integer",
"maximum": 9007199254740991,
"minimum": 1,
"description": "Page number (1-based) for pagination."
},
"task_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single task id.",
"exclusiveMinimum": 0
},
"user_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single user id.",
"exclusiveMinimum": 0
},
"per_page": {
"type": "integer",
"maximum": 2000,
"minimum": 1,
"description": "Results per page (1–2000, Harvest default 2000)."
},
"client_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single client id.",
"exclusiveMinimum": 0
},
"is_billed": {
"type": "boolean",
"description": "Only billed (true) or unbilled (false) entries."
},
"is_running": {
"type": "boolean",
"description": "Only running (true) or only stopped (false) entries."
},
"project_id": {
"type": "integer",
"maximum": 9007199254740991,
"description": "Filter to a single project id.",
"exclusiveMinimum": 0
},
"updated_since": {
"type": "string",
"description": "Only entries updated since this ISO-8601 datetime."
}
}
}