yt-toggl-mcp
by yentsun
README.md
# yt-toggl-mcp
A small, self-hosted [MCP](https://modelcontextprotocol.io) server for **Toggl Track (API v9)**.
It runs over stdio and exposes time tracking, projects/clients, and reporting to any MCP client.
No telemetry. The only network egress is to `api.track.toggl.com`. Workspace-level tokens are
stripped from every response and user emails are masked.
## Tools
| Tool | What it does |
| --- | --- |
| `toggl_check_auth` | Verify the token; returns the (masked) user and accessible workspaces. |
| `toggl_get_quota` | Remaining API requests and reset time per organization. |
| `toggl_list_workspaces` | List accessible workspaces. |
| `toggl_list_projects` | List projects in a workspace. |
| `toggl_list_clients` | List clients in a workspace. |
| `toggl_list_tags` | List tags in a workspace. |
| `toggl_get_current_entry` | Return the running timer with elapsed seconds. |
| `toggl_get_time_entry` | Load a single entry by id. |
| `toggl_get_time_entries` | List entries for a `period`, an inclusive `start_date`/`end_date` range, or `since`/`before`. |
| `toggl_create_time_entry` | Create a completed entry (`start` + `stop`/`duration`) or a running one. |
| `toggl_update_time_entry` | Edit an existing entry; only the fields you pass are changed. |
| `toggl_delete_time_entry` | Permanently delete an entry. |
| `toggl_start_timer` | Start a running timer with optional description, project, tags. |
| `toggl_stop_timer` | Stop the running timer (or a specific `entry_id`). |
| `toggl_report` | Total time for a range, grouped by project, sorted by hours. |
`period` accepts `today`, `yesterday`, `week`, `lastWeek`, `month`, `lastMonth`. Ranges are
interpreted in local time and `end_date` is inclusive at the tool boundary. `since` takes unix
seconds and, per Toggl, also returns entries deleted since that time.
Toggl enforces a sliding-window request quota per user per organization; on `402` the error
result carries `quota_remaining` and `quota_resets_in_seconds`.
`toggl_report` clips every entry to the requested range, so an entry crossing a boundary is neither
double-counted nor dropped. It scans backward in 84-day windows and respects Toggl's historical
retention boundary: if it reaches that boundary it returns `incomplete: true` together with
`incomplete_reason`, rather than reporting a silently short total. Any other error is propagated.
## Configuration
Credentials live in a per-tool file under your home directory, matching the other `yt-*` MCP
servers. Environment variables take precedence, so the file is optional in CI or containers.
`~/.yt-toggl-mcp/credentials.json`:
```json
{
"apiToken": "<your token>",
"workspaceId": 1234567
}
```
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `TOGGL_API_KEY` | no | `apiToken` from the credentials file | Toggl Track API token ([track.toggl.com/profile](https://track.toggl.com/profile)). |
| `TOGGL_DEFAULT_WORKSPACE_ID` | no | `workspaceId` from the credentials file, else auto if a single workspace | Default workspace for workspace-scoped tools. |
| `TOGGL_CACHE_TTL` | no | `3600000` | Metadata cache TTL in ms. |
A token must come from one of the two sources, otherwise the server exits with a message naming
the file to create. `workspaceId` is optional — omit it if you only have one workspace.
## Install
Prerequisites: Node.js `>=20.19.0` and a Toggl Track API token from
[track.toggl.com/profile](https://track.toggl.com/profile) (scroll to the bottom → "Click to reveal").
### npm
```bash
npx -y yt-toggl-mcp
```
Any MCP client that speaks stdio works. Generic client config:
```json
{
"mcpServers": {
"yt-toggl-mcp": {
"command": "npx",
"args": ["-y", "yt-toggl-mcp"]
}
}
}
```
`yt-toggl-mcp --help` prints the credential path and the environment variables; `--version` prints
the version. Both write to stderr, since stdout carries the MCP protocol.
### opencode
**1. Create the credentials file**
Write `~/.yt-toggl-mcp/credentials.json` (Windows: `C:\Users\<you>\.yt-toggl-mcp\credentials.json`):
```json
{
"apiToken": "<your token>",
"workspaceId": 1234567
}
```
`workspaceId` is optional. Alternatively set `TOGGL_API_KEY` (and optionally
`TOGGL_DEFAULT_WORKSPACE_ID`) in the environment — env vars win over the file.
**2. Register the server**
Add this to `~/.config/opencode/opencode.jsonc` (Windows:
`C:\Users\<you>\.config\opencode\opencode.jsonc`) under the existing `mcp` key:
```jsonc
{
"mcp": {
"yt-toggl-mcp": {
"type": "local",
"command": ["npx", "-y", "yt-toggl-mcp"]
}
}
}
```
No `environment` block is needed: the server reads its own credentials file, like `yt-gmail-mcp`
and `yt-zoho-mcp`.
**3. Restart opencode**
Config is read once at startup and is not hot-reloaded, so the server only loads after a restart.
**4. Verify**
Ask opencode to call `toggl_check_auth`. It should return your (masked) account and workspace list.
A quick win after that: ask "what am I currently tracking?".
## Development
```bash
npm install
npm run build
npm run lint
npm test
```
`npm test` runs the Vitest suite with HTTP mocked, so no token or live calls are needed.
`node dist/index.js` runs the built server locally — it reads the same credentials file described
above. `npm run dev` watches the source with `tsx` instead of building.
## License
MIT © yentsun — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive