TimeCard Recording System MCP Tools - provides tools for managing timecards, including getting projects, activities, timesheets, and saving timecard entries
TimeCard MCP has 6 tools with complete input schemas and descriptions. However, several critical gaps reduce confidence: (1) output schemas are NOT documented, tool descriptions state what data comes back informally, but JSON Schema output structures are absent, forcing LLMs to infer structure; (2) error handling is minimal, tools throw generic Error() strings with no recovery guidance or categorization; (3) tool composition is acceptable but timecard_save is complex and requires multi-step setup that isn't automated; (4) descriptions are good (100-300 chars) but lack explicit dependency hints for the workflow; (5) parameters are well-typed with proper constraints (entry_index 0-9, date format YYYY-MM-DD) and descriptions, but some edge cases (e.g., 'Notes cannot contain special characters') are buried in description prose rather than validated server-side with clear errors. Naming is clear and verb-driven (get_, save), which is strong. Tools are read-only except timecard_save, which reduces but does not eliminate risk.
Get list of activities for a specific project. Returns activity id, name, and value. The 'value' field (format: "bottom$uid$pid$progress") is the activity_value needed by timecard_save's entries parameter.
Get list of available projects. Returns project id and name. Use the project id with timecard_get_activities to get activity options, and with timecard_save to set entries.
Get summary statistics for the current timesheet week
Get timesheet data for a specific week. Read-only, no side effects. Returns for each entry: - daily_hours: Hours worked each day (monday-saturday) - daily_status: Approval status each day (draft/submitted/approved/rejected) - daily_notes: Notes for each day Status values: - draft: Saved but not submitted - submitted: Submitted for approval - approved: Approved by manager - rejected: Rejected by manager This retrieves SAVED data from the server. Use timecard_save to make changes.
Atomic save: apply entries, hours, and notes to a specific week in one operation. This tool fetches the target week's page, reconstructs the full form state, applies your changes on top, and POSTs to the server — all in a single call. No prior setup needed other than authentication (handled automatically). Parameters: - date (REQUIRED): YYYY-MM-DD — any date in the target week. Determines which week to save to. - entries: Set project/activity for row slots. Get activity_value from timecard_get_activities. - hours: Set hours for specific days. Use date in YYYY-MM-DD format. - notes: Set notes for specific days. Use date in YYYY-MM-DD format. All dates in hours/notes must fall within the same week as the top-level date. ⚠️ WORKFLOW: 1. timecard_get_timesheet(date) — view current data 2. timecard_get_activities(project_id) — get activity_value for entries 3. timecard_save({ — atomic save date: "2026-03-02", entries: [{ entry_index: 0, project_id: "17647", activity_value: "true$9$17647$100" }], hours: [ { entry_index: 0, date: "2026-03-02", hours: 8.0 }, { entry_index: 0, date: "2026-03-03", hours: 8.0 } ], notes: [ { entry_index: 0, date: "2026-03-02", note: "Development" } ] }) NOTE: Only 'save' (draft) is supported. 'submit' (for approval) is strictly prohibited. WARNING: Notes cannot contain special characters: #$%^&*=+{}[]|?'"
Output schemas are not documented for ANY tool. Tool descriptions explain what data is returned informally (e.g., 'Returns project id and name', 'Returns for each entry: daily_hours, daily_status, daily_notes'), but no JSON Schema output structures are defined. LLMs cannot reliably infer and parse response structures, forcing runtime trial-and-error.
timecard_get_summary description is critically short (45 characters) and uninformative. 'Get summary statistics for the current timesheet week' tells LLM nothing about what statistics are included, how they differ from timecard_get_timesheet, or what structure is returned. LLM cannot determine when to call this tool.
Error handling is absent. Tools throw generic Error('message') with no recovery guidance, categorization, or actionable next steps. Example: 'Failed to get activities for project X' gives LLM no way to recover. Should include: is this retryable? Should I try a different project_id? Is auth expired?
Inferred effective spec: 2026-07-28+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 66 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 13 | - | v1 |
Get TimeCard MCP version information. Returns: - commit: Git commit hash (e.g., "801fd99" or "801fd99-dirty" if has uncommitted changes) - branch: Git branch name (e.g., "v2-batch-operations") - buildDate: ISO timestamp when the MCP was built Use this to verify which version of TimeCard MCP is running.
Validation constraints in description are not enforced in schema. timecard_save notes parameter states 'cannot contain special characters: #$%^&*=+{}[]|?'"' in prose, but the schema has no regex pattern constraint. This relies on client-side compliance, server should validate and return actionable error (e.g., 'Invalid note: contains "#". Allowed characters: [a-zA-Z0-9 ]').
Multi-step workflow is complex and requires manual orchestration. Users must: (1) call timecard_get_timesheet, (2) call timecard_get_activities for each project, (3) extract activity_value, (4) call timecard_save with correct entry_index/date mapping. This is error-prone. Consider offering a higher-level 'set_timesheet_entry' tool that accepts project_name, activity_name, date, hours and does the lookups internally.
timecard_save output schema is undocumented. Unclear what is returned on success: boolean? Updated timesheet data? Error details on partial failure (e.g., entry 0 saved, entry 1 rejected)? Without output schema, LLM cannot plan follow-up calls.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) are present in any tool definition. MCP 2026-07-28 spec expects tools to declare their intent. timecard_save should have destructiveHint=true (modifies state), while all others should have readOnlyHint=true.