go-clockify

module
v1.2.1-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2026 License: MIT

README

clockify-mcp-go

A Model Context Protocol server for Clockify — plug any MCP client into your time-tracking workspace and let it log time, run reports, and manage projects on your behalf.

Go version Release MCP protocol

Works with Claude Code, Claude Desktop, Cursor, Codex, and anything else that speaks MCP.

Highlights

  • 128 tools — 40 always-on (timer, entries, projects, reports, agent workflows, tool activation, …) plus 88 on-demand (invoices, scheduling, approvals, admin, …) across 11 activatable groups.
  • Resources & prompts — six clockify:// URI templates and five built-in prompt templates alongside the tool surface.
  • Five policy modesread_only, time_tracking_safe, safe_core, standard, full — plus dry-run preview support for every destructive tool.
  • Three transports — stdio (default), streamable HTTP 2025-03-26 (shared services), opt-in gRPC behind a build tag. Cancellation, tools/list_changed, size limits, and malformed-JSON boundaries pinned with cross-transport parity tests.
  • Stdlib-only default build — zero external runtime dependencies; the default binary links no OpenTelemetry, gRPC, or protobuf symbols (verified in CI).
  • Signed releases — every binary and container image ships with cosign signatures and SPDX SBOMs; SLSA build provenance is attached when GitHub artifact attestations are available for the repository account tier.

Contents

Start Here

Pick a deployment profile and invoke the binary with --profile=<name> (or MCP_PROFILE=<name>). The profile applies a bundle of pinned defaults; explicit env overrides still win.

Profile Shape Doc Example env
local-stdio single user, stdio subprocess profile-local-stdio.md env.local-stdio.example
single-tenant-http one team, streamable HTTP + static bearer profile-single-tenant-http.md env.single-tenant-http.example
shared-service multi-tenant, postgres + OIDC, audit fail-closed production-profile-shared-service.md env.shared-service.example
private-network-grpc gRPC + mTLS behind a private perimeter (-tags=grpc) profile-private-network-grpc.md env.private-network-grpc.example
prod-postgres alias of shared-service with ENVIRONMENT=prod see shared-service doc

Not sure which profile matches your environment? Run clockify-mcp doctor — it prints every env var's effective value, its source (explicit / profile / default / empty), and whether Load() would succeed at startup. Add --strict for hosted-service posture checks. Exit code is 0 on a clean load, 2 on a load error, and 3 when strict posture findings are present.

Operators upgrading from before Wave I: see the operator overview and docs/operators/ for the deeper production checklist — profiles shortcut the common cases but do not replace ops review for critical deployments.

Install

# Go
go install github.com/apet97/go-clockify/cmd/clockify-mcp@latest

# npm (prebuilt binaries)
npx @apet97/clockify-mcp-go

# Or download a prebuilt binary from Releases:
# https://github.com/apet97/go-clockify/releases

Private/internal installs: while this repository is private, configure Go to bypass the public module proxy for this module and make sure your GitHub credentials can read the repo before running go install: go env -w GOPRIVATE=github.com/apet97/go-clockify. SSH auth, GitHub CLI auth, or an HTTPS credential/PAT with repo access are all valid. GitHub Releases and Issues also require access to the private repository.

Verify:

clockify-mcp --version

Get a Clockify API key from Profile → Advanced and export it:

export CLOCKIFY_API_KEY=your-key

For personal testing against one real workspace, pin the local stdio profile and workspace before connecting an AI client:

export MCP_PROFILE=local-stdio
export CLOCKIFY_WORKSPACE_ID=your-workspace-id
export CLOCKIFY_POLICY=time_tracking_safe

Use time_tracking_safe for exploratory AI-facing testing because it allows timer and time-entry workflows without project/client/tag/task creation. Switch to safe_core only when you intentionally want that workspace-shaping surface. For large workspaces, keep CLOCKIFY_REPORT_MAX_ENTRIES at its fail-closed default unless you have a specific reason to materialize more than 10,000 raw entries in one tool call.

