Skip to main content
Glama
wakapi-mcp

wakapi-mcp

by si-essence
README.md
# wakapi

MCP connector for a self-hosted [Wakapi](https://github.com/muety/wakapi) server, tested against Wakapi 2.18.2. It speaks the HTTP API under `/api` over stdio and over stateless Streamable HTTP on localhost.

Wakapi on GitHub is MIT software. The vendored swagger `info.license` field says GPL-3.0 and points at the same repository. GitHub reported SPDX `MIT` for `muety/wakapi` on 2026-11-03. This connector does not copy the Go server. `vendor/wakapi-swagger.json` is a copy of the swagger shipped with the local 2.18.2 binary. See `vendor/LICENSE-NOTE.md`. The connector is not affiliated with Wakapi.

`wakapi.routes.json` lists every operation in that swagger. 22 operations are tools. None are excluded. `scripts/gen-operations.mjs` writes `src/operations.ts` from the swagger. Do not edit `src/operations.ts` by hand.

`WAKAPI_URL` and `WAKAPI_API_KEY` are required. There is no default origin. This connector talks to your Wakapi server. It does not call wakatime.com.

## Setup

```bash
npm install
npm run ci
npm start
npm run start:http
```

`npm start` speaks stdio. `npm run start:http` serves Streamable HTTP at `http://127.0.0.1:3000/mcp` and `GET /health`. HTTP mode has no authentication of its own. Keep it on localhost.

```json
{
  "mcpServers": {
    "wakapi": {
      "command": "node",
      "args": ["/workspace/connectors/wakapi/dist/index.js"],
      "env": {
        "WAKAPI_URL": "http://127.0.0.1:8097",
        "WAKAPI_API_KEY": "...",
        "WAKAPI_ALLOW_WRITES": "false",
        "WAKAPI_TOOLSETS": "summaries,projects,leaderboard,heartbeats,meta"
      }
    }
  }
}
```

Docker, HTTP, no authentication, keep it on localhost.

```bash
docker build -t wakapi-mcp .
docker run -p 127.0.0.1:3000:3000 \
  -e WAKAPI_URL=http://127.0.0.1:8097 \
  -e WAKAPI_API_KEY=... \
  wakapi-mcp
```

Do not put secrets in the image.

Regenerate the registry after a spec bump.

```bash
npm run gen:operations
```

`scripts/live-check.mjs` talks to a real server over stdio. It reads the API key from `WAKAPI_API_KEY` or from `WAKAPI_API_KEY_FILE` (default `/workspace/tools/wakapi/api.key`). It unsets `DATABASE_URL`. It sets `WAKAPI_TOOLSETS=all` for the child process. It prints pass or fail lines only, and it redacts the key.

## Config

| Variable | Meaning |
| --- | --- |
| `WAKAPI_URL` | Required. Origin, `http` or `https`, no userinfo, query, or hash. Example `http://127.0.0.1:8097`. |
| `WAKAPI_API_KEY` | Required. Sent as `Authorization: Basic` plus base64 of the raw key. Not `user:password`. Never sent as `api_key` in the URL. Redacted in logs, errors, and tool results. |
| `WAKAPI_ALLOW_WRITES` | Must be the literal `true` before a confirmed write is sent. |
| `WAKAPI_TOOLSETS` | Comma list, or `all`. Default is the read-only set below. |
| `WAKAPI_PER_MINUTE` | Local request budget. Default 30. Cache hits do not spend it. |
| `WAKAPI_TIMEOUT_MS` | Upstream timeout. Default 20000. |
| `WAKAPI_CACHE_TTL_SEC` | Read cache TTL. Default 60. Writes clear the cache. |
| `WAKAPI_CONTACT` | Contact token in the User-Agent. Must not contain the API key. |
| `MCP_TRANSPORT` | `stdio` or `http`. `--http` overrides. |
| `PORT` | HTTP port. Default 3000. |

Invalid values are reported by field name and issue code. The rejected value is not included.

Paths in the swagger are mounted at `/api` on Wakapi 2.18.2. Health is `GET /api/health` and sends no API key. Shields badges send no key. Every other mapped route sends the Basic header.

## Safety

Default toolsets are reads. Heartbeat posts and the diagnostics post live on separate toolsets. Those toolsets are off until `WAKAPI_TOOLSETS` includes them or is `all`.

A write on an enabled toolset still needs `confirm` set to the boolean `true` and `WAKAPI_ALLOW_WRITES=true`. The string `"true"` is rejected. Otherwise the tool returns a dry-run preview of method, path, query, and body, and it sends nothing.

HTTP 401 is unauthorized. HTTP 403 is forbidden. HTTP 404 is not found. HTTP 400 and 422 are invalid input. HTTP 429 includes Retry-After when the header is present. Other failures are server, network, or timeout. Response bodies are capped at 1,000,000 bytes.

The swagger has no delete operations. Heartbeats you confirm stay on the server.

## Tools

Default `WAKAPI_TOOLSETS` publishes 5 tools and 13 read operations. `WAKAPI_TOOLSETS=all` publishes 7 tools and 22 operations. Each tool takes `action` plus optional `params`, `query`, `body`, and, on write tools, `confirm`.

`action` `help` with optional `target` returns the fields for one action.

| Toolset | Tool | Actions | Default |
| --- | --- | --- | --- |
| summaries | `wakapi_summaries` | summary, wakatime_summaries, stats, all_time, statusbar | yes |
| projects | `wakapi_projects` | list, get | yes |
| leaderboard | `wakapi_leaderboard` | list | yes |
| heartbeats | `wakapi_heartbeats` | list | yes |
| meta | `wakapi_meta` | health, badge, user, user_agents | yes |
| heartbeats_write | `wakapi_heartbeats_write` | create, create_bulk, user_create, user_bulk, v1_create, v1_bulk, compat_create, compat_bulk | no |
| diagnostics | `wakapi_diagnostics` | post | no |

`wakapi_summaries` filters by `project`, `language`, `editor`, `operating_system`, `machine`, and `label` where the route defines them. Native `summary` uses `from` and `to`. WakaTime `wakatime_summaries` uses `start` and `end`. `stats` takes path `range`, for example `last_7_days`. `all_time` and `statusbar` are the WakaTime-compatible totals.

Pass `query.format` as `csv` on any summaries action. The tool returns `dimension,key,total_seconds,text` and does not send `format` to Wakapi. `json` is the default.

`params.user` accepts `current` on the WakaTime-compatible routes. Heartbeat `list` requires query `date` (`YYYY-MM-DD`).

`create` is `POST /api/heartbeat`. `create_bulk` is `POST /api/heartbeats`. The `user_*`, `v1_*`, and `compat_*` actions are the alias paths in the swagger. A heartbeat body needs `entity`, `type`, `time`, and usually `project`.

Shields badges use path `interval` and `filter`. On the 2.18.2 server used for the live check, `interval:last_7_days` with `project:name` returned JSON. A bare `today` returned HTTP 403, `requested time range too broad`. The user must allow a public share window or the badge route rejects the range. Health is plain text (`app=1` and `db=1`).

## Other Wakapi and WakaTime MCP servers

`gh search repos "wakapi mcp"` on 2026-11-03 returned no repositories. `gh search repos "mcp-wakapi"` and a search for `WAKAPI_URL` found one Wakapi server. The other results target wakatime.com. Stars and licenses are from `gh api` the same day. File contents were read with `gh api`.

[impure0xntk/mcp-wakapi](https://github.com/impure0xntk/mcp-wakapi) is the only self-hosted Wakapi server in that search. 1 star, Apache-2.0, Python, last push 2026-10-04. Tools seen in the tree are `get_stats`, `get_projects`, `get_project_detail`, `get_leaders`, `get_user`, `get_all_time_since_today`, `get_recent_logs`, and `test_connection`. The client uses HTTP Basic. The README also says Bearer. Those two statements disagree. The client code is Basic. There is no summaries tool, no CSV output, no heartbeat POST, and no write switch.

[geeknees/wakatime-mcp](https://github.com/geeknees/wakatime-mcp) is 6 stars. GitHub has no license file. The README badge says MIT. It calls `https://api.wakatime.com/api/v1/` and exposes `wakatime_summaries` and `wakatime_today` only.

[geeknees/wakatime-mcp-rb](https://github.com/geeknees/wakatime-mcp-rb) is 1 star, MIT, the same two summary tools in Ruby, aimed at wakatime.com.

[dpshde/wakatime-mcp](https://github.com/dpshde/wakatime-mcp) is 0 stars, MIT, Python, default host `api.wakatime.com`. Tools are `get_coding_stats`, `get_summary`, `get_all_time`, `get_status_bar`, and `list_projects`. The client is GET only.

[efirvida/wakatime-mcp](https://github.com/efirvida/wakatime-mcp) is 0 stars, no license file. It calls `api.wakatime.com` with several read tools, including heartbeats as summarized counts. No CSV and no heartbeat POST.

[Mediel/WakaTimeMcp](https://github.com/Mediel/WakaTimeMcp) is 0 stars, MIT, C#, marked read-only. The default base URL is `https://wakatime.com/api/v1/`. It adds billing and free-slot helpers. No heartbeat list, no CSV, no writes.

[pipeworx-io/mcp-wakatime](https://github.com/pipeworx-io/mcp-wakatime) is 0 stars, MIT, a hosted gateway plus an npm bridge. It is not a self-hosted Wakapi client.

[thegauravgiri/mitra-mcp](https://github.com/thegauravgiri/mitra-mcp) is 2 stars, no GitHub license. WakaTime is four read tools against `wakatime.com` summaries. No Wakapi URL.

None of those servers combine a self-hosted Wakapi origin with summaries, projects, leaderboard, heartbeat read, opt-in heartbeat write, user and meta routes, and CSV summaries, with reads as the default.

## Live check

See `LIVE-CHECK.md` for the last run against Wakapi 2.18.2 at `http://127.0.0.1:8097`.

## License

MIT. See `LICENSE`.