Skip to main content
Glama

ehour-mcp

An MCP server that fills and saves 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 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

Related MCP server: Timesheet Assistant MCP

Setup

  1. Install dependencies:

    npm install
  2. Create your config from the example and fill it in:

    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:

    ./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:

    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

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

Available Tools

6 tools
apply_monthA

Fill and SAVE eHour timesheet entries for the configured project, one working day per entry. Groups entries by week, navigates each week, fills hours + the day comment, and saves per week (persisted as it goes), then reads the range back and compares it. Pass entriesFile (the draft_month file) instead of inline entries. Returns { weeks: [{ weekOf, savedDates, warnings, error?, filledButUnsaved? }], stoppedAt?, verification: { ok, checked, mismatches, unexpected } }. If a week fails, earlier weeks stay saved and stoppedAt names the failed week. Review the entries with the user BEFORE calling this — it commits to the timesheet.

NameRequiredDescriptionDefault
verifyNoRead the range back and compare after saving. Defaults to true.
entriesNoInline alternative to entriesFile, for a few days.
entriesFileNoPath to a JSON array of { date, hours?, comment }.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does it well: incremental per-week persistence, partial-failure containment ('earlier weeks stay saved and stoppedAt names the failed week'), read-back verification, and the committing nature of the call. The notable gap is whether existing entries are overwritten or only empty cells are filled — a critical behavior for a write tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and save model, then alternatives, then the return/failure shape, then the human-review warning. The inline return-shape sentence is dense but earns its place since there is no output schema; slightly long overall but no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations, yet the description supplies the return structure, failure semantics, verification results, and the pre-call human checkpoint — everything an agent needs to invoke it safely and interpret the outcome.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description adds selection guidance the schema lacks — entriesFile is the draft_month draft and is preferred, inline entries are for 'a few working days'. It does not expand on verify's cost or the per-week grouping semantics, so it stays above but not far above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Fill and SAVE eHour timesheet entries for the configured project') plus the unit of work ('one working day per entry') and the save strategy ('saves per week'). An agent can distinguish it from draft_month (drafting) and verify_entries (read-only check) without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to pass entriesFile (the draft_month file) rather than inline entries, and instructs to review entries with the user before calling because it commits. It never names verify_entries as the non-committing alternative, so the when-not-to-commit path is only implied through 'review with the user'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_loginA

Check whether the dedicated eHour Chrome is running and logged in. Returns { loggedIn, currentUrl, message }. Call this before apply_month/patch_day; if loggedIn is false, tell the user to sign in to the dedicated Chrome window.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose the return shape { loggedIn, currentUrl, message } plus the auth-failure handling, which is the key behavioral fact. It stops short of clarifying whether the check has side effects (e.g. launching the Chrome window if it is not running) or what latency/timeout to expect, leaving a real ambiguity for an unannotated tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences: what it does, what it returns, when to call it and what to do on failure. Everything is front-loaded and nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no annotations, the description steps in to name the return fields and the false-login branch, which is sufficient to call and act on the tool. The only residual gap is that it does not say whether currentUrl is the page Chrome currently sits on or the expected timesheet URL.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4. The description correctly says nothing about inputs and instead spends its words on return values and usage, which is the right allocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: check whether the dedicated eHour Chrome is running and logged in. The 'dedicated Chrome window' scoping distinguishes it from generic browser or session tools and from the timesheet siblings it gates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly prescribes ordering ('Call this before apply_month/patch_day') and names the concrete failure branch ('if loggedIn is false, tell the user to sign in'). The agent knows both when to call it and what to do with each outcome, with the relevant siblings named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

draft_monthA

Draft a timesheet from git commit messages (read-only, touches no eHour page). One entry per weekday in the range, 8h each: "[8] TICKET: Title" then " - bullet" lines from the commit subjects, ASCII-only. Weekend commits move to the nearest empty weekday. Writes the entries JSON to file and returns only a summary { file, days: [{ date, tickets, chars }], moved, gaps }. Read the file, shorten each comment to 1-3 outcome bullets per ticket, fill every gap (a gap has an empty comment and is rejected by apply_month), then show the month to the user.

NameRequiredDescriptionDefault
toYes
fromYes
repoNoGit repository to read; defaults to gitRepo from ehour.config.json.
authorNogit --author filter; defaults to the repo user.name.
outFileNoWhere to write the draft; defaults to drafts/<from>_<to>.json in this repo.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: read-only, no eHour mutation, writes entries JSON to a file and returns only a summary object with a named shape. It also discloses subtle behaviors — weekend commits moved to the nearest empty weekday, ASCII-only output, gaps having empty comments that apply_month will reject.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and the read-only guarantee, then tight supporting detail. It runs long because it packs in format rules, return shape and a workflow, but nearly every clause carries information; the `file`/`outFile` naming slip is the main blemish.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description names the exact return object fields and explains that the entries themselves are only in the written file, which is the critical thing an agent needs. It also completes the loop by describing the edit-then-apply workflow and the gap-rejection constraint.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 60%, with repo/author/outFile already documented inline. The description adds range semantics ('one entry per weekday in the range') but calls the output parameter `file` while the schema names it `outFile`, and says nothing extra about repo or author defaults. Roughly a baseline-plus score.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'Draft a timesheet from git commit messages' — plus the source of truth (git commits) and the shape of the generated entries. It implicitly separates itself from the eHour-writing siblings by calling itself read-only and naming apply_month as the downstream consumer.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the tool as a read-only drafting step that 'touches no eHour page' and gives a follow-on workflow: read the file, shorten comments, fill gaps, then show the month to the user. It doesn't state when to skip it entirely (e.g. no commits in range), but the context is clear enough to act on.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

