dhruv's devlog

#006: Making JIRA time tracking suck less with AI


Tracking time on JIRA is a terrible experience. The UI is unintuitive, slow, and requires a lot of clicks. This is especially worse for an “on-premise” installation which sits behind a VPN, as it does at my place of work.

My role involves a fair bit of context switching, which means my time tracking consists of a lot of interleaved worklogs, making JIRA’s interface even more painful to deal with. To make this process nicer, I created a command line tool a while back: punchout. It’s entirely keyboard driven, and lets you track time on issues via a TUI. It’s proven useful — all of my time tracking in the last year has been done with it.

However, punchout’s TUI is optimised for live time tracking, ie, creating worklogs as you actually work. Over time I’ve realized that I rarely track time as I work on tasks. I do it either at the end of the day, or the end of the week. This is where the TUI falls short, as I need to create entries in the past, which, as seen in the video below, involves a lot of tedious datetime selections.

Using punchout is still faster than tracking time via JIRA’s UI for me, but I was feeling the need for a more ergonomic solution. I figured I could speed up this mundane process by enabling time tracking via plain conversations. For this, I added a Model Context Protocol (MCP) server to punchout, which I can then interact with using Claude Code or any other AI agent.

Here’s me adding worklogs for 3 days by just talking to Claude Code.

The explicit instructions and deliberate checking in the video are for demo purposes. In practice, I put the instructions in CLAUDE.md, and don’t ask for the worklogs to be reviewed, saving me time.

The MCP server

Setting up a basic MCP server was straightforward enough. I provided it 4 tools that mimic the workflows already available via the TUI:

Here’s the transcript of the conversation with the agent from the video linked above:

Me: Let’s record time for this week so far. We’ll begin with Monday, the 25th of this month. Just so you know, I begin my work at 9:00 and have lunch between 12:00 and 1:00. So don’t add any work logs between 12:00 and 1:00. Also, don’t add any comments to any work log. On Monday, I started with the EU-hosted endpoint for the knowledge graph for about two hours, and then spent an hour on non-capitalizable work. After lunch, I spent about an hour on the sidecar issue and then about two hours on the data log issue. Finally I did some non-cap work at the end of the day, about 1.5 hours. Show me these entries before you save them.

Agent: Called `get_jira_issues`, then presented entries for approval

Me: looks good

Agent: Made 5 `add_worklog` calls

Me: Tuesday was a bit weird. I juggled between all of these a lot more. There were no meetings. I spend roughly an equal amount of time on each, switching between them every 30-40 minutes.

Agent: Calculated 13 time blocks and presented the entries for approval

Me: looks good

Agent: Made 13 `add_worklog` calls

Me: All right, Wednesday was simpler. First half was all non-cap work. Second half was about 3.5 hours on the sidecar issue. Finally, I did some non-cap work about 1.5 hours.

Agent: Proposed 3 entries for Wednesday

Me: yup

Agent: Made 3 `add_worklog` calls

Me: Show me all unsynced entries.

Agent: Called `get_unsynced_worklogs` and displayed all 21 local entries

Me: They look good, sync them to Jira.

Agent: Called `sync_worklogs_to_jira` which pushed all entries to JIRA

MCP seems to be quite flexible, though the landscape surrounding it seems to currently be in flux. The Go SDK I used had a few breaking changes between 0.2.0 and 0.3.0 (not unexpected, as it’s pre-1.0). Another quirk I came across is how the SDK handles “Structured Content” in tool call responses. As per the SPEC:

For backwards compatibility, a tool that returns structured content SHOULD also return the serialized JSON in a TextContent block.

At the time of writing, the SDK does not seem to handle this duplication by itself, which breaks usage in Claude Code (VS Code’s agent seems to handle that fine). To fix that, the same content needs to be serialized manually in application code. I’m sure these kinks will be resolved as the SPEC and the SDKs mature.

There seems to be quite a lot of other functionality supported by MCP, and I’m interested in seeing how it can lead to more useful AI agents. I’m also curious to see how the SPEC is implemented in the Rust and TypeScript SDKs.

Summary

Overall, this experiment has me optimistic about the future of human-computer interaction. The broader implication of a transition like this is interesting: we’re moving toward a world where many administrative tasks can be handled through natural language rather than complex interfaces.

If that means I never have to navigate JIRA’s time tracking UI again, I’m all for it.