The server defines 26 tools with reasonable naming and mostly complete schemas. However, there are significant gaps: (1) parameter descriptions are present but sparse (often single phrases), lacking guidance on constraints, valid ranges, and format expectations; (2) no output schemas are documented for any tool, forcing LLMs to infer result structure; (3) error handling is basic console logging with no recovery guidance; (4) descriptions are generally 50 - 100 characters but lack WHEN/WHY context; (5) tool descriptions do not explicitly state whether operations are destructive or reversible, despite having destructive/write/reversible tools; (6) no tool annotations (destructiveHint, readOnlyHint, idempotentHint) in the MCP tool definitions to signal operation side effects; (7) parameters like 'include', 'sort', 'status_id' accept open-ended strings with no enum constraints, inviting hallucinated values. The server covers a broad API surface (26 tools across issues, projects, time entries, users) and uses proper verb_noun naming throughout, which is a strength. However, descriptions read more as API documentation than LLM-optimized guidance.
Adds a watcher to an issue
Archives a project
Creates a new issue
Creates a new project
Creates a new time entry for an issue
Creates a new time entry for a project
Creates a new user
Deletes an existing issue
No output schemas documented for any of the 26 tools. LLMs cannot determine what fields to expect in responses, forcing them to infer structure and increasing errors when chaining tools. For example, list_issues returns paginated results but LLMs do not know if the response contains 'total', 'count', 'offset', 'issues', or 'data'.
Parameter descriptions are minimal and lack constraint guidance. Parameters like 'sort', 'include', 'status_id', 'tracker_id' accept open-ended values with no enum, format, or valid-value list. For example, status_id accepts number|string but the description does not state whether it should be 'open', '1', or 'closed'. This invites LLM hallucination of invalid values.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 53 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 36 | - | v1 |
Deletes a project
Deletes a time entry
Deletes a user
Gets a specific issue by ID
Lists issues with pagination and filters
Lists allowed statuses for project issues
Lists projects with pagination and filters
Lists time entries with pagination and filters
Lists users with pagination
Removes a watcher from an issue
Gets a specific project by ID or identifier
Gets a specific time entry by ID
Gets a specific user by ID
Unarchives a project
Updates an existing issue
Updates an existing project
Updates an existing time entry
Updates an existing user
Tool descriptions do not explicitly signal whether operations are destructive, reversible, or read-only. While the provided metadata labels tools as READ_ONLY, WRITE, REVERSIBLE, or DESTRUCTIVE, these signals are not carried into the MCP tool definitions themselves. MCP tool annotations (destructiveHint, readOnlyHint, idempotentHint) are absent, preventing the LLM and client from knowing at a glance which operations are safe to retry or require confirmation.
Error handling in handlers (src/handlers/index.ts) returns generic error messages with no recovery guidance. A 500 error or 'Unknown tool' response gives the LLM nothing actionable. For example, if a lookup fails, the response should suggest available alternatives or next steps, not just return the error text.
Tool descriptions lack context on WHEN and WHY to use them. Descriptions like 'Lists issues with pagination and filters' and 'Creates a new issue' are functional but do not explain the use case, dependencies, or relationship to other tools. For example, 'Create a new issue in a project. If you only have the project name, call search_projects() first to retrieve the project_id.' would guide the LLM.
Parameters like 'custom_fields', 'watcher_user_ids' are documented as optional arrays but no structure is given for array elements. Are custom_fields objects with 'id' and 'value' keys? Does watcher_user_ids accept numbers or strings? This ambiguity forces LLMs to guess.
Parameters with type union (e.g. status_id: number|string, assigned_to_id: number|string, id: string|number) lack clear guidance on which form to use in which context. The description 'Filter by status ID (or \'open\', \'closed\', \'*\')' contains example values, LLMs tend to reuse these literally rather than interpret them. Should use formal enum/pattern constraints instead.
No minimum/maximum bounds on numeric pagination parameters (limit, offset). An LLM could pass limit=1000000 or offset=999999999, causing DoS or timeout. Descriptions should state 'limit: 1 - 100 (default 10)' and 'offset: 0 - 999999 (0-indexed)'.