Summary
Issue #32 added a fields: minimal | standard | full parameter to get_tasks, which made that one endpoint manageable. The same class of problem still affects list_stories and get_epics, and get_tasks itself still has a handful of smaller token-economy issues that make real-world agent use expensive. This issue catalogues the remaining gaps.
Tested against @stevestomp/ohno-mcp@0.19.0 and @stevestomp/ohno-core@0.19.0.
Remaining problems
1. list_stories has no fields parameter
From server.js it accepts only { epic_id, status, limit (default 50), offset (default 0) }. From db.js the underlying getStories returns full story rows with all columns including description. Story descriptions in agent-managed projects are typically 500 B – 2 KB each; at the default limit of 50 that's roughly 25–100 KB = ~6–25K tokens per call, with no way to trim.
2. get_epics has no fields parameter either
Same story. { status, priority, limit (default 50) }. Full epic rows always returned, including their descriptions which tend to be the longest text in the system (I'm routinely seeing epic descriptions of 1.5–2.5 KB). 50 × full epic ≈ 75–150 KB ≈ 20–40K tokens.
Concretely, a single call in my current project:
list_stories limit=50 ≈ 57 KB (triggers Claude Code's "output too large" persisted-file fallback)
That's consistent with #32's original complaint — it was just never extended to the two other list endpoints.
3. No search parameter on any list endpoint
None of get_tasks, list_stories, get_epics support filtering by title substring, tag match, or description text. Agents looking for one specific item by name (very common — "find the task whose title contains 'migration'") have no choice but to retrieve the list and scan locally. That defeats the point of the fields optimization because the agent still has to load enough fields to match on.
A single title LIKE '%migration%' filter on each of the three endpoints would save an order of magnitude more context than tightening any of the existing parameters.
4. get_tasks lacks offset, breaking pagination
list_stories has offset. get_tasks does not (from server.js input schema). My project has 245 tasks and the hard limit is 100, so there's no reliable way to retrieve tasks 101+ via get_tasks. Combined with the fixed ORDER BY status CASE WHEN..., updated_at DESC, created_at DESC in db.js::getTasks, changing filters is the only way to reach the tail.
5. Default limit of 50 is high for agent-oriented tools
All three list endpoints default to limit: 50. For an interactive agent workflow, most calls want a handful of recent/matching items, not half the backlog. A default of 10 or 20 would match actual usage and dramatically reduce accidental token consumption when agents don't think to pass a lower limit. The max: 100 cap is fine; the complaint is the default, not the ceiling.
6. The minimal/standard/full naming invites agents to pick standard
(Minor.) The enum ["minimal", "standard", "full"] reads as "small, normal, big". Agents reaching for a sensible middle will pick "standard" — which includes description, handoff_notes, timestamps, and is significantly heavier than minimal. Renaming to ["id_only", "summary", "full"] or similar, or adding a "tiny" level that's just id + title + status, would nudge agents to the cheap option by default. Not a blocker; just a readability thing.
Suggested fixes, in rough order of impact
- Add
fields: minimal | standard | full to list_stories and get_epics, mirroring get_tasks. Highest single impact.
- Add
search (title substring match, case-insensitive) to all three list endpoints. Biggest effect for agents that know what they're looking for. If descriptions are expensive to scan, title-only is plenty for most cases.
- Add
offset to get_tasks. Aligns with list_stories. Unlocks reliable pagination on projects with >100 tasks.
- Lower default
limit to 10 (or 20) across all three endpoints. Max stays at 100.
- Consider adding a
"tiny" fields level returning only id, title, status — about 80 bytes per row. Best for "show me a menu of choices to pick from" flows.
Impact
This class of issue is especially relevant for Claude Code / MCP-based agents running against projects with >50 tasks or >10 epics, which is the expected working condition for a task-management tool. Context is the dominant cost for these agents, so any saving here is compounded over every agent session.
Happy to supply specific byte-size measurements from my own project, or test-case fixtures demonstrating the token cost of a typical agent session against a moderate-sized backlog (~200 tasks, ~40 stories, ~10 epics).
Credit to Jan Jetze (@JanJetze) for identifying the broader scope — I'm filing on his behalf.
Summary
Issue #32 added a
fields: minimal | standard | fullparameter toget_tasks, which made that one endpoint manageable. The same class of problem still affectslist_storiesandget_epics, andget_tasksitself still has a handful of smaller token-economy issues that make real-world agent use expensive. This issue catalogues the remaining gaps.Tested against
@stevestomp/ohno-mcp@0.19.0and@stevestomp/ohno-core@0.19.0.Remaining problems
1.
list_storieshas nofieldsparameterFrom
server.jsit accepts only{ epic_id, status, limit (default 50), offset (default 0) }. Fromdb.jsthe underlyinggetStoriesreturns full story rows with all columns includingdescription. Story descriptions in agent-managed projects are typically 500 B – 2 KB each; at the default limit of 50 that's roughly 25–100 KB = ~6–25K tokens per call, with no way to trim.2.
get_epicshas nofieldsparameter eitherSame story.
{ status, priority, limit (default 50) }. Full epic rows always returned, including their descriptions which tend to be the longest text in the system (I'm routinely seeing epic descriptions of 1.5–2.5 KB). 50 × full epic ≈ 75–150 KB ≈ 20–40K tokens.Concretely, a single call in my current project:
That's consistent with #32's original complaint — it was just never extended to the two other list endpoints.
3. No search parameter on any list endpoint
None of
get_tasks,list_stories,get_epicssupport filtering by title substring, tag match, or description text. Agents looking for one specific item by name (very common — "find the task whose title contains 'migration'") have no choice but to retrieve the list and scan locally. That defeats the point of thefieldsoptimization because the agent still has to load enough fields to match on.A single
title LIKE '%migration%'filter on each of the three endpoints would save an order of magnitude more context than tightening any of the existing parameters.4.
get_taskslacksoffset, breaking paginationlist_storieshasoffset.get_tasksdoes not (fromserver.jsinput schema). My project has 245 tasks and the hard limit is 100, so there's no reliable way to retrieve tasks 101+ viaget_tasks. Combined with the fixedORDER BY status CASE WHEN..., updated_at DESC, created_at DESCindb.js::getTasks, changing filters is the only way to reach the tail.5. Default limit of 50 is high for agent-oriented tools
All three list endpoints default to
limit: 50. For an interactive agent workflow, most calls want a handful of recent/matching items, not half the backlog. A default of 10 or 20 would match actual usage and dramatically reduce accidental token consumption when agents don't think to pass a lower limit. Themax: 100cap is fine; the complaint is the default, not the ceiling.6. The
minimal/standard/fullnaming invites agents to pickstandard(Minor.) The enum
["minimal", "standard", "full"]reads as "small, normal, big". Agents reaching for a sensible middle will pick"standard"— which includes description, handoff_notes, timestamps, and is significantly heavier thanminimal. Renaming to["id_only", "summary", "full"]or similar, or adding a"tiny"level that's just id + title + status, would nudge agents to the cheap option by default. Not a blocker; just a readability thing.Suggested fixes, in rough order of impact
fields: minimal | standard | fulltolist_storiesandget_epics, mirroringget_tasks. Highest single impact.search(title substring match, case-insensitive) to all three list endpoints. Biggest effect for agents that know what they're looking for. If descriptions are expensive to scan, title-only is plenty for most cases.offsettoget_tasks. Aligns withlist_stories. Unlocks reliable pagination on projects with >100 tasks.limitto 10 (or 20) across all three endpoints. Max stays at 100."tiny"fields level returning onlyid, title, status— about 80 bytes per row. Best for "show me a menu of choices to pick from" flows.Impact
This class of issue is especially relevant for Claude Code / MCP-based agents running against projects with >50 tasks or >10 epics, which is the expected working condition for a task-management tool. Context is the dominant cost for these agents, so any saving here is compounded over every agent session.
Happy to supply specific byte-size measurements from my own project, or test-case fixtures demonstrating the token cost of a typical agent session against a moderate-sized backlog (~200 tasks, ~40 stories, ~10 epics).
Credit to Jan Jetze (
@JanJetze) for identifying the broader scope — I'm filing on his behalf.