gryzzly-mcp
An MCP server that puts the whole Gryzzly time-tracking API (53 tools) in front of any MCP client, resolving names/dates/durations for you so logging time is one call.
Log and edit time —
log_time,log_time_bulk,update_time_entry,delete_time_entry; durations as2h30/90m/1.5h, dates asyesterday/2026-W38, projects/tasks by name, with the day's new total reported.Read your timesheet —
whoami,list_time_entries, andtimesheetfor per-day and per-project totals plus short days.Manage projects and tasks — list/get/create/update/delete projects, tasks, and their budget/time metrics.
Manage the directory — users (list, get, invite), customers (list, get, create, update, delete), plus read-only groups, groupsets, tags and tagsets.
Handle leaves — list/get/create/update/delete leave periods, and import them from CSV/XLSX.
Budget items — purchases and discounts (create, read, update, delete; needs Gryzzly's budget offer).
Exports —
export_projectsandexport_times_and_leavesas CSV/XLSX (upstream usually rejects API keys).Resources —
gryzzly://me,://projects,://users,://customers,://projects/{project}/tasks,://timesheet/{week}.Prompts —
fill_my_week,weekly_review,catch_up_timesheet, all of which read and ask before writing.Safety controls — deletes need
confirm: true,GRYZZLY_READ_ONLY=1withholds writes,GRYZZLY_TOOLSETStrims the surface, and it runs over stdio or Streamable HTTP.
mcp-gryzzly
Your timesheet, filled by asking.
A single Rust binary that puts the whole Gryzzly time-tracking API in front of any MCP client — and makes logging time the easy part.
Ask your assistant "log 2h30 on Alyxa yesterday", "what did I miss last week?", "fill my timesheet from my commits" — and have it land in the same Gryzzly your team actually reports on.
> log 2h30 on Alyxa yesterday, pairing on the importer
log_time 2h30 on Alyxa / Development, Thursday 2026-09-17
that day now totals 7h30
> did I miss anything last week?
timesheet 2026-W38 · 31h30 over 5 days
.INTERNE 16h40 47.6%
Alyxa 9h00 28.6%
Le14 5h50 23.8%
Friday 2026-09-18 is short: 4h of the 7h expectedNo identifiers, no seconds, no date arithmetic. You name a project, say 2h30, and
the server resolves the rest.
Why
Gryzzly's API is an RPC surface of 50 actions where time is attached to tasks by
UUID, durations are seconds, and a list that matches nothing answers 404. It is a
fine API to integrate and a miserable one to hand a language model raw. This server
is the translation layer.
The whole API, nothing hidden. All 50 documented actions, plus
whoami,log_time_bulkandtimesheet, which exist because the API has no/me, no batch and no aggregate. A test fails if that count ever drops.Names, not UUIDs. Every tool takes a project, task, user or customer by name, code, email or id. A name that matches two objects comes back with the candidates rather than a guess — the one thing you never want automated is which project your afternoon went to.
Durations and dates as people say them.
2h30,90m,1.5h,2:30;today,yesterday,monday,2026-W38,last week.Written for a model to read. Structured output with schemas on all 53 tools, annotations on every one, three prompts that stop and ask before writing, and server instructions that say up front that time hangs on tasks.
Fail-closed where it matters. Deletes refuse to run without
confirm: true.GRYZZLY_READ_ONLY=1withholds every write tool.GRYZZLY_TOOLSETStrims the surface to what you actually use.One binary, no state. No database, no OAuth dance, no background jobs. An API key in the environment, stdio or HTTP, and Gryzzly's own rate limit respected from the client side.
Related MCP server: Timesheet MCP Server
Install
git clone https://github.com/edouard-claude/gryzzly-mcp
cd gryzzly-mcp
cargo build --release
# the binary is at target/release/mcp-gryzzlycargo install --git https://github.com/edouard-claude/gryzzly-mcpdocker build -t mcp-gryzzly .
docker run --rm -i -e GRYZZLY_API_KEY=… mcp-gryzzlyThe image runs unprivileged and speaks stdio by default; add --http for the HTTP
transport. See Run it over HTTP instead.
Get an API key from Gryzzly: Administration → API keys. Then check the wiring before pointing a client at it:
GRYZZLY_API_KEY=… mcp-gryzzly --checkbase url https://api.gryzzly.io/v1
toolsets time, projects, directory, leaves, budget, exports
read only false
tools 53
team 6 users visible
acting as Edouard CLAUDE <edouard@squirrel.fr>
projects 41 (41 active)
ready.Configure
Variable | Required | Default | What it is |
| yes | The API key, sent as | |
| A file holding the key instead, for Docker secrets | ||
| The UUID of the person the server acts as | ||
| That person's email, resolved to an id at startup | ||
|
| API root, prefix included | |
| A project name, code or id used when a tool omits one | ||
|
|
| |
|
|
| |
|
| Per-request timeout | |
|
| How long name lookups are reused | |
|
| Retries on 429 and transient 5xx | |
|
| How far back a declaration is searched by id | |
| Listen address for the HTTP transport | ||
| Bearer token the HTTP transport requires | ||
|
|
|
One key, one person. A Gryzzly API key belongs to a team, not to a user, and
the API has no /me. So GRYZZLY_USER_ID or GRYZZLY_USER_EMAIL names whose
timesheet is being filled. A team of exactly one user needs neither. The binary
refuses to start on a malformed variable and names the one at fault.
Connect a client
claude mcp add gryzzly --scope user \
--env GRYZZLY_API_KEY=… \
--env GRYZZLY_USER_EMAIL=you@example.com \
-- /absolute/path/to/mcp-gryzzlyclaude_desktop_config.json:
{
"mcpServers": {
"gryzzly": {
"command": "/absolute/path/to/mcp-gryzzly",
"env": {
"GRYZZLY_API_KEY": "…",
"GRYZZLY_USER_EMAIL": "you@example.com"
}
}
}
}Same shape: one command pointing at the binary, the key in env. The server speaks
the stdio transport and prints nothing but protocol on stdout — logs go to stderr.
Point it at http://127.0.0.1:8080/mcp after starting the server with
--http 127.0.0.1:8080. See below.
Then ask "who am I in Gryzzly?". whoami should answer with your name, your role,
and this week's total.
Tools
53 tools in six toolsets. GRYZZLY_TOOLSETS picks which ones are registered;
GRYZZLY_READ_ONLY=1 keeps only the ones that declare themselves read-only.
time — the point of the whole thing
Tool | |
| Who the server acts as, what it may do, and this week's total |
| Declare time: a duration, a task or project name, a day |
| A whole week in one call, with one outcome line per entry |
| Declared time over a week or a period, names filled in |
| Totals per day and per project, plus the days that fall short |
| Change a declaration's duration, day, task or description |
| Remove one, with |
log_time is the one to know. {"project": "Alyxa", "duration": "2h30", "date": "yesterday", "description": "pairing on the importer"} is enough: the project is
matched by name, its single declarable task is chosen (or you name one), the duration
becomes seconds, and the answer repeats the day's new total so a double entry is
visible immediately.
projects — the catalogue, and its administration
Tool | |
| Filtered by status, customer, or a fragment of name or code |
| One project in full |
| The tasks of a project, containers and completed ones filtered out |
| One task in full |
| Budget and time counters |
| Project administration |
| Task administration |
directory — people and labels
Tool | |
| The team |
| Customers |
| Groups (read-only upstream) |
| Tags (read-only upstream) |
leaves — days off
Tool | |
| Read |
| Write |
| Feed Gryzzly a CSV or XLSX, inline or from a path |
budget — what a project costs beyond time
Tool | |
| Purchases |
| Discounts |
Gryzzly gates both behind its budget offer; without it every call answers
no_permission, and the error says so.
exports — the two download endpoints
Tool | |
| Gryzzly's project export, CSV or XLSX |
| Declarations and leaves, CSV or XLSX |
Both are exposed for completeness and both currently fail with an API key: see Gryzzly, as it actually behaves.
Resources and prompts
Four resources and two templates, for clients that prefer attaching context to calling a function:
URI | |
| The current user and their week |
| Every project |
| Every user the key can see |
| Every customer |
| The tasks of one project, by name or id |
| One week, totalled — |
Three prompts drive the workflows, and all three read before they write:
fill_my_week— read the week, propose the missing entries from real evidence, show a table, stop and wait, then write it in onelog_time_bulkcall.weekly_review— totals, per-project split, and what looks wrong. Writes nothing.catch_up_timesheet— find the empty working days over a period and close them one approved week at a time, leave periods excluded.
Gryzzly, as it actually behaves
Everything below was found against the live API, and every line of it is handled for you. It is written down because the next person integrating Gryzzly will hit the same walls.
What happens | What this server does |
A | Reads that 404 as the empty page it means, so "no time logged last week" is not an error |
| Always sends both |
There is no |
|
There is no |
|
| Reads the current values first, so a partial update stays partial |
| Says exactly that, and points at |
Purchases and discounts answer | Surfaces |
| Reported as a configuration problem when it is |
50 requests per 10 seconds, per team | A sliding window paces the process; 429 and transient 5xx are retried with backoff, honouring |
| Walked page by page when more is needed |
Safety
Filling a timesheet is a write operation on the record your employer bills from, so the defaults lean careful.
Deletes are fail-closed. Seven tools can destroy something; each refuses without
confirm: trueand says what would go. They are annotateddestructiveHint, so a client can warn before running them.Read-only is structural.
GRYZZLY_READ_ONLY=1drops every route that does not annotate itselfreadOnlyHint— not a list of names to keep in sync, so a new write tool is excluded by construction. A test asserts it.Nothing is guessed. An ambiguous name is an error with candidates. A malformed duration is refused before any HTTP call.
log_timereports the day's new total rather than letting a duplicate pass unnoticed.The key never leaks. It is redacted in
Debug, marked sensitive on the HTTP header, and never serialized into a tool answer or a log line.The prompts ask first. All three stop for explicit approval before writing, and the one that proposes entries is told not to invent what it cannot see.
Run it over HTTP instead
mcp-gryzzly --http 127.0.0.1:8080
# MCP at http://127.0.0.1:8080/mcp, health at /healthzOff loopback, the server refuses to start without GRYZZLY_HTTP_TOKEN: one API
key means one identity, and an open endpoint is an open proxy to your team's
timesheet. With the token set, every request to /mcp needs
Authorization: Bearer <token>; /healthz stays open for probes.
docker run -d --name mcp-gryzzly -p 8080:8080 \
-e GRYZZLY_API_KEY=… \
-e GRYZZLY_USER_EMAIL=you@example.com \
-e GRYZZLY_HTTP_BIND=0.0.0.0:8080 \
-e GRYZZLY_HTTP_TOKEN="$(openssl rand -hex 32)" \
mcp-gryzzlyPut TLS in front of it. The process speaks plain HTTP and does not pretend otherwise.
Verify
cargo test # 88 tests
cargo clippy --all-targets -- -D warnings
cargo fmt --all --check
mcp-gryzzly --list-tools # the surface, as registered
mcp-gryzzly --check # the configuration, against the live APIThe suite includes the protocol itself: tests/mcp_stdio.rs spawns the real binary,
speaks JSON-RPC to its stdin and asserts on what comes back — the handshake, all 53
tools with their schemas, the resources, the prompts, an ambiguous name, a refused
delete, read-only mode. tests/api_contract.rs holds every quirk in the table above
against a fake Gryzzly, and tests/mcp_http.rs checks the HTTP transport and its
bearer guard.
src/
├── client.rs RPC over HTTP: rate limiting, retries, the empty-list 404
├── config.rs the environment, validated once, with the key redacted
├── resolve.rs names to identifiers, and the refusal to guess
├── duration.rs 2h30, 90m, 1.5h, 2:30
├── dates.rs today, monday, 2026-W38
├── model.rs the Gryzzly objects, read leniently
├── tools/ one module per toolset, one function per tool
├── resources.rs four URIs and two templates
├── prompts.rs three workflows that ask before writing
└── server.rs capabilities, instructions, and the glueContributing
Issues and pull requests welcome. A change is ready when cargo test,
cargo clippy --all-targets -- -D warnings and cargo fmt --all --check pass, and
when a new tool carries a description, an annotation and an output schema — three
tests will tell you if it does not.
gh repo edit edouard-claude/gryzzly-mcp --add-topic \
mcp,model-context-protocol,mcp-server,gryzzly,time-tracking,timesheet,rust,rmcp,llm-tools,ai-agents,claude,claude-desktop,claude-code,anthropic,api-client,productivity,developer-tools,automation,stdio,streamable-httpLicense
MIT — see LICENSE. Not affiliated with Gryzzly.
mcp-name: io.github.edouard-claude/gryzzly-mcp
Available Tools
53 toolscreate_customerA
Create a customer, the organisation projects are attached to and billed for. Managers can be given by name, email or id. Use it before create_project when the customer does not exist yet; check list_customers first, since a second call creates a duplicate. Returns the new customer with its id.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The customer's name. | |
| managers | No | The managers, by name, email or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The customer's identifier. |
| name | No | The customer's name. |
| managers | No | The users managing this customer. |
| is_active | No | Whether the customer is active. |
| created_at | No | When the customer was created. |
| updated_at | No | When the customer was last updated. |
create_discountA
Grant a discount on exactly one project or one task, named or identified, with a name and an amount taken off its budget. Use it to add a discount; use update_discount to change one. Each call creates a new record, so check list_discounts first to avoid granting it twice. Passing both a project and a task, or neither, is refused before any request. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The discount's name. | |
| task | No | The task it applies to, by name or id. One of project or task. | |
| amount | No | How much is taken off. | |
| project | No | The project it applies to, by name, code or id. One of project or task. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The discount's identifier. |
| name | No | The discount's name. |
| amount | No | How much is taken off. |
| task_id | No | The task it applies to. |
| created_at | No | When the discount was created. |
| project_id | No | The project it applies to. |
| updated_at | No | When the discount was last updated. |
create_leave_periodA
Declare a leave period (days off) for a user, the current one by default. Use it for holidays and absences; use update_leave_period to move one and list_leave_periods to check existing ones first. Half days are expressed with start_type and end_type: a single afternoon off is the same day twice, pm to pm. Gryzzly refuses a leave over days that already carry time unless delete_declarations is true, which deletes that time irreversibly.
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Whose leave it is, by name, email or id. Defaults to the current user. | |
| end_at | No | Last day off. Defaults to `start_at`, which is one day off. | |
| end_type | No | How much of the last day is off. Defaults to `full`. | |
| start_at | Yes | First day off. | |
| start_type | No | How much of the first day is off. Defaults to `full`. | |
| description | No | Why the person is away. | |
| delete_declarations | No | Delete the declarations already made over those days. Defaults to false, which makes Gryzzly refuse the leave when time is already declared. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The leave period's identifier. |
| end_at | No | The last day of the leave. |
| user_id | No | The user on leave. |
| end_type | No | `full`, `am` or `pm`. |
| start_at | No | The first day of the leave. |
| edited_by | No | Who last edited the leave period. |
| created_at | No | When the leave period was created. |
| start_type | No | `full`, `am` or `pm`. |
| updated_at | No | When the leave period was last updated. |
| description | No | Why the person is away. |
create_projectA
Create a project, the container tasks and time are attached to. A customer and managers or contributors can be named rather than identified. Gryzzly needs a start date, so today is used when none is given; a private project takes contributors, a public one must not. Check list_projects first, since a second call creates a duplicate; then add tasks with create_task, because time cannot be logged on a project without one.
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | The project's short code. | |
| name | Yes | The project's name. | |
| tags | No | Tag identifiers to attach. | |
| end_at | No | When the project is supposed to end. | |
| groups | No | Group identifiers to assign. | |
| customer | No | The customer, by name or id. | |
| managers | No | The managers, by name, email or id. | |
| start_at | No | When the project starts. Required by Gryzzly. Defaults to today. | |
| visibility | No | `public` (everyone) or `private` (contributors only). | |
| is_billable | No | Whether the project is billable. | |
| contributors | No | The contributors, by name, email or id. Must be empty on a public project. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The project's identifier. |
| code | No | The project's short code. |
| name | No | The project's name. |
| note | No | The project note. |
| tags | No | The tags attached to the project. |
| end_at | No | When the project is supposed to end. |
| groups | No | The groups assigned to the project. |
| status | No | One of `active`, `done`, `archived`. |
| managers | No | The users managing the project. |
| start_at | No | When the project starts. |
| created_at | No | When the project was created. |
| updated_at | No | When the project was last updated. |
| visibility | No | `public` or `private`. |
| customer_id | No | The customer this project belongs to, when any. |
| is_billable | No | Whether the project is billable. |
| contributors | No | The users allowed to declare on a private project. |
create_purchaseA
Record a purchase (an expense outside declared time) against exactly one project or one task, both accepted by name or id. Use it to add a cost; use update_purchase to change an existing one. Creates a new record on every call, so check list_purchases first to avoid duplicates. billing_policy add counts it in the budget, ignore records it only. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | What was bought. | |
| task | No | The task it is charged to, by name or id. One of project or task. | |
| paid_at | No | When it was paid. | |
| project | No | The project it is charged to, by name, code or id. One of project or task. | |
| billed_at | No | When it was billed. | |
| paid_price | No | What it cost. | |
| billed_price | No | What it is billed for. | |
| billing_policy | No | Whether it counts in the budget. Defaults to `add`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The purchase's identifier. |
| name | No | What was bought. |
| paid_at | No | When it was paid. |
| task_id | No | The task it is charged to. |
| billed_at | No | When it was billed. |
| created_at | No | When the purchase was created. |
| paid_price | No | What it cost. |
| project_id | No | The project it is charged to. |
| updated_at | No | When the purchase was last updated. |
| billed_price | No | What it was billed for. |
| billing_policy | No | `add` or `ignore`, how it weighs on the budget. |
create_taskA
Create a task in a project, both named or identified. Tasks are what time is declared against, so a project needs at least one before log_time works. A task with is_container true only holds other tasks and takes no time; a subtask names its parent. planned_duration and estimated_duration accept human durations (40h, 90m). Check list_tasks first, since a second call creates a duplicate.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The task's name. | |
| tags | No | Tag names to attach. | |
| end_at | No | When the task is supposed to end. | |
| groups | No | Group identifiers to assign. | |
| parent | No | The parent task, by name or id, when this is a subtask. | |
| project | Yes | The project it belongs to, by name, code or id. | |
| start_at | No | When the task starts. Required by Gryzzly. Defaults to today. | |
| budget_type | No | How the budget is expressed. | |
| hourly_rate | No | The hourly rate, when the type calls for one. | |
| is_container | No | Whether this task only holds other tasks. A container takes no time. | |
| budget_amount | No | The budget amount, when the type calls for one. | |
| hourly_rate_mode | No | Where the hourly rate comes from. | |
| planned_duration | No | Planned time, as a duration (`40h`, `3600s`, `90m`). | |
| estimated_duration | No | Estimated time, as a duration. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The task's identifier. |
| name | No | The task's name. |
| tags | No | The tags attached to the task. |
| end_at | No | When the task is supposed to end. |
| groups | No | The groups assigned to the task. |
| start_at | No | When the task starts. |
| parent_id | No | The parent task, when this task is a subtask. |
| created_at | No | When the task was created. |
| project_id | No | The project the task belongs to. |
| updated_at | No | When the task was last updated. |
| budget_type | No | One of `none`, `detailed`, `global`, `time`. |
| hourly_rate | No | The task's hourly rate. |
| completed_at | No | When the task was completed. |
| is_container | No | Whether the task only holds other tasks. |
| budget_amount | No | The task's budget. |
| hourly_rate_mode | No | One of `task`, `group`, `contributor`. |
| planned_duration | No | Planned duration, in seconds. |
delete_customerADestructiveIdempotent
Delete a customer. Gryzzly refuses while projects are attached to it.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | Must be `true` to delete. Ignored when reading. | |
| customer | Yes | The customer, by name or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_discountADestructiveIdempotent
Delete a discount, which puts its amount back into the project's budget.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_leave_periodADestructiveIdempotent
Delete a leave period, which frees its days for declarations again.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The leave period's identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_projectADestructiveIdempotent
Delete a project. Gryzzly refuses while declarations are attached to it,
which is the safety net; confirm: true is this server's.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | Must be `true`. Without it nothing is deleted. | |
| project | Yes | The project to delete, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_purchaseADestructiveIdempotent
Delete a purchase, which removes its amount from the project's budget.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_taskADestructiveIdempotent
Delete a task. Gryzzly refuses while declarations are attached to it.
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | The task to delete, by name or id. | |
| confirm | No | Must be `true`. Without it nothing is deleted. | |
| project | No | The project it belongs to, to disambiguate a name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
delete_time_entryADestructiveIdempotent
Delete one time declaration by its id, as returned by list_time_entries. Irreversible: Gryzzly has no undo, so the call refuses to run without confirm true, and the person should see the entry and agree first. Use update_time_entry instead to correct a duration, day, task or description.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The declaration's identifier. | |
| confirm | No | Must be `true`. Without it nothing is deleted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | What was deleted. |
| kind | Yes | The kind of object that was deleted. |
| deleted | Yes | Always true: a failure is an error, not a `false`. |
export_projectsARead-only
Download Gryzzly's project export, as CSV or XLSX. Upstream this endpoint wants a browser session, so with an API key it usually fails with an explanation rather than a file.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Last day of the period. | |
| from | No | First day of the period. | |
| format | No | The file format. Defaults to `csv`. | |
| save_to | No | A path on the machine running this server to write the file to. | |
| projects | No | The projects to export, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the file was too large to inline. |
| text | No | The file itself, when it is text and small enough to read here. |
| bytes | Yes | How many bytes came back. |
| saved_to | No | Where the file was written, when `save_to` was given. |
| content_type | Yes | The file's media type, as Gryzzly labelled it. |
export_times_and_leavesARead-only
Download Gryzzly's combined export of declared time and leave periods over a date range, as CSV or XLSX, optionally saved to a path on the server's machine. Prefer list_time_entries or timesheet for reading time: this endpoint authenticates a browser session upstream, so with an API key it currently fails with an explanation rather than a file. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Last day of the period. | |
| from | No | First day of the period. | |
| format | No | The file format. Defaults to `csv`. | |
| save_to | No | A path on the machine running this server to write the file to. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the file was too large to inline. |
| text | No | The file itself, when it is text and small enough to read here. |
| bytes | Yes | How many bytes came back. |
| saved_to | No | Where the file was written, when `save_to` was given. |
| content_type | Yes | The file's media type, as Gryzzly labelled it. |
get_customerARead-only
Read one customer: whether it is active, and who manages it.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | Must be `true` to delete. Ignored when reading. | |
| customer | Yes | The customer, by name or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The customer's identifier. |
| name | No | The customer's name. |
| managers | No | The users managing this customer. |
| is_active | No | Whether the customer is active. |
| created_at | No | When the customer was created. |
| updated_at | No | When the customer was last updated. |
get_discountARead-only
Read one discount by its identifier: name, amount, and the project or task it applies to. Use list_discounts to find the id first. Read-only; an unknown id is reported as not found. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The discount's identifier. |
| name | No | The discount's name. |
| amount | No | How much is taken off. |
| task_id | No | The task it applies to. |
| created_at | No | When the discount was created. |
| project_id | No | The project it applies to. |
| updated_at | No | When the discount was last updated. |
get_groupARead-only
Read one group by identifier: its name, its groupset, its manager.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The object's identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The group's identifier. |
| name | No | The group's name. |
| created_at | No | When the group was created. |
| manager_id | No | The group's manager. |
| updated_at | No | When the group was last updated. |
| groupset_id | No | The groupset the group belongs to. |
get_groupsetARead-only
Read one groupset by identifier, and whether its groups are exclusive.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The object's identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The groupset's identifier. |
| name | No | The groupset's name. |
| color | No | The colour shown in the interface. |
| created_at | No | When the groupset was created. |
| updated_at | No | When the groupset was last updated. |
| is_group_unique | No | Whether one group of this set at most may be attributed. |
get_leave_periodARead-only
Read one leave period by identifier: its days, its half days, its reason.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The leave period's identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The leave period's identifier. |
| end_at | No | The last day of the leave. |
| user_id | No | The user on leave. |
| end_type | No | `full`, `am` or `pm`. |
| start_at | No | The first day of the leave. |
| edited_by | No | Who last edited the leave period. |
| created_at | No | When the leave period was created. |
| start_type | No | `full`, `am` or `pm`. |
| updated_at | No | When the leave period was last updated. |
| description | No | Why the person is away. |
get_projectARead-only
Read one project in full, found by name, code or id: status, dates, visibility, contributors, managers, groups, tags, customer and note. Use list_projects to browse or search; use get_project_metrics for budget and time counters. Read-only. An ambiguous name is refused with the matching candidates rather than guessed.
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | The project, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The project's identifier. |
| code | No | The project's short code. |
| name | No | The project's name. |
| note | No | The project note. |
| tags | No | The tags attached to the project. |
| end_at | No | When the project is supposed to end. |
| groups | No | The groups assigned to the project. |
| status | No | One of `active`, `done`, `archived`. |
| managers | No | The users managing the project. |
| start_at | No | When the project starts. |
| created_at | No | When the project was created. |
| updated_at | No | When the project was last updated. |
| visibility | No | `public` or `private`. |
| customer_id | No | The customer this project belongs to, when any. |
| is_billable | No | Whether the project is billable. |
| contributors | No | The users allowed to declare on a private project. |
get_project_metricsARead-only
Read the budget and time counters of one project, found by name, code or id: budget amount, budget spent, planned time and elapsed (declared) time, durations in seconds. Use list_projects_metrics to compare several projects in one call, and get_project for the project's settings rather than its numbers. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | The project, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| project_id | No | The project these metrics belong to. |
| budget_spent | No | How much of the budget is spent. |
| time_elapsed | No | Declared time, in seconds. |
| time_planned | No | Planned time, in seconds. |
| budget_amount | No | The project's budget. |
get_purchaseARead-only
Read one purchase by its identifier: name, project or task it is charged to, paid and billed prices, dates and billing policy. Use list_purchases to find the id first. Read-only; an unknown id is reported as not found. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The identifier. | |
| confirm | No | Must be `true` to delete. Ignored when reading. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The purchase's identifier. |
| name | No | What was bought. |
| paid_at | No | When it was paid. |
| task_id | No | The task it is charged to. |
| billed_at | No | When it was billed. |
| created_at | No | When the purchase was created. |
| paid_price | No | What it cost. |
| project_id | No | The project it is charged to. |
| updated_at | No | When the purchase was last updated. |
| billed_price | No | What it was billed for. |
| billing_policy | No | `add` or `ignore`, how it weighs on the budget. |
get_tagARead-only
Read one tag by identifier: its name and the tagset it belongs to.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The object's identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The tag's identifier. |
| name | No | The tag's name. |
| tagset_id | No | The tagset the tag belongs to. |
| created_at | No | When the tag was created. |
| updated_at | No | When the tag was last updated. |
get_tagsetARead-only
Read one tagset by identifier, and whether its tags are exclusive.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The object's identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The tagset's identifier. |
| name | No | The tagset's name. |
| color | No | The colour shown in the interface. |
| created_at | No | When the tagset was created. |
| updated_at | No | When the tagset was last updated. |
| is_tag_unique | No | Whether one tag of this set at most may be attributed. |
get_taskARead-only
Read one task in full: its budget, its rate, its planned time, its place in the project's hierarchy.
| Name | Required | Description | Default |
|---|---|---|---|
| task | Yes | The task, by name or id. | |
| project | No | The project the task belongs to, to disambiguate a name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The task's identifier. |
| name | No | The task's name. |
| tags | No | The tags attached to the task. |
| end_at | No | When the task is supposed to end. |
| groups | No | The groups assigned to the task. |
| start_at | No | When the task starts. |
| parent_id | No | The parent task, when this task is a subtask. |
| created_at | No | When the task was created. |
| project_id | No | The project the task belongs to. |
| updated_at | No | When the task was last updated. |
| budget_type | No | One of `none`, `detailed`, `global`, `time`. |
| hourly_rate | No | The task's hourly rate. |
| completed_at | No | When the task was completed. |
| is_container | No | Whether the task only holds other tasks. |
| budget_amount | No | The task's budget. |
| hourly_rate_mode | No | One of `task`, `group`, `contributor`. |
| planned_duration | No | Planned duration, in seconds. |
get_userARead-only
Read one user: their role, their groups, the date their times are approved until, and their rates when the plan exposes them.
| Name | Required | Description | Default |
|---|---|---|---|
| user | Yes | The user, by name, email, id, or `me`. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The user's identifier. |
| code | No | The user's code, as set by the administrators. |
| name | No | The user's display name. |
| role | No | One of `contributor`, `collaborator`, `manager`, `director`, `admin`. |
| No | The user's email address. | |
| groups | No | The groups the user belongs to. |
| created_at | No | When the user was created. |
| updated_at | No | When the user was last updated. |
| disabled_at | No | When the user was disabled, if they were. |
| hourly_cost | No | The user's hourly cost. Only on the budget offer. |
| hourly_rate | No | The user's hourly rate. Only on the budget offer. |
| is_disabled | No | Deprecated upstream in favour of `disabled_at`. |
| timesheet_approved_until | No | The date until which this user's times are approved. |
import_leave_periodsA
Import leave periods from a CSV or an XLSX. The content can be written inline, or read from a path on the machine running this server. The report names every line Gryzzly refused.
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | The format. Inferred from the file extension, or `csv` for inline content. | |
| content | No | The file's contents, for a CSV written inline. | |
| file_path | No | A path on the machine running this server, for a CSV or an XLSX. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | Whether the import went through. |
| errors | No | Every line the importer rejected. |
invite_userA
Invite someone to the team by email. Gryzzly sends the invitation; the user exists from that moment, pending their acceptance.
| Name | Required | Description | Default |
|---|---|---|---|
| role | No | The role to grant. Defaults to `contributor`. | |
| Yes | The email address to invite. Gryzzly sends the invitation itself. | ||
| group_ids | No | Group identifiers to put the new user in. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The user's identifier. |
| code | No | The user's code, as set by the administrators. |
| name | No | The user's display name. |
| role | No | One of `contributor`, `collaborator`, `manager`, `director`, `admin`. |
| No | The user's email address. | |
| groups | No | The groups the user belongs to. |
| created_at | No | When the user was created. |
| updated_at | No | When the user was last updated. |
| disabled_at | No | When the user was disabled, if they were. |
| hourly_cost | No | The user's hourly cost. Only on the budget offer. |
| hourly_rate | No | The user's hourly rate. Only on the budget offer. |
| is_disabled | No | Deprecated upstream in favour of `disabled_at`. |
| timesheet_approved_until | No | The date until which this user's times are approved. |
list_customersARead-only
List customers, the organisations projects are attached to and billed for. Use it to find a customer's id or name before create_project or list_projects(customer=...); use get_customer for one customer's detail. Read-only. Filter by name fragment, active status, or managers given by name, email or id. An empty result is an empty list, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only customers whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| managers | No | Keep only customers managed by these people, by name, email or id. | |
| is_active | No | Keep only active, or only inactive, customers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_discountsARead-only
List discounts (amounts taken off a project's or task's budget) with their names and amounts. Use it to audit what was granted on a project; use get_discount when you already hold one discount id. Read-only. Filters accept project and task names, codes or ids. Without Gryzzly's budget offer every call answers no_permission.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| tasks | No | Keep only charges of these tasks, by name or id. | |
| offset | No | How many objects to skip, for the next page. | |
| projects | No | Keep only charges of these projects, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_groupsARead-only
List groups, the user groupings Gryzzly assigns projects and rates to. Read-only upstream: groups are managed in the Gryzzly interface.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | Keep only these identifiers. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only entries whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| set_ids | No | Keep only members of these sets, by identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_groupsetsARead-only
List groupsets, the families user groups belong to (a groupset holds groups such as teams or sites). Use it to understand how the team is organised before reading list_groups; use get_groupset for one groupset. Read-only, and read-only upstream too: groupsets are managed in the Gryzzly web app. An empty result is an empty list.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | Keep only these identifiers. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only entries whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| set_ids | No | Keep only members of these sets, by identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_leave_periodsARead-only
List leave periods over a week or a period. Useful before logging time: Gryzzly refuses a declaration on a day already declared as leave.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Last day of an explicit period. | |
| from | No | First day of an explicit period. | |
| week | No | A week: `this week`, `last week`, `2026-W38`, or a date inside it. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| users | No | Whose leaves to read, by name, email or id. Defaults to everyone. | |
| offset | No | How many objects to skip, for the next page. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_projectsARead-only
List projects, filtered by status, customer or a fragment of their name
or code. This is the starting point for logging time: a project's name
here is what log_time accepts.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only projects whose name or code contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| status | No | Keep only these statuses. Defaults to every status. | |
| customer | No | Keep only projects of this customer, by name or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_projects_metricsARead-only
Read budget and time counters (budget amount, budget spent, planned and elapsed time in seconds) for several projects in one call, each given by name, code or id. Use it to compare projects or build a portfolio view; use get_project_metrics for a single project. Read-only. Every name is resolved before the request: an unknown or ambiguous one fails the whole call with the candidates listed.
| Name | Required | Description | Default |
|---|---|---|---|
| projects | Yes | The projects to measure, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_purchasesARead-only
List purchases (extra costs such as licences or subcontracting) charged to projects or tasks, with paid and billed amounts and dates. Use it to review what a project cost beyond time; use get_purchase when you already hold one purchase id. Read-only. Filters accept project and task names, codes or ids; an unknown name is an error listing what exists. Without Gryzzly's budget offer every call answers no_permission.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| tasks | No | Keep only charges of these tasks, by name or id. | |
| offset | No | How many objects to skip, for the next page. | |
| projects | No | Keep only charges of these projects, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_tagsARead-only
List tags, which projects and tasks are labelled with. Read-only upstream: tags are managed in the Gryzzly interface.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | Keep only these identifiers. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only entries whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| set_ids | No | Keep only members of these sets, by identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_tagsetsARead-only
List tagsets, the families tags belong to (a tagset holds tags used to label projects and tasks). Use it before list_tags to see which tag families exist; use get_tagset for one tagset. Read-only, and read-only upstream too: tagsets are managed in the Gryzzly web app. An empty result is an empty list.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | Keep only these identifiers. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only entries whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| set_ids | No | Keep only members of these sets, by identifier. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_tasksARead-only
List the tasks of a project, which is what time is actually declared against. Container tasks and completed tasks are filtered out by default, since neither is a place to log time.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only tasks whose name contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| project | No | Keep only tasks of this project, by name, code or id. | |
| include_completed | No | Include tasks already completed. Defaults to true. | |
| include_containers | No | Include container tasks, which hold other tasks and take no time. Defaults to false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
list_time_entriesARead-only
Read declared time over a week or a period, with task and project names filled in, per-day and per-project totals, and the identifiers needed to change an entry. Read before you write.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Last day of an explicit period. Defaults to `from`. | |
| from | No | First day of an explicit period. Ignored when `week` is set. | |
| task | No | Keep only this task, by name or id. | |
| user | No | Whose time to read. Defaults to the user this server acts as. | |
| week | No | A week: `this week`, `last week`, `2026-W38`, or a date inside it. | |
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| offset | No | How many objects to skip, for the next page. | |
| project | No | Keep only this project, by name, code or id. |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | Last day of the period. |
| days | Yes | One line per day that carries time. |
| from | Yes | First day of the period. |
| user | Yes | Whose time this is. |
| week | No | The ISO week, when the period is exactly one. |
| total | Yes | The same, human readable. |
| entries | No | The declarations themselves, when the caller asked for them. |
| projects | Yes | One line per project, largest first. |
| total_hours | Yes | The same, in decimal hours. |
| total_seconds | Yes | Declared time over the period, in seconds. |
| missing_workdays | Yes | Working days of the period with nothing declared. |
list_usersARead-only
List the users this API key can see, which is the whole team. Disabled users are left out unless asked for.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | How many objects to return. Upstream maximum is 1000. | |
| query | No | Keep only users whose name or email contains this text. | |
| offset | No | How many objects to skip, for the next page. | |
| include_disabled | No | Include users who have been disabled. Defaults to false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Set when the answer is worth a word of explanation. |
| count | Yes | How many objects match the filters upstream, beyond this page. |
| items | Yes | The objects. |
| returned | Yes | How many objects this answer carries. |
log_timeA
Declare time. Gryzzly attaches time to a task, so name a task, or a
project whose tasks can be narrowed down to one. Durations are human:
2h30, 90m, 1.5h. The answer repeats the day's new total, which is
how you notice you have logged the same afternoon twice.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | The day: `today` (the default), `yesterday`, a weekday, `YYYY-MM-DD`. | |
| task | No | The task, by name or id. Optional when the project has one task only. | |
| user | No | Whose time it is. Defaults to the user this server acts as. | |
| project | No | The project, by name, code or id. Narrows the task lookup. | |
| duration | Yes | How long: `2h30`, `90m`, `1.5h`, `2:30`, or a bare number of minutes. | |
| description | No | What the time was spent on. Worth filling: it is what a human reads later. |
Output Schema
| Name | Required | Description |
|---|---|---|
| entry | Yes | The declaration Gryzzly created. |
| day_total | Yes | What the whole day now totals, so a double entry is visible at once. |
| day_total_seconds | Yes | The same, in seconds. |
log_time_bulkA
Declare several time entries in one call, which is what filling a week looks like: each entry takes the same arguments as log_time. Entries are created in order; by default a refusal does not stop the others, and every outcome is reported with its position. Read the week first with timesheet: Gryzzly accepts duplicates, so calling this twice logs twice.
| Name | Required | Description | Default |
|---|---|---|---|
| entries | Yes | The declarations to create, in order. | |
| stop_on_error | No | Stop at the first refusal instead of carrying on. Defaults to false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | Total time created, human readable. |
| failed | Yes | How many were refused. |
| created | Yes | How many declarations were created. |
| outcomes | Yes | One line per requested entry, in order. |
timesheetARead-only
Summarise declared time over a week or a period for one user, the current one by default: totals per day and per project, each project's share, and the working days below the expected hours. Use it to answer how much was logged or what is missing; use list_time_entries when you need the individual entries and their ids. Read-only. Optional project and task filters narrow the totals, not just a listing.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Last day of an explicit period. Defaults to `from`. | |
| from | No | First day of an explicit period. Ignored when `week` is set. | |
| task | No | Keep only this task, by name or id. | |
| user | No | Whose time to read. Defaults to the user this server acts as. | |
| week | No | A week: `this week`, `last week`, `2026-W38`, or a date inside it. | |
| project | No | Keep only this project, by name, code or id. | |
| expected_hours_per_day | No | Hours expected on a working day, used to list the days that fall short. Defaults to 7. |
Output Schema
| Name | Required | Description |
|---|---|---|
| to | Yes | Last day of the period. |
| days | Yes | One line per day that carries time. |
| from | Yes | First day of the period. |
| user | Yes | Whose time this is. |
| week | No | The ISO week, when the period is exactly one. |
| total | Yes | The same, human readable. |
| entries | No | The declarations themselves, when the caller asked for them. |
| projects | Yes | One line per project, largest first. |
| total_hours | Yes | The same, in decimal hours. |
| total_seconds | Yes | Declared time over the period, in seconds. |
| missing_workdays | Yes | Working days of the period with nothing declared. |
update_customerAIdempotent
Change an existing customer, found by name or id: rename it, mark it active or inactive, or replace its managers (the list you pass replaces the current one). Fields you omit are kept; Gryzzly requires a name on every update, so the current one is resent. Use delete_customer to remove a customer instead.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | A new name. Gryzzly requires one on every update; the current one is sent when this is absent. | |
| customer | Yes | The customer to change, by name or id. | |
| managers | No | The managers, by name, email or id. Replaces the current list. | |
| is_active | No | Whether the customer is active. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The customer's identifier. |
| name | No | The customer's name. |
| managers | No | The users managing this customer. |
| is_active | No | Whether the customer is active. |
| created_at | No | When the customer was created. |
| updated_at | No | When the customer was last updated. |
update_discountAIdempotent
Change an existing discount's name or amount, by its identifier. Only the fields you pass are sent. Use create_discount for a new one and delete_discount to remove one; the project or task a discount applies to cannot be moved. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The discount's identifier. | |
| name | No | A new name. | |
| amount | No | A new amount. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The discount's identifier. |
| name | No | The discount's name. |
| amount | No | How much is taken off. |
| task_id | No | The task it applies to. |
| created_at | No | When the discount was created. |
| project_id | No | The project it applies to. |
| updated_at | No | When the discount was last updated. |
update_leave_periodAIdempotent
Change a leave period: move it, shorten it, turn a full day into a half one.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The leave period's identifier. | |
| end_at | No | A new last day. | |
| end_type | No | How much of the last day is off. | |
| start_at | No | A new first day. | |
| start_type | No | How much of the first day is off. | |
| description | No | A new description. | |
| delete_declarations | No | Delete the declarations already made over those days. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The leave period's identifier. |
| end_at | No | The last day of the leave. |
| user_id | No | The user on leave. |
| end_type | No | `full`, `am` or `pm`. |
| start_at | No | The first day of the leave. |
| edited_by | No | Who last edited the leave period. |
| created_at | No | When the leave period was created. |
| start_type | No | `full`, `am` or `pm`. |
| updated_at | No | When the leave period was last updated. |
| description | No | Why the person is away. |
update_projectAIdempotent
Change a project. Gryzzly requires a start date on every update, so the current one is sent when none is given.
| Name | Required | Description | Default |
|---|---|---|---|
| code | No | A new code. | |
| name | No | A new name. | |
| tags | No | Tag identifiers. Replaces the current list. | |
| end_at | No | A new end date. | |
| groups | No | Group identifiers. Replaces the current list. | |
| status | No | A new status. | |
| project | Yes | The project to change, by name, code or id. | |
| customer | No | A new customer, by name or id. | |
| managers | No | The managers, by name, email or id. Replaces the current list. | |
| start_at | No | A new start date. Gryzzly requires one on every update; the current one is sent when this is absent. | |
| visibility | No | A new visibility. | |
| is_billable | No | Whether the project is billable. | |
| contributors | No | The contributors, by name, email or id. Replaces the current list. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The project's identifier. |
| code | No | The project's short code. |
| name | No | The project's name. |
| note | No | The project note. |
| tags | No | The tags attached to the project. |
| end_at | No | When the project is supposed to end. |
| groups | No | The groups assigned to the project. |
| status | No | One of `active`, `done`, `archived`. |
| managers | No | The users managing the project. |
| start_at | No | When the project starts. |
| created_at | No | When the project was created. |
| updated_at | No | When the project was last updated. |
| visibility | No | `public` or `private`. |
| customer_id | No | The customer this project belongs to, when any. |
| is_billable | No | Whether the project is billable. |
| contributors | No | The users allowed to declare on a private project. |
update_purchaseAIdempotent
Change an existing purchase: name, paid or billed price, paid or billed date, billing policy. Only the fields you pass are sent; the rest are left as they are. Use create_purchase for a new cost and delete_purchase to remove one. Dates accept YYYY-MM-DD, today or yesterday. Requires Gryzzly's budget offer.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The purchase's identifier. | |
| name | No | A new name. | |
| paid_at | No | A new paid date. | |
| billed_at | No | A new billed date. | |
| paid_price | No | A new paid price. | |
| billed_price | No | A new billed price. | |
| billing_policy | No | A new billing policy. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The purchase's identifier. |
| name | No | What was bought. |
| paid_at | No | When it was paid. |
| task_id | No | The task it is charged to. |
| billed_at | No | When it was billed. |
| created_at | No | When the purchase was created. |
| paid_price | No | What it cost. |
| project_id | No | The project it is charged to. |
| updated_at | No | When the purchase was last updated. |
| billed_price | No | What it was billed for. |
| billing_policy | No | `add` or `ignore`, how it weighs on the budget. |
update_taskAIdempotent
Change a task: rename it, move its dates, set its budget or its rate, mark it completed.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | A new name. | |
| tags | No | Tag names. Replaces the current list. | |
| task | Yes | The task to change, by name or id. | |
| end_at | No | A new end date. | |
| groups | No | Group identifiers. Replaces the current list. | |
| project | No | The project it belongs to, to disambiguate a name. | |
| start_at | No | A new start date. | |
| hourly_rate | No | A new hourly rate. | |
| completed_at | No | When the task was completed. Marks it done. | |
| budget_amount | No | A new budget amount. | |
| hourly_rate_mode | No | Where the hourly rate comes from. | |
| planned_duration | No | Planned time, as a duration (`40h`, `90m`). |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The task's identifier. |
| name | No | The task's name. |
| tags | No | The tags attached to the task. |
| end_at | No | When the task is supposed to end. |
| groups | No | The groups assigned to the task. |
| start_at | No | When the task starts. |
| parent_id | No | The parent task, when this task is a subtask. |
| created_at | No | When the task was created. |
| project_id | No | The project the task belongs to. |
| updated_at | No | When the task was last updated. |
| budget_type | No | One of `none`, `detailed`, `global`, `time`. |
| hourly_rate | No | The task's hourly rate. |
| completed_at | No | When the task was completed. |
| is_container | No | Whether the task only holds other tasks. |
| budget_amount | No | The task's budget. |
| hourly_rate_mode | No | One of `task`, `group`, `contributor`. |
| planned_duration | No | Planned duration, in seconds. |
update_time_entryAIdempotent
Change one time entry (a declaration), by the id list_time_entries returns: its duration, its day, its task, its description. Gryzzly's update requires all of them, so whatever is left out is read back from the existing entry first. Use log_time to add time and delete_time_entry to remove an entry.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The declaration's identifier, as returned by `list_time_entries`. | |
| date | No | The new day. Left alone when absent. | |
| task | No | The new task, by name or id. Left alone when absent. | |
| user | No | Whose declaration it is, when it is not the current user's. | |
| project | No | The project the new task belongs to, to narrow the lookup. | |
| duration | No | The new duration. Left alone when absent. | |
| description | No | The new description. Left alone when absent. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The declaration's identifier, needed to update or delete it. |
| date | Yes | The day, as `YYYY-MM-DD`. |
| task | No | The task's name, when it could be resolved. |
| project | No | The project's name, when it could be resolved. |
| seconds | Yes | The duration in seconds, which is what Gryzzly stores. |
| task_id | Yes | The task the time is declared against. |
| user_id | Yes | Whose time it is. |
| duration | Yes | The duration, human readable. |
| project_id | No | The project the task belongs to. |
| description | No | What the time was spent on. |
whoamiARead-only
Who this server declares time for, what it is allowed to do, and how much time is already logged this week. Call it first: Gryzzly API keys belong to a team, not to a person, so the person has to be named by configuration, and this is where you see which one was.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| role | No | The user's role in Gryzzly. |
| user | Yes | The user this server declares time for. |
| toolsets | Yes | The toolsets this server exposes. |
| read_only | Yes | True when every write tool was withheld. |
| this_week | Yes | This week, so a client knows where it stands before logging anything. |
| team_users | Yes | How many users the API key can see. |
| identified_by | No | Which environment variable named this user, if any did. |
| default_project | No | The project used when a tool omits one. |
| timesheet_approved_until | No | The date until which this user's times are approved and locked. |
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
53 tool updates
v0.1.0- First observed
create_customer - First observed
create_discount - First observed
create_leave_period - First observed
create_project - First observed
create_purchase - First observed
create_task - First observed
delete_customer - First observed
delete_discount - First observed
delete_leave_period - First observed
delete_project - First observed
delete_purchase - First observed
delete_task - First observed
delete_time_entry - First observed
export_projects - First observed
export_times_and_leaves - First observed
get_customer - First observed
get_discount - First observed
get_group - First observed
get_groupset - First observed
get_leave_period - First observed
get_project - First observed
get_project_metrics - First observed
get_purchase - First observed
get_tag - First observed
get_tagset - First observed
get_task - First observed
get_user - First observed
import_leave_periods - First observed
invite_user - First observed
list_customers - First observed
list_discounts - First observed
list_groups - First observed
list_groupsets - First observed
list_leave_periods - First observed
list_projects - First observed
list_projects_metrics - First observed
list_purchases - First observed
list_tags - First observed
list_tagsets - First observed
list_tasks - First observed
list_time_entries - First observed
list_users - First observed
log_time - First observed
log_time_bulk - First observed
timesheet - First observed
update_customer - First observed
update_discount - First observed
update_leave_period - First observed
update_project - First observed
update_purchase - First observed
update_task - First observed
update_time_entry - First observed
whoami
TDQS
Scored across 53 tools
Each tool has a distinct action and resource, and descriptions explicitly cross-reference alternatives (e.g., list_projects vs get_project_metrics vs list_projects_metrics). The CRUD pairs and specialized tools (timesheet, log_time_bulk) are clearly delineated, leaving no real overlap.
The vast majority follow a consistent verb_noun pattern (list_projects, create_customer, update_task). Minor deviations like 'timesheet' (noun) and 'whoami' (phrase) are the only exceptions.
53 tools is excessive for any single server; even with a broad domain, this exceeds the 50-tool threshold for extreme mismatch. Many tools could be consolidated or grouped into resources.
Core entities (projects, tasks, time entries, leave, discounts, purchases, customers) have full CRUD and specialized operations. Minor gaps exist for users (no update/delete) and read-only upstream entities (groups/tags), but the surface is largely complete.
Maintenance
Related MCP Connectors
Read time entries, projects, clients, tasks and invoices; log and update tracked time.
Track time in Clockify: time entries, projects, clients, tags and reports; start, stop and log time.
Read projects, invoices, hours and contacts; register hours, create tasks in Gripp.
Start and stop timers, log time entries, and read projects, tasks and time entries in solidtime.
Related MCP Servers
- -licenseAqualityNot gradedmaintenanceEnables natural language time tracking through Claude with markdown file storage. Supports multi-company tracking, flexible time parsing, auto-calculated summaries, and commitment warnings all through conversational input.1-
- AlicenseNot gradedqualityDmaintenanceEnables automated timesheet management including creating entries, listing work activities, managing daily scrum updates, and viewing assigned projects with automatic authentication handling.2 npmMIT
- AlicenseNot gradedqualityDmaintenanceIntegrates with Clockify time tracking API to retrieve user information, manage projects, and log time entries with flexible time specifications across workspaces.MIT
- AlicenseBqualityBmaintenanceEnables MCP clients to query a self-hosted TimeTracker instance over its /api/v1 REST API, exposing tracked hours, per-day and per-project summaries, projects, clients, tasks, search, and active-timer status in natural language. Optionally registers write tools to start, stop, pause, resume, and create timers or time entries when write mode is enabled.10MIT