clockodo-mcp-server

clockodo-mcp-server

Enables interaction with the Clockodo time tracking API, providing tools, prompts, and resources for time tracking, HR analytics, and team management with role-based access.

Category
访问服务器

README

Clockodo MCP Server

MCP server wrapper for the Clockodo time tracking API with configurable feature sets.

MCP Badge Docker Image Security Scans

🐳 Docker Image: ghcr.io/pfaeffli/clockodo-mcp-server:latest

Table of Contents

Features

This MCP server provides comprehensive time tracking capabilities through:

  • Tools: 25+ tools for time tracking, HR analytics, and team management
  • Prompts: Interactive prompt templates for common workflows
  • Resources: Real-time access to time entries, customers, and services
  • Role-Based Access: Configurable permission levels (employee, team_leader, hr_analytics, admin)

Architecture & Patterns

This project follows specific architectural patterns to maintain clean, testable, and maintainable code.

1. Layered Architecture

┌─────────────────────────────────────┐
│   MCP Server Layer (server.py)     │  ← Tool registration, MCP protocol
├─────────────────────────────────────┤
│   Service Layer (services/)         │  ← Business logic, orchestration
├─────────────────────────────────────┤
│   Client Layer (client.py)          │  ← HTTP API communication
├─────────────────────────────────────┤
│   External API (Clockodo REST API)  │  ← Third-party service
└─────────────────────────────────────┘

Rules:

  • Server Layer: Only handles MCP tool registration and protocol. No business logic.
  • Service Layer: Contains all business logic. Services use clients but never handle MCP directly.
  • Client Layer: Pure HTTP/API client. No business logic, only request/response handling.
  • Dependencies flow downward only: Server → Service → Client (never upward)

2. Configuration Management

Pattern: Feature Flags with Environment Variables

# config.py - Central configuration
class ServerConfig:
    hr_readonly: bool = True      # Default safe
    user_read: bool = False        # Opt-in
    admin_edit: bool = False       # Explicit opt-in

    @classmethod
    def from_env(cls) -> "ServerConfig":
        """Load from environment with safe defaults"""

Rules:

  • All configuration comes from environment variables
  • Safe defaults (read-only, minimal permissions)
  • Preset configurations available (readonly, user, admin)
  • No hardcoded credentials or API keys

3. Dependency Injection

Pattern: Constructor Injection

class HRService:
    def __init__(self, client: ClockodoClient):
        """Inject dependencies explicitly"""
        self.client = client

    def check_overtime_compliance(self, year: int) -> dict:
        # Use injected client
        reports = self.client.get_user_reports(year=year)

Rules:

  • Services receive their dependencies through constructors
  • Makes testing easy (mock the dependencies)
  • Clear dependency graph
  • No global state or singletons (except config)

4. Separation of Concerns

Pattern: Single Responsibility Principle

client.py          → HTTP communication only
hr_analyzer.py     → Pure data analysis (no I/O)
hr_service.py      → Orchestration (client + analyzer)
hr_tools.py        → MCP tool wrappers (service → MCP)
server.py          → Tool registration

Rules:

  • Each module has ONE clear purpose
  • Analyzers are pure functions (input → output, no side effects)
  • Services handle orchestration
  • Tools are thin wrappers

5. API Version Handling

Pattern: Resource-Specific Versioning

Clockodo uses a resource-specific versioning scheme. This server always targets the most recent stable version for each resource:

  • v4: Projects, Services, Absences
  • v3: Users, Customers
  • v2: Clock, Entries
  • v1: User Reports (Legacy reports with no newer version available)

Rules:

  • Base URL is normalized to end with /api/
  • All client methods explicitly use the required version prefix (e.g., v3/users)
  • Responses are normalized to maintain internal consistency (e.g., mapping data key to resource-specific keys)
  • Legacy v1 endpoints are called without a version prefix

6. Error Handling

Pattern: Let Errors Bubble Up with Context

