Skip to main content
Glama

kimai-timelog-mcp

tests

An MCP server that lets Claude (or any MCP-capable LLM client) read and write your Kimai timesheets. You say "log 9 to 12:30 on the portal revamp, fixing the login redirect" and the entry appears in Kimai.

Every request is made as you — it uses your personal Kimai API token, so it can only see and change what your Kimai account is allowed to.


1. Get a Kimai API token

  1. Open Kimai → click your name (top right) → My profile → API access tab.

  2. Create a token, give it a name like claude, and copy it immediately — Kimai shows it exactly once.

Related MCP server: Kimai MCP Server

2. Install

You need uv (recommended) or Python 3.10+.

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows (PowerShell)
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"

Then either:

A. From a shared folder / git repo (what colleagues will do)

uvx --from git+https://github.com/Alpha101Code/kimai-timelog-mcp kimai-mcp --check

B. From a local copy

cd /path/to/kimai-timelog-mcp
uv run kimai-mcp --check

--check verifies the URL and token and prints your visible projects. Set the two environment variables first:

export KIMAI_URL=https://timesheet-sd.maccs.mu
export KIMAI_API_TOKEN=your-token-here

3. Wire it into your client

Claude Desktop

Settings → Developer → Edit Config, then add:

{
  "mcpServers": {
    "kimai": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/Alpha101Code/kimai-timelog-mcp", "kimai-mcp"],
      "env": {
        "KIMAI_URL": "https://timesheet-sd.maccs.mu",
        "KIMAI_API_TOKEN": "your-token-here"
      }
    }
  }
}

Restart Claude Desktop. On Windows use uvx.exe if uvx is not found on PATH.

Claude Code

claude mcp add kimai \
  --env KIMAI_URL=https://timesheet-sd.maccs.mu \
  --env KIMAI_API_TOKEN=your-token-here \
  -- uvx --from git+https://github.com/Alpha101Code/kimai-timelog-mcp kimai-mcp

Cursor / Windsurf / Cline / Zed

Same JSON shape as Claude Desktop, in that client's MCP config file (~/.cursor/mcp.json for Cursor).

Anything else

It is a standard stdio MCP server. Command: kimai-mcp. Config: the two environment variables above.


Tools

Tool

What it does

whoami

Who the token belongs to, their timezone, today's date

list_projects

Projects you can book against, searchable by name

list_activities

Activities valid for a project (project-specific + global)

list_customers

Customers you can see

list_tags

Tag names configured in Kimai

list_timesheets

Your entries for a date range, with totals

recent_entries

Your most recent project/activity/description combos

summarize_time

Hours totalled by project, activity or day

log_time

Write a finished entry

start_timer

Start a running entry

active_timers

What is currently running

stop_timer

Stop the running entry

restart_timer

Clone an old entry as a new running one

update_timesheet

Change an existing entry

delete_timesheet

Delete an entry (requires an explicit confirm)

Design choices worth knowing

  • Names, not IDs. project: "Portal Revamp" works; so does a unique partial like "portal". Ambiguous names come back as an error listing the candidates, which the model can put to you as a question.

  • Loose time input. date: today, yesterday, monday, 3 days ago, 2026-08-24, 25/08/2026. start/end: 09:00, 9am, 5.30pm, 0930. duration: 1h30m, 90m, 1.5h, 1:30.

  • Your timezone. Kimai reports the token owner's timezone; everything is resolved against that, not the server's clock.

  • No invented hours. log_time needs start+end, start+duration, or duration — if none is given it returns an error telling the model to ask you rather than guessing.

  • Delete is two-step. The first call returns what would be deleted; only a second call with confirm: true removes it.

Example prompts

Log 9:00–12:30 today on Portal Revamp, development, "fixed the login redirect".
What did I log this week? Break it down by project.
Same as yesterday afternoon, but for today.
Start a timer on Internal Tools / Admin.
I forgot Monday — 4 hours on Mobile App, release testing.
Move entry 512 to start at 10:15 instead.

Rolling it out to colleagues

Everyone needs three things: uv installed, their own Kimai token, and the config block above. Nothing is shared between users — no server to run, no central token.

If you later want a single hosted server instead of a per-machine install, the tool layer stays as-is; only the transport in __main__.py changes.

Security

  • The token is a password equivalent. It lives in your client's config file on your own machine — do not commit it, do not paste it into a shared doc.

  • Give tokens an expiry date in Kimai and rotate them.

  • The server talks only to KIMAI_URL. It has no other network access, no filesystem access, and no shell.

  • If your Kimai is internal-only, this must run on a machine that can reach it (VPN or office network).

Development

src/kimai_mcp/
  client.py     Kimai REST client — auth, errors, name→id resolution, caching
  timeutil.py   parsing for human dates, times and durations
  server.py     the MCP tools
  __main__.py   stdio entrypoint + --check
tests/
  mock_kimai.py a stand-in Kimai instance
  test_e2e.py   drives the real server over stdio against it

Run the suite (no Kimai instance needed):