Connect to an MCP client

The examples below are the local stdio path: your MCP client launches clockify-mcp as a subprocess and forwards CLOCKIFY_API_KEY in its environment. Copy-ready snippets also live in examples/.

Claude Code (CLI)
claude mcp add clockify -- clockify-mcp

Then set the personal tester env vars above in your shell before starting Claude Code. If you inline env with claude mcp add -e, include MCP_PROFILE, CLOCKIFY_API_KEY, CLOCKIFY_WORKSPACE_ID, and CLOCKIFY_POLICY.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "clockify": {
      "command": "clockify-mcp",
      "env": {
        "MCP_PROFILE": "local-stdio",
        "CLOCKIFY_API_KEY": "your-key",
        "CLOCKIFY_WORKSPACE_ID": "your-workspace-id",
        "CLOCKIFY_POLICY": "time_tracking_safe"
      }
    }
  }
}
Cursor

Add to .cursor/mcp.json in your workspace:

{
  "mcpServers": {
    "clockify": {
      "command": "clockify-mcp",
      "env": {
        "MCP_PROFILE": "local-stdio",
        "CLOCKIFY_API_KEY": "your-key",
        "CLOCKIFY_WORKSPACE_ID": "your-workspace-id",
        "CLOCKIFY_POLICY": "time_tracking_safe"
      }
    }
  }
}
Codex CLI

Add to your Codex MCP config:

{
  "mcpServers": {
    "clockify": {
      "command": "clockify-mcp",
      "env": {
        "MCP_PROFILE": "local-stdio",
        "CLOCKIFY_API_KEY": "your-key",
        "CLOCKIFY_WORKSPACE_ID": "your-workspace-id",
        "CLOCKIFY_POLICY": "time_tracking_safe"
      }
    }
  }
}
npm wrapper (all clients)

If you installed via npm/npx, swap the command for:

{
  "command": "npx",
  "args": ["@apet97/clockify-mcp-go"]
}

Common workflows

For longer intent-keyed examples, see the agent cookbook.

Built-in prompt templates are available through MCP prompts/list and prompts/get: log-week-from-calendar, weekly-review, find-unbilled-hours, find-duplicate-entries, and generate-timesheet-report. They are short planning prompts that point clients at the current structured tools, including clockify_log_time for finished past entries and clockify_timesheet_review for gaps, overlaps, and suggested next-tool actions.

Start and stop a timer:

→ clockify_start_timer { "project": "My Project" }
← { "ok": true, "action": "timer_started", "data": { "id": "abc123" } }

→ clockify_stop_timer {}
← { "ok": true, "action": "timer_stopped" }

Log time retroactively:

→ clockify_log_time { "project": "Project Alpha", "start": "today 9:00", "end": "today 11:00", "description": "Code review", "dry_run": true }

Review and close a timesheet gap:

→ clockify_timesheet_review { "date": "2026-05-03", "timezone": "UTC" }
← { "ok": true, "action": "clockify_timesheet_review", "data": { "issues": [], "suggestedActions": [] } }

→ clockify_timesheet_fill_gap { "project": "Project Alpha", "start": "2026-05-03T09:00:00Z", "end": "2026-05-03T10:00:00Z", "description": "Planning", "dry_run": true }

Discover a Tier 2 domain or tool:

→ clockify_list_tools { "query": "invoice" }
← { "count": 6, "all_results": [ { "type": "group", "name": "invoices" }, { "type": "tool", "name": "clockify_send_invoice" } ] }

Activate a Tier 2 domain:

→ clockify_activate_group { "name": "invoices" }
← { "activated": "invoices", "tool_count": 12, "activated_tools": ["clockify_list_invoices", "..."], "total_visible_tools": 47 }

Optionally activate a single Tier 2 tool:

→ clockify_activate_tool { "name": "clockify_send_invoice" }
← { "activated": "clockify_send_invoice", "group": "invoices", "tool_count": 12, "activated_tools": ["clockify_list_invoices", "..."], "total_visible_tools": 47 }

