Skip to main content
Glama
tasks.md11.8 kB
# Tasks: Todoist Labels Tool **Feature**: `002-todoist-labels-tool` **Input**: Design documents from `/specs/002-todoist-labels-tool/` **Prerequisites**: research.md, data-model.md, contracts/todoist_labels_tool.json, quickstart.md ## ⚠️ IMPORTANT: API Documentation Reference **Before working on ANY task, review the official Todoist API documentation:** - **Labels API Reference**: https://developer.todoist.com/api/v1#tag/Labels - This documentation is the authoritative source for endpoint specifications, request/response formats, and error codes ## Execution Flow ``` 1. Setup: TypeScript project dependencies, validation schemas 2. Tests First (TDD): Contract tests MUST be written and MUST FAIL before implementation 3. Core Implementation: Tool handler, API integration, error handling 4. Integration: Server registration, caching integration 5. Polish: Unit tests, documentation, manual validation ``` ## Format: `[ID] [P?] Description` - **[P]**: Can run in parallel (different files, no dependencies) - Include exact file paths in descriptions --- ## Phase 3.1: Setup - [x] **T001** Add label validation schemas to `src/schemas/validation.ts` - Add `LabelToolInputSchema` with Zod validation - Define conditional validation for action-based parameters - Add `TodoistLabel` output type if not already present --- ## Phase 3.2: Tests First (TDD) ⚠️ MUST COMPLETE BEFORE 3.3 **CRITICAL: These tests MUST be written and MUST FAIL before ANY implementation** - [x] **T002 [P]** Contract test: create_personal_label in `tests/contract/todoist_labels.test.ts` - Test creating new label with name, color, is_favorite - Verify response schema matches contract - Use in-memory API service mock - [x] **T003 [P]** Contract test: create_duplicate_label_idempotent in `tests/contract/todoist_labels.test.ts` - Test duplicate name returns existing label - Verify idempotent behavior (same ID returned) - Verify message indicates label already exists - [x] **T004 [P]** Contract test: get_label_by_id in `tests/contract/todoist_labels.test.ts` - Test retrieving label by valid ID - Verify all fields returned (id, name, color, order, is_favorite) - [x] **T005 [P]** Contract test: get_nonexistent_label in `tests/contract/todoist_labels.test.ts` - Test invalid label ID returns LABEL_NOT_FOUND - Verify error code and retryable=false - [x] **T006 [P]** Contract test: update_label in `tests/contract/todoist_labels.test.ts` - Test updating color and is_favorite - Verify name remains unchanged - [x] **T007 [P]** Contract test: delete_label in `tests/contract/todoist_labels.test.ts` - Test label deletion returns success - Verify data is null, message confirms deletion - [x] **T008 [P]** Contract test: list_labels_default_pagination in `tests/contract/todoist_labels.test.ts` - Test listing labels without limit parameter - Verify metadata includes total_count and next_cursor - [x] **T009 [P]** Contract test: list_labels_with_pagination in `tests/contract/todoist_labels.test.ts` - Test listing with limit=10 and cursor - Verify pagination metadata present - [x] **T010 [P]** Contract test: list_labels_invalid_limit in `tests/contract/todoist_labels.test.ts` - Test limit=250 returns VALIDATION_ERROR - Verify error details include field, value, constraint - [x] **T011 [P]** Contract test: rename_shared_label in `tests/contract/todoist_labels.test.ts` - Test renaming shared label with name and new_name - Verify success message mentions "across all tasks" - [x] **T012 [P]** Contract test: remove_shared_label in `tests/contract/todoist_labels.test.ts` - Test removing shared label by name - Verify success message confirms removal from all tasks - [x] **T013 [P]** Contract test: rate_limit_exceeded in `tests/contract/todoist_labels.test.ts` - Test rate limit error response - Verify retryable=true and retry_after field present - [x] **T014 [P]** Unit test: label validation in `tests/unit/label-validation.test.ts` - Test action enum validation - Test name length validation (0, 128, 129 chars) - Test limit validation (0, 1, 200, 201) - Test conditional required fields per action --- ## Phase 3.3: Core Implementation (ONLY after tests are failing) - [x] **T015** Implement TodoistApiService label methods in `src/services/todoist-api.ts` - Add `getLabels(cursor?: string, limit?: number)` - GET /api/v1/labels - Add `getLabel(labelId: string)` - GET /api/v1/labels/{id} - Add `createLabel(params)` - POST /api/v1/labels - Add `updateLabel(labelId, params)` - POST /api/v1/labels/{id} - Add `deleteLabel(labelId)` - DELETE /api/v1/labels/{id} - Add `renameSharedLabel(name, newName)` - Sync API command - Add `removeSharedLabel(name)` - Sync API command - All methods use existing rate limiter (restRateLimiter for REST, syncRateLimiter for Sync) - [x] **T016** Create TodoistLabelsTool in `src/tools/todoist-labels.ts` - Implement `getToolDefinition()` returning MCP tool definition from contract - Implement `execute(params)` with action routing - Implement `handleCreate()` with duplicate name check - Implement `handleGet()` - Implement `handleUpdate()` - Implement `handleDelete()` - Implement `handleList()` with pagination - Implement `handleRenameShared()` using Sync API - Implement `handleRemoveShared()` using Sync API - Use `handleToolError()` wrapper for error responses - [x] **T017** Add error mapping in `src/utils/error-handler.ts` - Map 404 → NotFoundError → "LABEL_NOT_FOUND" - Ensure existing rate limit and validation error mappings apply --- ## Phase 3.4: Integration - [x] **T018** Register todoist_labels tool in `src/server.ts` - Import TodoistLabelsTool - Instantiate in `initializeTools()` - Add to tools map: `this.tools.set('todoist_labels', labelsTool)` - Add tool definition: `this.toolDefinitions.push(TodoistLabelsTool.getToolDefinition())` - [x] **T019** Integrate label cache invalidation in `src/services/cache.ts` - On create: Add or update cached label - On update: Update cached label - On delete: Remove from cache - On list: Update cache with results - On rename_shared/remove_shared: Invalidate entire cache --- ## Phase 3.5: Integration Tests - [x] **T020 [P]** Integration test: label lifecycle in `tests/integration/label-workflows.test.ts` - Create label → Update color → Delete label - Verify each step succeeds - [x] **T021 [P]** Integration test: label and task relationship in `tests/integration/label-workflows.test.ts` - Create label → Assign to task → Delete label - Verify label removed from task.labels - [x] **T022 [P]** Integration test: pagination workflow in `tests/integration/label-workflows.test.ts` - Create 150 test labels - Page through with limit=50 - Verify cursor handling and next_cursor=null at end - [x] **T023 [P]** Integration test: shared label operations in `tests/integration/label-workflows.test.ts` - Create shared label on tasks - Rename shared label - Verify name changed across tasks - Remove shared label - Verify removed from all tasks --- ## Phase 3.6: Polish - [x] **T024** Update helper mocks in `tests/helpers/inMemoryTodoistApiService.ts` - Add in-memory label storage - Implement mock label CRUD methods - Support duplicate name detection - [x] **T025** Update helper mocks in `tests/helpers/mockTodoistApiService.ts` - Add Jest mock factory for label methods - Support all label actions - [x] **T026** Run manual validation from `specs/002-todoist-labels-tool/quickstart.md` - Execute all 9 acceptance scenarios - Execute all 3 edge case scenarios - Verify against real Todoist API - Document any deviations - [x] **T027 [P]** Update CLAUDE.md with label tool documentation - Add todoist_labels to tool list - Document action parameter options - Add example usage - [x] **T028** Verify test coverage ≥80% for label code - Run `npm run test:coverage -- --testPathPattern=label` - Ensure coverage meets threshold --- ## Dependencies **Critical Path:** ``` T001 (validation schemas) ↓ T002-T014 (all contract/unit tests - PARALLEL) ↓ T015 (API service methods) ↓ T016 (tool implementation) ↓ T017 (error mapping - can be parallel with T016 if no shared files) ↓ T018 (server registration) ↓ T019 (cache integration) ↓ T020-T023 (integration tests - PARALLEL) ↓ T024-T025 (test helper updates - PARALLEL) ↓ T026-T028 (polish - PARALLEL) ``` **Blocking Rules:** - T015 blocks T016 (tool needs API methods) - T016 blocks T018 (can't register tool that doesn't exist) - T018 blocks T020-T023 (integration tests need registered tool) - All tests (T002-T014) MUST fail before T015-T016 start --- ## Parallel Execution Examples ### Contract Tests (T002-T013) ```bash # All contract tests can run in parallel since they use in-memory mocks # Launch together: Task: "Contract test create_personal_label in tests/contract/todoist_labels.test.ts" Task: "Contract test create_duplicate_label_idempotent in tests/contract/todoist_labels.test.ts" Task: "Contract test get_label_by_id in tests/contract/todoist_labels.test.ts" Task: "Contract test get_nonexistent_label in tests/contract/todoist_labels.test.ts" Task: "Contract test update_label in tests/contract/todoist_labels.test.ts" Task: "Contract test delete_label in tests/contract/todoist_labels.test.ts" Task: "Contract test list_labels_default_pagination in tests/contract/todoist_labels.test.ts" Task: "Contract test list_labels_with_pagination in tests/contract/todoist_labels.test.ts" Task: "Contract test list_labels_invalid_limit in tests/contract/todoist_labels.test.ts" Task: "Contract test rename_shared_label in tests/contract/todoist_labels.test.ts" Task: "Contract test remove_shared_label in tests/contract/todoist_labels.test.ts" Task: "Contract test rate_limit_exceeded in tests/contract/todoist_labels.test.ts" ``` ### Integration Tests (T020-T023) ```bash # Integration tests can run in parallel - different test scenarios Task: "Integration test label lifecycle in tests/integration/label-workflows.test.ts" Task: "Integration test label and task relationship in tests/integration/label-workflows.test.ts" Task: "Integration test pagination workflow in tests/integration/label-workflows.test.ts" Task: "Integration test shared label operations in tests/integration/label-workflows.test.ts" ``` ### Polish Tasks (T024-T028) ```bash # Polish tasks operate on different files Task: "Update inMemoryTodoistApiService helper in tests/helpers/" Task: "Update mockTodoistApiService helper in tests/helpers/" Task: "Update CLAUDE.md documentation" ``` --- ## Notes - **[P] tasks** = different files, no dependencies, can run in parallel - **TDD Required**: All contract tests (T002-T014) MUST fail before implementation starts - **Commit Strategy**: Commit after each task completion - **Error Handling**: Use existing `handleToolError()` wrapper, no new error classes needed - **Rate Limiting**: Inherited from TodoistApiService, no new code needed - **Caching**: Leverage existing cache infrastructure in `src/services/cache.ts` - **Shared Labels**: Use Sync API commands (already available in `apiService.sync()`) --- ## Validation Checklist *Verify before marking feature complete* - [ ] All 12 contract scenarios pass - [ ] All 4 integration workflows pass - [ ] Unit tests cover validation edge cases - [ ] Manual quickstart.md scenarios validated against real API - [ ] Test coverage ≥80% for label-related code - [ ] Tool appears in MCP tool list when server starts - [ ] No duplicate labels created on name collision - [ ] LABEL_NOT_FOUND error returns proper code - [ ] Pagination works with cursor handling - [ ] Rate limit errors include retry_after field

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shayonpal/mcp-todoist'

If you have feedback or need assistance with the MCP directory API, please join our Discord server