def _request(self, method: str, endpoint: str) -> dict:
    resp = httpx.request(...)
    resp.raise_for_status()  # Let HTTPStatusError bubble up
    return resp.json()

Rules:

  • Don't catch exceptions unless you can handle them
  • Use httpx's built-in error handling
  • Add context when re-raising
  • Let MCP framework handle final error presentation

7. Type Safety

Pattern: Type Hints Everywhere

def check_overtime_compliance(
    self, year: int, max_overtime_hours: float = 80
) -> dict:
    """
    Clear input/output types

    Args:
        year: Year to check (e.g., 2024)
        max_overtime_hours: Maximum allowed overtime hours

    Returns:
        Dictionary with overtime violations
    """

Rules:

  • All functions have type hints
  • Use from __future__ import annotations for forward references
  • Docstrings explain the structure of complex dicts
  • mypy validation in CI/CD

8. Testing Strategy

Pattern: Layered Testing

Unit Tests          → Pure functions (analyzers)
Integration Tests   → Services with mocked clients
Manual Tests        → Jupyter notebooks for real API

Rules:

  • Mock external HTTP calls (use respx)
  • Test business logic in isolation
  • Use pytest fixtures for common setup
  • Manual testing with real credentials in notebooks

9. Documentation as Code

Pattern: Self-Documenting Code

@mcp.tool()
def check_overtime_compliance(year: int, max_overtime_hours: float = 80) -> dict:
    """
    Check which employees have excessive overtime.

    This docstring becomes the MCP tool description.
    """

Rules:

  • Docstrings on all public functions
  • Type hints provide inline documentation
  • README explains patterns and architecture
  • Examples in manual-test/ folder

10. Environment-Based Behavior

Pattern: Configuration Over Code

# Don't do this:
if production_mode:
    do_something()

# Do this:
config = ServerConfig.from_env()
if config.is_enabled(FeatureGroup.ADMIN_EDIT):
    register_admin_tools()

Rules:

  • Feature flags control behavior
  • No if/else for environments in code
  • Test different configurations via env vars
  • Document all environment variables

11. Project Versioning

Pattern: Automated Git Tag Versioning

The project version is automatically managed using setuptools-scm based on Git tags. This ensures that the version in pyproject.toml and at runtime always matches the latest Git tag.

Rules:

  • Version is NOT hardcoded in pyproject.toml (uses dynamic = ["version"])
  • src/clockodo_mcp/__init__.py retrieves the version at runtime using importlib.metadata or a generated _version.py file
  • New releases are created by tagging the repository (e.g., git tag v0.3.0)
  • The version matches semantic versioning principles

Setup

Option 1: Using Pre-built Docker Image from GitHub Container Registry

For Local MCP Clients (Claude Desktop, IDEs) - stdio transport

Add configuration to your IDE's MCP settings (e.g., Claude Desktop):

{
  "mcpServers": {
    "clockodo": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e",
        "CLOCKODO_API_USER=your@email.com",
        "-e",
        "CLOCKODO_API_KEY=your_api_key",
        "-e",
        "CLOCKODO_USER_AGENT=my-company/1.0",
        "-e",
        "CLOCKODO_BASE_URL=https://my.clockodo.com/api/",
        "-e",
        "CLOCKODO_EXTERNAL_APP_CONTACT=dev@company.com",
        "-e",
        "CLOCKODO_MCP_ROLE=employee",
        "ghcr.io/pfaeffli/clockodo-mcp-server:latest"
      ]
    }
  }
}

For Remote Access (Web Apps) - HTTP/SSE transport

⚠️ Note: SSE transport is currently experimental and has known issues. Not recommended for production use.

docker run -d \
  -p 8000:8000 \
  -e CLOCKODO_API_USER=your@email.com \
  -e CLOCKODO_API_KEY=your_api_key \
  -e CLOCKODO_MCP_ROLE=employee \
  -e CLOCKODO_MCP_TRANSPORT=sse \
  -e CLOCKODO_MCP_HOST=0.0.0.0 \
  -e CLOCKODO_MCP_PORT=8000 \
  ghcr.io/pfaeffli/clockodo-mcp-server:latest

