Clockify MCP Go
Clockify MCP Server (Go) β stdlib-only Model Context Protocol server for Clockify
Ask AI about Clockify MCP Go
Powered by Claude Β· Grounded in docs
I know everything about Clockify MCP Go. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
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.
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 modes β
read_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 Β· Install Β· Connect a client Β· Common workflows Β· Tool tiers
- Policy modes Β· Configuration Β· Architecture Β· Docker Β· Build and test
- Compatibility Β· Troubleshooting Β· Deployment Β· Contributing
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_IDfor 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=falsefor summary, weekly, detailed, and quick reports when you need totals rather than raw rows. - Use
pageandpage_sizeon list tools. The default ispage=1,page_size=50, and the maximum page size is 200. - Report responses expose
meta.paginationandmeta.limits.CLOCKIFY_REPORT_MAX_ENTRIESapplies when a call materializes raw entries withinclude_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
- Shared Service profile
- Support Matrix
- Client Compatibility
- Deploy-Readiness Checklist
- Operator Guides (Shared Service vs Self-Hosted)
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
- Adoption expectations, response-time posture,
v1.xwire-format stability guarantee: SUPPORT.md - Governance (single-maintainer, merge gate, sensitive-area self-review): GOVERNANCE.md
- Security vulnerabilities: SECURITY.md (private disclosure channel)
- Bug reports and feature requests: GitHub Issues (requires repo access while private)
- Release history: CHANGELOG.md Β· GitHub Releases (requires repo access while private)
- Versioning, support window, breaking-change policy: docs/release-policy.md
- Documentation map: docs/README.md