uv run --with mcp --with httpx python tests/test_e2e.py

Compatibility

Works with both major versions of the Python MCP SDK: mcp 1.x (FastMCP) and 2.x (MCPServer). The server picks the right one at import time, and anticipated failures subclass the SDK's ToolError so the message reaches the model instead of a generic "error executing tool". The suite is run against both in CI.

The distribution is named kimai-timelog-mcp (matching the repo); the command it installs is kimai-mcp.

Built against the Kimai 2 REST API (/api, Authorization: Bearer <token>). Endpoint reference: https://www.kimai.org/documentation/rest-api.html and your own instance's /api/doc.

Available Tools

15 tools
active_timersB

Any currently running time entries for this user.

Inputs: no named parameters. Returns: result

delete_timesheetA

Permanently delete a time entry.

Args: timesheet_id: the entry to delete. confirm: must be true. Show the user what will be deleted first.

Inputs: timesheet_id (required), confirm. Returns: object

list_activitiesA

List activities, optionally the ones valid for a given project.

Args: project: project name or id. Omit to list every activity. search: optional substring filter on the activity name.

Inputs: search, project. Returns: result

list_customersA

List customers visible to this user.

Inputs: no named parameters. Returns: result

list_projectsA

List the projects this user can book time against.

Args: search: optional substring to filter project or customer names. customer: optional customer name or id to scope the list.

Inputs: search, customer. Returns: result

list_tagsA

Tag names configured in this Kimai instance.

Inputs: no named parameters. Returns: result

list_timesheetsA

The user's own time entries for a date range, newest first.

Defaults to the last 7 days. Use this before writing an entry to avoid duplicates, and to answer "what did I log this week".

Args: from_date: 'today', 'monday', '2026-08-24', '3 days ago'. to_date: same formats; defaults to today. project: optional project name or id to filter by. search: optional free-text search over descriptions. limit: maximum entries to return (max 500).

Inputs: limit, search, project, to_date, +1 more. Returns: object

log_timeA

Write a finished time entry to Kimai.

Give either start+end, or start+duration, or duration alone (which books the period ending now). Do not guess missing times — ask the user instead.

Args: project: project name or id. activity: activity name or id, must be valid for the project. description: what was worked on. Strongly recommended. date: 'today', 'yesterday', 'monday', '2026-08-24'. start: '09:00', '9am', '14.30'. end: same formats as start. duration: '1h30m', '90m', '1.5h', '1:30'. tags: optional list of Kimai tag names. billable: optional override of the project default.

Inputs: project (required), activity (required), end, date, +5 more. Returns: object

recent_entriesA

The project/activity/description combinations this user booked most recently.

Best first call for "log the usual" or "same as yesterday" requests.

Inputs: limit. Returns: result

restart_timerA

Start a new running entry that copies an existing one's project/activity.

Inputs: timesheet_id (required). Returns: object

start_timerB

Start a running timer now (or at a given start time today).

Args: project: project name or id. activity: activity name or id. description: what is being worked on. start: optional start time such as '09:00'; defaults to now.

Inputs: project (required), activity (required), start, description. Returns: object

stop_timerA

Stop a running timer.

Args: timesheet_id: which entry to stop. Omit to stop the only running one.

Inputs: timesheet_id. Returns: object

summarize_timeA

Total the user's logged hours over a range, grouped for reporting.

Args: from_date: defaults to 7 days ago. to_date: defaults to today. group_by: 'project', 'activity' or 'day'.

Inputs: to_date, group_by, from_date. Returns: object

update_timesheetA

Change an existing time entry. Only the fields you pass are touched.

Args: timesheet_id: the entry to change (from list_timesheets). date/start/end/duration: same formats as log_time. Passing any of these recomputes the entry's begin and end.

Inputs: timesheet_id (required), end, date, tags, +6 more. Returns: object

whoamiA

Who the Kimai API token belongs to, plus their timezone and today's date.

Call this once at the start of a time-logging conversation so that relative dates ("yesterday") and times are anchored correctly.

Inputs: no named parameters. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 15 tools

    Disambiguation5/5

    Each tool targets a distinct operation: reference data listing, timesheet queries, entry creation, timer control, editing, deletion, and reporting. Even similar tools like list_timesheets and recent_entries are clearly differentiated by what they return.

    Naming Consistency4/5

    The set mostly follows a clear list_ for read-only collections and verb_noun for actions, such as log_time and stop_timer. Minor deviations like active_timers, recent_entries, and whoami break the pattern slightly but remain understandable.

    Tool Count5/5

    At 15 tools, the server covers discovery, logging, timer lifecycle, modifications, deletion, and reporting without feeling bloated. Each tool contributes a meaningful piece of the time-logging workflow.

    Completeness5/5

    The toolset supports a full time-logging lifecycle: lookup reference data, check existing entries, log time, start and stop timers, restart entries, update or delete entries, and summarize hours. It also includes helpful context tools like whoami and recent_entries; admin CRUD for projects or customers is outside the apparent purpose.

    Related MCP Connectors

    Related MCP Servers