Deactivate the domain when the task is done:

→ clockify_deactivate_group { "name": "invoices" }
← { "deactivated": "invoices", "tool_count": 12, "deactivated_tools": ["clockify_list_invoices", "..."], "total_visible_tools": 35 }

Preview a destructive operation first:

→ clockify_delete_entry { "entry_id": "abc123", "dry_run": true }
← { "dry_run": true, "preview": { "id": "abc123", "description": "Meeting" }, "note": "No changes were made." }

Execute after preview:

→ clockify_delete_entry { "entry_id": "abc123", "dry_run": false }
← { "ok": true, "action": "clockify_delete_entry", "data": { "deleted": true, "entryId": "abc123" } }

Large workspace report hygiene:

  • Pin CLOCKIFY_WORKSPACE_ID for personal API-key testing even when auto-detection works today. It keeps the target stable if the key later gains access to another workspace.
  • Prefer short date ranges and include_entries=false for summary, weekly, detailed, and quick reports when you need totals rather than raw rows.
  • Use page and page_size on list tools. The default is page=1, page_size=50, and the maximum page size is 200.
  • Report responses expose meta.pagination and meta.limits. CLOCKIFY_REPORT_MAX_ENTRIES applies when a call materializes raw entries with include_entries=true; cap errors are intentional fail-closed behavior.

Tool tiers

Tier 1 (40 tools, always loaded): timer, entries, projects, clients, tags, tasks, users, workspaces, reports, workflows, search, activation, context.

Tier 2 (88 tools, 11 groups, on demand): invoices, expenses, scheduling, time off, approvals, shared reports, user admin, webhooks, custom fields, groups/holidays, project admin.

Call clockify_list_tools to discover a Tier 2 group or specific tool, clockify_activate_group / clockify_activate_tool to widen the current session, and clockify_deactivate_group to shrink the visible surface after a task. Activation updates tools/list at runtime, and activated_tools only lists names that are visible after bootstrap and policy filtering. clockify_search_tools remains as a deprecated compatibility shim for older clients.

Policy modes

CLOCKIFY_POLICY controls which tools are exposed based on trust level:

Mode Read Write Delete Tier 2 Use case
read_only yes no no no Untrusted agents — observe only
time_tracking_safe yes time-entry allowlist no no Recommended AI-facing default for time tracking
safe_core yes broader allowlist no no Trusted assistants that may create projects, clients, tags, and tasks
standard yes yes yes on demand Raw no-profile default / trusted operator mode; code-level allow rules match full
full yes yes yes on demand Admin automation label for operators intentionally running the unrestricted policy

Introspection tools (clockify_whoami, clockify_policy_info, clockify_list_tools, clockify_activate_group, clockify_activate_tool, clockify_deactivate_group, clockify_search_tools, clockify_resolve_name, clockify_resolve_debug) are always available regardless of policy. clockify_resolve_debug is a compatibility alias; new clients should call clockify_resolve_name.

standard and full currently share the same enforcement semantics: any non-denied tool or group is policy-allowed. Their operational difference is convention plus bootstrap/activation posture, not a separate RiskClass gate. Use time_tracking_safe or safe_core for hosted AI-facing defaults, and use CLOCKIFY_DENY_*, CLOCKIFY_ALLOW_GROUPS, and CLOCKIFY_BOOTSTRAP_MODE to narrow a trusted operator deployment.

Configuration

The essentials (regenerate with go run ./cmd/gen-config-docs -mode=all):

