Skip to main content
Glama

timetree-worklog-mcp

A local-first MCP server for daily work logs, completed work, progress reports, and optional TimeTree memo publication.

  • Nine tools. No delete, update, calendar-management, invite, or memo-deletion operations.

  • Local-first. The canonical record is Markdown on your machine. SQLite only indexes it.

  • Safe by default. Remote writes are disabled until you explicitly enable them.

  • Verified writes. Every remote create is read back and hash-checked before success is reported.

The local Markdown archive is the canonical durable record. A transactional SQLite ledger indexes it for retrieval, search, revisions, and sync state. Every work log is saved locally before any remote operation. TimeTree synchronization is optional, disabled by default, and never treated as successful until the created memo has been read back and verified.

Project status: local storage, validation, reports, MCP transport, mock-provider synchronization, reconciliation, and failure recovery are covered by automated tests. Live TimeTree integration has not been verified against an authorized account in this repository. Do not claim that live publication works until the gated procedure in docs/LIVE_TIMETREE_VERIFICATION.md has been completed.


Table of contents


Related MCP server: worklog-telegram

Important TimeTree notice

TimeTree's official Connect API was discontinued in December 2023. This project does not implement a discontinued API and does not claim official TimeTree support.

The optional community provider uses the same unofficial web endpoints used by the reviewed ehs208/TimeTree-MCP project at commit 3f77995f4d074364c6ffe14bb95a9d0c43a7c1d8. The adapter here is intentionally narrow: list calendars, list memos, read one memo, and create one memo. It is not a copy of that project's broad tool surface, and its installer is not used.

These endpoints are undocumented, may change without notice, and may be subject to TimeTree's terms of service. Use a private calendar you control, keep remote writes disabled until you have reviewed the behavior, and never use the project to bypass authentication, CAPTCHA, access controls, or rate limits.

Google sign-in accounts

This adapter only supports email/password sign-in. It authenticates with:

PUT <TIMETREE_BASE_URL>/api/v1/auth/email/signin
{ "uid": "<TIMETREE_EMAIL>", "password": "<TIMETREE_PASSWORD>" }

There is no Google OAuth or social-login flow. If your TimeTree account was created with "Continue with Google" and you have never set a separate TimeTree password, this server cannot sign in to that account as configured.

What to check before going further:

  1. Open the TimeTree app or website and look in Account / Settings for an option to set or change a password. Some accounts that originally used Google sign-in can also be given a password. If TimeTree offers this, set one, then use your email plus that password here.

  2. If there is no way to set a password on a Google-linked account, this provider will not work for that account. The local-only tools (preview_daily_worklog, save_worklog, get_daily_worklog, search_worklogs, generate_progress_report, get_sync_status) still work with no TimeTree account at all — only the remote read/write tools need credentials.

  3. TimeTree's behavior in this area is not documented and is outside this project's control. This repository cannot grant, reset, or work around your TimeTree credentials.

Always keep TIMETREE_ENABLE_REMOTE_WRITES=false until you have read the security and privacy section and the gated live verification procedure.

What this server does

  • Validates and normalizes a daily work log with strict Zod schemas.

  • Previews the exact local Markdown and remote memo payload before anything is saved or sent.

  • Saves a canonical Markdown file and a transactional SQLite revision ledger locally.

  • Retrieves and searches saved work logs without contacting TimeTree.

  • Generates an attributed Markdown progress report and writes it to the local reports directory.

  • Optionally publishes one saved work log as one all-day TimeTree memo in one configured private calendar.

  • Reconciles before a retry, verifies every remote write by reading it back, and refuses to report remote success when the outcome is uncertain.

Requirements

  • Node.js 22.12 or newer (Node 24 is also supported).

  • npm.

  • Native build tooling for better-sqlite3 if a prebuilt binary is unavailable for your platform.

  • macOS, Linux, or Windows.

The exact dependency versions are locked. package.json also pins install-script approvals for better-sqlite3, esbuild, and fsevents; review those pins when upgrading dependencies.

The server uses stdio transport only. It does not open an HTTP port.

Installation

git clone https://github.com/gideon211/timetree-worklog-mcp.git
cd timetree-worklog-mcp
npm ci
npm run build

Sanity checks:

npm test          # 91 tests
npm run verify    # typecheck + lint + format + test + build
npm audit         # dependency vulnerabilities

For development without a build:

npm run dev       # tsx src/index.ts

