A comprehensive Model Context Protocol (MCP) server for integrating with the Kimai time-tracking API. This server allows AI assistants like Claude to efficiently interact with Kimai instances to manage time tracking, projects, activities, customers, users, teams, absences, and more.
Speaks MCP protocol revision 2026-07-28 and every earlier revision (MCP Python SDK 2.x), tracked against Kimai 2.65. Older Kimai instances keep working; features that need a specific Kimai version are marked below.
# Install from PyPI
pip install kimai-mcp
# Run with your Kimai credentials
kimai-mcp --kimai-url=https://your-kimai.com --kimai-token=your-token
# Or use the interactive setup wizard
kimai-mcp --setupFor enterprise/team environments: Deploy the server once and let all users connect remotely!
| Server | Command | Best For |
|---|---|---|
| Local | kimai-mcp |
Claude Desktop, single user, development |
| Streamable HTTP | kimai-mcp-streamable |
Claude.ai Connectors (web/mobile), teams |
Removed in v2.16.0: the SSE server and its
kimai-mcp-servercommand are gone. The SSE transport was dropped from the MCP specification in favour of Streamable HTTP, and this project's implementation had been non-functional and deprecated since v2.12.0. Usekimai-mcp-streamablefor remote access.
Since v2.12.0 the Streamable HTTP server includes an OAuth 2.1 authorization server. Users authenticate with a user slug and a per-user auth_secret instead of a secret URL.
# 1. Generate a random slug and an auth_secret per user
python -c "import secrets; print(secrets.token_urlsafe(16))" # slug
python -c "import secrets; print(secrets.token_urlsafe(32))" # auth_secret
# 2. Create config file
mkdir config
cat > config/users.json << 'EOF'
{
"xK9mP2qW7vL4aB8c": {
"kimai_url": "https://your-kimai.com",
"kimai_token": "your-api-token",
"auth_secret": "long-random-oauth-login-secret"
}
}
EOF
# 3. Start server
docker-compose up -dSecurity Warning: Use random slugs, NOT usernames! The server warns at startup about low-entropy slugs (shorter than 16 characters or plain lowercase words). Slugs may only contain letters, digits,
-and_.
The Streamable HTTP server works with Claude.ai custom connectors:
- Set an
auth_secretfor each user inusers.json(see above) - Run the server behind an HTTPS reverse proxy:
kimai-mcp-streamable \ --users-config ./config/users.json \ --public-url https://mcp.example.com \ --trusted-proxy 127.0.0.1 \ --oauth-state-file ./config/oauth_clients.json \ --disable-legacy-slugs
- In Claude.ai: Settings → Connectors → Add custom connector
- Enter URL:
https://mcp.example.com/mcp(no slug in the URL) - Claude.ai registers itself automatically (Dynamic Client Registration). When connecting, a login page appears — enter your user slug and
auth_secret.
Access tokens are valid for 1 hour and refreshed automatically (refresh tokens up to 30 days). Tokens are kept in memory, so users must reconnect after a server restart.
Legacy endpoints: The previous per-user URLs /mcp/{slug} still work but are deprecated. Migrate to the OAuth endpoint /mcp and start the server with --disable-legacy-slugs.
Instead of the built-in slug + auth_secret form, the Streamable HTTP server can delegate user authentication to any standard OpenID Connect provider (Microsoft Entra ID / Azure AD, Keycloak, Auth0, Google, Okta, …). The server stays the OAuth 2.1 authorization server toward Claude.ai (same opaque tokens, DCR and PKCE); it only federates the login step: /authorize redirects to your OIDC provider, the id_token is verified (signature via JWKS, iss/aud/exp/nonce), and the resulting identity is mapped to a configured user.
kimai-mcp-streamable \
--users-config ./config/users.json \
--public-url https://mcp.example.com \
--auth-backend oidc \
--oidc-issuer https://login.microsoftonline.com/<tenant-id>/v2.0 \
--oidc-client-id <client-id>
# Confidential clients: set KIMAI_MCP_OIDC_CLIENT_SECRET (env preferred over the CLI flag).Map each OIDC identity to a Kimai user by adding the oidc_identity field (matched case-insensitively against --oidc-identity-claim, default email):
{
"x7Kp2mQ9wL4r": {
"kimai_url": "https://kimai.example.com",
"kimai_token": "api_token_for_alice",
"oidc_identity": "alice@example.com"
}
}Register <public-url>/oauth/oidc/callback as the redirect URI at your OIDC provider. Requires the [server] extra (pip install "kimai-mcp[server]", which pulls in PyJWT[crypto]). The built-in slug login form is not exposed while the OIDC backend is active.
When mapping by email, the id_token must also assert email_verified: true, otherwise the email claim is ignored — so a provider that lets users self-assert an unverified address cannot impersonate a mapped user. For providers that do not emit email_verified but are trusted to only issue verified emails, pass --oidc-allow-unverified-email (or KIMAI_MCP_OIDC_ALLOW_UNVERIFIED_EMAIL=true).
The mapping above still has to be maintained by hand, and each entry needs an API token that an administrator first created in Kimai's web UI. With --auto-provision, an identity that matches no configured user is instead resolved against Kimai's own user list and given its own personal API token at first sign-in; after that, signing in with the IdP is the only step a user ever performs.
kimai-mcp-streamable \
--users-config ./config/users.json \
--public-url https://mcp.example.com \
--auth-backend oidc \
--oidc-issuer https://login.microsoftonline.com/<tenant-id>/v2.0 \
--oidc-client-id <client-id> \
--auto-provision \
--provision-kimai-url https://kimai.example.com \
--disable-legacy-slugs
# Prefer the env var for the admin token: KIMAI_MCP_PROVISION_ADMIN_TOKENRequirements
- The
ApiTokenBundleplugin on your Kimai server. Core Kimai can only delete access tokens through the API; creating one is a web-form action. The plugin addsPOST /api/users/{id}/api-tokenbehind Kimai's own permission check. Without it every first-time sign-in is rejected, and the server probes for the plugin at startup and says so once. - An admin token (
--provision-admin-token) belonging to a user withapi-token_other_profile(to mint the token) andview_user(to list users at all:GET /api/userscarries its own permission check). ROLE_SUPER_ADMIN has both in Kimai's default role mapping. The server probes for each at startup rather than failing on the first sign-in. --auth-backend oidc. There is no verified identity to resolve without a federated login.
How an identity is matched. Rules run from strongest to weakest and stop at the first one that matches. A rule matching more than one Kimai user aborts instead of guessing, because a wrong match would hand one employee another employee's token. --provision-match selects how far to go:
| Mode | Rules |
|---|---|
exact |
Kimai email equals the identity; Kimai username equals the identity |
normalized (default) |
…plus username equals the address local part, plus a folded comparison of username/alias/email that makes anna.vondorf and Anna von Dorf compare equal. The folded comparison needs an address of at least two name parts, so max@ is never matched against a colleague whose alias is Max or whose address is max@ on another mail domain |
fuzzy |
…plus the name / given_name+family_name claims against the Kimai alias, plus single name parts (anna@ vs. anna.vondorf@) |
The fuzzy rules are heuristics; enable them only if you know the shape of your directory. The minted token is verified against /api/users/me and discarded if it resolves to a different user, but that guards against a wrong token, not a wrong match.
Restrict the domains. Every rule except the two exact ones compares the address local part, which says nothing about where the identity came from. If your issuer can assert more than one domain (Microsoft Entra's common/organizations endpoints, B2B guest accounts, Google without an hd claim, Auth0 or Okta social connections), then an outside account named anna.vondorf@somewhere-else.example matches the Kimai user anna.vondorf as the single candidate, so the ambiguity guard never fires and that employee's personal API token is handed over. Set --provision-allowed-domains corp.example,corp.de to bound it. Leaving it unset is only safe with a single-tenant issuer, and the server logs a warning at startup to that effect.
Whatever prevents an onboarding (no match, ambiguous match, plugin missing, missing permission, Kimai unreachable), the response is the same generic "not authorized" page as before, with the actual reason in the server log only. The feature is off by default and cannot change behaviour for an existing deployment.
Persistence. Provisioned users live in memory by default, like the OAuth access and refresh tokens: after a restart the next sign-in re-provisions them, which is idempotent (tokens are replaced by name, so nothing piles up in the Kimai profile). Pass --provision-store FILE to keep them across restarts; that file holds Kimai API tokens in plaintext and is written with mode 0600. A hand-written users.json entry always wins over a stored one.
A stored token that Kimai stops accepting, because an admin deleted it or a second replica re-minted it under the same name, is detected and discarded: the session is dropped, the entry is removed from the store, and the user's next sign-in provisions them again. Running several replicas against one Kimai still means they re-mint each other's tokens (Kimai replaces tokens by name), which now costs a re-provisioning rather than a session stuck in permanent failure. Give each replica its own --provision-token-name to avoid it entirely.
Idle sessions. A provisioned user's session is released after an hour without requests and rebuilt on their next one. Without that, every directory member who ever signed in kept a Kimai connection pool and a session manager for the lifetime of the process.
Slugs. Provisioned users get a random slug of the same strength as the ones users.example.json tells you to generate, and no auth_secret, so the local login form cannot be used for them. The slug alone is a credential on the deprecated /mcp/{slug} routes, so run auto-provisioning with --disable-legacy-slugs; the server warns at startup when both are active.
Options for the local server (kimai-mcp):
| Option | Description |
|---|---|
--kimai-url URL |
Kimai server URL (e.g., https://kimai.example.com) |
--kimai-token TOKEN |
API authentication token from your Kimai user profile |
--kimai-user USER_ID |
Deprecated — accepted but ignored (use the user_scope parameter of the tools instead) |
--ssl-verify VALUE |
SSL verification: true (default), false, or path to CA certificate |
--setup |
Interactive setup wizard for Claude Desktop configuration |
--help |
Show help message and exit |
--version |
Show version number and exit |
Options for the Streamable HTTP server (kimai-mcp-streamable):
| Option | Environment variable | Description |
|---|---|---|
--host HOST |
— | Host to bind to (default: 0.0.0.0) |
--port PORT |
— | Port to bind to (default: 8000) |
--users-config FILE |
USERS_CONFIG_FILE |
Path to users.json |
--public-url URL |
KIMAI_MCP_PUBLIC_URL |
Public base URL, used as OAuth issuer/resource URL (required behind a reverse proxy) |
--oauth-state-file FILE |
KIMAI_MCP_OAUTH_STATE_FILE |
JSON file to persist registered OAuth clients across restarts |
--disable-legacy-slugs |
KIMAI_MCP_DISABLE_LEGACY_SLUGS |
Disable the deprecated /mcp/{slug} endpoints |
--trusted-proxy IP |
KIMAI_MCP_TRUSTED_PROXIES (comma-separated) |
Reverse proxy IPs whose X-Forwarded-For/X-Real-IP headers are honored; may be given multiple times |
--rate-limit-rpm N |
RATE_LIMIT_RPM |
Maximum requests per minute per IP (default: 60, 0 to disable) |
--auth-backend {local,oidc} |
KIMAI_MCP_AUTH_BACKEND |
Login backend: local (built-in slug form, default) or oidc (federate to an external OIDC provider) |
--oidc-issuer URL |
KIMAI_MCP_OIDC_ISSUER |
OIDC issuer URL (required for --auth-backend oidc) |
--oidc-client-id ID |
KIMAI_MCP_OIDC_CLIENT_ID |
OIDC client ID (required for --auth-backend oidc) |
--oidc-client-secret SECRET |
KIMAI_MCP_OIDC_CLIENT_SECRET |
OIDC client secret (optional; public/PKCE-only if omitted — prefer the env var) |
--oidc-scopes SCOPES |
KIMAI_MCP_OIDC_SCOPES |
Requested scopes (default: openid email profile) |
--oidc-identity-claim CLAIM |
KIMAI_MCP_OIDC_IDENTITY_CLAIM |
id_token claim mapped to a user's oidc_identity (default: email) |
--oidc-discovery-url URL |
KIMAI_MCP_OIDC_DISCOVERY_URL |
Override the discovery URL (default: <issuer>/.well-known/openid-configuration) |
--oidc-allow-unverified-email |
KIMAI_MCP_OIDC_ALLOW_UNVERIFIED_EMAIL |
Accept the email claim without email_verified: true |
--auto-provision |
KIMAI_MCP_AUTO_PROVISION |
Onboard unknown OIDC identities automatically (requires --auth-backend oidc and the ApiTokenBundle plugin) |
--provision-kimai-url URL |
KIMAI_MCP_PROVISION_KIMAI_URL |
Kimai URL written into provisioned user configs (required for --auto-provision) |
--provision-admin-token TOKEN |
KIMAI_MCP_PROVISION_ADMIN_TOKEN |
Admin token used to mint per-user tokens; needs api-token_other_profile and view_user (prefer the env var) |
--provision-allowed-domains DOMAINS |
KIMAI_MCP_PROVISION_ALLOWED_DOMAINS |
Comma-separated mail domains that may be onboarded. Strongly recommended unless the issuer is single-tenant |
--provision-token-name NAME |
KIMAI_MCP_PROVISION_TOKEN_NAME |
Name of the created tokens as shown in the Kimai profile (default: Kimai MCP (auto)) |
--provision-match {exact,normalized,fuzzy} |
KIMAI_MCP_PROVISION_MATCH |
How far to go when matching an identity to a Kimai user (default: normalized) |
--provision-store FILE |
KIMAI_MCP_PROVISION_STORE |
Persist provisioned users across restarts (plaintext tokens, written 0600) |
--provision-ssl-verify VALUE |
KIMAI_MCP_PROVISION_SSL_VERIFY |
SSL verification for provisioning calls: true, false or a CA path |
- Entity Tool (
entity) - Universal CRUD operations for projects, activities, customers, users, teams, tags, invoices, holidays - Timesheet Tool (
timesheet) - Complete timesheet management (list, create, update, delete, export, batch operations) - Timer Tool (
timer) - Active timer operations (start, stop, restart, view active/recent) - Rate Tool (
rate) - Rate management across all entity types - Team Access Tool (
team_access) - Team member and permission management - Absence Tool (
absence) - Complete absence workflow (create, approve, reject, list, attendance, batch operations, auto-split) - Calendar Tool (
calendar) - Unified calendar data access - Meta Tool (
meta) - Custom field management for customers, projects, activities, timesheets, and invoices (invoice meta requires Kimai 2.56+) - User Current Tool (
user_current) - Current user information - Project Analysis Tool (
analyze_project_team) - Advanced project analytics - Config Tool (
config) - Server configuration (timesheet settings, color codes, plugins, version info) - Comment Tool (
comment) - Comments on projects and customers: list, create, delete, pin (requires Kimai 2.57+)
- Timesheet Management - Create, update, delete, start/stop timers, view active timers
- Project & Activity Management - Browse and view projects and activities
- Customer Management - Browse and view customer information including the full detail set (VAT ID, structured address, contact, budget, meta fields, plus
languageandinvoiceEmailfrom Kimai 2.63+). Listings can requestfilters.fullfor the address and VAT ID (Kimai 2.62+, needs thedetails_customerpermission); contact, email and budget are only returned for a single customer viaaction=get - User Management - List, view, create, update user accounts, and configure work contracts (preferences)
- Team Management - Create teams, manage members, control access permissions
- Absence Management - Create, approve, reject, and track absences
- Tag Management - Create and manage tags for better organization
- Invoice Queries - View invoice information and status
- Comments - Manage pinned and regular comments on projects and customers (Kimai 2.57+)
- Real-time Timer Control - Start, stop, and monitor active time tracking
- Comprehensive Filtering - Advanced filters for all data types
- Permission Management - Respect Kimai's role-based permissions
- Error Handling - API errors are reported with status code and validation details; 403 responses include a permission hint (Kimai has tightened API permissions repeatedly, most recently in 2.65 for revoking a team's customer/project/activity access)
- Flexible Configuration - Multiple configuration methods (CLI args, .env files, environment variables)
- Python 3.10+
- A Kimai instance with API access enabled
- API token from your Kimai user profile
pip install kimai-mcp# Clone the repository
git clone https://github.com/glazperle/kimai_mcp.git
cd kimai_mcp
# Install in development mode
pip install -e ".[dev]"- Log into your Kimai instance
- Go to your user profile (click your username)
- Navigate to the "API" or "API Access" section
- Create a new API token or copy an existing one
- Note your Kimai instance URL (e.g.,
https://kimai.example.com)
Add the Kimai MCP server to your Claude Desktop configuration file:
On macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
On Windows:
%APPDATA%\Claude\claude_desktop_config.json
Add the following to your Claude Desktop configuration:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp",
"args": [
"--kimai-url=https://your-kimai-instance.com",
"--kimai-token=your-api-token-here"
]
}
}
}Important Notes:
- Replace
https://your-kimai-instance.comwith your actual Kimai URL - Replace
your-api-token-herewith your API token from Kimai - The
kimai-mcpcommand is available afterpip install kimai-mcp
Alternative: If kimai-mcp is not in your PATH, use python -m kimai_mcp.server instead:
{
"mcpServers": {
"kimai": {
"command": "python",
"args": [
"-m", "kimai_mcp.server",
"--kimai-url=https://your-kimai-instance.com",
"--kimai-token=your-api-token-here"
]
}
}
}After saving the configuration file, restart Claude Desktop for the changes to take effect.
If you prefer using a .env file for configuration, create a .env file in your project directory:
# .env file in the kimai_mcp directory
KIMAI_URL=https://your-kimai-instance.com
KIMAI_API_TOKEN=your-api-token-here
KIMAI_SSL_VERIFY=true # or path to CA certificateThen use this Claude Desktop configuration:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp",
"cwd": "/path/to/your/kimai_mcp/directory"
}
}
}Important Notes for .env Configuration:
- Replace
/path/to/your/kimai_mcp/directorywith the actual path to your kimai_mcp directory - The
cwdparameter ensures the .env file is found in the correct directory - Keep your .env file secure and never commit it to version control
- On Windows, use forward slashes in the path or escape backslashes
Example Windows Path:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp",
"cwd": "C:/Users/YourName/Projects/kimai_mcp"
}
}
}If you prefer system environment variables, you can set:
export KIMAI_URL="https://your-kimai-instance.com"
export KIMAI_API_TOKEN="your-api-token-here"Then use this Claude Desktop configuration:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp"
}
}
}{
"tool": "timesheet",
"parameters": {
"action": "list",
"filters": {
"project": 17,
"user_scope": "self"
}
}
}{
"tool": "timesheet",
"parameters": {
"action": "create",
"data": {
"project": 1,
"activity": 5,
"description": "Working on API integration",
"begin": "2024-08-03T09:00:00",
"end": "2024-08-03T10:30:00"
}
}
}{
"tool": "timer",
"parameters": {
"action": "start",
"data": {
"project": 1,
"activity": 5,
"description": "Working on API integration"
}
}
}{
"tool": "timer",
"parameters": {
"action": "stop",
"id": 12345
}
}{
"tool": "entity",
"parameters": {
"type": "project",
"action": "list",
"filters": {"customer": 1}
}
}{
"tool": "entity",
"parameters": {
"type": "project",
"action": "get",
"id": 17
}
}{
"tool": "entity",
"parameters": {
"type": "activity",
"action": "list",
"filters": {"project": 17}
}
}{
"tool": "entity",
"parameters": {
"type": "user",
"action": "list"
}
}{
"tool": "entity",
"parameters": {
"type": "team",
"action": "create",
"data": {
"name": "Development Team",
"color": "#3498db"
}
}
}{
"tool": "team_access",
"parameters": {
"action": "add_member",
"team_id": 1,
"user_id": 5
}
}{
"tool": "absence",
"parameters": {
"action": "create",
"data": {
"comment": "Vacation in the mountains",
"date": "2024-02-15",
"end": "2024-02-20",
"type": "holiday"
}
}
}{
"tool": "absence",
"parameters": {
"action": "list",
"filters": {
"user": "5",
"status": "all"
}
}
}{
"tool": "absence",
"parameters": {
"action": "attendance",
"date": "2024-12-29"
}
}Returns a report showing present and absent employees with absence reasons.
Batch operations allow executing multiple API calls in parallel for efficient bulk processing.
{
"tool": "absence",
"parameters": {
"action": "batch_delete",
"ids": [1, 2, 3, 4, 5]
}
}{
"tool": "absence",
"parameters": {
"action": "batch_approve",
"ids": [10, 11, 12, 13]
}
}{
"tool": "timesheet",
"parameters": {
"action": "batch_delete",
"ids": [100, 101, 102, 103]
}
}{
"tool": "timesheet",
"parameters": {
"action": "batch_export",
"ids": [200, 201, 202]
}
}{
"tool": "entity",
"parameters": {
"type": "project",
"action": "batch_delete",
"ids": [5, 6, 7]
}
}{
"tool": "rate",
"parameters": {
"entity": "customer",
"action": "list",
"entity_id": 1
}
}{
"tool": "comment",
"parameters": {
"entity": "project",
"entity_id": 17,
"action": "list"
}
}{
"tool": "comment",
"parameters": {
"entity": "customer",
"entity_id": 5,
"action": "create",
"data": {
"message": "Billing contact changed, see email from 2026-06-01",
"pinned": true
}
}
}{
"tool": "user_current"
}The MCP automatically handles Kimai's limitations when creating absences:
Year-Boundary Splitting: Kimai doesn't allow absences spanning multiple years. The MCP automatically splits them.
{
"tool": "absence",
"parameters": {
"action": "create",
"data": {
"date": "2025-09-01",
"end": "2026-03-31",
"type": "parental",
"comment": "Parental leave"
}
}
}This automatically becomes two entries:
2025-09-01to2025-12-312026-01-01to2026-03-31
30-Day Limit Splitting: Kimai limits absences to 30 days maximum. Longer absences are automatically split into 30-day chunks.
{
"tool": "absence",
"parameters": {
"action": "create",
"data": {
"date": "2025-09-01",
"end": "2025-11-29",
"type": "parental",
"comment": "Parental leave (90 days)"
}
}
}This automatically becomes three 30-day entries with output:
Created 3 absence(s) for parental
Period: 2025-09-01 to 2025-11-29 (90 days)
IDs: 123, 124, 125
(Automatically split due to Kimai limitations)
- Verify Kimai URL: Ensure your Kimai URL is correct and accessible
- Check API Token: Verify your API token is valid and not expired
- API Access: Ensure your Kimai instance has API access enabled
- Network: Check if there are any firewall or network restrictions
- Creating timesheets for other users requires admin permissions
- Managing users and teams requires appropriate role permissions
- Some absence operations require manager permissions
- Claude Desktop Config: Verify the JSON syntax is correct
- Path Issues: Ensure Python can find the
kimai_mcpmodule - Arguments: Check that command-line arguments are properly formatted
If you're running a self-hosted Kimai instance with a custom CA certificate (e.g., self-signed certificates), you may encounter this error:
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate in certificate chain
Solution 1: Use the --ssl-verify CLI option
# Point to your CA certificate file
kimai-mcp --kimai-url=https://kimai.example.com --kimai-token=your-token --ssl-verify=/path/to/ca-bundle.crt
# Or disable verification (not recommended for production)
kimai-mcp --kimai-url=https://kimai.example.com --kimai-token=your-token --ssl-verify=falseSolution 2: Use environment variables
# Using httpx's built-in SSL environment variables
SSL_CERT_DIR=/etc/ssl/certs kimai-mcp --kimai-url=... --kimai-token=...
# Or using the KIMAI_SSL_VERIFY environment variable
KIMAI_SSL_VERIFY=/path/to/ca-bundle.crt kimai-mcp --kimai-url=... --kimai-token=...Claude Desktop configuration with custom certificates:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp",
"args": [
"--kimai-url=https://kimai.example.com",
"--kimai-token=your-token",
"--ssl-verify=/path/to/ca-bundle.crt"
]
}
}
}Or using the environment variable:
{
"mcpServers": {
"kimai": {
"command": "kimai-mcp",
"args": ["--kimai-url=...", "--kimai-token=..."],
"env": {
"KIMAI_SSL_VERIFY": "/path/to/ca-bundle.crt"
}
}
}
}For debugging, you can run the server directly:
# Using command line arguments
kimai-mcp --kimai-url=https://your-kimai.com --kimai-token=your-token
# Using .env file (make sure you're in the directory with the .env file)
kimai-mcp
# Alternative: using Python module execution
python -m kimai_mcp.server --kimai-url=https://your-kimai.com --kimai-token=your-tokenThe server includes comprehensive logging. Check the logs for detailed error information.
- API Token Security: Keep your API token secure and never commit it to version control
- Network Security: Use HTTPS for your Kimai instance
- Permission Management: Use appropriate Kimai roles and permissions
- Regular Updates: Keep the MCP server and dependencies updated
kimai_mcp/
├── src/
│ ├── kimai_mcp/
│ │ ├── __init__.py
│ │ ├── server.py # Local MCP server (stdio)
│ │ ├── streamable_http_server.py # Streamable HTTP server with OAuth (Claude.ai)
│ │ ├── oauth.py # Embedded OAuth 2.1 authorization server
│ │ ├── user_config.py # users.json / env multi-user configuration
│ │ ├── security.py # Rate limiting, security headers, enumeration protection
│ │ ├── client.py # Kimai API client
│ │ ├── models.py # Data models
│ │ └── tools/ # MCP tool implementations
│ │ ├── entity_manager.py
│ │ ├── timesheet_consolidated.py # timesheet + timer tools
│ │ ├── rate_manager.py
│ │ ├── team_access_manager.py
│ │ ├── absence_manager.py
│ │ ├── calendar_meta.py # calendar, meta, user_current tools
│ │ ├── comment_tool.py # project/customer comments
│ │ ├── project_analysis.py
│ │ ├── config_info.py
│ │ ├── user_discovery.py # shared user resolution helper
│ │ ├── batch_utils.py
│ │ ├── absence_analytics.py
│ │ └── timesheet_analytics.py
├── tests/
├── README.md
├── pyproject.toml
└── .gitignore
pytest tests/ -v- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Kimai MCP Server: MIT License (this project)
- Kimai Core: AGPL-3.0 License (separate project)
- Model Context Protocol: Open standard by Anthropic
This MCP server is an independent integration tool that communicates with Kimai via its public API. It is not a derivative work of Kimai itself and can be freely used under the MIT license terms.
We welcome contributions! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Clone the repository
- Install development dependencies:
pip install -e ".[dev]" - Run tests:
pytest tests/ -v - Follow the existing code style and add tests for new features
- Issues: Please use the GitHub issue tracker
- Documentation: Check the examples in the
examples/directory - Kimai Documentation: Visit kimai.org for Kimai-specific questions
- Anthropic for creating the Model Context Protocol
- Kimai Team for the excellent time-tracking software and API
- MCP Community for examples and best practices