MCP Server for Visma Intempus
MCP server for Visma Intempus offering role-based time registration, approval, balances, cases, employees, and planning via one endpoint.
Employee self-service: search capabilities, identify yourself, list cases/work types, view your profile/contracts, list/register/edit/delete your own time reports (while unapproved/unlocked), view your balances and planning.
Approver read-only team view: list team, team work reports (e.g., awaiting approval), team balances, and team planning, scoped to your responsibilities.
Admin company-wide: manage employees, contracts, login access, approvers/responsibilities, time for anyone, cases, customers, balances, schedules, planned work, reference data, and allowlisted generic reads; two-step prepare/commit for deletes and period locks.
Safety: identity fails closed, scope enforced, writes validated and require
INTEMPUS_ENABLE_WRITES=true, idempotent retries, HMAC-signed two-step irreversible changes, audit logging.
Click on "Deploy 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., "@MCP Server for Visma Intempus register 7.5 hours on case 12345 for yesterday"
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.
mcp-server-intempus
MCP server for Visma Intempus — time registration, approval, balances (saldi), cases, employees and planning — with employee, approver and admin roles on one endpoint and per-user scoping.
Roles
One server, one endpoint. Every user holds one or more roles, and the tools they see are the union of those roles. With INTEMPUS_PROFILE=roles the roles arrive per request in X-MCP-Roles. The gateway derives that header from the user's Entra security groups (a roles table in hosts.json), and it is honored only together with INTEMPUS_TRUST_FORWARDED_USER=true; a user with no role gets 403. A fixed role or list (e.g. INTEMPUS_PROFILE=employee or employee,approver) gives every request the same roles, which is useful for stdio.
employee— self-service for full- and part-time employees, hard-scoped to the requesting user:intempus_get_my_profile,intempus_list_my_work_reportsintempus_register_timeintempus_update_my_work_report/intempus_delete_my_work_report, only while the report is neither approved nor lockedintempus_get_my_balances,intempus_get_my_planning
approver— a read-only team view:intempus_list_teamintempus_list_team_work_reports, e.g. what awaits approvalintempus_get_team_balances,intempus_get_team_planning
Scope is the employees, departments and cases the user is responsible for in Intempus (
responsible_for_employee/_department/_case), or everyone withINTEMPUS_APPROVER_UNASSIGNED_SCOPE=allwhen Intempus has no assignments. Approving happens in Intempus itself — see below.admin— company-wide:employees (
intempus_manage_employeecreate/update/offboard), contracts, login accessapprovers and responsibilities, which is what scopes the approver role
time for anyone, cases, customers, balances, schedules, planned work, reference data
allowlisted generic reads (
intempus_get_resource)the two-step
intempus_prepare_admin_change→intempus_commit_prepared_operationfor deletes and period locks (contractlocked_date)
Every role gets intempus_whoami (shows your roles and linked employee), intempus_search_capabilities, intempus_list_cases and intempus_list_work_types.
Related MCP server: HR System MCP Server
Guarantees
Identity fails closed. The gateway-verified UPN (
X-MCP-User, honored whenINTEMPUS_TRUST_FORWARDED_USER=trueandMCP_HTTP_TOKENis set) must resolve to exactly one Intempus employee — byINTEMPUS_IDENTITY_MAP, then Intempus username, then work email, case-insensitive. The privatepersonal_emailis never used. Employee and approver tools never accept a foreign employee id as "me"; reports of others read as "not found".Approvers stay in scope. A user without an approver level in Intempus gets nothing on the approver endpoint, and one with a level but no assignments sees nobody (unless
INTEMPUS_APPROVER_UNASSIGNED_SCOPE=all).Registrations are checked before they are sent against the rules Intempus enforces: a contract covering the date, outside the contract's locked period, a work type from the contract's work model, start/end times for interval work types, a case for project work, an open case. Editing or deleting an existing report is also refused when its current date lies in the locked period, so time cannot be moved out of or removed from a closed period.
creation_id(a name-based UUID, SHA-256, of user + employee +idempotencyKey) makes retries safe — a retry returns the same report.Irreversible admin changes are two-step (deleting work reports and schedules included —
intempus_manage_work_reportandintempus_manage_scheduleonly create and update): the prepare result is an HMAC-signed preview naming every affected record; commit accepts only an unaltered operation signed by this server, within 15 minutes, by the user who prepared it, whose steps still pass the allowlist. The gateway can gate the commit tool with a separate duty group.Forwarded headers need the bearer token. The HTTP transport refuses to start with
INTEMPUS_TRUST_FORWARDED_USER=trueand noMCP_HTTP_TOKEN;X-MCP-UserandX-MCP-Rolesare honored only under both. The token is compared in constant time.Writes need
INTEMPUS_ENABLE_WRITES=true— checked in the policy and again in every write path.Attribution. The API key belongs to one Intempus user, so Intempus' own history shows that user for every change. The JSONL audit (
INTEMPUS_AUDIT_LOG) records the Entra user, roles, tool and a hash of the arguments (plus the operation hash on commits); requests withoutX-MCP-Userare refused when trust is enabled.No credentials in tool arguments or results: generated passwords are never echoed, password/PIN fields are stripped from raw reads,
api_key/outlook_credentialare not readable.
Not possible via Intempus' public API
Verified live on 2026-09-29 (details in docs/api-notes.md):
Approving time.
approvedis read-only, andapproved_by_initial/approved_by_finalcan be set (to a user profile) without the report becoming approved. Approval stays in Intempus' web/approval app; the approver role shows what is waiting. Intempus' own MCP server (mcp.intempus.dk, needs anX-Security-Keyfrom Intempus) advertises bulk approval — the way to get approval into Claude, if wanted.Locking work reports (
work_report/bulk/) needs Intempus' "work report state" feature, which ONE's account does not have (401 "…only be updated if the feature is enabled"). The prepare kindlock_work_reportsworks once Intempus enables it; period locks via the contract'slocked_datework today.Deleting employees. Intempus refuses (409) while a user profile exists, every employee gets one, and user profiles cannot be deleted. Employees are removed by offboarding: open contracts end on the last day and backend/approval logins are revoked.
Intempus facts this server relies on
Verified against a production account on 2026-09-29; details in docs/api-notes.md.
Auth
Authorization: ApiKey <username>:<key>; the username is case-sensitive.employeecannot be filtered on email, and username has no case-insensitive filter, so identity is matched in memory (cached 60 s).explored_employee_balanceandscheduleanswer HTTP 500 to cursor pagination; the client falls back to offset paging.Relations are URIs in lists but embedded objects in some detail responses (e.g.
work_type.work_model); both are handled.Holiday balances accrue at month end: a balance "as of today" does not include this month's accrual yet.
Rate limit is 500 requests/minute per Intempus user, shared with every integration using the same key (e.g. bpc).
Relation to other Intempus integrations
Other systems may keep their own direct Intempus integration (cases out, approved time in). This server follows the common case convention: intempus_manage_case with projectNumber names the case "<projektnr> - <navn>", and refuses a create when the number or name already exists.
Configuration
See .env.example. Minimal production set: INTEMPUS_API_USER, INTEMPUS_API_KEY, INTEMPUS_PROFILE=roles, INTEMPUS_TRUST_FORWARDED_USER=true, INTEMPUS_ENABLE_WRITES=true, INTEMPUS_AUDIT_LOG=/data/audit.jsonl, INTEMPUS_OPERATION_SECRET, and MCP_HTTP_TOKEN (shared with the gateway).
Deployment
One container (INTEMPUS_PROFILE=roles) behind an authenticating MCP gateway. The gateway maps Entra security groups to roles (X-MCP-Roles):
Role | Entra group |
| one group per company, e.g. employees |
| approvers |
| admins |
duty group for | admin commit |
Group membership must be direct (the app emits ApplicationGroup claims; nested groups are not included), and each group must be assigned to the gateway's enterprise app. Each person's Entra UPN must match their Intempus username or work email (or be mapped with INTEMPUS_IDENTITY_MAP).
Run
npm install
npm run dev # stdio (acting user from INTEMPUS_DEFAULT_USER)
npm run dev:http # streamable HTTP on :3000/mcp (stateless)
npm test
INTEMPUS_PROFILE=admin SMOKE_USER=you@example.com npm run smoke:live # read-only; roles: employee | approver | admin # read-only, against the real APIDocker images: ghcr.io/borgels/mcp-server-intempus (published on push to main).
Available Tools
11 toolsintempus_delete_my_work_reportDelete My Time Registration (Intempus)ADestructive
Delete one of your own time registrations. Only possible while it is neither approved nor locked.
Inputs: workReportId (required).
intempus_get_my_balancesMy Balances (Intempus)ARead-onlyIdempotent
Your balances (ferie, feriefri, timebank/flex, sygdom …) as computed by Intempus up to a date (default today). Holiday accrues at month end, so pass to = the end of the holiday year to see the full entitlement. Only balances visible to employees.
Inputs: to, from.
intempus_get_my_planningMy Planning (Intempus)CRead-onlyIdempotent
Your planned work in a period (default: the next 14 days).
Inputs: to, from.
intempus_get_my_profileMy Profile (Intempus)ARead-onlyIdempotent
Your Intempus employee record, contracts (work model, locked date) and approver levels.
Inputs: no named parameters.
intempus_list_casesList Cases (Intempus)BRead-onlyIdempotent
Search cases/projects that accept time registrations, by number, name or customer.
Inputs: limit, query, includeInactive.
intempus_list_my_work_reportsMy Time Registrations (Intempus)BRead-onlyIdempotent
Your time registrations in a period (default: last 31 days), with approval status and total.
Inputs: to, from, limit, approved.
intempus_list_work_typesList Work Types (Intempus)ARead-onlyIdempotent
Work types (projekttimer, ferie, sygdom, kørsel …). Employees and approvers get the types of their own work model; admins may filter by work model or employee.
Inputs: query, employeeId, workModelId.
intempus_register_timeRegister Time (Intempus)A
Register time for yourself. Give a work type, optional case, a date and either startTime+endTime (optionally breakHours) or hours. Checks that you have a contract on the date, that the work type belongs to your work model and that the case is open. Pass idempotencyKey to make a retry safe.
Inputs: date (required), workTypeId (required), hours, caseId, +7 more.
intempus_search_capabilitiesSearch Intempus CapabilitiesARead-onlyIdempotent
Search the Intempus MCP server capabilities and examples. Use this first when deciding which tool to call.
Inputs: limit, query.
intempus_update_my_work_reportEdit My Time Registration (Intempus)A
Change one of your own time registrations. Only possible while it is neither approved nor locked.
Inputs: workReportId (required), date, hours, caseId, +7 more.
intempus_whoamiWho Am I (Intempus)BRead-onlyIdempotent
Show this endpoint's profile and the Intempus employee (and approver levels) the session is bound to.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Most tools have clearly distinct purposes (list work types, list cases, register/update/delete time, balances, planning). However, intempus_whoami and intempus_get_my_profile overlap in showing employee/approver info, which could cause an agent to pick the wrong one.
All tools use the intempus_ prefix and snake_case, with a mostly consistent verb_noun pattern (list_work_types, get_my_balances, register_time). The outlier is intempus_whoami, which does not follow the verb_noun format, but this is a common exception.
11 tools is well within the ideal range and each tool maps to a distinct operation within the employee self-service domain (time registration CRUD, profiles, balances, planning). No tool feels redundant or missing at the count level.
Core employee workflows are covered: time registration create/read/update/delete, work types, cases, balances, and planning. Approver-specific operations (e.g., approving/rejecting reports) are absent despite approver levels being mentioned, and there is no single-report retrieval, but these are minor workable gaps.
Maintenance
Related MCP Connectors
Read Tamigo departments, employees, shifts, absences and opening hours; register attendance.
Read hours, absences and projects; start timers, add entries, approve leave in TimeTac.
Rosters, shifts, absence and Norwegian working-time rules from VaktFlyt.
Read Papershift absences, vacation, time tracking and shifts; request and review absences.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables automated timesheet management including creating entries, listing work activities, managing daily scrum updates, and viewing assigned projects with automatic authentication handling.8 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables employee information lookup, directory listing, payroll access, and time-off request management with Okta token validation.-
- AlicenseAqualityDmaintenanceProvides Planview Enterprise One API access with Okta passwordless authentication, enabling work item and project management, and automated timesheet completion.7MIT
- AlicenseAqualityCmaintenanceEnables viewing, creating, and managing time registrations, absences, and timesheet approvals through the Timelog API using natural language.211ISC