The server speaks MCP over stdin/stdout. Diagnostic logs go to stderr and are redacted.

Quick start with the mock provider

The mock provider is safe for local evaluation and does not contact TimeTree. Start here even if you intend to use TimeTree later.

  1. Open examples/mock-mcp-config.json and replace the placeholder path with the absolute path to dist/index.js on your machine.

  2. Paste the mcpServers block into your MCP client's configuration (see MCP client configuration).

  3. Restart your MCP client. It should now expose 9 tools.

  4. Call preview_daily_worklog, then save_worklog, then generate_progress_report.

Everything in this flow is local. No credentials are required and nothing is sent anywhere.

Connecting your TimeTree account

Read Google sign-in accounts first. Email/password sign-in is required; Google-only accounts may not be usable.

Step 1 — Start read-only

In your MCP client config, switch to the community provider. Keep writes disabled:

"TIMETREE_PROVIDER": "community",
"TIMETREE_EMAIL": "your-account@example.com",
"TIMETREE_PASSWORD": "<from OS keychain or secret injection, never a committed file>",
"TIMETREE_ENABLE_REMOTE_WRITES": "false"

Restart the client and call list_calendars. This is read-only. It returns the calendars visible to your account.

If sign-in fails with an authentication error, your email/password pair is wrong or the account cannot use email/password sign-in. Do not keep retrying in a loop; the provider backs off and opens a circuit breaker after repeated failures.

Step 2 — Choose a private calendar

From list_calendars, pick a private calendar you control. Do not use a shared, family, team, or public calendar. Set that single ID in the config:

"TIMETREE_CALENDAR_ID": "<chosen-private-calendar-id>"

Restart the client and call get_sync_status. Confirm summary.health.status is ok and the calendar is configured.

Step 3 — Preview and save locally

Call preview_daily_worklog, inspect the rendered Markdown and the remote note payload, then call save_worklog. Keep the returned previewHash.

Step 4 — Enable writes and publish

Only now flip the gate:

"TIMETREE_ENABLE_REMOTE_WRITES": "true"

Call publish_worklog with the previewHash from the current saved revision and confirmation: "PUBLISH".

All of these must be true or the call refuses:

  • Remote writes are enabled.

  • A single private calendar is configured and exists for this account.

  • The preview hash matches the current saved revision.

  • No suspected secret patterns are detected in the content.

  • The confirmation literal is exactly PUBLISH.

After creating the memo, the server reads it back, compares the stable work-log ID and the content hash, and only then reports PUBLISHED. If it cannot verify, it reports UNCERTAIN and never claims success.

Live verification before trusting it

Because the endpoints are unofficial and unverified in this repo, run the gated procedure in docs/LIVE_TIMETREE_VERIFICATION.md with a dedicated private test calendar and synthetic content before relying on live publication.

MCP client configuration

The server does not auto-load .env files. Configuration comes only from the environment block in the client config, or from exported shell variables. Use .env.example as a variable reference.

Client config locations (create or merge the mcpServers block):

  • Claude Desktop: claude_desktop_config.json

  • Cursor / Windsurf / VS Code-style clients: their mcp.json or equivalent

  • Generic: any client that launches an MCP server as a child process over stdio

Examples:

MCP client configurations commonly store secrets as plaintext. If your client supports environment injection, OS keychain integration, or a secret manager, use that instead of putting a password directly in a checked-in JSON file.

Configuration reference

Variable

Default

Purpose

WORKLOG_TIMEZONE

Africa/Accra

Default IANA time zone for dates without an explicit timezone.

WORKLOG_DATA_DIR

Platform application-data directory

Base directory for the database, archive, and reports.

WORKLOG_DB_PATH

<WORKLOG_DATA_DIR>/worklog.sqlite

SQLite ledger path. Use :memory: only for tests.

WORKLOG_ARCHIVE_DIR

<WORKLOG_DATA_DIR>/worklogs

Canonical Markdown archive.

WORKLOG_REPORTS_DIR

<WORKLOG_DATA_DIR>/reports

Generated progress reports.

WORKLOG_LOG_LEVEL

info

debug, info, warn, or error. Logs go to stderr.

TIMETREE_PROVIDER

community

community or mock.

TIMETREE_BASE_URL

https://timetreeapp.com

Unofficial TimeTree web base URL.

TIMETREE_EMAIL

unset

TimeTree account email. Keep out of source control.

TIMETREE_PASSWORD

unset

TimeTree account password. Keep out of source control.

TIMETREE_CALENDAR_ID

unset

The single private calendar permitted for memos.

TIMETREE_ENABLE_REMOTE_WRITES

false

Additional explicit gate for any remote write.

TIMETREE_MAX_RPS

1

Maximum TimeTree requests per second.

TIMETREE_TIMEOUT_MS

20000

Per-request timeout.

TIMETREE_MAX_RETRIES

3

Retries for read-only requests only; writes are never retried blindly.

TIMETREE_REMOTE_MAX_CHARS

20000

Maximum remote note length. The local archive is never truncated.

TIMETREE_MAX_RESPONSE_BYTES

2000000

Maximum accepted upstream response body.

Default data directories:

  • macOS: ~/Library/Application Support/timetree-worklog-mcp

  • Linux: $XDG_DATA_HOME/timetree-worklog-mcp or ~/.local/share/timetree-worklog-mcp

  • Windows: %APPDATA%\timetree-worklog-mcp

The application creates directories with best-effort 0700 permissions and files with 0600 where the platform supports POSIX permissions.

Tool reference

The MCP surface is deliberately limited to these nine tools.

Tool

Local/remote

Purpose

list_calendars

Remote read

List calendars for setup. Requires credentials in community mode; does not require a calendar ID.

preview_daily_worklog

Local read

Validate and render the Markdown and remote payload without writing.

save_worklog

Local write

Save Markdown first, then commit the SQLite ledger transaction.

get_daily_worklog

Local read

Retrieve by stable worklog ID or by date plus timezone.

search_worklogs

Local read

Search text, date range, timezone, and sync state.

generate_progress_report

Local write

Build and write an attributed Markdown progress report.

publish_worklog

Remote write

Create and verify one memo after all gates pass.

get_sync_status

Local read

Show counts, per-worklog state, attempts, and provider health.

retry_pending_sync

Remote read/write

Reconcile prior attempts; never performs a first publication.

Every successful tool response uses an { "ok": true, "data": ... } envelope. Failures use { "ok": false, "error": { "code", "message", "retryable", "details?" } } and the MCP isError flag. Unknown arguments are rejected at the schema boundary.

Daily workflows

Record a day's work

  1. preview_daily_worklog — supply the facts the user actually provided. Do not invent dates, deadlines, completed work, decisions, or evidence.

  2. Inspect the rendered Markdown, the remote note, and any secret warnings.

  3. save_worklog — writes the local record. Keep the previewHash if you may publish later.

  4. get_daily_worklog — verify the saved revision when needed.

  5. generate_progress_report — build an attributed report over a date range (max 366 days).

Publish to TimeTree

  1. preview_daily_worklog — inspect the remote payload.

  2. save_worklog — ensure the revision matches the preview.

  3. publish_worklog — pass the matching previewHash and confirmation: "PUBLISH".

Check and repair synchronization

  1. get_sync_status — inspect counts, per-log state, attempts, and provider health.

  2. retry_pending_sync — defaults to a dry run that only lists what would happen.

  3. For a live retry, set dryRun: false and confirmation: "RETRY" (max 10 logs per call).

After editing a published log

If the work log is edited after publication, the state becomes STALE. Republishing is blocked as a CONFLICT because this server intentionally has no destructive update operation. Resolve the remote memo manually if necessary. A publish_worklog call then reconciles without creating a memo and clears the conflict if the recorded memo is gone. Inspect the calendar and call publish_worklog again only if a new memo is intended.

Local data model

Stable identifier

A work log has one stable identifier per date and timezone:

wl_<YYYY-MM-DD>_<timezone-slug>

Example: wl_2026-10-26_africa-accra.

Revisions increment when content changes. The identifier stays stable, and prior revisions remain in SQLite.

Markdown

The canonical archive is Markdown with YAML front matter:

<WORKLOG_ARCHIVE_DIR>/<YYYY>/<MM>/<YYYY-MM-DD>--<timezone-slug>.md

The front matter contains the worklog ID, date, timezone, title, revision, content hash, timestamps, and synchronization metadata. The body contains executive summary, completed tasks, work in progress, blockers/risks, decisions, next actions, and evidence/source references.

SQLite

The ledger stores current worklogs, revision snapshots, synchronization state, sync attempts, idempotency keys, remote memo references, and local events. Writes use WAL mode, foreign keys, busy_timeout, and synchronous=FULL. The Markdown file is written atomically before the database transaction commits; a failed transaction restores the previous archive file on a best-effort basis.

Remote note

A remote memo title includes the stable ID:

Work Log 2026-10-26 [wl_2026-10-26_africa-accra]

The note begins with machine-readable metadata:

Worklog-ID: wl_2026-10-26_africa-accra
Worklog-Date: 2026-10-26
Worklog-Timezone: Africa/Accra
Worklog-Revision: 1
Worklog-Hash: <sha256>

If the note exceeds TIMETREE_REMOTE_MAX_CHARS, only the body is truncated. The metadata header is retained so reconciliation can still verify identity and content.

Synchronization states

State

Meaning

NOT_PUBLISHED

Saved locally and eligible for publication.

PUBLISHING

A create attempt was durably recorded before the remote call.

PUBLISHED

A memo was read back and its ID and content hash matched.

FAILED_RETRYABLE

The write failed with a retryable error and a known not-applied outcome.

FAILED_PERMANENT

The write failed permanently or the upstream rejected it.

UNCERTAIN

The write outcome is unknown. Never assume success or failure.

STALE

Local content changed after a remote memo was recorded or a publication was attempted.

CONFLICT

A memo with this worklog ID has different content, duplicates exist, or the expected memo disappeared.

BLOCKED

Reserved for an operator-blocked condition.

Uncertain writes

A timeout does not mean the memo was not created.

  1. Do not call publish_worklog again.

  2. Call retry_pending_sync with its default dry-run mode. It lists memos in the configured calendar and compares the stable work-log ID and content hash.

  3. If a matching memo exists, the verified result is recorded as PUBLISHED and no duplicate is created.

  4. If a memo with the same ID but a different hash exists, the verified result is recorded as CONFLICT and no duplicate is created.

  5. If the listing finds no memo, the dry run reports what a live retry would do but does not persist the absence or a disappeared-memo conflict. Only a live retry persists the absence and may create a memo from an uncertain or publishing attempt.

  6. If the listing itself fails, the state remains uncertain and no write is attempted.

  7. A live retry requires dryRun: false, confirmation: "RETRY", writes enabled, and at most 10 work logs per call. CONFLICT, FAILED_PERMANENT, blocked states, and work logs that have never been published (NOT_PUBLISHED) are never retried by retry_pending_sync; a first publication must go through publish_worklog after preview. After fixing the cause of a FAILED_PERMANENT record, an explicit publish_worklog with a matching preview may recover it; reconciliation still runs first.

Reconciliation uses the upstream memo listing. If the upstream service is eventually consistent, wait and reconcile again rather than creating a second memo.

Security and privacy

  • Remote writes are disabled by default; credentials are required only for the optional community provider and are read only from the process environment. No credentials are written to the archive, database, or logs.

  • Session cookies and CSRF tokens are held in memory for the provider instance only.

  • Diagnostic logs go to stderr and pass through a redacting logger. Secret-like values and credential fields are redacted.

  • Work-log content is scanned for common credential patterns. Publication is blocked if a suspected secret is detected, but this is a safety net, not a guarantee.

  • Only the configured calendar ID is accepted. A different calendar ID is rejected before a write.

  • Remote note size and upstream response size are bounded.

  • Read requests use bounded retries and exponential backoff. Writes are not retried after transport, timeout, server, or schema failures. A write may be replayed once after a 401/403 authentication/session rejection, which is treated as not applied; other retries are explicit and reconciled.

  • A circuit breaker opens after repeated upstream failures.

  • The project does not bypass authentication, CAPTCHA, access controls, or rate limits.

  • No HTTP listener is opened. MCP is stdio only.

  • Back up the data directory, protect it with OS permissions, and avoid syncing it to an untrusted location.

Operations and deployment

Running as a service

The server is a stdio child process, not a daemon. It runs under whatever MCP client launches it. To run it yourself for debugging:

npm start              # node dist/index.js

It will block on stdin waiting for MCP messages. Logs go to stderr.

Backups

Back up the entire data directory, which contains the Markdown archive, the SQLite database, and generated reports. The Markdown files are the durable record; the database is an index and ledger. There is no automatic reindex from Markdown after database loss, so losing the database without a backup means losing search, revision history, and sync state even though the Markdown files survive.

Upgrades

git pull
npm ci
npm run verify
npm run build

Review the dependency lockfile diff and the allowScripts pins before accepting upgrades.

One process per data directory

Publication and retry calls are serialized within one process. Multiple server processes sharing a database are not coordinated. Run one instance per data directory.

Troubleshooting

Sign-in fails with an authentication error. Your email/password pair is wrong, or the account cannot use email/password sign-in (for example, a Google-only account). See Google sign-in accounts. The adapter backs off and opens a circuit breaker after repeated failures, so do not retry in a loop.

Sign-in fails with a permission or 403 error. TimeTree blocked the sign-in. Do not attempt to bypass it. This project will not circumvent access controls, CAPTCHA, or rate limits.

list_calendars fails but local tools work. Expected when credentials are missing or wrong. All local tools work with no TimeTree account. Only the remote read/write tools need credentials.

publish_worklog returns PREVIEW_REQUIRED. The saved revision changed after you previewed it, or it changed while publication was being prepared. Run preview_daily_worklog again, review, save, and use the new hash.

A publish returned UNCERTAIN. Do not publish again. Follow Uncertain writes. The server reconciles before any retry so it never creates a duplicate.

get_sync_status shows CONFLICT. A remote memo exists with different content, duplicates exist, or the expected memo disappeared. Resolve it manually in the calendar, then use an explicit publish_worklog to reconcile and clear.

The remote note is truncated. Only the body is truncated, and only when it exceeds TIMETREE_REMOTE_MAX_CHARS. The metadata header is always retained. The local archive is never truncated.

Server does not appear in the MCP client. Confirm the command is node and args[0] is the absolute path to dist/index.js, then restart the client. Check that npm run build has been run so dist/index.js exists.

Testing

npm run typecheck
npm run lint
npm run format
npm test
npm run build
npm run test:coverage
npm audit

The automated suite uses the mock provider and temporary directories. It covers:

  • invalid inputs, dates, timezones, evidence references, and secret detection;

  • local save, retrieval, search, report generation, revisions, and idempotency;

  • missing credentials, auth/session behavior, rate limiting, schema changes, and timeouts in the community adapter using a fake fetch;

  • publish gates, duplicate prevention, uncertain pre-write and post-write timeouts, conflicts, restart recovery, and retry policy;

  • MCP schema boundaries and a real stdio client/server round trip.

Gated live smoke test

The live smoke test is read-only, requires explicit opt-in, and is not part of npm test:

TIMETREE_LIVE_SMOKE=1 \
TIMETREE_EMAIL="..." \
TIMETREE_PASSWORD="..." \
npm run test:live

It signs in, lists calendars, and prints only a summary. It does not print the password, session cookie, CSRF token, or note contents. Add -- --include-memos and set TIMETREE_CALENDAR_ID to also count memos in that one calendar. The full authorization, write-test, and cleanup procedure is in docs/LIVE_TIMETREE_VERIFICATION.md.

Known limitations

  • Live TimeTree publication is unverified in this repository.

  • The TimeTree community endpoints are unofficial and can change or stop working.

  • Email/password sign-in only. No Google OAuth, social login, or multi-account session management. Google-only accounts may not be usable.

  • No memo update or delete operation is exposed. Editing a published work log results in STALE and then CONFLICT rather than a remote update.

  • One configured calendar per server instance.

  • No attachments, checklists, attendees, reminders, or recurring memos.

  • No background scheduler; all actions are MCP calls.

  • Run one server process per data directory. Publication and retry calls are serialized within a process, but cross-process coordination is outside this project.

  • Publication re-checks the local content hash after reconciliation and again after read-back. A local save that lands during the remote request leaves the memo representing the previous revision, and the state is marked STALE immediately.

  • Progress reports are limited to 366 calendar days per request.

  • Search uses SQLite FTS5 when available and falls back to LIKE otherwise.

  • There is no automatic reindex of the SQLite ledger from the Markdown archive after database loss. Back up both, and treat the Markdown files as the durable record.

Documentation

License

MIT. See LICENSE. TimeTree is a trademark of its respective owner. This project is not affiliated with or endorsed by TimeTree.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables recording, querying, and summarizing daily work entries with tags using a local SQLite database. Supports work logging, search, timeline queries, tag management, and automated reminders for tracking daily tasks.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides an append-only SQLite journal for orchestrator/worker AI workflows, enabling delegation, reporting, verification, and tracking of tasks with built-in search and optional cloud sync.
    0
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables developers to maintain a local engineering journal, log work manually or from git history, and let AI assistants query, summarize, and draft standup updates, changelogs, and retro notes.
    MIT