Available image tags:

  • latest - Latest stable release
  • v1.0.0, v1.0, v1 - Semantic version tags
  • main-<sha> - Latest main branch build

Option 2: Build Locally

  1. Build the Docker image:

    make build-mcp
    
  2. Add configuration to your IDE's MCP settings using clockodo-mcp:latest instead of the ghcr.io image.

Environment Variables

API Credentials (Required)

  • CLOCKODO_API_USER - Your Clockodo email
  • CLOCKODO_API_KEY - Your Clockodo API key

API Configuration (Optional)

  • CLOCKODO_USER_AGENT - Custom user agent string (default: "clockodo-mcp/unknown")
  • CLOCKODO_BASE_URL - API base URL (default: "https://my.clockodo.com/api/")
  • CLOCKODO_EXTERNAL_APP_CONTACT - Contact info for external app header (default: API user email)

Transport Configuration (Optional)

  • CLOCKODO_MCP_TRANSPORT - Transport protocol (default: "stdio")
    • stdio - Standard input/output for local processes (Claude Desktop, IDEs) [Recommended]
    • sse - HTTP/SSE for remote access [Experimental - Known Issues]
  • CLOCKODO_MCP_HOST - Host address to bind to (default: "0.0.0.0")
  • CLOCKODO_MCP_PORT - Port for SSE transport (default: 8000)

⚠️ SSE Transport Limitation: The SSE transport is experimental and currently has issues with the MCP library (v1.25.0). The server accepts connections and messages but does not properly send responses back through the event stream, causing client initialization timeouts. Use stdio transport for production. SSE support depends on upstream fixes in the MCP library.

Role Configuration (Recommended)

Use CLOCKODO_MCP_ROLE to set the user's role:

CLOCKODO_MCP_ROLE=employee      # Default - Track your own time
CLOCKODO_MCP_ROLE=team_leader   # Employee + approve vacations & edit team entries
CLOCKODO_MCP_ROLE=hr_analytics  # View HR compliance reports only
CLOCKODO_MCP_ROLE=admin         # Full access to everything
Role Can Do
employee Track own time, request vacation
team_leader Everything employee can + approve team vacations + edit team entries
hr_analytics View HR compliance reports (overtime, vacation violations) for all employees
admin Full access to all features

Legacy Configuration (Deprecated)

The following are still supported but deprecated. Use CLOCKODO_MCP_ROLE instead:

Legacy Presets:

  • CLOCKODO_MCP_PRESET=readonly - Maps to hr_analytics role
  • CLOCKODO_MCP_PRESET=user - Maps to employee role
  • CLOCKODO_MCP_PRESET=team_leader - Maps to team_leader role
  • CLOCKODO_MCP_PRESET=admin - Maps to admin role

Legacy Granular Flags:

  • CLOCKODO_MCP_ENABLE_HR_READONLY=true
  • CLOCKODO_MCP_ENABLE_USER_READ=true
  • CLOCKODO_MCP_ENABLE_USER_EDIT=true
  • CLOCKODO_MCP_ENABLE_TEAM_LEADER=true
  • CLOCKODO_MCP_ENABLE_ADMIN_READ=true
  • CLOCKODO_MCP_ENABLE_ADMIN_EDIT=true

Available Features

Core Tools (Always Available)

  • health - Health check (shows enabled features)
  • list_users - List all Clockodo users
  • list_customers - List all customers
  • list_services - List all services
  • list_projects - List all projects
  • get_raw_user_reports(year) - Get raw API response for debugging

Prompts (Always Available)

  • start_tracking - Start tracking time for a customer and service
  • stop_tracking - Stop tracking the current time entry
  • request_vacation - Request vacation time

Resources (Always Available)

  • clockodo://current-entry - Get the currently running time entry
  • clockodo://customers - Get the list of available customers
  • clockodo://services - Get the list of available services
  • clockodo://projects - Get the list of available projects
  • clockodo://recent-entries - Get recent time entries (last 7 days)

HR Analytics (when HR_READONLY enabled)

  • check_overtime_compliance(year, max_overtime_hours) - Check employee overtime
  • check_vacation_compliance(year, min_vacation_days, max_vacation_remaining) - Check vacation usage
  • get_hr_summary(year, ...) - Complete HR compliance report

User Tools (when USER_READ or USER_EDIT enabled)

  • get_my_clock() - Get currently running clock
  • get_my_time_entries(time_since, time_until) - Get your time entries
  • start_my_clock(...) - Start tracking time
  • stop_my_clock() - Stop tracking time
  • add_my_time_entry(...) - Add a manual time entry
  • edit_my_time_entry(entry_id, data) - Edit your time entry
  • delete_my_time_entry(entry_id) - Delete your time entry
  • add_my_vacation(date_since, date_until) - Request vacation
  • delete_my_vacation(absence_id) - Delete vacation request

Team Leader Tools (when TEAM_LEADER enabled)

  • list_pending_vacation_requests(year) - List all pending vacation requests
  • approve_vacation_request(absence_id) - Approve a vacation request
  • reject_vacation_request(absence_id) - Reject a vacation request
  • adjust_vacation_dates(absence_id, new_date_since, new_date_until) - Adjust vacation length
  • create_team_member_vacation(user_id, date_since, date_until, ...) - Create vacation for team member
  • edit_team_member_entry(entry_id, data) - Edit team member's time entry
  • delete_team_member_entry(entry_id) - Delete team member's time entry

Development

# Build
make build-mcp

# Run tests
make test

# Type checking
make type

# Linting
make lint

# Style check
make format-check

Security Scanning

Run comprehensive security scans on the Docker image:

# Run all security scans (vulnerability, Docker best practices, licenses, SBOM)
make all-scans

# Individual scans
make vulnerability-scan  # Trivy vulnerability scanning
make docker-scan        # Dockle Docker best practices
make license-check      # Python dependency license check
make sbom              # Generate Software Bill of Materials

All security tools run via Docker containers - no local installation required.

Manual Testing

For manual testing with real Clockodo API credentials, use the Jupyter notebook:

make manual-test

Open http://localhost:8888 and navigate to work/manual-test/test_clockodo.ipynb.

See manual-test/JUPYTER_TESTING.md for detailed instructions.

Project Structure

clockodo-mcp/
├── src/clockodo_mcp/
│   ├── server.py              # MCP tool registration
│   ├── client.py              # Clockodo API client
│   ├── config.py              # Feature flag configuration
│   ├── hr_analyzer.py         # Pure data analysis functions
│   ├── services/
│   │   ├── hr_service.py      # Business logic orchestration
│   │   ├── user_service.py    # User operations
│   │   └── team_leader_service.py  # Team leader operations
│   └── tools/
│       ├── hr_tools.py        # MCP tool wrappers
│       ├── user_tools.py      # User tool wrappers
│       ├── team_leader_tools.py    # Team leader tool wrappers
│       └── debug_tools.py     # Debugging utilities
├── tests/                      # Unit and integration tests
├── manual-test/               # Jupyter notebooks for manual testing
├── docker-compose.yml         # Dev and server services
├── docker-compose.test.yml    # Test and Jupyter services
└── makefile                   # Build and test targets

Contributing

When adding new features, follow these patterns:

  1. New API Endpoint: Add method to client.py
  2. Business Logic: Create/update service in services/
  3. MCP Tool: Add tool registration in server.py
  4. Tests: Add unit tests in tests/
  5. Documentation: Update README and docstrings

Always maintain the layered architecture: Server → Service → Client

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选