blok-berichtsheft
by j551n-ncloud
README.md
# blok-berichtsheft MCP server
An MCP server that fills out your [BLok](https://www.online-ausbildungsnachweis.de/blok/) Berichtsheft
(Ausbildungsnachweis) via browser automation. BLok is an Apache Wicket app whose forms autosave
per-field over AJAX (`change` for dropdowns, `blur` for text/number fields) — there's no public API,
so this drives a real headless Chromium with [Playwright](https://playwright.dev) instead of raw HTTP calls.
## Setup
```bash
npm install
npx playwright install chromium
npm link # exposes the `blok-berichtsheft-mcp` binary on PATH
cp .env.example .env # then fill in your real credentials
```
`.env` is only used when running the server or scripts standalone (e.g. `blok-berichtsheft-mcp`
directly). It is git-ignored — never commit it.
## Registering with Claude Code
```bash
claude mcp add blok-berichtsheft -s user \
-e BLOK_USERNAME=your-username -e BLOK_PASSWORD=your-password \
-- blok-berichtsheft-mcp
```
(or, without `npm link`, use `-- node /absolute/path/to/index.js` instead)
Check it's connected:
```bash
claude mcp get blok-berichtsheft
```
Credentials passed via `-e` are stored in `~/.claude.json`, not in this project — that's what Claude
Code actually uses at runtime. The `.env` file here is a separate, optional copy for local testing.
To remove: `claude mcp remove blok-berichtsheft -s user`
## Registering with opencode
opencode has a native `opencode mcp add` command, but the simplest path is editing its config
directly (`~/.config/opencode/opencode.jsonc` or `opencode.json` in a project) and adding an entry
under `mcp`:
```jsonc
"mcp": {
"blok-berichtsheft": {
"type": "local",
"command": ["blok-berichtsheft-mcp"],
"environment": {
"BLOK_USERNAME": "your-username",
"BLOK_PASSWORD": "your-password"
},
"enabled": true
}
}
```
(or `"command": ["node", "/absolute/path/to/index.js"]` without `npm link`)
Verify with:
```bash
opencode mcp list
```
## Registering with Codex CLI
Codex CLI (`codex`, from OpenAI) configures MCP servers in `~/.codex/config.toml`:
```toml
[mcp_servers.blok-berichtsheft]
command = "blok-berichtsheft-mcp"
env = { "BLOK_USERNAME" = "your-username", "BLOK_PASSWORD" = "your-password" }
```
(or `command = "node"`, `args = ["/absolute/path/to/index.js"]` without `npm link`)
Recent Codex CLI versions also support `codex mcp add`, e.g.:
```bash
codex mcp add blok-berichtsheft \
--env BLOK_USERNAME=your-username --env BLOK_PASSWORD=your-password \
-- blok-berichtsheft-mcp
```
Codex CLI isn't installed on this machine, so this section is based on documented conventions
rather than a locally verified run — check `codex mcp --help` / `codex --help` against your
installed version if the exact flags differ.
## Tools
All date parameters are `YYYY-MM-DD` and must fall on a Monday–Friday (BLok doesn't track weekends).
Passing any date within a week navigates to that week automatically — past or future.
- **`get_week(date?)`** — reads the week containing `date` (defaults to the current week): each day's
location, presence, activities (text + hours), the week's department and remarks.
- **`add_activity(date, text, hours?, location?, presence?, department?)`** — adds an activity entry
for a day. Reuses an empty row for that day if one exists, otherwise adds a new row.
- **`set_day_status(date, location?, presence?)`** — sets a day's location/presence without adding an
activity.
- **`list_departments(date?)`** — returns the account's actual valid "Abteilung/Sparte" codes (read
live from the account's own autocomplete list). Call this and ask the user which one applies
before calling `set_department` or `add_activity` with a department — never guess a code.
- **`set_department(date, department)`** — sets the week's "Abteilung/Sparte" field to a code
returned by `list_departments`.
- **`set_week_remarks(date, text)`** — sets the week's free-text "Bemerkungen".
`location` is one of `berufsschule`, `ausbildungsbetrieb`, `ueberbetrieblich`.
`presence` is one of `anwesend`, `arbeitsunfaehig`, `abwesend`, `urlaub`, `sonderurlaub`, `feiertag`.
`hours` accepts any format BLok itself accepts: `"1h:30min"`, `"1:30"`, or `"1,5"`.
## What it deliberately does not do
None of these tools touch "Freigeben zur Abnahme durch Ausbilder" — submitting a week for trainer
approval stays a manual, in-app action.
## Files
- `index.js` — MCP server entry point, tool definitions (schemas via `zod`)
- `report.js` — page actions: read/write entries, day status, department, remarks
- `browser.js` — login, session reuse, and week navigation (parses the "Kalenderwoche vom … bis …"
banner and clicks the week-forward/backward links until it lands on the target week)
## Known quirk
The "Abteilung/Sparte" field is a jQuery UI autocomplete widget. Do not send `Escape` to close its
suggestion menu after typing — jQuery UI's default `Escape` handler reverts the field to its prior
value, which silently discards the edit before the save fires. Just blur the field (e.g. `Tab`).
## Known issues
- **Adding a brand-new row can occasionally throw** `Clicked "Zeile hinzufügen" but no new activity
row appeared` even though the row *is* added server-side a moment later — BLok's AJAX response for
that specific action is sometimes slower than the fixed wait this checks against. Safe to just
retry the same `add_activity` call; it will reuse the now-existing empty row instead of adding
another one.
- **No delete/remove tool yet.** BLok's UI does support deleting a row (a "Zeile löschen" link sits
next to each activity row), so this is addable, but no `remove_activity` tool exists in this
version.
- BLok also disables editing for weeks too far in the future (somewhere between 4 and 7 weeks
ahead, in testing) — not a bug in this tool, just BLok's own limit on how far in advance you can
log entries.
TDQS
A4.1/5.0
Scored across 6 tools
Disambiguation5/5
Each tool targets a distinct operation: reading a week, adding an activity, setting day status, listing departments, setting department, and setting week remarks. There is no functional overlap.
Naming Consistency5/5
All tools follow a consistent verb_noun pattern (e.g., get_week, add_activity, set_day_status), making the API intuitive and predictable.
Tool Count5/5
With 6 tools, the server is well-scoped for managing a training log (Berichtsheft). Each tool serves a clear purpose without redundancy or deficiency.
Completeness4/5
The core workflow (read week, add activity, set status/department/remarks) is covered. However, there is no explicit update or delete operation for activities, which could be a minor gap.
Maintenance
ActivitySlowing
ResponsivenessNo issues