{
  "markdown": "# keeping-mcp\n\n![CI](https://github.com/red-square-software/keeping-mcp/actions/workflows/ci.yml/badge.svg)\n\nOpen-source Model Context Protocol (MCP) server that exposes the Keeping (api.keeping.nl) time-tracking API as tools an AI coding assistant can call. Built for solo developers who use Claude Code (or any MCP-capable client) and want their billable hours logged into Keeping at the end of a session instead of typed in by hand, while keeping Keeping's existing native Jortt invoicing integration intact. Every write tool is dry-run by default — your hours never reach Keeping until you explicitly confirm.\n\n> ## ⚠ Writes are dry-run BY DEFAULT\n>\n> Every write tool (`keeping_add_entry`, `keeping_update_entry`, `keeping_delete_entry`,\n> `keeping_start_timer`, `keeping_stop_timer`, `keeping_resume_timer`) returns a\n> **preview** unless you pass `confirm: true` in the tool call.\n>\n> Setting `KEEPING_REQUIRE_CONFIRM=false` in your environment **disables this gate**.\n> Writes then happen on the first call — there is no second chance.\n>\n> Recommendation: **never disable this gate** unless you are running\n> the server in a non-interactive automation context and have explicitly accepted\n> the loss of the confirmation step.\n\n## Install\n\n### From npm\n\nNo install required — `npx` fetches the package on first run:\n\n```bash\nKEEPING_TOKEN=kp_live_your_token_here npx -y keeping-mcp\n```\n\nThe server speaks the [MCP stdio protocol](https://modelcontextprotocol.io/specification/draft/basic/transports#stdio) and stays in the foreground waiting for JSON-RPC frames on stdin — exit with `Ctrl+C`. In practice you do not run it by hand; an MCP-capable client (Claude Code, Claude Desktop, Cursor, etc.) spawns it for you using the config snippets below.\n\nOptional — install globally so `keeping-mcp` is on your `PATH`:\n\n```bash\nnpm install -g keeping-mcp\nKEEPING_TOKEN=kp_live_your_token_here keeping-mcp\n```\n\nRequires Node.js `>=22`. The package is published to [npmjs.com/package/keeping-mcp](https://www.npmjs.com/package/keeping-mcp) with [sigstore provenance attestations](#verifying-provenance).\n\n### Claude Code on Windows 11\n\nAdd to `%APPDATA%\\Claude\\claude_desktop_config.json` or to your project's `.mcp.json` file.\n\n```json\n{\n  \"mcpServers\": {\n    \"keeping-mcp\": {\n      \"command\": \"cmd\",\n      \"args\": [\"/c\", \"npx\", \"-y\", \"keeping-mcp\"],\n      \"env\": {\n        \"KEEPING_TOKEN\": \"kp_live_your_token_here\"\n      }\n    }\n  }\n}\n```\n\nThe `cmd /c` wrapper is required on Windows — `npx` resolves to `npx.cmd`, and Claude Code's process spawn does not search PATHEXT extensions (see [anthropics/claude-code#58510](https://github.com/anthropics/claude-code/issues/58510)).\n\n### Claude Code on macOS / Linux\n\nAdd to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `~/.config/Claude/claude_desktop_config.json` (Linux), or your project's `.mcp.json`.\n\n```json\n{\n  \"mcpServers\": {\n    \"keeping-mcp\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"keeping-mcp\"],\n      \"env\": {\n        \"KEEPING_TOKEN\": \"kp_live_your_token_here\"\n      }\n    }\n  }\n}\n```\n\n### Other MCP clients\n\nAny MCP-capable client that supports the stdio transport works. The server is started by `npx -y keeping-mcp` and reads `KEEPING_TOKEN` from its environment. Discoverable in the [MCP Registry](https://registry.modelcontextprotocol.io/) as `io.github.Red-Square-Software/keeping-mcp`.\n\n## Get a Keeping access token\n\n1. Sign in to your Keeping account.\n2. Open **Preferences** (top-right menu).\n3. Find the section **Show features for developers** and enable it.\n4. A new **Personal access tokens** section appears.\n5. Click **Generate new token**, name it (e.g. \"Claude Code\"), and copy the value.\n6. Store it as `KEEPING_TOKEN` in your shell environment OR in your Claude Code config `env` block.\n\nThe token has full read+write access to your time entries — treat it like a password. Never commit it to git, never paste it into a chat, never read it back from a tool response (`keeping-mcp` never echoes it).\n\n## Configuration\n\n| Variable | Required | Default | Purpose |\n|----------|----------|---------|---------|\n| `KEEPING_TOKEN` | yes | — | Keeping personal access token (created via the section above). |\n| `KEEPING_REQUIRE_CONFIRM` | no | `true` | When `true`, write tools return a preview unless called with `confirm: true`. Setting to `false` disables the gate entirely — see warning below. |\n| `KEEPING_ORG_ID` | no | — | Pin all calls to one organisation id. When unset and the token has access to multiple orgs, write tools require explicit `organisation_id` input per call. |\n| `KEEPING_LOG_LEVEL` | no | `info` | Server stderr log verbosity. Accepts: `debug`, `info`, `warn`, `error`. |\n\n> ## ⚠ Writes are dry-run BY DEFAULT\n>\n> Every write tool (`keeping_add_entry`, `keeping_update_entry`, `keeping_delete_entry`,\n> `keeping_start_timer`, `keeping_stop_timer`, `keeping_resume_timer`) returns a\n> **preview** unless you pass `confirm: true` in the tool call.\n>\n> Setting `KEEPING_REQUIRE_CONFIRM=false` in your environment **disables this gate**.\n> Writes then happen on the first call — there is no second chance.\n>\n> Recommendation: **never disable this gate** unless you are running\n> the server in a non-interactive automation context and have explicitly accepted\n> the loss of the confirmation step.\n\n## Tools\n\nkeeping-mcp registers 12 tools when the server starts. Read tools (`keeping_me`, `keeping_organisations`, `keeping_projects`, `keeping_tasks`, `keeping_list_entries`, `keeping_timer_status`) call Keeping's API without confirmation. Write tools (`keeping_add_entry`, `keeping_update_entry`, `keeping_delete_entry`, `keeping_start_timer`, `keeping_stop_timer`, `keeping_resume_timer`) return a dry-run preview unless invoked with `confirm: true` (default behavior controlled by `KEEPING_REQUIRE_CONFIRM`).\n\n## Dry-run workflow (example transcript)\n\nWrite tools follow a two-step pattern: propose-then-confirm. The first call returns a preview of the HTTP request the server would send; the second call (with `confirm: true`) actually sends it.\n\nStep 1 — preview (no `confirm`, no API call made). Illustrative; actual field names match Keeping's OpenAPI (see https://developer.keeping.nl).\n\n```json\n{\n  \"tool\": \"keeping_add_entry\",\n  \"input\": {\n    \"description\": \"Phase 4 release prep\",\n    \"hours\": 1.5,\n    \"project_id\": 123\n  },\n  \"response\": {\n    \"would_post\": {\n      \"method\": \"POST\",\n      \"url\": \"https://api.keeping.nl/v1/456/time-entries\",\n      \"body\": {\n        \"description\": \"Phase 4 release prep\",\n        \"hours\": 1.5,\n        \"project_id\": 123,\n        \"date\": \"2026-06-12\",\n        \"purpose\": \"work\"\n      }\n    }\n  }\n}\n```\n\nStep 2 — confirm (`confirm: true` added, request is sent to Keeping). Illustrative; actual response shape mirrors Keeping's OpenAPI.\n\n```json\n{\n  \"tool\": \"keeping_add_entry\",\n  \"input\": {\n    \"description\": \"Phase 4 release prep\",\n    \"hours\": 1.5,\n    \"project_id\": 123,\n    \"confirm\": true\n  },\n  \"response\": {\n    \"id\": 98765,\n    \"day\": \"2026-06-12\",\n    \"hours\": 1.5,\n    \"description\": \"Phase 4 release prep\",\n    \"project_id\": 123,\n    \"purpose\": \"work\"\n  }\n}\n```\n\n## Verifying provenance\n\nReleases are published via GitHub Actions OIDC trusted publishing (no long-lived npm tokens). Every release carries an npm provenance attestation linking the published tarball to a specific commit in this repository.\n\n```bash\nnpm audit signatures\n# or, for a single package:\nnpm view keeping-mcp --json | jq '.dist.attestations'\n```\n\n## Local development\n\n```bash\ngit clone https://github.com/red-square-software/keeping-mcp.git\ncd keeping-mcp\nnpm ci\nnpm test\nnpm run build\nKEEPING_TOKEN=kp_live_your_token_here node dist/bin/keeping-mcp.js\n```\n\nAll server output goes to stderr — stdout is reserved for MCP JSON-RPC framing. Never write diagnostic output to stdout; use `console.error` for logging.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n",
  "bytes": 7924,
  "sha": "21662f9297a1ceeb19e2ea3789366d2235accc29841b6e3b7973268af762bfd5",
  "repo_slug": "red-square-software/keeping-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_red_square_software_keeping_mc_9e5e35ea/readme"
}