feat: add Reports API tools (person assignments, assignable people, overdue)#39
Conversation
…verdue) [*]
Add three read-only tools wrapping the Basecamp Reports API
(bc-api sections/reports.md):
- get_assignable_people — GET /reports/todos/assigned.json
- get_person_assignments — GET /reports/todos/assigned/{person_id}.json
(optional group_by: bucket|date)
- get_overdue_todos — GET /reports/todos/overdue.json
get_person_assignments returns one person's active, pending to-dos
across ALL projects in a single call. Previously this required
iterating every project and todolist, which was slow and easy to get
wrong: projects missed by the iteration read as "no assignments".
The per-person report is a single JSON object; its embedded todos list
follows Link-header pagination defensively (merged into one report,
MAX_PAGES guarded).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds three Reports API-backed Basecamp MCP tools for assignable people, person assignments, and overdue todos, with pagination aggregation, grouping support, authentication/error handling, documentation, and unit tests. ChangesReports API integration
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant FastMCPServer
participant BasecampClient
participant ReportsAPI
FastMCPServer->>BasecampClient: request report data
BasecampClient->>ReportsAPI: GET Reports API endpoint
ReportsAPI-->>BasecampClient: JSON payload and Link header
BasecampClient->>ReportsAPI: follow rel="next" pages
BasecampClient-->>FastMCPServer: return aggregated report
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
basecamp_fastmcp.py (1)
303-303: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider constraining
group_byto the two valid values.The API only accepts
'bucket'or'date'(per the docstring); typing this asOptional[Literal["bucket", "date"]]would let the MCP tool schema expose the valid enum to calling agents instead of an unconstrained string.♻️ Proposed refactor
-async def get_person_assignments(person_id: str, group_by: Optional[str] = None) -> Dict[str, Any]: +async def get_person_assignments(person_id: str, group_by: Optional[Literal["bucket", "date"]] = None) -> Dict[str, Any]:(requires adding
Literalto thetypingimport if not already present)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@basecamp_fastmcp.py` at line 303, Update the get_person_assignments signature to type group_by as Optional[Literal["bucket", "date"]], adding Literal to the typing imports if necessary, so the MCP schema exposes only the API-supported values while preserving its optional behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@basecamp_client.py`:
- Around line 607-654: Update the shared get() HTTP helper to pass an explicit
requests timeout, using the established timeout pattern from download_upload or
download_attachment, so get_person_assignments and the other report methods
cannot block indefinitely. Preserve existing request behavior and error handling
while applying the timeout to every underlying GET call.
---
Nitpick comments:
In `@basecamp_fastmcp.py`:
- Line 303: Update the get_person_assignments signature to type group_by as
Optional[Literal["bucket", "date"]], adding Literal to the typing imports if
necessary, so the MCP schema exposes only the API-supported values while
preserving its optional behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 85f1cfb6-8bd4-48ea-bf4a-0ad85541fe4d
📒 Files selected for processing (5)
CHANGELOG.mdREADME.mdbasecamp_client.pybasecamp_fastmcp.pytests/test_assignment_reports.py
…teral [*] Addresses CodeRabbit review on PR georgeantonopoulos#39: - pass timeout=(10, 300) in the shared get() helper so report methods (and all other GET-based tools) cannot block indefinitely - type group_by as Optional[Literal["bucket", "date"]] so the MCP tool schema exposes the valid enum values Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
georgeantonopoulos
left a comment
There was a problem hiding this comment.
Thanks — the Reports API work is useful, and I confirmed CodeRabbit’s timeout and group_by concerns are resolved. One compatibility pass is required before merge:
- Add
get_assignable_people,get_person_assignments, andget_overdue_todostomcp_server_cli.pyin both_get_available_tools()and_execute_tool(), matching the FastMCP schemas and response shapes (includinggroup_by: bucket|date). - Add focused CLI tests proving the tools appear in
tools/listand dispatch correctly. - Update the branch onto current
mainand resolve theCHANGELOG.mdconflict, then let the Actions matrix run.
The CLI is legacy, but this repo explicitly keeps it for compatibility and tests, and recent public-tool changes update both entry points. The current head passes its 75 tests; this request is about maintaining that contract.
What
Adds three read-only MCP tools wrapping the Basecamp Reports API:
get_assignable_peopleGET /reports/todos/assigned.jsonget_person_assignmentsGET /reports/todos/assigned/{person_id}.json(optionalgroup_by: bucket|date)get_overdue_todosGET /reports/todos/overdue.jsonWhy
get_person_assignmentsis the API counterpart of the web report at/reports/todos/assigned/{person_id}and returns one person's active, pending to-dos across all projects in a single call. Without it, answering "what is assigned to person X?" requires iterating every project and todolist — slow, and projects missed by the iteration silently read as "no assignments" (false negatives in downstream reporting).get_assignable_peopleprovides the person IDs to feed into the report;get_overdue_todosis the third report endpoint of the same API section.Implementation notes
get_*naming, consistent with the existing toolset).get_assignable_peopleuses the sharedget_all_pagespagination helper.person,grouped_by,todos); the embeddedtodoslist followsLink-header pagination defensively and merges pages into one report, guarded byMAX_PAGES.Tests
tests/test_assignment_reports.py— endpoint/params wiring,group_bypass-through, multi-page merge, non-200 errors,MAX_PAGEScap. Full suite: 75 passed.🤖 Generated with Claude Code
Summary by CodeRabbit