An MCP server that exposes the Timelog time registration API as tools for Claude. It lets you view, create, and manage time registrations, absences, and timesheet approvals through natural language.
Node.js 18 or higher — the server uses the native fetch global, which was introduced in Node 18. Running on an older version will exit immediately with a clear error message.
The included .nvmrc and bin/run.sh wrapper target Node 22, which is the recommended version for running this server.
- View time registrations — by week or arbitrary date range, including financial/billable data
- Create, update, and delete time registrations on any task you have access to
- Absence management — search absence codes and register vacation, sick leave, etc.
- Timesheet approval — check submission status and submit timesheets, with filtering by employee, department, approver, or legal entity
- Organization — look up legal entities and the current user profile
- Task search — find tasks to register time on by name or number
Get the authenticated user's profile (name, email, department). No parameters.
Get all legal entities in the organization. Returns ID, name, active status, currency, and country for each entity. No parameters.
Get time registrations for a specific week, grouped by day with norm hours.
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate |
string | Yes | Monday of the week (YYYY-MM-DD) |
Get time registrations between two dates.
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate |
string | Yes | Start date (YYYY-MM-DD) |
endDate |
string | Yes | End date (YYYY-MM-DD) |
Get financial data (billable/invoice status) for time registrations in a date range.
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate |
string | Yes | Start date (YYYY-MM-DD) |
endDate |
string | Yes | End date (YYYY-MM-DD) |
Search for tasks the user can register time on. Returns task IDs needed for creating time registrations.
| Parameter | Type | Required | Description |
|---|---|---|---|
searchText |
string | No | Task name or task number to search for |
searchAll |
boolean | No | Search all tasks, not just recent (default: false) |
Create a new time registration on a task. Use search_tasks first to find the TaskID.
| Parameter | Type | Required | Description |
|---|---|---|---|
TaskID |
integer | Yes | Task identifier (from search_tasks) |
Date |
string | Yes | Date of the registration (YYYY-MM-DD) |
Hours |
number | Yes | Number of hours to register |
Comment |
string | No | Comment for the registration |
JiraId |
string | No | JIRA ticket ID (e.g. XXX-1234) |
Billable |
boolean | No | Whether this time is billable (defaults to task setting) |
Update an existing time registration. Only supply the fields you want to change.
| Parameter | Type | Required | Description |
|---|---|---|---|
TimeRegistrationID |
integer | Yes | Time registration ID to update |
TaskID |
integer | Yes | Task identifier |
Date |
string | No | New date (YYYY-MM-DD) |
Hours |
number | No | New hours value |
Comment |
string | No | New comment |
JiraId |
string | No | JIRA ticket ID (e.g. SGI-82108) |
Billable |
boolean | No | Whether this time is billable |
Delete a time registration by its GUID.
| Parameter | Type | Required | Description |
|---|---|---|---|
id |
string (UUID) | Yes | GUID of the time registration to delete |
Search for absence codes (e.g. Ferie, Sygdom). Returns AbsenceCodeID needed for create_absence_registration.
| Parameter | Type | Required | Description |
|---|---|---|---|
searchText |
string | No | Filter by absence code name or number |
Create an absence registration (vacation, sick leave, etc.). Use search_absence_codes to find the AbsenceCodeID. Registers a full working day by default.
| Parameter | Type | Required | Description |
|---|---|---|---|
AbsenceCodeID |
integer | Yes | Absence code identifier (from search_absence_codes) |
Date |
string | Yes | Date of the absence (YYYY-MM-DD) |
Hours |
number | No | Hours to register (omit for a full working day) |
Comment |
string | No | Comment for the registration |
Get weekly timesheet approval/submission status. Defaults to the authenticated user. Omit userId to get all employees (manager view).
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate |
string | Yes | Start date (YYYY-MM-DD) |
endDate |
string | Yes | End date (YYYY-MM-DD) |
userId |
integer | No | Filter by employee UserID (omit for all employees) |
departmentId |
integer | No | Filter by department ID |
approverId |
integer | No | Filter by approver UserID |
legalEntityId |
integer | No | Filter by legal entity ID |
Submit a timesheet for approval for a date range (e.g. a full week).
| Parameter | Type | Required | Description |
|---|---|---|---|
startDate |
string | Yes | Start date (YYYY-MM-DD) |
endDate |
string | Yes | End date (YYYY-MM-DD) |
comment |
string | No | Comment for the submission |
employeeUserId |
integer | No | UserID of the employee to submit for (defaults to authenticated user) |
Use get_timesheet_status without a userId to get the submission status for all employees in a period. Filter by departmentId, approverId, or legalEntityId to narrow the scope.
Once you've identified employees with open timesheets, use submit_timesheet with employeeUserId to submit on their behalf.
Example prompts:
"Show me everyone who hasn't submitted their timesheet this week" "Submit this week's timesheet for user 1234" "Submit all open timesheets for department 5 this week"
This repo doubles as a Claude Code plugin marketplace. Add it once, then install the plugin:
/plugin marketplace add Amoeslund/Timelog-MCP-server
/plugin install timelog@timelog-mcp
Claude Code will prompt for your Timelog Personal Access Token and API base URL during install and wire up the MCP server for you (it runs the published timelog-mcp package via npx). No manual .mcp.json editing required. See Configuration for how to obtain those values.
Add to your Claude Code .mcp.json or Claude Desktop config:
{
"mcpServers": {
"timelog": {
"command": "npx",
"args": ["-y", "timelog-mcp"],
"env": {
"TIMELOG_PAT": "<your-personal-access-token>",
"TIMELOG_BASE_URL": "https://app[X].timelog.com/<your-account>/api"
}
}
}
}The package includes a wrapper script (bin/run.sh) that sources nvm at startup and runs the server with the version declared in .nvmrc (Node 22). This means the correct Node version is selected on every run, regardless of what your shell's default is.
nvm users: MCP servers run as subprocesses and don't inherit nvm shell hooks, so your shell's active version doesn't apply. The wrapper handles this automatically. If you prefer to use
npxdirectly without the wrapper, make sure your nvm default is Node 18+:nvm alias default 22
git clone git@github.com:Amoeslund/Timelog-MCP-server.git
cd Timelog-MCP-server
nvm use # picks up .nvmrc (Node 22)
npm install
npm run buildThen point your MCP config at the wrapper script so the correct Node version is used on every launch:
{
"mcpServers": {
"timelog": {
"command": "/path/to/Timelog-MCP-server/bin/run.sh",
"args": [],
"env": {
"TIMELOG_PAT": "<your-personal-access-token>",
"TIMELOG_BASE_URL": "https://app[X].timelog.com/<your-account>/api"
}
}
}
}Alternatively, if you want to call node directly, use an absolute path to a Node 18+ binary:
{
"mcpServers": {
"timelog": {
"command": "/path/to/node",
"args": ["/path/to/Timelog-MCP-server/dist/index.js"],
"env": {
"TIMELOG_PAT": "<your-personal-access-token>",
"TIMELOG_BASE_URL": "https://app[X].timelog.com/<your-account>/api"
}
}
}
}Generate a PAT at https://login.timelog.com/personaltoken.
Your URL follows the pattern https://app[X].timelog.com/<your-account>/api where [X] is a server number (1–10) and <your-account> is your Timelog account name. See the Timelog API docs for details.
| Variable | Required | Description |
|---|---|---|
TIMELOG_PAT |
Yes | Personal Access Token (see above) |
TIMELOG_BASE_URL |
Yes | API base URL (see above) |
ISC