Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
The Jira MCP server has functional tool definitions with reasonable schema completeness, but suffers from inconsistent description quality, missing parameter-level constraints, and several composition issues. 5 of 7 tools have documented input schemas with proper typing, but descriptions are uneven in quality and actionability. Error handling exists but is generic rather than recovery-focused. The server follows basic tool patterns but misses several production-grade practices from the 54 Agentic Tool Patterns.
Explicitly initializes the connection to the Jira instance using configured credentials. Useful to call first if other tools report connection errors. Returns the connection status and authentication method used.
Parameter constraints missing: 'fields' and 'expand' accept free-form lists with no documented valid values or format guidance. LLMs cannot infer which Jira fields are valid (created, updated, customfield_10001, etc.). This invites hallucinated field names.
Generic error handling: Tools return {'error': 'message'} or {'error': 'message', 'success': false} without recovery guidance. Errors like 'Failed to get issue PROJ-123: <exception>' do not tell the LLM whether to retry, ask the user, or call a discovery tool. No error classification (retryable vs user-fixable vs fatal).
Add formal output schemas to all tools. Document return types as JSON Schema (e.g., 'Returns: {issue_key: string, summary: string, status: string, assignee: {name: string, accountId: string}, ...}'). This enables LLMs to plan downstream calls and extract needed fields.
Constrain 'fields' and 'expand' parameters: either provide enums of valid Jira fields (created, updated, summary, description, status, assignee, priority, labels, changelog, etc.) or add a discovery tool (list_jira_fields) that returns valid field names. Current free-form lists invite hallucination.
Rewrite error handling to be recovery-focused: (1) Categorize errors: retryable (connection timeout, 429 rate limit) vs user-fixable (invalid field name) vs fatal (auth failure). (2) Include the constraint violated and the LLM's next step. Example: 'Invalid transition "Resolve" for status "In Progress". Available transitions for this issue: ["Close", "Reopen"]. Call jira_get_transitions to see all options.'
Add tool annotations (readOnlyHint, destructiveHint) to guide MCP clients. Mark jira_client_init, jira_get_issue, jira_get_batch_issues, jira_get_transitions, jira_download_attachments with readOnlyHint=true. Mark jira_update_issue and jira_transition_issue with destructiveHint=true and idempotentHint=false.
Clarify the boundary between jira_update_issue and jira_transition_issue in their descriptions. Suggest: 'Use jira_update_issue for field-level changes (summary, assignee, priority, labels). Use jira_transition_issue to change status and provide resolution. Both can add comments and update custom fields, but transition may require a resolution_name field depending on the target status.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Score history
Overall score trend
↑ 10 points across a rubric change (v1 → v2)
49/100
Scored
Grade
Overall
Spec posture
Rubric
2026-09-22
F
49
<=2025-11-25
v2
2026-03-09
F
39
-
v1
jira_update_issue
writeauthsource verified72/100
Updates fields of an existing Jira issue. Can also add a comment.
Missing output schema documentation: Tool responses are inferred from code (dict, list) but no formal output schemas are provided in tool definitions. The LLM cannot plan downstream tool calls (e.g., what fields does get_issue return? What structure do transitions have?). No pagination or result limiting documented despite jira_get_batch_issues returning a list.
Inconsistent parameter naming for mutable state: 'priority_name', 'assignee_name' imply the name field, but 'labels' is a direct list. This inconsistency forces the LLM to reason about field types. Additionally, 'assignee_name' accepts 'null' as a string, which is ambiguous, should it be a null type, an empty string, or the literal string 'null'?
Description brevity and vagueness: jira_download_attachments description is only 86 characters and lacks actionable context ('Downloads all attachments...' tells the LLM WHAT but not WHEN or WHY to use it vs other tools). jira_get_transitions (54 chars) is similarly sparse.
Composition issue: jira_update_issue and jira_transition_issue both accept 'custom_fields' and 'comment' parameters. This creates redundancy and ambiguity, when should the LLM use update vs transition? Transition typically changes status and may require resolution; update changes other fields. The descriptions do not clarify this boundary.
No dry-run or confirmation pattern for destructive/state-changing operations: jira_update_issue and jira_transition_issue modify state without a preview or confirmation step. Agents can accidentally transition issues or update fields without user approval. Pattern: confirmation-request.
No result limiting or pagination for jira_get_batch_issues: The tool accepts an unbounded list of issue_keys and returns all issues without documented limits. If an LLM calls this with 100+ keys, the response could explode the context window. No max_results or pagination documented.
Missing tool annotation hints: No tool has idempotentHint, readOnlyHint, or destructiveHint metadata. This prevents MCP clients from inferring whether a tool is safe to retry (idempotent) or modifies state (destructive). jira_client_init, jira_get_issue, jira_get_batch_issues, jira_get_transitions, and jira_download_attachments should be marked readonly.
Add parameter constraints: (1) assignee_name should accept null explicitly (not the string 'null'). (2) priority_name should list valid values (High, Medium, Low) or reference Jira instance config. (3) transition should validate against available transitions from jira_get_transitions. (4) custom_fields should document the field ID format (customfield_XXXXX).
Implement result limiting for jira_get_batch_issues: cap at 50 issues per call and document this in the description. Add a 'limit' parameter (default 50, max 100) or return a 'next_batch_keys' field for pagination if more than 50 items are requested.
Add a dry-run or preview mode for jira_update_issue and jira_transition_issue: Either (a) add a 'dry_run' parameter that returns the intended changes without executing, or (b) return a confirmation prompt via MRTR (Multi Round-Trip Request) with result.type='input_required' asking the user to approve the change before committing.
Expand tool descriptions from current 50-150 chars to 100-250 chars. Include: WHAT it does, WHEN to use it (vs similar tools), what it requires, and what common errors mean. Example: 'Retrieves a single Jira issue by key (e.g., PROJ-123). Returns issue details including summary, description, status, assignee, and custom fields. Use jira_get_batch_issues for multiple issues. Use jira_get_transitions to see available status changes. Returns error if issue not found (404), call jira_search_issues if you have a partial key or need to filter by other criteria.'
Add a discovery tool: jira_search_issues(query, max_results=20) to help LLMs find issues by text, status, assignee, or label. This reduces guessing on issue keys and enables more flexible workflows.
Document parameter relationships. For example, in jira_transition_issue, resolution_name is required for certain target statuses (Done, Resolved) but not others. State: 'If transitioning to a "Done" or "Resolved" status, resolution_name is required (e.g., "Fixed", "Won\'t Fix", "Duplicate"). Call jira_get_transitions first to see which resolutions are required for your target status.'
Validate inputs early in tools and return structured error objects. Replace generic 'Failed to get issue' with: '{"error": {"code": "ISSUE_NOT_FOUND", "message": "Issue PROJ-123 not found.", "suggestions": ["Check the issue key (case-sensitive)", "Call jira_search_issues() to find issues by text or status"]}, "success": false}'.
Document target_dir behavior in jira_download_attachments. What if the directory doesn't exist? What if attachment names conflict? Clarify: 'Creates target_dir if it does not exist. If an attachment name already exists, appends a numeric suffix (e.g., file_1.pdf). Returns a summary: {"issue_key": "PROJ-123", "downloaded_count": 3, "files": ["file1.pdf", "image1.png", "doc1.docx"], "total_size_bytes": 5242880}'.