An MCP server that connects Claude Code to Ruddr for time tracking. Lets you log time entries directly from a Claude Code conversation — Claude reads your recent git activity, suggests the right project, role, task, and notes, then waits for your approval before submitting anything.
This is a local MCP server — it runs as a subprocess on your machine when Claude Code starts. No hosting required. Each developer runs it with their own Ruddr API key.
Claude's typical flow when you ask it to log time:
- Reads recent commits and
git diff --staton your current branch - Calls
get_git_contextto get the repo URL, branch, open PR URL, and any.ruddr-projecthint - Uses the
.ruddr-projecthint if present, otherwise callslist_projectsto find the project - Infers the role from where the changes landed (frontend, backend, docs, etc.)
- Calls
list_project_tasksand tries to match a task to the branch name or issue refs - Drafts a complete time entry — notes always include a URL (PR > branch > repo), duration rounded to the nearest 15 minutes
- Presents the draft for your approval
- Submits only after you confirm
One of the following to run the server:
- uv — handles dependencies automatically, no virtualenv setup needed (recommended)
- Python 3.10+ with
pip install "mcp[cli]>=1.0" httpx— works ifuvisn't available
A Ruddr account with API access is also required.
In Ruddr: Settings → API Keys → Create API Key. Copy the key.
Run a quick curl to look yourself up:
curl -s -H "Authorization: Bearer <your-api-key>" \
"https://www.ruddr.io/api/workspace/members?email=you@example.com" \
| python3 -m json.tool | grep '"id"' | head -1Or you can skip this step and let Claude look it up via get_my_member_id on first use.
git clone git@github.com:makepath/ruddr-mcp.git ~/git/ruddr-mcp
# or wherever you keep your toolsAdd the server to ~/.claude/settings.json:
{
"mcpServers": {
"ruddr": {
"command": "uv",
"args": ["run", "/home/you/git/ruddr-mcp/server.py"],
"env": {
"RUDDR_API_KEY": "your-ruddr-api-key-here",
"RUDDR_MEMBER_ID": "your-member-uuid-here"
}
}
}
}If you're using python3 directly instead of uv:
{
"mcpServers": {
"ruddr": {
"command": "python3",
"args": ["/home/you/git/ruddr-mcp/server.py"],
"env": {
"RUDDR_API_KEY": "your-ruddr-api-key-here",
"RUDDR_MEMBER_ID": "your-member-uuid-here"
}
}
}
}Or register it via the CLI (user scope, available in all projects):
claude mcp add \
-e RUDDR_API_KEY=your-key \
-e RUDDR_MEMBER_ID=your-member-uuid \
--scope user \
ruddr -- python3 /home/you/git/ruddr-mcp/server.pyNote:
RUDDR_MEMBER_IDis optional but recommended — it saves a lookup on every session. If omitted, ask Claude to runget_my_member_idonce to find it.
Restart Claude Code (or run /mcp to reload servers). You should see ruddr listed.
Just describe what you want in natural language. A few examples:
Log 2 hours of time for today's work on the satellite imagery feature.
I worked on the NRC project from about 9am to 11:30am fixing the BDR report layout.
Help me log that.
What time have I logged this week?
Log yesterday's work — I was mostly fixing backend bugs related to the geoenrichment service.
Claude will:
- Check your recent git commits for context
- Include a URL in notes when one is available (PR > branch > repo); skips it for meetings/admin
- Round the duration to the nearest 15 minutes
- Propose a complete entry (date, duration, project, role, task, notes)
- Ask you to confirm or edit before submitting
You can update any field on an existing time entry — duration, notes, date, role, or task.
Increase the duration on my last entry to 45 minutes.
Fix the notes on yesterday's NRC entry — it should reference PR #88.
Claude will look up the entry, show you the proposed change, and only update it after you confirm.
Claude includes a URL in notes whenever one makes sense. For code work, get_git_context
finds the best available link in priority order:
- Open PR URL — if
ghCLI is installed and there's an open PR on the current branch - Branch URL —
https://github.com/org/repo/tree/your-branch - Repo URL —
https://github.com/org/repo
Example: Fixed layout bug in BDR report — https://github.com/makepath/nrc/pull/142
For non-code work — meetings, 1:1s, admin tasks — a URL isn't required and Claude won't invent one.
You can import multiple time entries at once from a CSV. Paste the CSV directly into the chat or reference a file path.
date,minutes,project,role,task,notes
2026-03-01,90,NRC Easement,Backend,BDR report fix,Fixed layout bug — https://github.com/org/repo/pull/42
2026-03-02,60,Agency Ops,,,Team standup — https://github.com/org/repo
2026-03-03,1h 30m,Battleship,Frontend,,Dashboard updates — https://github.com/org/repo/tree/feat/dashboardColumn reference:
| Column | Required | Format |
|---|---|---|
date |
yes | YYYY-MM-DD |
minutes |
yes | Integer minutes (90), float hours (1.5), or 1h 30m / 1:30 |
project |
yes | Project name (partial match ok) or UUID |
role |
no | Role name (partial match ok) or UUID |
task |
no | Task name (partial match ok) or UUID |
notes |
no | Free text; include a URL when possible |
- Paste the CSV and ask Claude to bulk import it
- Claude calls
bulk_import_time_entrieswithdry_run=Trueand shows you a preview table - Review the table — correct any errors in the CSV if needed
- Confirm, and Claude submits all entries
Example prompt:
Bulk import these time entries:
date,minutes,project,notes
2026-03-01,90,NRC Easement,Fixed BDR report layout — https://github.com/makepath/nrc/pull/42
2026-03-02,30,Agency Ops,Team standup — https://github.com/makepath/ruddr-mcp
All durations are automatically rounded to the nearest 15-minute increment before submission — both for single entries and bulk imports. If rounding changes the value, the original duration is shown in the confirmation:
Duration: 1h 15m (rounded from 1h 11m)
Drop a .ruddr-project file at the root of any repo and Claude will automatically
use it — no need to mention it every time. Claude reads this file via get_git_context
before every time entry.
# .ruddr-project
project_id = 550e8400-e29b-41d4-a716-446655440000
project_name = NRC Easement Monitoring
When the file is present, Claude skips list_projects and uses the hint directly.
| Tool | What it does |
|---|---|
get_git_context |
Returns repo URL, branch, PR URL, and .ruddr-project hint for use in notes |
get_my_member_id |
Returns your member ID (or lists all members if not configured) |
list_projects |
Lists all active projects with IDs, clients, and required fields |
list_project_roles |
Lists roles for a project (used to infer Frontend / Backend / etc.) |
list_project_tasks |
Lists tasks for a project, optionally filtered by name |
list_recent_time_entries |
Shows what you've logged recently (good for avoiding duplicates) |
create_time_entry |
Submits a single time entry — always asks for confirmation first |
update_time_entry |
Updates fields on an existing entry (duration, notes, date, role, task) — always asks for confirmation first |
bulk_import_time_entries |
Parses a CSV, previews a table, then submits all entries |
Claude infers the right role from git diff --stat output:
| Dominant change area | Typical role |
|---|---|
assets/, frontend/ |
Frontend Developer |
backend/ |
Backend Developer |
docs/, *.md |
Documentation / Technical Writer |
| Mixed | Claude will ask you to choose |
The actual role names come from your Ruddr project configuration, so they may differ.
"RUDDR_API_KEY environment variable is not set"
Check that RUDDR_API_KEY is present in the env block of your MCP config.
Server doesn't appear in /mcp
If using uv, make sure it's on your PATH. Test with which uv. If installed via curl,
it's usually at ~/.local/bin/uv — use the full path in the command field if needed.
Alternatively, switch to python3 (see Setup above).
"No active projects found"
Your API key may belong to a user without access to projects. Confirm you can see projects
at https://app.ruddr.io.
Time entry fails with 422
The project may require a role or task. Claude should handle this automatically, but you
can check by running list_project_roles and list_project_tasks manually in the chat.
Bulk import: "Ambiguous project" error The project name matched more than one project. Use a more specific substring or paste the project UUID directly in the CSV.
PR URL not appearing in notes
get_git_context tries gh pr view to find the PR URL. Install the
GitHub CLI and run gh auth login once to enable this.