MCP Server
MCP Server Reference
This page lists every tool Timemator's MCP server offers an AI agent: what each one does, its parameters, its result, its annotations and one example call. It is generated from the tool list the app itself serves, so it matches the app.
If you have not connected an agent yet, start with Using the MCP server with Timemator. You do not need this page to use the server: your agent reads the same descriptions from the server. It is for checking what a tool does, and for people who write their own agents, skills or prompts.
The MCP server is in Beta. Tool names, parameters and results may still change in a minor release of Timemator; every change is listed in the changelog.
Conventions#
Endpoint. POST http://127.0.0.1:<port>/mcp, port 2140 unless you changed it in Preferences → Integrations. The server speaks MCP over Streamable HTTP with plain JSON responses: no event streams, no sessions. It accepts the protocol revisions 2025-11-25, 2025-06-18 and 2025-03-26 and offers tools only, no resources or prompts. Every request needs the header Authorization: Bearer <token>.
Calling a tool. A client sends tools/call with the tool's name and its arguments. The examples below show those two, and the result the tool returns. The result is in structuredContent and, as JSON text, in the one text block of content, for clients that ignore structured output. Arguments a tool does not take are refused, so a misspelt name is an error, not ignored.
Folders and tasks are named by their id or their exact path: the names from the top level down, separated by /, such as "Acme/Website". Paths are case-sensitive, and a name that is only close is never guessed: call search_tasks to find the id or path first. Time entries and activity records are named by id only.
Dates are ISO 8601 with a UTC offset, such as 2026-10-21T09:30:00+02:00, in both directions; a date without an offset is refused. Results are in the Mac's time zone. Periods such as today or this_week are whole periods in the Mac's time zone, and weeks start on the first weekday set in Timemator's preferences. Call get_status for the zone and the current time. Durations are in seconds, money is in the hourly rate's currency as Timemator shows it.
Lists are paginated: limit is 100 when left out and at most 500, and next_cursor is not null when there is more. Pass it as cursor to get the next page.
Annotations are hints for the client. readOnlyHint true means the tool changes no data; destructiveHint true marks the tools that delete or replace data (the three deletes and merge_time_entries), and most clients ask before running them; idempotentHint true means a second identical call changes nothing more; openWorldHint is always false, since every tool works on the Timemator library on this Mac only. Timemator itself never asks: it relies on your client.
Errors. A tool that refuses answers a result with isError: true and no structuredContent; the one text block of content holds {"code": …, "message": …} as JSON. A refusal never contradicts the tool's output schema, so clients that validate results pass it on to the agent. The code is stable and listed under Error codes; the message is English, whatever language the Mac uses, and often says what to do instead. A request the server cannot read at all gets a JSON-RPC error instead.
Read-only mode. When the trial (or a beta build) has expired, every tool that changes data is refused with readOnlyMode. Reading still works, and so do the tools that change no data: set_auto_tracking_enabled, show_in_app, open_reports and export_time_entries without mark_as_billed.
Status and timer#
What is going on right now, and the timer. Timemator's word for stopping the timer is pause; there is no toggle, so an agent never flips the timer the wrong way.
Tool: get_status#
Get Status
Returns the timer's state, the task and time entry it is on, whether Timemator is read-only, whether auto-tracking is on, and the Mac's time zone and current time. Call this first: every date, period and "today" in Timemator is in that time zone, and dates you send need an offset. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters: none.
Result
| Field | Values | Description |
|---|---|---|
auto_tracking_enabledboolean | Whether auto-tracking is switched on for the app. | |
current_tasktask or null | A task, or a folder (kind says which). | |
current_time_entrytime_entry or null | A time entry. | |
nowdate (string) | ISO 8601 with offset | The Mac's current time, with its offset. |
read_onlyboolean | Whether Timemator is in read-only mode (an expired trial); every write is refused then. | |
runningboolean | Whether a time entry is being tracked right now. | |
time_zonestring | The Mac's time zone, an IANA identifier such as Europe/Berlin. | |
timer_statestring | idle, idle_with_task, paused, running_manually, running_autotracked | idle (no task), idle_with_task (a task, nothing tracked), paused, running_manually or running_autotracked. |
Example: A timer running on Acme/Website.
{
"name": "get_status",
"arguments": {}
}Result (structuredContent):
{
"timer_state": "running_manually",
"running": true,
"current_task": {
"id": "9E4B2C71-5A3D-4F8E-B1C6-7D2E8F9A0B12",
"kind": "task",
"name": "Website",
"path": "Acme/Website",
"parent_id": "6C1F0A52-3B7E-4D2A-9F4E-2A8B7C5D1E01",
"color": "blue",
"archived": false,
"billing": "inherited",
"billable": true,
"hourly_rate": 90,
"notes": null,
"running": true,
"auto_tracking": false,
"total_duration": 52200,
"last_tracked": "2026-10-21T14:05:00+02:00"
},
"current_time_entry": {
"id": "D41E7A3C-2B9F-4C6D-8E1A-5F3B7C9D2E45",
"task_id": "9E4B2C71-5A3D-4F8E-B1C6-7D2E8F9A0B12",
"task_path": "Acme/Website",
"begin": "2026-10-21T14:05:00+02:00",
"end": null,
"duration": 1500,
"original_end": null,
"running": true,
"notes": "Landing page",
"billing_status": "unbilled",
"billable": true,
"hourly_rate": 90,
"revenue": 37.5,
"autotracked": false
},
"read_only": false,
"auto_tracking_enabled": true,
"time_zone": "Europe/Berlin",
"now": "2026-10-21T14:30:00+02:00"
}Tool: start_timer#
Start Timer
Starts tracking time on a task and returns the running time entry. task is the task's id or its exact path ("Clients/Acme/Website": /-separated, case-sensitive); call search_tasks first, since a path that is only close is refused with objectNotFound, never guessed. Without task, the current task is continued (refused with noCurrentTask when there is none). A running time entry is paused first. On the task that is already running, and without at, nothing new starts and the running entry is returned (notes land on it). at backdates the start and must not be in the future (invalidDateRange). Refused for an archived task (taskArchived) and in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
atdate (string), optional | ISO 8601 with offset | When the time entry began, with an offset; now when left out. |
notesstring, optional | Notes for the time entry. | |
taskstring, optional | The task's id or exact path. Leave it out to continue the current task. |
Result: a time_entry object.
Example: Start the timer on a task, with notes.
{
"name": "start_timer",
"arguments": {
"task": "Acme/Website",
"notes": "Landing page"
}
}Result (structuredContent):
{
"id": "D41E7A3C-2B9F-4C6D-8E1A-5F3B7C9D2E45",
"task_id": "9E4B2C71-5A3D-4F8E-B1C6-7D2E8F9A0B12",
"task_path": "Acme/Website",
"begin": "2026-10-21T14:05:00+02:00",
"end": null,
"duration": 0,
"original_end": null,
"running": true,
"notes": "Landing page",
"billing_status": "unbilled",
"billable": true,
"hourly_rate": 90,
"revenue": 0,
"autotracked": false
}Tool: pause_timer#
Pause Timer
Pauses the running time entry (Timemator's word for stopping the timer) at at, or now, and returns was_running. Nothing running is no error: was_running is false and nothing changes, so it is safe to call again. at must be after the running entry's begin (invalidDateRange). The task stays the timer's current task; start_timer without task continues it. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint true · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
atdate (string), optional | ISO 8601 with offset | When the time entry ended, with an offset; now when left out. |
Result
| Field | Values | Description |
|---|---|---|
was_runningboolean | Whether a time entry was running and is paused now. |
Example: Pause the running time entry at a given time.
{
"name": "pause_timer",
"arguments": {
"at": "2026-10-21T15:00:00+02:00"
}
}Result (structuredContent):
{
"was_running": true
}Tool: clear_timer#
Clear Timer
Makes the timer forget its current task and time entry, so it is idle. A running time entry is paused first and kept; nothing is deleted. Returns ok. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint true · openWorldHint false
Since: Timemator 3.4.0
Parameters: none.
Result
| Field | Values | Description |
|---|---|---|
okboolean | Always true. |
Example
{
"name": "clear_timer",
"arguments": {}
}Result (structuredContent):
{
"ok": true
}Folders and tasks#
Finding, creating and changing folders and tasks, and reading a task's auto-tracking rules. Rules cannot be edited by an agent.
Tool: search_tasks#
Search Tasks
Finds folders and tasks. With query, returns those whose name or path contains it, ignoring case and diacritics; without query, returns all of them. Each item has kind (folder or task), id and path: pass a task's id or path to start_timer, update_task and get_auto_tracking_rules, a folder's to create_task's in_folder or update_task's parent. Archived items are left out unless include_archived is true. Sorted by path, paginated: when next_cursor is not null, pass it as cursor for the next page. Call this before any write that names a task. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
cursorstring, optional | next_cursor from the previous page; leave it out for the first page. | |
include_archivedboolean, optional | Whether to include archived folders and tasks; false when left out. | |
limitinteger, optional | minimum 1 | How many items to return: 100 when left out, at most 500 (a larger value is treated as 500). |
querystring, optional | Text to look for in names and paths; leave it out to list everything. |
Result
| Field | Values | Description |
|---|---|---|
next_cursorstring or null | Pass as cursor to get the next page; null on the last page. | |
tasksarray of task | The folders and tasks found, sorted by path. |
Example: Find everything with "acme" in its name or path.
{
"name": "search_tasks",
"arguments": {
"query": "acme",
"limit": 2
}
}Result (structuredContent):
{
"tasks": [
{
"id": "6C1F0A52-3B7E-4D2A-9F4E-2A8B7C5D1E01",
"kind": "folder",
"name": "Acme",
"path": "Acme",
"parent_id": null,
"color": "blue",
"archived": false,
"billing": "always_billable",
"billable": true,
"hourly_rate": 90,
"notes": null,
"running": false,
"auto_tracking": false,
"total_duration": 97200,
"last_tracked": null
},
{
"id": "3A7D9E1F-8B2C-4E5A-A6D3-1F9C8B7E6D23",
"kind": "task",
"name": "Design",
"path": "Acme/Design",
"parent_id": "6C1F0A52-3B7E-4D2A-9F4E-2A8B7C5D1E01",
"color": "blue",
"archived": false,
"billing": "inherited",
"billable": true,
"hourly_rate": 90,
"notes": "Logo and style guide",
"running": false,
"auto_tracking": true,
"total_duration": 45000,
"last_tracked": "2026-10-20T10:00:00+02:00"
}
],
"next_cursor": "Mg=="
}Tool: create_task#
Create Task
Returns the task at path, creating it and any missing folders along the way, as Shortcuts and AppleScript do: "Clients/Acme/Website" reuses the folders Clients and Acme when they exist and creates what is missing, and an active task of that name in that folder is reused (an archived one is not). Names are compared exactly, case-sensitive and not trimmed. With in_folder (a folder's id or exact path) the path starts in that folder instead of at the top level. color, notes, billing and hourly_rate are set on the task, a reused one too. Undoable in the app as one step. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
pathstring, required | The task's path, folders and task name separated by "/", e.g. "Clients/Acme/Website". | |
billingstring, optional | inherited, always_billable, never_billable | Billable like the folder above (inherited), always or never. |
colorstring, optional | white, gray, red, brown, orange, green2, green, teal, blue, violett, light_pink, indigo, light_red, pink, yellow, light_green, cyan, light_blue, light_violett, light_indigo | The task's colour; the next colour of the colour set when left out. |
hourly_ratenumber or null, optional | minimum 0 | The task's own hourly rate; null or left out inherits the folder's. |
in_folderstring, optional | A folder's id or exact path the path starts in; the top level when left out. | |
notesstring, optional | The task's notes. |
Result: a task object.
Example: Create a task in a folder that does not exist yet.
{
"name": "create_task",
"arguments": {
"path": "Acme/Support",
"billing": "always_billable",
"hourly_rate": 75
}
}Result (structuredContent):
{
"id": "B8C2E4F6-1A3D-4B5E-9C7F-2D4E6A8B0C34",
"kind": "task",
"name": "Support",
"path": "Acme/Support",
"parent_id": "6C1F0A52-3B7E-4D2A-9F4E-2A8B7C5D1E01",
"color": "green",
"archived": false,
"billing": "always_billable",
"billable": true,
"hourly_rate": 75,
"notes": null,
"running": false,
"auto_tracking": false,
"total_duration": 0,
"last_tracked": null
}Tool: update_task#
Update Task
Changes a task or a folder (id is its id or exact path) and returns it as it is afterwards. Give at least one field; fields left out stay as they are. notes: null clears them (folders have none: folderHasNoNotes). hourly_rate: null inherits the folder's. parent: a folder's id or exact path to move into (at the end), null for the top level. position: its place among its siblings, from 1. archived: true archives it the way the task list does, a folder with everything inside it; false unarchives. auto_tracking switches the task's auto-tracking rules on or off; a task without rules is refused with taskHasNoRuleSet (see get_auto_tracking_rules). Every change is undoable in the app. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idstring, required | The id or exact path of the task or folder to change. | |
archivedboolean, optional | true archives it (a folder with everything inside), false unarchives it. | |
auto_trackingboolean, optional | Switches the task's auto-tracking rules on or off. | |
billingstring, optional | inherited, always_billable, never_billable | Billable like the folder above (inherited), always or never. |
colorstring, optional | white, gray, red, brown, orange, green2, green, teal, blue, violett, light_pink, indigo, light_red, pink, yellow, light_green, cyan, light_blue, light_violett, light_indigo | The colour. |
hourly_ratenumber or null, optional | minimum 0 | Its own hourly rate; null inherits the folder's. |
namestring, optional | The new name. | |
notesstring or null, optional | The task's notes; null clears them. | |
parentstring or null, optional | The id or exact path of the folder to move it into; null moves it to the top level. | |
positioninteger, optional | minimum 1 | Its place among its siblings, from 1; a larger number puts it last. |
Result: a task object.
Example: Rename a task and give it notes.
{
"name": "update_task",
"arguments": {
"id": "Acme/Support",
"name": "Support 2026",
"notes": "Retainer, 10 hours a month"
}
}Result (structuredContent):
{
"id": "B8C2E4F6-1A3D-4B5E-9C7F-2D4E6A8B0C34",
"kind": "task",
"name": "Support 2026",
"path": "Acme/Support 2026",
"parent_id": "6C1F0A52-3B7E-4D2A-9F4E-2A8B7C5D1E01",
"color": "green",
"archived": false,
"billing": "always_billable",
"billable": true,
"hourly_rate": 75,
"notes": "Retainer, 10 hours a month",
"running": false,
"auto_tracking": false,
"total_duration": 0,
"last_tracked": null
}Tool: get_auto_tracking_rules#
Get Auto-Tracking Rules
Returns a task's auto-tracking rules, or rule_set null when it has none: whether they are on, what happens when one matches (start_behavior, start_delay) and when none matches any more (pause_behavior, pause_delay), and the rules, any one of which starts tracking; a combination's rules must all match. Use it to explain why a task started or paused on its own. task is the task's id or exact path. Rules can only be edited in Timemator; update_task's auto_tracking switches them on and off. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
taskstring, required | The task's id or exact path. |
Result
| Field | Values | Description |
|---|---|---|
rule_setrule_set or null | A task's auto-tracking rules. |
Example: A task that starts when a Figma window is in front or a website is open.
{
"name": "get_auto_tracking_rules",
"arguments": {
"task": "Acme/Design"
}
}Result (structuredContent):
{
"rule_set": {
"id": "5F7A9C1E-3B5D-4E7F-8A2C-4E6B8D0F2A56",
"active": true,
"start_behavior": "start_automatically",
"start_delay": 10,
"pause_behavior": "pause_automatically",
"pause_delay": 60,
"rules": [
{
"id": "7A9C1E3B-5D7F-4A2C-9E4B-6D8F0A2C4E67",
"active": true,
"kind": "launched_application",
"application_path": "/Applications/Figma.app",
"file_path": null,
"website_url": null,
"text": null,
"match": null,
"in_active_window": true,
"rules": []
},
{
"id": "8B0D2F4A-6C8E-4B3D-A5F7-7E9A1C3E5F78",
"active": true,
"kind": "website",
"application_path": null,
"file_path": null,
"website_url": "acme.example.com",
"text": null,
"match": "containing",
"in_active_window": true,
"rules": []
}
]
}
}Time entries#
Listing, logging, correcting and merging time entries. Every change can be undone in Timemator with Edit → Undo and syncs like a change made in the app.
Tool: list_time_entries#
List Time Entries
Lists the time entries in a range, sorted by begin. Give period (today, yesterday, this_week, last_week, this_month, last_month, this_year: whole periods in the Mac's calendar and time zone, see get_status) or from and to, not both. An entry counts when it overlaps the range: one that began before from and ended after it counts, one that merely touches the range does not, and the running entry counts when it began before to. task_ids takes ids or exact paths of tasks and folders (call search_tasks for them); a folder stands for every task inside it. billing_status keeps the entries in those statuses; entries of archived tasks are left out unless include_archived is true. Paginated: when next_cursor is not null, pass it as cursor for the next page. to at or before from is refused with invalidDateRange. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
billing_statusarray of string, optional | unbilled, billed, paid | Only time entries in these billing statuses; every status when left out. |
cursorstring, optional | next_cursor from the previous page; leave it out for the first page. | |
fromdate (string), optional | ISO 8601 with offset | The start of the range, with an offset; with to, instead of period. |
include_archivedboolean, optional | Whether to include the time entries of archived tasks; false when left out. | |
limitinteger, optional | minimum 1 | How many items to return: 100 when left out, at most 500 (a larger value is treated as 500). |
periodstring, optional | today, yesterday, this_week, last_week, this_month, last_month, this_year | A whole period around now; instead of from and to. |
task_idsarray of string, optional | Only these tasks; a folder stands for every task inside it. All tasks when left out. | |
todate (string), optional | ISO 8601 with offset | The end of the range (exclusive), with an offset; with from. |
Result
| Field | Values | Description |
|---|---|---|
next_cursorstring or null | Pass as cursor to get the next page; null on the last page. | |
time_entriesarray of time_entry | The time entries found, sorted by begin. |
Example: Yesterday's unbilled time on everything in the folder Acme.
{
"name": "list_time_entries",
"arguments": {
"period": "yesterday",
"task_ids": [
"Acme"
],
"billing_status": [
"unbilled"
]
}
}Result (structuredContent):
{
"time_entries": [
{
"id": "A1C3E5F7-9B2D-4F6A-8C1E-3D5F7A9B1C89",
"task_id": "3A7D9E1F-8B2C-4E5A-A6D3-1F9C8B7E6D23",
"task_path": "Acme/Design",
"begin": "2026-10-20T09:00:00+02:00",
"end": "2026-10-20T10:30:00+02:00",
"duration": 5400,
"original_end": "2026-10-20T10:30:00+02:00",
"running": false,
"notes": "Logo variants",
"billing_status": "unbilled",
"billable": true,
"hourly_rate": 90,
"revenue": 135,
"autotracked": true
}
],
"next_cursor": null
}Tool: create_time_entry#
Create Time Entry
Logs a finished time entry from begin to end on a task (its id or exact path; call search_tasks first) and returns it. end must be after begin (invalidDateRange). With replace_existing true, the task's finished entries that overlap the range are deleted first (one that merely touches it stays, and so does the running entry); other tasks' entries are never touched. The deletion and the new entry are one undo step in the app. Does not start the timer: use start_timer for that. Refused for an unknown task (objectNotFound) and in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
begindate (string), required | ISO 8601 with offset | When the time entry began, with an offset. |
enddate (string), required | ISO 8601 with offset | When it ended, with an offset; after begin. |
taskstring, required | The task's id or exact path. | |
billing_statusstring, optional | unbilled, billed, paid | unbilled when left out. |
notesstring, optional | Notes for the time entry. | |
replace_existingboolean, optional | Whether to delete the task's entries that overlap the range first; false when left out. |
Result: a time_entry object.
Example: Log a meeting that has already happened.
{
"name": "create_time_entry",
"arguments": {
"task": "Acme/Website",
"begin": "2026-10-21T10:00:00+02:00",
"end": "2026-10-21T10:45:00+02:00",
"notes": "Kick-off call with Jane"
}
}Result (structuredContent):
{
"id": "E2F4A6B8-0C1D-4E3F-9A5B-7C9D1E3F5A90",
"task_id": "9E4B2C71-5A3D-4F8E-B1C6-7D2E8F9A0B12",
"task_path": "Acme/Website",
"begin": "2026-10-21T10:00:00+02:00",
"end": "2026-10-21T10:45:00+02:00",
"duration": 2700,
"original_end": "2026-10-21T10:45:00+02:00",
"running": false,
"notes": "Kick-off call with Jane",
"billing_status": "unbilled",
"billable": true,
"hourly_rate": 90,
"revenue": 67.5,
"autotracked": false
}Tool: update_time_entry#
Update Time Entry
Changes a time entry (id from list_time_entries or get_status) and returns it as it is afterwards. Give at least one field; fields left out stay as they are. task moves it to another task (id or exact path). The resulting end must be after the resulting begin (invalidDateRange). The running entry's begin can move into the past, not after now (invalidDateRange, as for start_timer's at). Setting end on the running entry pauses the timer at that date. end cannot be cleared to resume an entry (end: null is refused with runningEntryCannotBeResumed); call start_timer instead. notes: null clears the notes. Undoable in the app. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idstring, required | The time entry's id. | |
begindate (string), optional | ISO 8601 with offset | The new begin, with an offset. |
billing_statusstring, optional | unbilled, billed, paid | The billing status. |
enddate (string), optional | ISO 8601 with offset | The new end, with an offset; on the running entry it pauses the timer. |
notesstring or null, optional | The notes; null clears them. | |
taskstring, optional | The id or exact path of the task to move it to. |
Result: a time_entry object.
Example: Move a time entry to another task and mark it billed.
{
"name": "update_time_entry",
"arguments": {
"id": "E2F4A6B8-0C1D-4E3F-9A5B-7C9D1E3F5A90",
"task": "Acme/Design",
"billing_status": "billed"
}
}Result (structuredContent):
{
"id": "E2F4A6B8-0C1D-4E3F-9A5B-7C9D1E3F5A90",
"task_id": "3A7D9E1F-8B2C-4E5A-A6D3-1F9C8B7E6D23",
"task_path": "Acme/Design",
"begin": "2026-10-21T10:00:00+02:00",
"end": "2026-10-21T10:45:00+02:00",
"duration": 2700,
"original_end": "2026-10-21T10:45:00+02:00",
"running": false,
"notes": "Kick-off call with Jane",
"billing_status": "billed",
"billable": true,
"hourly_rate": 90,
"revenue": 67.5,
"autotracked": false
}Tool: merge_time_entries#
Merge Time Entries
Replaces two or more finished time entries with one and returns it; the originals are deleted. The merged entry begins at the earliest begin and lasts the durations added up; with fill_gaps true it runs to the latest end instead, the gaps included. The notes are joined. Entries on different tasks need into_task (an id or exact path), else timeEntriesOnSeveralTasks; into_task also moves entries of one task. Refused for fewer than two entries (tooFewTimeEntriesToMerge), for the running entry (runningEntryCannotBeDeleted: pause the timer first), for an unknown id (objectNotFound) and in read-only mode (readOnlyMode). Undoable in the app as one step.
Annotations: readOnlyHint false · destructiveHint true · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idsarray of string, required | The time entries to merge, two or more. | |
fill_gapsboolean, optional | Whether the merged entry runs from the earliest begin to the latest end; false adds up the durations. | |
into_taskstring, optional | The id or exact path of the task the merged entry goes on; the entries' own task when left out. |
Result: a time_entry object.
Example: Merge two short entries of the same task, the gap between them included.
{
"name": "merge_time_entries",
"arguments": {
"ids": [
"F3A5B7C9-1D2E-4F4A-8B6C-8D0E2F4A6B01",
"04B6C8D0-2E3F-4A5B-9C7D-9E1F3A5B7C12"
],
"fill_gaps": true
}
}Result (structuredContent):
{
"id": "15C7D9E1-3F4A-4B6C-8D9E-0F2A4B6C8D23",
"task_id": "3A7D9E1F-8B2C-4E5A-A6D3-1F9C8B7E6D23",
"task_path": "Acme/Design",
"begin": "2026-10-21T08:00:00+02:00",
"end": "2026-10-21T09:10:00+02:00",
"duration": 4200,
"original_end": "2026-10-21T09:10:00+02:00",
"running": false,
"notes": "Icons\nIcons, second pass",
"billing_status": "unbilled",
"billable": true,
"hourly_rate": 90,
"revenue": 105,
"autotracked": false
}Reports and export#
Totals as the Reports window calculates them, and CSV or PDF files as the Export window writes them.
Tool: get_time_summary#
Get Time Summary
Sums the time tracked in a range, as Timemator's Reports window does: total duration in seconds, total revenue, the number of time entries, and one total per task. Give exactly one of: period (today, yesterday, this_week, last_week, this_month, last_month, this_year); scope (daily, weekly, monthly, yearly) with on, a date inside the period (now when left out); or from and to. Two of them together are refused with invalidArgument. Periods are whole, in the Mac's time zone (see get_status) and the first weekday Timemator's preferences set. An entry that overlaps an end of the range counts with its part inside; the running entry counts up to now; revenue is the billable entries'. task_ids (ids or exact paths of tasks and folders, from search_tasks), billing_status and include_archived select the entries as list_time_entries does. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
billing_statusarray of string, optional | unbilled, billed, paid | Only time entries in these billing statuses; every status when left out. |
fromdate (string), optional | ISO 8601 with offset | The start of the range, with an offset; with to. |
include_archivedboolean, optional | Whether to include the time entries of archived tasks; false when left out. | |
ondate (string), optional | ISO 8601 with offset | A date inside the scope's period, with an offset; now when left out. |
periodstring, optional | today, yesterday, this_week, last_week, this_month, last_month, this_year | A whole period around now. |
scopestring, optional | daily, weekly, monthly, yearly | The Reports window's period length; with on. |
task_idsarray of string, optional | Only these tasks; a folder stands for every task inside it. All tasks when left out. | |
todate (string), optional | ISO 8601 with offset | The end of the range (exclusive), with an offset; with from. |
Result
| Field | Values | Description |
|---|---|---|
begindate (string) | ISO 8601 with offset | The start of the range summed. |
enddate (string) | ISO 8601 with offset | The end of the range summed (exclusive). |
scopestring | daily, weekly, monthly, yearly, custom | The period's length: daily, weekly, monthly or yearly, custom for from and to. |
task_totalsarray of object | One total per task with time in the range, in the task list's order; they add up to total_duration. | |
task_totals[].durationnumber | Its time in the range, in seconds. | |
task_totals[].revenuenumber | Its revenue in the range. | |
task_totals[].task_idstring | The task's id. | |
task_totals[].task_pathstring | The task's path. | |
time_entry_countinteger | How many time entries were counted. | |
total_durationnumber | All time in the range, in seconds. | |
total_revenuenumber | The revenue of the billable time. |
Example: This month's total per task in the folder Acme.
{
"name": "get_time_summary",
"arguments": {
"period": "this_month",
"task_ids": [
"Acme"
]
}
}Result (structuredContent):
{
"scope": "monthly",
"begin": "2026-10-01T00:00:00+02:00",
"end": "2026-11-01T00:00:00+01:00",
"total_duration": 97200,
"total_revenue": 2430,
"time_entry_count": 31,
"task_totals": [
{
"task_id": "3A7D9E1F-8B2C-4E5A-A6D3-1F9C8B7E6D23",
"task_path": "Acme/Design",
"duration": 45000,
"revenue": 1125
},
{
"task_id": "9E4B2C71-5A3D-4F8E-B1C6-7D2E8F9A0B12",
"task_path": "Acme/Website",
"duration": 52200,
"revenue": 1305
}
]
}Tool: export_time_entries#
Export Time Entries
Writes the time entries from from to to into a CSV or PDF file, as Timemator's Export window does, and returns the file's path. file is an absolute path ("~/" is expanded) or a bare file name, which is written to ~/Downloads; a relative path with folders is refused (invalidArgument). An existing file is never touched unless overwrite is true: when a file is already at the path, the call is refused (fileExists) and writes and marks nothing; overwrite true replaces that file. A folder at the path is refused (invalidArgument), with overwrite too. The entries are the ones list_time_entries returns for the same from, to, task_ids, billing_status and include_archived. Options left out take the Export window's defaults; options of the other format are ignored: delimiter and include_roundings are CSV's, group_by and duration_format PDF's. mark_as_billed true marks the exported entries as billed once the file is written (undoable in the app); it is refused in read-only mode (readOnlyMode), a plain export is not. A failing export is exportFailed and marks nothing.
Annotations: readOnlyHint false · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
filestring, required | An absolute path, or a bare file name for ~/Downloads, such as "acme-october.pdf". | |
formatstring, required | csv, pdf | csv or pdf. |
fromdate (string), required | ISO 8601 with offset | The start of the range, with an offset. |
todate (string), required | ISO 8601 with offset | The end of the range (exclusive), with an offset. |
billing_statusarray of string, optional | unbilled, billed, paid | Only time entries in these billing statuses; every status when left out. |
delimiterstring, optional | comma, semicolon, colon, tab | CSV only: the column separator; semicolon when left out. |
duration_formatstring, optional | hours_and_minutes, decimal | PDF only: hours_and_minutes (the default) or decimal hours. |
group_bystring, optional | none, date, task | PDF only: how the rows are grouped; date when left out. |
include_archivedboolean, optional | Whether to include the time entries of archived tasks; false when left out. | |
include_notesboolean, optional | Whether to include the notes column; true when left out. | |
include_revenueboolean, optional | Whether to include the revenue column; true when left out. | |
include_roundingsboolean, optional | CSV only: whether to include the roundings column; true when left out. | |
mark_as_billedboolean, optional | Whether to mark the exported entries as billed after writing the file; false when left out. | |
overwriteboolean, optional | Whether to replace a file that already exists at the path; false when left out, and then an existing file is refused (fileExists). | |
task_idsarray of string, optional | Only these tasks; a folder stands for every task inside it. All tasks when left out. |
Result
| Field | Values | Description |
|---|---|---|
pathstring | The absolute path of the file written. |
Example: October's unbilled Acme time as a new CSV file in Downloads, marked as billed afterwards.
{
"name": "export_time_entries",
"arguments": {
"from": "2026-10-01T00:00:00+02:00",
"to": "2026-11-01T00:00:00+01:00",
"file": "acme-october.csv",
"format": "csv",
"task_ids": [
"Acme"
],
"billing_status": [
"unbilled"
],
"mark_as_billed": true
}
}Result (structuredContent):
{
"path": "/Users/jane/Downloads/acme-october.csv"
}Activity log and auto-tracking#
The activity log records which app and window were in front, when activity tracking is on. It stays on this Mac.
Tool: list_activity_records#
List Activity Records
Lists Timemator's activity log between from and to, sorted by begin: which app was in front, with its window title and, for browsers and document apps, the website or file. Use it to reconstruct what the user worked on. A record counts when it overlaps the range (one that merely touches it does not); the record being recorded counts when it began before to. bundle_ids keeps the records of those apps (compared exactly, such as com.apple.Safari). to at or before from is refused with invalidDateRange. Paginated: when next_cursor is not null, pass it as cursor for the next page. Changes nothing.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
fromdate (string), required | ISO 8601 with offset | The start of the range, with an offset. |
todate (string), required | ISO 8601 with offset | The end of the range (exclusive), with an offset. |
bundle_idsarray of string, optional | Only the records of these apps; all apps when left out. | |
cursorstring, optional | next_cursor from the previous page; leave it out for the first page. | |
limitinteger, optional | minimum 1 | How many items to return: 100 when left out, at most 500 (a larger value is treated as 500). |
Result
| Field | Values | Description |
|---|---|---|
activity_recordsarray of activity_record | The records found, sorted by begin. | |
next_cursorstring or null | Pass as cursor to get the next page; null on the last page. |
Example: What was in front between nine and ten.
{
"name": "list_activity_records",
"arguments": {
"from": "2026-10-21T09:00:00+02:00",
"to": "2026-10-21T10:00:00+02:00",
"limit": 2
}
}Result (structuredContent):
{
"activity_records": [
{
"id": "x-coredata://10B1F909-3D53-4782-AE2D-19769A4AFA6E/BrowserActivityRecord/p812",
"begin": "2026-10-21T08:58:12+02:00",
"end": "2026-10-21T09:21:40+02:00",
"duration": 1408,
"running": false,
"bundle_identifier": "com.apple.Safari",
"application_name": "Safari",
"title": "Acme – Staging",
"website_url": "https://staging.acme.example.com/",
"file_path": null
},
{
"id": "x-coredata://10B1F909-3D53-4782-AE2D-19769A4AFA6E/DocumentAppActivityRecord/p813",
"begin": "2026-10-21T09:21:40+02:00",
"end": "2026-10-21T09:48:05+02:00",
"duration": 1585,
"running": false,
"bundle_identifier": "com.apple.iWork.Pages",
"application_name": "Pages",
"title": "Acme proposal.pages",
"website_url": null,
"file_path": "/Users/jane/Documents/Acme proposal.pages"
}
],
"next_cursor": "Mg=="
}Tool: set_auto_tracking_enabled#
Set Auto-Tracking Enabled
Switches auto-tracking on or off for the whole app, the switch in Timemator's preferences, and returns the new state. While it is off, no task's rules start or pause the timer; each task's own rules stay as they are (update_task's auto_tracking switches those). get_status reads the current state. A preference, not a change to the library: not undoable, and allowed in read-only mode.
Annotations: readOnlyHint false · destructiveHint false · idempotentHint true · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
enabledboolean, required | true switches auto-tracking on, false off. |
Result
| Field | Values | Description |
|---|---|---|
enabledboolean | Whether auto-tracking is on now. |
Example: Switch auto-tracking off for a focus session.
{
"name": "set_auto_tracking_enabled",
"arguments": {
"enabled": false
}
}Result (structuredContent):
{
"enabled": false
}Windows#
Hand the user over to Timemator at the right place. Both tools bring Timemator to the front.
Tool: show_in_app#
Show in Timemator
Brings Timemator's main window to the front with a folder, task or time entry selected, so the user can look at it or edit it there. id is a folder's or task's id or exact path (from search_tasks), or a time entry's id (from list_time_entries). Unknown ids are refused with objectNotFound. Changes no data. Returns ok.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idstring, required | The id or exact path of a folder or task, or a time entry's id. |
Result
| Field | Values | Description |
|---|---|---|
okboolean | Always true. |
Example
{
"name": "show_in_app",
"arguments": {
"id": "Acme/Website"
}
}Result (structuredContent):
{
"ok": true
}Tool: open_reports#
Open Reports
Opens Timemator's Reports window on the day, week, month or year (scope) that contains on, now when on is left out, and brings it to the front. Weeks start on the first weekday Timemator's preferences set. Use get_time_summary for the numbers; this is for showing them to the user. Changes no data. Returns ok.
Annotations: readOnlyHint true · destructiveHint false · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
scopestring, required | daily, weekly, monthly, yearly | The report's period length. |
ondate (string), optional | ISO 8601 with offset | A date inside the period, with an offset; now when left out. |
Result
| Field | Values | Description |
|---|---|---|
okboolean | Always true. |
Example: Show last week's report.
{
"name": "open_reports",
"arguments": {
"scope": "weekly",
"on": "2026-10-14T12:00:00+02:00"
}
}Result (structuredContent):
{
"ok": true
}Deletes#
The three tools that delete. They check every id first and delete nothing when one is refused.
Tool: delete_items#
Delete Folders and Tasks
Deletes folders and tasks together with everything inside them: a folder's subfolders and tasks, and every time entry of every task deleted. ids are ids or exact paths of folders and tasks (from search_tasks). Returns how many folders, tasks and time entries were deleted. Every id is checked first: one unknown id (objectNotFound) deletes nothing. Undoable in the app as one step. Refused in read-only mode (readOnlyMode). To keep the time but hide a task, archive it with update_task instead.
Annotations: readOnlyHint false · destructiveHint true · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idsarray of string, required | The folders and tasks to delete. |
Result
| Field | Values | Description |
|---|---|---|
deleted_foldersinteger | How many folders were deleted, subfolders included. | |
deleted_tasksinteger | How many tasks were deleted, those inside the folders included. | |
deleted_time_entriesinteger | How many time entries went with the tasks. |
Example: Delete a folder with everything in it.
{
"name": "delete_items",
"arguments": {
"ids": [
"Old clients/Initech"
]
}
}Result (structuredContent):
{
"deleted_folders": 1,
"deleted_tasks": 3,
"deleted_time_entries": 42
}Tool: delete_time_entries#
Delete Time Entries
Deletes time entries by id (from list_time_entries) and returns how many were deleted. Every id is checked first, and nothing is deleted when one is refused: the running time entry (runningEntryCannotBeDeleted: pause the timer first) or an unknown id (objectNotFound). Undoable in the app as one step. Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint true · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idsarray of string, required | The time entries to delete. |
Result
| Field | Values | Description |
|---|---|---|
deletedinteger | How many time entries were deleted. |
Example
{
"name": "delete_time_entries",
"arguments": {
"ids": [
"E2F4A6B8-0C1D-4E3F-9A5B-7C9D1E3F5A90"
]
}
}Result (structuredContent):
{
"deleted": 1
}Tool: delete_activity_records#
Delete Activity Records
Deletes records of the activity log by id (from list_activity_records) and returns how many were deleted. This cannot be undone, not even in the app. Every id is checked first, and nothing is deleted when one is refused: the record being recorded right now (runningActivityRecordCannotBeDeleted) or an unknown id (objectNotFound). Refused in read-only mode (readOnlyMode).
Annotations: readOnlyHint false · destructiveHint true · idempotentHint false · openWorldHint false
Since: Timemator 3.4.0
Parameters
| Parameter | Values | Description |
|---|---|---|
idsarray of string, required | The activity records to delete. |
Result
| Field | Values | Description |
|---|---|---|
deletedinteger | How many activity records were deleted. |
Example
{
"name": "delete_activity_records",
"arguments": {
"ids": [
"x-coredata://10B1F909-3D53-4782-AE2D-19769A4AFA6E/BrowserActivityRecord/p812"
]
}
}Result (structuredContent):
{
"deleted": 1
}Objects#
The objects the tools return. A value that is not there is null, never left out. Clients should ignore fields they do not know: a later version may add some.
Object: task#
A folder or a task; kind says which. A folder has no notes and no auto-tracking, and is running while a task inside it is.
Returned by: get_status, search_tasks, create_task, update_task
| Field | Values | Description |
|---|---|---|
archivedboolean | Whether it is archived. | |
auto_trackingboolean | Whether its auto-tracking rules are on; false when it has none and for a folder. | |
billableboolean | Whether its time is billable, the setting resolved. | |
billingstring | inherited, always_billable, never_billable | The billing setting: inherited from the folder above, always billable or never billable. |
colorstring | white, gray, red, brown, orange, green2, green, teal, blue, violett, light_pink, indigo, light_red, pink, yellow, light_green, cyan, light_blue, light_violett, light_indigo | The colour. |
hourly_ratenumber | The hourly rate in effect, its own or inherited. | |
idstring | The sync identifier; pass it wherever a task or folder is asked for. | |
kindstring | folder, task | folder or task. |
last_trackeddate (string) or null | ISO 8601 with offset | When tracking last began on it; null when never. |
namestring | The name. | |
notesstring or null | The task's notes; null when it has none and for a folder. | |
parent_idstring or null | The id of the folder it is in; null at the top level. | |
pathstring | The names of the folders above it and its own, joined with "/": the exact path it can be addressed by. | |
runningboolean | Whether the timer is tracking it (for a folder: a task inside it) right now. | |
total_durationnumber | All time tracked on it (a folder: inside it), the running time entry included, in seconds. |
Object: time_entry#
A time entry: a stretch of time tracked on a task. The running one has no end yet.
Returned by: get_status, start_timer, list_time_entries, create_time_entry, update_time_entry, merge_time_entries
| Field | Values | Description |
|---|---|---|
autotrackedboolean | Whether auto-tracking started it. | |
begindate (string) | ISO 8601 with offset | When it began. |
billableboolean | Whether it is billable. | |
billing_statusstring | unbilled, billed, paid | unbilled, billed or paid. |
durationnumber | Its length in seconds, up to now while it runs. | |
enddate (string) or null | ISO 8601 with offset | When it ended; null while it runs. |
hourly_ratenumber | Its hourly rate. | |
idstring | The sync identifier. | |
notesstring or null | Its notes. | |
original_enddate (string) or null | ISO 8601 with offset | The end before rounding; null when it was never rounded. |
revenuenumber | Its revenue; 0 when not billable. | |
runningboolean | Whether it is being tracked right now. | |
task_idstring or null | The id of its task. | |
task_pathstring or null | The path of its task. |
Object: rule_set#
A task's auto-tracking rules, as the rules window shows them.
Returned by: get_auto_tracking_rules
| Field | Values | Description |
|---|---|---|
activeboolean | Whether the rules are on: the task's auto_tracking. | |
idstring | The sync identifier. | |
pause_behaviorstring | never, notify, pause_automatically | What happens when no rule matches any more while the timer is on the task. |
pause_delaynumber | How long, in seconds, no rule must match before the pause. | |
rulesarray of rule | The rules in the rules window's order; any one matching is enough. | |
start_behaviorstring | notify, start_automatically | What a matching rule does while the timer is not on the task. |
start_delaynumber | How long, in seconds, a rule must match before the start (0 is immediately). |
Object: rule#
One auto-tracking rule. Only the fields its kind uses are set; the others are null. A combination holds rules of the same shape in rules, all of which must match.
Returned by: get_auto_tracking_rules
| Field | Values | Description |
|---|---|---|
activeboolean | Whether the rule is on. | |
application_pathstring or null | The application of a launched_application rule. | |
file_pathstring or null | The document of an opened_document rule, the folder of an opened_folder rule. | |
idstring | The sync identifier. | |
in_active_windowboolean or null | Whether the rule looks at the front window only; null for a combination. | |
kindstring | launched_application, opened_document, opened_folder, window_title, website, slack, skype, combination | What the rule watches; combination for rules that must all match. |
matchstring or null | exactly, containing, starting_with, ending_with, path_exactly, name_containing, path_containing, name_matches_regex, path_matches_regex | How text or website_url is compared. |
rulesarray of object | A combination's rules, all of which must match; empty for a plain rule. | |
textstring or null | What a window_title, slack or skype rule looks for, the name or path pattern of an opened_document rule. | |
website_urlstring or null | The address of a website rule. |
Object: activity_record#
One record of the activity log: an app, and its window, in front for a while.
Returned by: list_activity_records
| Field | Values | Description |
|---|---|---|
application_namestring or null | The app's name; the bundle identifier when the app is not installed. | |
begindate (string) | ISO 8601 with offset | When it began. |
bundle_identifierstring or null | The app's bundle identifier, such as com.apple.Safari. | |
durationnumber | Its length in seconds, up to now while it is being recorded. | |
enddate (string) or null | ISO 8601 with offset | When it ended; null while it is being recorded. |
file_pathstring or null | A document record's file; null for other apps. | |
idstring | The record's id. | |
runningboolean | Whether it is being recorded right now. | |
titlestring or null | The window title; null when there was none. | |
website_urlstring or null | A browser record's address; null for other apps. |
Error codes#
The code of a refused tool call. The codes are stable: a code is renamed or removed only with an entry in the changelog. Compare the code, not the message, which may be reworded.
| Code | Meaning | What to do |
|---|---|---|
readOnlyMode | Timemator is in read-only mode because the trial or the beta has expired. Nothing can be changed. | Tell the user: they have to open Timemator to continue, for example to buy a license. Reading still works, and so do the tools that change no data. |
objectNotFound | No folder, task, time entry or activity record has this id, or no folder or task has this exact path. | Call search_tasks (folders and tasks), list_time_entries or list_activity_records for the id. Paths are case-sensitive and separated by /. |
taskArchived | The task is archived, so the timer cannot start on it. | Pick another task, or unarchive it with update_task (archived: false) if the user wants that. |
noCurrentTask | start_timer was called without task, and the timer has no current task to continue. | Pass the task to start the timer on. |
invalidDateRange | The end is not after the start, a start date is in the future (start_timer's at, or the begin of the running time entry in update_time_entry), or the arguments name no period. The message says which. | Check the dates and their offsets; get_status returns the Mac's time zone and current time. |
runningEntryCannotBeDeleted | The running time entry cannot be deleted or merged. | Pause the timer with pause_timer first. |
runningEntryCannotBeResumed | update_time_entry was asked to clear a time entry's end (end: null), which would resume it. | Call start_timer to continue tracking instead. |
taskHasNoRuleSet | The task has no auto-tracking rules, so its auto_tracking cannot be switched. | Leave auto_tracking out. Rules are made in Timemator's rules window; get_auto_tracking_rules shows whether there are any. |
exportFailed | The export could not write the file. Nothing was marked as billed. | Check that the folder exists and can be written to, or use a bare file name to write to ~/Downloads. |
archivedIsReadOnly | archived was set as a property where only archiving is allowed. Not returned by the MCP tools today: update_task's archived archives and unarchives. | Use update_task with archived true or false. |
writeFailed | Timemator could not save the change. The message carries the reason when there is one. | Try again; if it keeps failing, the user should check Timemator, and write to support@timemator.com with the message. |
rulesAreReadOnly | Auto-tracking rules cannot be edited by automation. Not returned by the MCP tools today, which have no tool to edit rules. | The user edits rules in Timemator. update_task's auto_tracking switches a task's rules on and off. |
runningActivityRecordCannotBeDeleted | The activity record being recorded right now cannot be deleted. Nothing was deleted. | Leave that id out, or try again once the record has ended. |
activityRecordsAreReadOnly | The activity log cannot be changed by automation, apart from deleting records. Not returned by the MCP tools today, which only read and delete records. | Read records with list_activity_records; delete them with delete_activity_records. |
missingValue | A required value is empty, such as a task path with no name in it or an empty name. The message names it. | Pass a value that is not empty. |
folderHasNoNotes | Notes were given for a folder. Only tasks have notes. | Leave notes out when the id names a folder. |
folderMovedIntoItself | A folder was to be moved into itself or into a folder inside it. | Pick another parent, or null for the top level. |
tooFewTimeEntriesToMerge | merge_time_entries needs two time entries or more. | Pass at least two ids. |
timeEntriesOnSeveralTasks | The time entries to merge are on different tasks, and no task to merge them into was given. | Pass into_task. |
invalidArgument | An argument is missing, of the wrong type, out of range, not a date with an offset, unknown to the tool, or combined with one it excludes (such as period with from and to). The message names it. | Correct the argument the message names; the tool's parameters are listed above. |
fileExists | export_time_entries was given the path of a file that already exists (a symbolic link counts), without overwrite: true. The file was left as it was, and nothing was exported or marked as billed. The message names the path. | Ask the user whether to replace the file; if they agree, call again with overwrite: true. Otherwise pick another file name. |
internal | The tool failed in a way it does not expect. The message carries the error's domain and code. | Try again; if it keeps failing, write to support@timemator.com with the tool, the arguments and the message. |
Errors that are not a tool's: the HTTP status of a request the server does not accept, and the JSON-RPC errors of a request it cannot read. A client shows these as connection or protocol errors.
| Code | Meaning | What to do |
|---|---|---|
| HTTP 401 | The Authorization: Bearer header is missing or the token is wrong. | Copy the token again from Preferences → Integrations; it changes when someone clicks Regenerate…. |
| HTTP 403 | The request came from a web browser (it has an Origin header), or its Host is not 127.0.0.1:<port> or localhost:<port>. | Connect from an MCP client on this Mac to http://127.0.0.1:<port>/mcp. Web pages cannot use the server. |
| HTTP 404 / 405 | The path is not /mcp, or the method is not POST. | Use POST on /mcp. The server has no event stream for GET. |
| HTTP 413 / 415 | The body is larger than 4 MB, or it is not application/json. | Send JSON with Content-Type: application/json. |
| -32700 | The body is not JSON. | Send a JSON-RPC 2.0 message. |
| -32600 | The message is not a JSON-RPC 2.0 request. | Send jsonrpc: "2.0", a method and an id that is a string or a number. |
| -32601 | The method is not one the server knows. It answers initialize, ping, tools/list and tools/call, and accepts notifications. | Use one of those methods. |
| -32602 | The params are wrong: no protocolVersion for initialize, no tool name, a tool that does not exist, or arguments that are not an object. | Call tools/list for the tool names. |
| -32603 | The server could not answer. | Try again; if it keeps failing, write to support@timemator.com. |
Changelog#
Changes to the tools, their parameters, results and error codes. While the server is in Beta, a change may come in a minor release.
Timemator 3.4.0#
- First release of the MCP server (Beta), off by default: Streamable HTTP on
127.0.0.1, port 2140, with a bearer token; protocol revisions 2025-11-25, 2025-06-18 and 2025-03-26;serverInfo.nametimemator,serverInfo.versionthe app's version. - 21 tools:
get_status,start_timer,pause_timer,clear_timer,search_tasks,create_task,update_task,get_auto_tracking_rules,list_time_entries,create_time_entry,update_time_entry,merge_time_entries,get_time_summary,export_time_entries,list_activity_records,set_auto_tracking_enabled,show_in_app,open_reports,delete_items,delete_time_entriesanddelete_activity_records. - Objects
task,time_entry,rule_set,ruleandactivity_record; error codes as listed above.