ehour-mcp
# ehour-mcp
An [MCP](https://modelcontextprotocol.io) server that fills and saves
[eHour](https://github.com/te-con/ehour) timesheets for you. Ask your agent "submit my June
hours": it drafts each day from your `git log`, shows you the month, and after your OK fills
the timesheet in a real Chrome window, saves it week by week and reads it back to check.
- **Drafts from commits.** `PROJ-123 Title - detail` subjects become one entry per weekday;
weekend commits move to the nearest free weekday.
- **Review before anything is saved.** The draft is a JSON file the agent shows and edits with you.
- **Verified saves.** Every week is read back after saving and compared with what you approved.
- **Small fixes.** `patch_day` corrects one day without touching the rest.
- **No stored credentials.** It attaches over the Chrome DevTools Protocol to a Chrome
window where you logged in yourself.
See [docs/DESIGN.md](docs/DESIGN.md) for how it works and what it refuses to do.
## Requirements
- Node.js 20 or newer
- Google Chrome (any Chromium-based browser works via `cdpBrowser`)
- An eHour account with one project row on your timesheet
- An MCP client such as Claude Code
## Setup
1. Install dependencies:
```bash
npm install
```
2. Create your config from the example and fill it in:
```bash
cp ehour.config.example.json ehour.config.json
```
| Key | Required | Meaning |
|---|---|---|
| `url` | yes | Your eHour timesheet page, e.g. `https://ehour.example.com/eh/consultant/overview?1&openPanel=TIMESHEET` |
| `projectCode` | yes | The project code shown on your timesheet row, e.g. `PROJ` |
| `ticketPrefixes` | no | Ticket keys to recognise in commit subjects, e.g. `["PROJ", "OPS"]`. Default: any `UPPERCASE-123` key |
| `gitRepo` | no | Repository `draft_month` reads by default |
| `cdpPort` | no | Chrome remote-debugging port, default `9237` |
| `cdpProfile` | no | Chrome profile folder, default `~/.ehour-cdp-profile` |
| `cdpBrowser` | no | Browser binary, default Google Chrome on macOS |
| `host` | no | Host used to find the eHour tab, default taken from `url` |
Every key can also be set as an environment variable (`EHOUR_URL`, `EHOUR_PROJECT_CODE`,
`EHOUR_TICKET_PREFIXES` as a comma list, `EHOUR_GIT_REPO`, `EHOUR_CDP_PORT`, …), which wins
over the file. `EHOUR_CONFIG` points to a different config file.
3. Start the dedicated Chrome and sign in to eHour once:
```bash
./scripts/start-ehour-chrome.sh
```
It uses its own profile, so your normal browsing is untouched and the session survives restarts.
4. Register the server with your MCP client. For Claude Code:
```bash
claude mcp add ehour -- node /absolute/path/to/ehour-mcp/src/server.mjs
```
## Use
- "Submit my June hours" → `draft_month` writes `drafts/<from>_<to>.json` from your commits and
returns a summary. The agent shortens each day, fills the gaps, shows you the month, and on
your OK calls `apply_month` with that file.
- "June 3 should say X" → `patch_day`.
- "What's in eHour for last week?" → `read_timesheet`.
| Tool | Purpose |
|---|---|
| `check_login` | Is the dedicated Chrome up and logged in? |
| `draft_month` | Draft entries from `git log` into a file; returns a summary only |
| `apply_month` | Fill and save entries, then read back and report differences |
| `verify_entries` | Compare an entries file with eHour; differences only |
| `patch_day` | Correct a single saved day |
| `read_timesheet` | Read saved hours and comments for a date range |
## Notes
- The server never closes Chrome. Quit it with `./scripts/stop-ehour-chrome.sh`.
- If the session expires, `check_login` says so: sign in again in that window.
- Every day gets 8 hours unless an entry says otherwise. Comments are converted to ASCII
because eHour stores them in CP-1252.
- Tested against one eHour installation with the standard web UI. A customised skin may need
the selectors in `src/ehour-dom.mjs` adjusted.
## Development
```bash
npm test # unit tests: entries, week math, drafting, config
npm run smoke # read-only checks against your live eHour: page | login | read FROM TO
```
## License
[MIT](LICENSE)
TDQS
Scored across 6 tools
Each tool has a clearly distinct role in a single linear workflow: check_login (session state), draft_month (offline generation from git), apply_month (bulk write), verify_entries (file vs. server diff), patch_day (single-day correction), read_timesheet (live read). The only near-neighbor pair, verify_entries and read_timesheet, is separated by description (file comparison vs. raw live state).
All six tools follow a strict verb_noun snake_case pattern (check_login, draft_month, apply_month, verify_entries, patch_day, read_timesheet) with no stylistic deviations. The verb choices (draft/apply/verify/patch/read/check) meaningfully encode the read-only vs. write vs. check semantics.
Six tools is well-scoped for a focused timesheet-automation server; each tool maps to a necessary stage (preflight, draft, commit, verify, correct, inspect) with no filler. Nothing appears redundant or missing at the structural level.
The draft → apply → verify → patch → read lifecycle is covered end to end, but there is no explicit way to delete or clear an already-saved day (patch_day only updates hours/comment), nor any tool to discover projects or tickets the server is configured for. These are workaroundable gaps rather than dead ends, since hours could presumably be zeroed via patch_day.