Clockify MCP
The Clockify MCP server provides comprehensive programmatic management of Clockify workspaces through 61 tools and a generic API escape hatch. It supports natural language time inputs (e.g., "yesterday 09:00 for 2h30m") and resolves names for projects, tasks, and tags.
Time Entries & Timers: Start/stop timers, log single or bulk workday entries, list with totals, summarize by project/task/day/description/tag (free plan), and update or delete entries.
Projects, Clients, Tasks & Tags: List, search, create, update, archive, and delete. Tasks can be marked done; all can be identified by name.
People & Workspaces: View identity (
whoami), list/inspect workspaces, find and manage users (invite, activate/deactivate, remove), and handle user groups (create, rename, add/remove members).Reports (paid plan): Summary, detailed, and weekly reports; a free
clockify_time_summaryalternative provides essential totals.Time Off & Approvals: Holidays, policies, balances, requests, and timesheet approvals (some features require a paid plan).
Paid-Plan Extras: Custom fields, expenses (list/create), invoices, and webhooks.
Generic API Access:
clockify_api_requestfor any Clockify endpoint not covered by dedicated tools, respecting read-only and workspace lock constraints.
Provides tools for managing Clockify timers, time entries, projects, tasks, tags, people, reports, and time off via the Clockify API.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Clockify MCPlog 2h30m on project website"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Clockify MCP
An MCP server for Clockify — timers, time entries, projects, tasks, tags, people, reports and time off, over the Model Context Protocol.
61 tools, plus clockify_api_request — a generic escape hatch to any Clockify endpoint that has
no dedicated tool, across all three of its API hosts.
The headline feature: times are given the way people say them. 09:00, yesterday, 2h30m —
resolved in the account's own time zone, across daylight-saving boundaries, so an entry lands on the
day you meant. Projects, tasks and tags can be named instead of addressed by id.
Two ways to run it
Mode | Transport | Configuration comes from | Use it when |
Hosted | Streamable HTTP on | request headers, per call | clients should connect to a URL with nothing installed |
Local | stdio | environment variables | credentials must not leave the machine |
The public deployment lives at https://clockify-mcp.webapace.ink — the landing page on /, the
MCP endpoint on /mcp. Connecting to it needs no install:
claude mcp add --transport http clockify \
https://clockify-mcp.webapace.ink/mcp \
--header "X-Clockify-Key: YOUR_API_KEY"Or write the configuration yourself. The same object goes into .mcp.json in a repository,
~/.claude.json, claude_desktop_config.json or .cursor/mcp.json — fill in the blanks:
{
"mcpServers": {
"clockify": {
"type": "http",
"url": "https://clockify-mcp.webapace.ink/mcp",
"headers": {
"X-Clockify-Key": "",
"X-Clockify-Workspace-Id": "",
"X-Clockify-Project-Id": ""
}
}
}
}Header | Fill in with | If left empty |
| your personal API key | the request is refused — this one is required |
| a workspace id from | the workspace the account is active in |
| the project this connection logs to | every entry needs its own project, or lands without one |
Where the ids come from walks through finding all three values in Clockify.
X-Clockify-Workspace-Lock, X-Clockify-Read-Only and X-Clockify-Timezone can be added the same
way; see Hosted mode for the full header list.
Keep the file out of version control, or write "X-Clockify-Key": "${CLOCKIFY_API_KEY}" — Claude
Code and Cursor substitute environment variables, so the secret stays in your shell.
Two things worth knowing when a change appears to do nothing:
In Claude Code an entry added to the local scope (kept in
~/.claude.json) takes precedence over the project's.mcp.json.claude mcp listshows what is actually in use, andclaude mcp remove <name> -s localdrops a stale one.Client configuration is read at startup, so restart the app after editing the file.
The rest of this document is for running your own copy in either mode.
Related MCP server: @lewinnovation/clockify-mcp-server
Install
git clone https://github.com/amalychev/clockify-mcp
cd clockify-mcp
npm install
npm run buildRequires Node.js 20 or newer.
API key
Clockify → your avatar → Profile settings → scroll to the bottom → API → Generate.
The key carries every permission your account has, in every workspace you belong to; Clockify has no scoped keys. Regenerating it in that screen invalidates the old one immediately, which is the way to revoke a leaked key.
What needs a paid Clockify plan, and returns 403 on the free one: the Reports API
(clockify_summary_report, clockify_detailed_report, clockify_weekly_report), expenses,
invoices, approvals and custom fields. Everything else — timers, entries, projects, tasks, tags,
people, holidays, time off — works on the free plan, and clockify_time_summary produces totals
without the Reports API by adding up the entries themselves.
Where the ids come from
The key is the only value that is required. A workspace id and a project id are what turn a generic connection into one that logs to the right place without being told every time.
Workspace id. Clockify → Settings in the left sidebar. The address bar becomes
https://app.clockify.me/workspaces/5e8395d5261ba37dee85a378/settings — the 24-character chunk in
the middle is the id. From the terminal instead:
curl -s -H "X-Api-Key: $CLOCKIFY_API_KEY" https://api.clockify.me/api/v1/workspaces \
| jq -r '.[] | "\(.id) \(.name)"'Project id. Clockify → Projects → open the project. The address bar becomes
https://app.clockify.me/projects/60f9c8b1a2d4e51f3c7b8a29/…; again, the 24-character chunk is the
id. Or list the active projects of a workspace:
curl -s -H "X-Api-Key: $CLOCKIFY_API_KEY" \
"https://api.clockify.me/api/v1/workspaces/<workspaceId>/projects?archived=false&page-size=200" \
| jq -r '.[] | "\(.id) \(.name)"'Or ask the assistant. With the server already connected on the key alone, clockify_whoami
reports the account, the active workspace and how the server is configured, clockify_list_workspaces
returns every workspace with its id, and clockify_find_project searches projects by part of a name.
Put the values into the configuration and restart the client, which reads it only at startup.
CLOCKIFY_PROJECT_ID and X-Clockify-Project-Id accept a project name as well — Website redesign rather than 60f9c8… — resolved once against the workspace, and refused if it matches
several projects. A name does not survive a rename, so prefer the id for anything long-lived.
Configuration
In stdio mode everything is configured through environment variables.
Variable | Required | Default | Description |
| yes | — | Personal API key |
| no | active workspace | Default workspace for every tool |
| no |
|
|
| no | — | Default project for new entries; an id or an unambiguous project name |
| no |
|
|
| no | account setting | IANA zone for wall-clock arguments |
| no |
| Main API root; a bare host gets |
| no | derived | Reports API root, normally |
| no | derived | Time-off API root, normally |
| no |
|
|
| no |
| Per-request timeout |
Aliases that are also read: CLOCKIFY_KEY / CLOCKIFY_TOKEN for the key, TZ for the zone,
CLOCKIFY_LOCK_WORKSPACE for the lock, CLOCKIFY_DEFAULT_PROJECT for the project.
Connecting a local copy
claude mcp add clockify \
--env CLOCKIFY_API_KEY=xxxxxxxx \
-- node /absolute/path/clockify-mcp/dist/index.jsOr in .mcp.json, so the configuration travels with the project:
{
"mcpServers": {
"clockify": {
"command": "node",
"args": ["/absolute/path/clockify-mcp/dist/index.js"],
"env": {
"CLOCKIFY_API_KEY": "xxxxxxxx",
"CLOCKIFY_WORKSPACE_ID": "5e8395d5261ba37dee85a378",
"CLOCKIFY_WORKSPACE_LOCK": "true",
"CLOCKIFY_PROJECT_ID": "60f9c8b1a2d4e51f3c7b8a29"
}
}
}
}To verify the connection, ask for clockify_whoami — it returns the account, the active workspace,
the time zone in use and how this server is configured.
Times, durations and names
This is what the server does beyond wrapping the API, and where most of its logic lives.
Instants. Anywhere a tool takes a time:
You write | It means |
| this moment |
| that wall-clock time, on the day the tool is working with |
| that wall-clock time on that date |
| midnight local |
| exactly that instant — zone handling is skipped |
Values without a zone are resolved in the account's zone, looked up once per session from the
Clockify profile and overridable with CLOCKIFY_TIMEZONE. The offset is computed for that specific
date, so an entry on a daylight-saving switchover lands at the wall-clock time you asked for.
Dates. today, yesterday and tomorrow work wherever a date is accepted, and are resolved in
the same zone rather than the server's.
Durations. 2h30m, 1.5h, 90m, PT2H30M, or a bare number, which is read as minutes.
Names instead of ids. project_name, task_name and tag_names are accepted alongside the id
arguments. An exact name wins; an ambiguous one is an error listing the candidates, because guessing
would book hours to the wrong client.
Hosted mode
Start the HTTP transport with MCP_TRANSPORT=http (or --http). It serves:
Route | Purpose |
| the landing page ( |
| the MCP endpoint, stateless — one server instance per request |
| liveness probe |
| generated per request from the |
| static files from |
GET /index.html redirects to / so the page has a single canonical address.
Every request carries its own credentials, so one deployment serves many people without holding state:
Header | Maps to | Notes |
|
| required unless the deployment sets a default; |
|
| default workspace |
|
|
|
|
| default project for new entries; a project name works too |
|
|
|
|
| IANA zone for wall-clock arguments |
|
| on-premise installations |
|
|
|
A blank header counts as absent, so a template shipped with empty strings falls back to the deployment defaults. Timeouts are deliberately not header-controlled: they are process-wide and belong to whoever runs the deployment.
Deployment settings:
Variable | Default | Description |
|
|
|
|
| listen address |
|
| page served at |
|
| icons, manifest and preview image |
| — | comma-separated hostnames; when set, only these may be targeted |
| — | fallbacks used when the corresponding header is absent |
Without an allowlist the server refuses private addresses (localhost, RFC 1918 ranges,
169.254.*, *.internal, *.local) so a public deployment cannot be used to probe the network it
runs in.
docker build -t clockify-mcp .
docker run -p 8080:8080 clockify-mcpDeploying
deploy.sh does the whole cycle on the server — pull, build, swap the container, verify, purge the
CDN cache:
./deploy.sh # the usual deploy
./deploy.sh --page-only # only replace landing.html and assets/ in the running container
./deploy.sh --no-pull # deploy the working tree as it is
./deploy.sh --logs # follow the container log afterwardsCopy deploy.env.example to deploy.env on the server and set the container name, PUBLIC_URL
and, if the site sits behind Cloudflare, a zone id and an API token with the Cache Purge permission.
deploy.env is git-ignored, so server-specific values stay there.
When a docker-compose.yml sits next to the script, it drives Compose instead of docker run:
building through docker compose build, swapping with docker compose up -d, and health-checking
from inside the container, because a Compose service behind a reverse proxy publishes no host port.
Compose names the container itself — usually <project>-app-1 — so put that exact name in
deploy.env, or the health check addresses nothing.
The previous image is tagged :previous before every build, and a failed health check restores it
automatically and exits non-zero, so a broken build never stays deployed.
Landing page assets
assets/ holds everything the page references: favicon.svg (the source of every raster icon),
favicon.ico, the touch and PWA icons, site.webmanifest, and og-image.png — the 1200×630
preview used by link unfurlers, rendered from assets/og-card.html.
The PNG and ICO files are committed, so a normal build needs nothing extra. Regenerate them only
after editing favicon.svg or og-card.html:
npm run assets # headless Chrome does the rasterising; set CHROME=… if it is not foundThe page carries a description, canonical URL, Open Graph and Twitter cards, and JSON-LD
(SoftwareApplication, WebSite, FAQPage). Those absolute URLs point at
clockify-mcp.webapace.ink; a self-hosted copy that should be indexed under its own name needs them
replaced in landing.html — robots.txt and sitemap.xml already follow the request host.
Because the endpoint accepts API keys from callers, put it behind TLS and treat access logs accordingly. The server itself keeps nothing: no sessions, no storage, one throwaway server instance per request.
Scoping: workspace and project
Most people belong to more than one workspace, and an assistant that wanders into the wrong one logs hours against the wrong client. Two levels of confinement, plus a default project inside them:
A default workspace. CLOCKIFY_WORKSPACE_ID (or X-Clockify-Workspace-Id) is used whenever a
tool omits workspace_id. Other workspaces stay reachable by asking for them explicitly.
A hard lock. Add CLOCKIFY_WORKSPACE_LOCK=true and the workspace becomes the only one that
exists:
every tool that takes
workspace_idrefuses any other value;clockify_list_workspacesis refused outright;clockify_api_requestmust address/workspaces/<the locked id>/…, with only/userexempt.
The refusal is explicit, so the assistant reports the boundary instead of silently returning nothing:
Refused: this server is locked to workspace 5e8395… (CLOCKIFY_WORKSPACE_LOCK=true),
so `61ab…` is out of scope.Read-only mode is the orthogonal control: CLOCKIFY_READ_ONLY=true refuses every tool that writes,
including non-GET calls through clockify_api_request.
A default project
CLOCKIFY_PROJECT_ID, or X-Clockify-Project-Id in hosted mode, names the project new time entries
belong to. clockify_start_timer, clockify_log_time and clockify_log_many use it whenever the
call itself carries no project_id or project_name — so a connection set up for one repository
logs into that repository's project, and nobody has to repeat the name in every request. A project
given in the call still wins, and task_name can then be resolved on its own, because the project it
belongs to is already known.
It is a default, not a lock. Reading tools are unaffected: clockify_list_time_entries and
clockify_time_summary still cover the whole workspace unless a project is asked for, which is what
makes "what did I do today" answer honestly. clockify_update_time_entry ignores it as well — an
edit to a description would otherwise quietly move the entry to another project.
Alongside CLOCKIFY_WORKSPACE_LOCK it gives a per-project connection: the workspace is the only one
reachable, and everything logged inside it lands on one project by default.
Tools
61 tools. Names are stable; the assistant picks them, so this list is for knowing what is possible.
Time entries and timers
Tool | Purpose |
| the running timer and how long it has been going |
| start the clock |
| stop it and return the finished entry |
| write one finished entry from local times |
| write a whole workday in one call, reporting each entry |
| entries for a day or range, with a total |
| totals per project, task, day or tag — no paid plan needed |
| one entry in full |
| change description, project, tags or times |
| delete one, with |
Projects, clients, tasks, tags
Tool | Purpose |
| find and inspect projects |
| manage them; archiving is |
| clients |
| tasks inside a project |
| tags |
People and workspaces
Tool | Purpose |
| account, active workspace, time zone, server configuration |
| workspaces |
| members and their ids |
| membership |
| teams |
| team membership |
Reports — paid plan
Tool | Purpose |
| totals grouped as in the Clockify summary report |
| every entry in the range, one row each |
| the weekly grid |
Time off and approvals
Tool | Purpose |
| the holiday calendar |
| policies and remaining days |
| requests |
| timesheet approvals — paid plan |
Everything else
Tool | Purpose |
| paid-plan features |
| any endpoint, on any of the three API hosts, honouring read-only and the workspace lock |
Development
src/
config.ts environment and header configuration, validation
time.ts wall clock ↔ UTC, durations, human formatting
clockify-client.ts HTTP, pagination, errors, workspace resolution and lock
server.ts builds the MCP server and registers every tool module
http.ts hosted transport: landing page, static assets, /mcp
index.ts entry point, picks stdio or HTTP
tools/
helpers.ts defineTool, shared argument shapes, read-only guard
resolve.ts name → id lookups for projects, tasks and tags
core.ts identity, workspaces, members
time-entries.ts timers, logging, listing, summarising
projects.ts projects and clients
tasks.ts tasks
tags.ts tags
users.ts membership and groups
reports.ts the Reports API
timeoff.ts holidays, policies, requests, approvals
misc.ts paid-plan corners and the raw API escape hatchnpm run dev # tsc --watch
npm run typecheck # no emit
npm run assets # regenerate icons and the social cardAdding a tool means one defineTool call in the right module: it wires up the input schema, the
read-only guard and uniform error handling, so the handler only makes the Clockify call.
Troubleshooting
Symptom | Cause |
| wrong key, or it was regenerated in Clockify, which invalidates the old one |
| the feature needs a paid plan, or your workspace role is too low |
| wrong id, or the key's owner is not a member of that workspace |
| Clockify allows about 50 requests a second per key |
Entries on the wrong day | check the zone |
| the name was ambiguous; use the exact name or the id |
|
|
Entries land without a project | no |
| working as intended |
| working as intended |
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseCqualityAmaintenanceEnables interacting with Clockify time-tracking data through natural language, providing tools to manage workspaces, projects, time entries, reports, and more via the MCP protocol.Last updated481MIT
- Alicense-qualityDmaintenanceMCP server that enables AI agents to interact with Clockify time tracking via curated workflows and a generic API tool for managing workspaces, projects, tasks, and time entries.Last updated13MIT
- AlicenseBqualityCmaintenanceMCP server for Clockify time tracking, enabling CRUD operations on workspaces, projects, tasks, clients, tags, users, and time entries.Last updated36MIT
- Alicense-qualityBmaintenanceRemote-first MCP server for personal Clockify time tracking, exposing tools to manage timers, entries, and reports via MCP clients like ChatGPT.Last updated1MIT
Related MCP Connectors
MCP server for generating rough-draft project plans from natural-language prompts.
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
Markdown-first MCP server for Notion API with 8 composite tools and 39 actions.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/amalychev/clockify-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server