Variable Default Purpose
CLOCKIFY_API_KEY API key (required for stdio/http/grpc and MCP_PROFILE=single-tenant-http; optional for shared-service / prod-postgres streamable_http where tenant credentials come from the control plane)
CLOCKIFY_BOOTSTRAP_MODE full_tier1 Initial tool surface
CLOCKIFY_DEDUPE_MODE warn Duplicate entry detection
CLOCKIFY_DRY_RUN enabled Enable dry-run preview support for tools that expose dry_run:true
CLOCKIFY_POLICY standard Tool-access policy tier
CLOCKIFY_RATE_LIMIT 120 Global tool calls per 60s window (0=disabled). For multi-subject HTTP/gRPC deployments, size this at least active_subjects * CLOCKIFY_PER_TOKEN_RATE_LIMIT so per-subject fairness can engage.
CLOCKIFY_WORKSPACE_ID auto Workspace ID (auto-detected if only one)
MCP_ALLOW_DEV_BACKEND Permit memory/file backends for streamable_http or grpc (single-process only)
MCP_AUDIT_DURABILITY best_effort Audit persist-failure behaviour (defaults to fail_closed when ENVIRONMENT=prod); fail_closed_strict also surfaces post-mutation outcome persistence failures
MCP_AUTH_MODE Authentication mode (per-transport support varies; see matrix)
MCP_CONTROL_PLANE_AUDIT_CAP 0 File/memory audit cap (0=unbounded). Postgres uses retention instead.
MCP_CONTROL_PLANE_AUDIT_RETENTION 720h Audit retention [1h,8760h]; 0=off
MCP_CONTROL_PLANE_DSN memory Control-plane DSN: memory, file://, postgres://...
MCP_GRPC_BIND :9090 gRPC listen address (requires -tags=grpc)
MCP_HTTP_BIND :8080 HTTP listen address
MCP_HTTP_INLINE_METRICS_AUTH_MODE inherit_main_bearer Auth mode for inline /metrics
MCP_HTTP_INLINE_METRICS_ENABLED 0 Expose /metrics on the main HTTP listener
MCP_HTTP_LEGACY_POLICY warn Legacy HTTP startup behaviour (defaults to deny when ENVIRONMENT=prod)
MCP_HTTP_MAX_BODY 4194304 Deprecated — use MCP_MAX_MESSAGE_SIZE. Deprecated alias for MCP_MAX_MESSAGE_SIZE
MCP_HTTP_RATELIMIT_GET_PER_SESSION 0 Concurrent streamable HTTP SSE GET connections allowed per session on this process (0=disabled; hosted profiles default to 4)
MCP_HTTP_RATELIMIT_PER_IP 0 Process-local HTTP admission limit per source IP per minute (0=disabled; hosted profiles default to 600)
MCP_HTTP_RATELIMIT_PER_PRINCIPAL 0 Process-local HTTP admission limit per authenticated subject+tenant per minute (0=disabled; hosted profiles default to 300)
MCP_LOG_FORMAT text Log format (stderr; PII-scrubbed)
MCP_MAX_MESSAGE_SIZE 4194304 Max request size in bytes (primary knob); 0 < N <= 104857600
MCP_METRICS_AUTH_MODE static_bearer (when MCP_METRICS_BIND set) Auth mode for dedicated metrics listener
MCP_METRICS_BEARER_TOKEN Bearer token (>=16 chars) for static_bearer metrics
MCP_METRICS_BIND Dedicated metrics listener (optional; recommended for streamable_http)
MCP_OIDC_VERIFY_CACHE_TTL 60s OIDC verify cache TTL [1s,5m]; hosted profiles clamp values above 60s
MCP_PROFILE Apply a bundle of pinned defaults for a named deployment shape; explicit env overrides still win
MCP_TRANSPORT stdio Transport mode; http is legacy POST-only (deprecated)

Run clockify-mcp --help for the complete list (75+ variables covering concurrency, timeouts, control plane, metrics, auth, CORS, and webhook DNS validation).

Architecture

Four clean layers: protocol core (internal/mcp/), Clockify client (internal/clockify/), tool surface (internal/tools/), and safety layer (internal/enforcement/). The protocol core has zero domain imports and plugs into the rest via Enforcement, Activator, Notifier, and ResourceProvider interfaces.

Docker