patch_dayA

Correct a single already-saved day for the configured project: navigate to its week, update hours and/or comment, save. Does NOT touch any other day. Returns { date, saved, error?, before, after }. Provide at least one of hours/comment.

NameRequiredDescriptionDefault
dateYes
hoursNo
commentNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does well: it discloses the UI-navigation mechanics ('navigate to its week ... save'), the strict single-day blast radius, and the return shape including 'before/after'. It does not state what happens when the target day was never saved, nor any auth or lock/approval preconditions, which is the remaining gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with purpose and scope, then the return contract, then the parameter constraint. No filler; every clause carries decision-relevant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter mutation with no annotations and no output schema, the description supplies both the return shape and the safety boundary, which is most of what an agent needs. Missing only edge-case behavior (target day not yet saved, locked or approved periods) that would matter for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate and only partly does: it clarifies the hours/comment mutual-requirement ('at least one of') and that date selects the target week. It adds nothing about hours units/rounding, whether a comment can be cleared given minLength 1, or what an omitted field means (leave unchanged vs. clear).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource+scope: 'Correct a single already-saved day for the configured project'. The explicit negative 'Does NOT touch any other day' plus the 'single day' framing cleanly separates it from month-level siblings like draft_month and apply_month.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Correct a single already-saved day' tells the agent this is an edit of existing data, not a create, and 'Provide at least one of hours/comment' gives an invocation precondition. It stops short of naming the alternative to use for bulk corrections or new entries, leaving sibling routing partially inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_timesheetA

Read back the currently-saved project hours + comments for a date range (inclusive). Read-only. Returns { days: [{ date, hours, comment }] } for days that have any hours or comment. Use to show the live state before/after a patch.

NameRequiredDescriptionDefault
toYes
fromYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does state 'Read-only', the inclusive range semantics, and the filtering rule that only days with hours or comments are returned. It omits auth/permission needs and any error behavior for malformed ranges, so it falls short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with what it does, then safety ('Read-only'), then return shape, then usage. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, but the description supplies the return shape inline, so an agent knows what it gets back. Missing details are minor: timezone/date interpretation and behavior on invalid or reversed ranges.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate; it conveys 'inclusive' range semantics but never explains which parameter is the start vs end or the date format (that lives only in the schema pattern). Partial compensation for a 2-param tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('read back') and resource ('currently-saved project hours + comments') with explicit scope (inclusive date range). The 'before/after a patch' framing implicitly distinguishes it from the mutating sibling patch_day.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Use to show the live state before/after a patch' gives clear context for when to call it and contrasts with the write path. It stops short of naming patch_day or stating exclusions, so it is not a full when/when-not specification.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

verify_entriesA

Compare an entries file with what eHour holds for its date range (read-only). Returns { ok, checked, mismatches: [{ date, field, expected?, actual? }], unexpected: [dates saved but not in the file] }.

NameRequiredDescriptionDefault
entriesFileYesPath to a JSON array of { date, hours?, comment }.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does meaningful work: it declares the operation read-only and spells out the response contract including the meaning of the 'unexpected' array (dates saved server-side but absent from the file). It leaves out failure behavior for a malformed file and any permission requirements.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, zero filler. The operation and its read-only nature come first, and the return contract is compactly encoded in-line rather than prose-padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description compensates by defining the result object field-by-field, which is exactly what an agent needs to interpret mismatches. Missing only error/edge-case behavior for an invalid or unreadable entries file.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

One parameter with 100% schema description coverage, which already documents the path and the { date, hours?, comment } element shape. The description adds only that the date range is derived from the file, which is a small increment over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: compares a caller-supplied entries file against eHour's stored data for the file's date range. That is distinguishable from read_timesheet (which reads server state) because the input is a file to be diffed, though the description never names the sibling to make the contrast explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The '(read-only)' tag and the comparison framing imply a verification/preview role before apply_month, but the description never says when to use this instead of read_timesheet or apply_month, nor does it state preconditions. Usage must be inferred from the sibling list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.2.0
    • First observedapply_month
    • First observedcheck_login
    • First observeddraft_month
    • First observedpatch_day
    • First observedread_timesheet
    • First observedverify_entries

TDQS

A4.3/5.0

Scored across 6 tools

Disambiguation5/5

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).

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers