EARLY 时间追踪 MCP 服务

EARLY MCP Server 是一个通过 MCP 协议将 EARLY 时间追踪 API 接入 AI 助手的服务,提供活动管理、计时器控制、时间条目和效率报表等功能,适用于时间记录、工时分析与日程管理场景。

  • by sakebomb
  • Python
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 sakebomb/early_mcp

使用说明

EARLY MCP Server

An MCP (Model Context Protocol) server that integrates with the EARLY (Timeular v4) time tracking API. Gives AI assistants like Claude full access to time tracking, activity management, and analytics.

Features

  • Activity Management - Create, update, list, and delete activities
  • Time Tracking - Start/stop timers, view current tracking status
  • Time Entries - Query, create, and delete manual time entries
  • Analytics - Time summaries, efficiency reports with gap detection, and billing reports
  • API Explorer - Raw authenticated access to any EARLY API endpoint

Tools

Tool Description
get_me Show the authenticated user's profile
list_tags_and_mentions List tags and mentions (IDs used in notes)
list_activities List active, inactive and archived activities
create_activity Create a new activity in a folder (folder ID required)
update_activity Update an existing activity's name or color
delete_activity Archive an activity (entries are kept)
unarchive_activity Restore an archived activity
current_tracking Get the currently running timer
start_tracking Start tracking time for an activity
edit_tracking Change the running timer's activity, start time or note
stop_tracking Stop the current tracker, creating a time entry; round_minutes snaps it to e.g. quarter hours
cancel_tracking Discard the running timer without creating an entry
list_time_entries Query time entries within a date range
get_time_entry Get one time entry by ID
create_time_entry Create a manual time entry
edit_time_entry Change an entry's activity, times or note
delete_time_entry Delete a time entry
time_summary Aggregate hours by activity for a period
efficiency_report Analyze time distribution and detect untracked gaps
billing_report Calculate billable hours and cost by activity
timesheet Roll entries into "Activity: note" rows with rounded hours per local day, optionally for one folder
explore_api Make raw authenticated GET requests to any EARLY API endpoint (writes opt-in)

Setup

Prerequisites

  • Python 3.12+
  • uv package manager
  • An EARLY developer API key and secret

Install

git clone git@github.com:sakebomb/early_mcp.git
cd early_mcp
uv sync

Configuration

Create a .env file with your EARLY API credentials:

EARLY_API_KEY=your_api_key
EARLY_API_SECRET=your_api_secret

Optional settings:

Variable Default Effect
EARLY_TIMEZONE system timezone IANA zone (e.g. America/New_York) that dates and naive timestamps are read in
EARLY_EXPLORE_ALLOW_WRITES unset Set to 1 to let explore_api send POST/PATCH/PUT/DELETE

Tool hints

Every tool declares MCP annotations so clients can decide what to confirm. Tools that can lose tracked time are marked destructive: deleting or editing an entry, cancelling a timer, and also creating an entry or stopping a timer, because EARLY splits or removes existing entries that a new one overlaps. explore_api is advertised read-only unless writes are enabled.

Dates and timezones

The EARLY API stores timestamps in UTC without an offset. Tools take dates (YYYY-MM-DD) and naive timestamps as local time in EARLY_TIMEZONE and convert them to UTC, so a "day" means your local day. Timestamps with an explicit offset (+01:00, Z) are converted from that offset. Raw entries returned by list_time_entries keep EARLY's UTC timestamps; report tools group by local day.

Stopping a timer

EARLY rejects a stop less than one minute after the start and discards the timer along with it, so stop_tracking checks the timer's age first and leaves a younger one running. With round_minutes, both ends of the entry are snapped to the nearest step (on the UTC grid) after the stop. A neighbouring entry off that grid, for example one made in the app, would then overlap and EARLY would split or remove it, so the rounded span is clamped to its neighbours, and it keeps its exact times if under a minute would remain.

Command line

early_cli.py runs the same tools from a hook or timer, printing JSON:

uv run python early_cli.py stop --round 15 --folder <folder_id>   # only stops a timer in that folder
uv run python early_cli.py timesheet 2026-10-17 2026-10-30 --folder <folder_id>

Claude Code

Add this to your Claude Code MCP settings (~/.claude/settings.json):

{
  "mcpServers": {
    "early": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/early_mcp", "python", "early.py"],
      "env": {
        "EARLY_API_KEY": "your_api_key",
        "EARLY_API_SECRET": "your_api_secret"
      }
    }
  }
}

Project Structure

early.py          # MCP server with tool definitions
early_client.py   # API client, auth, and utility functions
early_cli.py      # Command-line entry for hooks and timers
tests/            # pytest suite (mocked HTTP; run with `uv run pytest`)
pyproject.toml    # Project config and dependencies

Authentication

The server uses EARLY's developer sign-in flow. It exchanges your API key/secret for a bearer token, caches it in memory, and automatically refreshes on expiry.