The published image defaults to the spec-strict streamable HTTP transport. The single-tenant-http profile wires the matching auth + control-plane defaults so the example below boots without a Postgres container or an OIDC issuer.

docker build -f deploy/Dockerfile -t clockify-mcp .

docker volume create clockify-mcp-data
export MCP_BEARER_TOKEN="$(openssl rand -base64 24)"

docker run -p 8080:8080 \
  -v clockify-mcp-data:/var/lib/clockify-mcp \
  -e MCP_PROFILE=single-tenant-http \
  -e CLOCKIFY_API_KEY=your-key \
  -e MCP_BEARER_TOKEN="$MCP_BEARER_TOKEN" \
  clockify-mcp

Validate the running server with the operator-facing endpoints:

curl http://127.0.0.1:8080/health

curl --oauth2-bearer "$MCP_BEARER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  http://127.0.0.1:8080/mcp

The repository also ships deploy/docker-compose.yml with a Caddy reverse proxy for TLS termination, and a Helm chart at deploy/helm/.

Build and test

make check   # fast inner loop: gofmt + go vet + go test
make verify  # pre-PR local pipeline: lint, coverage floors, fuzz-short,
             # build-tag checks, HTTP smoke, k8s render, govulncheck
             # (lint/k8s/fips/vuln tiers skip when local tools are missing)
make release-check  # pre-ship/tag gate: docs, scripts, smokes, gRPC E2E, deploy render
make cover   # coverage report
make build   # binary with version from git tags

make verify mirrors the PR-blocking CI jobs that can run on a laptop when their tools are installed; CI remains authoritative for skipped local tiers. make release-check is the laptop-runnable pre-ship gate. Neither command replaces the external launch-candidate evidence gates tracked in docs/launch-candidate-checklist.md.

Go 1.25.10, stdlib only. Module path: github.com/apet97/go-clockify.

Compatibility

Component Version
MCP Protocol 2025-11-25 (back-compat: 2025-06-18, 2025-03-26, 2024-11-05)
Go 1.25.10 pinned
Node.js (npm wrapper) 18+

Troubleshooting

No tools visible — Check CLOCKIFY_BOOTSTRAP_MODE. In minimal mode most tools are hidden; use clockify_list_tools to discover them.

401 Unauthorized — API key is invalid or expired. Generate a new one.

Multiple workspaces — Set CLOCKIFY_WORKSPACE_ID explicitly.

Tool not found — It may be a Tier 2 tool. Use clockify_list_tools to find it, then clockify_activate_group or clockify_activate_tool to activate its group.

Dry-run not working — Ensure CLOCKIFY_DRY_RUN=enabled (default) and pass "dry_run": true in tool call parameters.

Stale tool list — Stdio, streamable_http, and grpc clients all receive notifications/tools/list_changed after activation (streamable_http via the SSE stream on GET /mcp; gRPC fans the notification through every active Exchange stream). Only legacy http clients must manually re-fetch tools/list.

Deployment

Reference Kubernetes manifests live in deploy/k8s/ and deploy/helm/: Deployment (non-root distroless, read-only root FS, dropped capabilities), NetworkPolicy (default-deny), PodDisruptionBudget, ServiceMonitor, and a PrometheusRule with burn-rate alerts for a 99.9% SLO.

For a single-page operator overview that links the threat model, transports, auth modes, deployment targets, runbooks, and compliance posture, see the operator overview.

Operator resources

Contributing

See CONTRIBUTING.md.

Autonomous agents should start with AGENTS.md and the current launch-state handoff in docs/agent-handoff.md. The Claude Code continuation packet is retained as the historical post-PR #51 handoff.

Support

License

MIT

Directories

Path Synopsis
cmd
clockify-mcp command
gen-config-docs command
Command gen-config-docs renders config/help documentation from the internal/config EnvSpec registry.
Command gen-config-docs renders config/help documentation from the internal/config EnvSpec registry.
internal
auditbridge
Package auditbridge converts mcp.AuditEvent records into the controlplane.AuditEvent shape the durable audit store accepts.
Package auditbridge converts mcp.AuditEvent records into the controlplane.AuditEvent shape the durable audit store accepts.
enforcement
Package enforcement provides the concrete Enforcement and Activator implementations that compose the safety subsystems (policy, rate limiting, dry-run, truncation, bootstrap) into the MCP server's pluggable interfaces.
Package enforcement provides the concrete Enforcement and Activator implementations that compose the safety subsystems (policy, rate limiting, dry-run, truncation, bootstrap) into the MCP server's pluggable interfaces.
jsonmergepatch
Package jsonmergepatch is a hand-rolled, stdlib-only implementation of JSON Merge Patch (RFC 7396).
Package jsonmergepatch is a hand-rolled, stdlib-only implementation of JSON Merge Patch (RFC 7396).
jsonpatch
Package jsonpatch implements RFC 6902 JSON Patch: a sequence of add, remove, replace operations that transforms one JSON document into another.
Package jsonpatch implements RFC 6902 JSON Patch: a sequence of add, remove, replace operations that transforms one JSON document into another.
jsonschema
Package jsonschema is a tiny stdlib-only JSON-schema validator scoped to the keyword subset that the Clockify MCP server's Tier 1 + Tier 2 tool input schemas actually use.
Package jsonschema is a tiny stdlib-only JSON-schema validator scoped to the keyword subset that the Clockify MCP server's Tier 1 + Tier 2 tool input schemas actually use.
logging
Package logging provides a stdlib-only slog.Handler decorator that scrubs sensitive values from log attributes before they reach the underlying handler.
Package logging provides a stdlib-only slog.Handler decorator that scrubs sensitive values from log attributes before they reach the underlying handler.
mcp
metrics
Package metrics provides a stdlib-only Prometheus text exposition format encoder.
Package metrics provides a stdlib-only Prometheus text exposition format encoder.
paths
Package paths centralises Clockify URL path construction for handlers.
Package paths centralises Clockify URL path construction for handlers.
runtime
Package runtime wires the clockify-mcp process: it loads the config-derived dependencies (policy, rate limit, dedupe, dry-run, truncation, bootstrap) and owns transport dispatch.
Package runtime wires the clockify-mcp process: it loads the config-derived dependencies (policy, rate limit, dedupe, dry-run, truncation, bootstrap) and owns transport dispatch.
testharness
Package testharness wires the real MCP dispatch path (auth → enforcement pipeline → tool handler → Clockify client) against a fake Clockify upstream so tests can assert policy, auth, and idempotency properties end-to-end without bypassing the layers that enforce them.
Package testharness wires the real MCP dispatch path (auth → enforcement pipeline → tool handler → Clockify client) against a fake Clockify upstream so tests can assert policy, auth, and idempotency properties end-to-end without bypassing the layers that enforce them.
tracing
Package tracing is the stdlib-only tracing facade.
Package tracing is the stdlib-only tracing facade.
tracing/otel module
scripts
gen-tool-catalog command
gen-tool-catalog walks the Tier-1 registry and every Tier-2 group builder and emits a machine-readable catalog (JSON) and a human-readable rendering (Markdown) for docs/tool-catalog.{json,md}.
gen-tool-catalog walks the Tier-1 registry and every Tier-2 group builder and emits a machine-readable catalog (JSON) and a human-readable rendering (Markdown) for docs/tool-catalog.{json,md}.
tests
chaos command
Package main is the clockify-mcp chaos harness.
Package main is the clockify-mcp chaos harness.
harness
Package harness provides a unified TransportHarness interface that lets one test body exercise stdio, legacy HTTP, streamable HTTP, and gRPC in parallel.
Package harness provides a unified TransportHarness interface that lets one test body exercise stdio, legacy HTTP, streamable HTTP, and gRPC in parallel.
load command
Package main is the clockify-mcp load harness.
Package main is the clockify-mcp load harness.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL